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

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) ===
This PR fixes an issue reported at https://discuss.linuxcontainers.org/t/cannot-launch-container-in-a-project-on-ubuntu-20-04-cluster/8744 where if an image is initially download into a project and then the next instance created is on a different node AND a different project then the image wouldn't be transferred from the first node and instance creation would fail.
From 1fbd3a7e1be6ec91ed720ddbb61bfbb751d08c39 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 17 Sep 2020 16:37:19 +0100
Subject: [PATCH 1/4] lxd/instance: Removes image download from cluster node
 from instanceCreateFromImage

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/instance.go | 28 ----------------------------
 1 file changed, 28 deletions(-)

diff --git a/lxd/instance.go b/lxd/instance.go
index e865de0068..e1457534d8 100644
--- a/lxd/instance.go
+++ b/lxd/instance.go
@@ -5,7 +5,6 @@ import (
        "fmt"
        "os"
        "os/exec"
-       "path/filepath"
        "strconv"
        "strings"
        "time"
@@ -15,7 +14,6 @@ import (
        cron "gopkg.in/robfig/cron.v2"
 
        "github.com/flosch/pongo2"
-       "github.com/lxc/lxd/lxd/cluster"
        "github.com/lxc/lxd/lxd/db"
        deviceConfig "github.com/lxc/lxd/lxd/device/config"
        "github.com/lxc/lxd/lxd/instance"
@@ -96,32 +94,6 @@ func instanceCreateFromImage(d *Daemon, args 
db.InstanceArgs, hash string, op *o
                return nil, fmt.Errorf("Requested image's type '%s' doesn't 
match instance type '%s'", imgType, args.Type)
        }
 
-       // Check if the image is available locally or it's on another node.
-       nodeAddress, err := s.Cluster.LocateImage(hash)
-       if err != nil {
-               return nil, errors.Wrapf(err, "Locate image %s in the cluster", 
hash)
-       }
-       if nodeAddress != "" {
-               // The image is available from another node, let's try to 
import it.
-               logger.Debugf("Transferring image %s from node %s", hash, 
nodeAddress)
-               client, err := cluster.Connect(nodeAddress, 
d.endpoints.NetworkCert(), false)
-               if err != nil {
-                       return nil, err
-               }
-
-               client = client.UseProject(args.Project)
-
-               err = imageImportFromNode(filepath.Join(d.os.VarDir, "images"), 
client, hash)
-               if err != nil {
-                       return nil, err
-               }
-
-               err = d.cluster.AddImageToLocalNode(args.Project, hash)
-               if err != nil {
-                       return nil, err
-               }
-       }
-
        // Set the "image.*" keys.
        if img.Properties != nil {
                for k, v := range img.Properties {

From fb8a2e6980646e01182f9dd032a5e2238e0cd01a Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 17 Sep 2020 16:37:35 +0100
Subject: [PATCH 2/4] lxd/db/images: Error message uppercase first letter

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

diff --git a/lxd/db/images.go b/lxd/db/images.go
index 37f676d151..96346a26ae 100644
--- a/lxd/db/images.go
+++ b/lxd/db/images.go
@@ -610,7 +610,7 @@ WHERE images.fingerprint = ?
                return "", err
        }
        if len(addresses) == 0 {
-               return "", fmt.Errorf("image not available on any online node")
+               return "", fmt.Errorf("Image not available on any online node")
        }
 
        for _, address := range addresses {

From a3345b5d651cb7f9a7abab9e4a959242f4996a80 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 17 Sep 2020 16:38:08 +0100
Subject: [PATCH 3/4] lxd/daemon/images: Error quoting

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

diff --git a/lxd/daemon_images.go b/lxd/daemon_images.go
index 5d71a690d8..a7ead3c82c 100644
--- a/lxd/daemon_images.go
+++ b/lxd/daemon_images.go
@@ -155,20 +155,20 @@ func (d *Daemon) ImageDownload(op *operations.Operation, 
server string, protocol
                }
 
                if shared.Int64InSlice(poolID, poolIDs) {
-                       logger.Debugf("Image already exists on storage pool 
\"%s\"", storagePool)
+                       logger.Debugf("Image already exists on storage pool 
%q", storagePool)
                        return info, nil
                }
 
                // Import the image in the pool
-               logger.Debugf("Image does not exist on storage pool \"%s\"", 
storagePool)
+               logger.Debugf("Image does not exist on storage pool %q", 
storagePool)
 
                err = imageCreateInPool(d, info, storagePool)
                if err != nil {
-                       logger.Debugf("Failed to create image on storage pool 
\"%s\": %s", storagePool, err)
+                       logger.Debugf("Failed to create image on storage pool 
%q: %v", storagePool, err)
                        return nil, err
                }
 
-               logger.Debugf("Created image on storage pool \"%s\"", 
storagePool)
+               logger.Debugf("Created image on storage pool %q", storagePool)
                return info, nil
        }
 
@@ -368,7 +368,7 @@ func (d *Daemon) ImageDownload(op *operations.Operation, 
server string, protocol
                }
 
                if raw.StatusCode != http.StatusOK {
-                       return nil, fmt.Errorf("Unable to fetch %s: %s", 
server, raw.Status)
+                       return nil, fmt.Errorf("Unable to fetch %q: %s", 
server, raw.Status)
                }
 
                // Progress handler
@@ -402,7 +402,7 @@ func (d *Daemon) ImageDownload(op *operations.Operation, 
server string, protocol
                // Validate hash
                result := fmt.Sprintf("%x", sha256.Sum(nil))
                if result != fp {
-                       return nil, fmt.Errorf("Hash mismatch for %s: %s != 
%s", server, result, fp)
+                       return nil, fmt.Errorf("Hash mismatch for %q: %s != 
%s", server, result, fp)
                }
 
                // Parse the image

From c003d0140e9d2501b9e8f666afb8394dde139c2b Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 17 Sep 2020 16:38:47 +0100
Subject: [PATCH 4/4] lxd/daemon/image: Moves logic to download image from
 another cluster node into ImageDownload

It seems more appropriate to be here, and also allows us to check earlier 
whether the image is available on another node, before we create the DB entry 
for our own node (which skews the subsequent locate results).

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/daemon_images.go | 45 ++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 41 insertions(+), 4 deletions(-)

diff --git a/lxd/daemon_images.go b/lxd/daemon_images.go
index a7ead3c82c..6cc97faf68 100644
--- a/lxd/daemon_images.go
+++ b/lxd/daemon_images.go
@@ -10,6 +10,8 @@ import (
        "sync"
        "time"
 
+       "github.com/pkg/errors"
+
        "github.com/lxc/lxd/client"
        "github.com/lxc/lxd/lxd/cluster"
        "github.com/lxc/lxd/lxd/db"
@@ -106,12 +108,25 @@ func (d *Daemon) ImageDownload(op *operations.Operation, 
server string, protocol
                }
        }
 
-       // Check if the image already exists in this project (partial hash 
match)
+       // Check if the image already exists in this project (partial hash 
match).
+       nodeAddress := ""
        _, imgInfo, err := d.cluster.GetImage(project, fp, false)
-       if err == db.ErrNoSuchObject {
+       if err == nil {
+               // Check if the image is available locally or it's on another 
node.
+               nodeAddress, err = 
d.State().Cluster.LocateImage(imgInfo.Fingerprint)
+               if err != nil {
+                       return nil, errors.Wrapf(err, "Locate image %q in the 
cluster", imgInfo.Fingerprint)
+               }
+       } else if err == db.ErrNoSuchObject {
                // Check if the image already exists in some other project.
                _, imgInfo, err = d.cluster.GetImageFromAnyProject(fp)
                if err == nil {
+                       // Check if the image is available locally or it's on 
another node.
+                       nodeAddress, err = 
d.State().Cluster.LocateImage(imgInfo.Fingerprint)
+                       if err != nil {
+                               return nil, errors.Wrapf(err, "Locate image %q 
in the cluster", imgInfo.Fingerprint)
+                       }
+
                        // We just need to insert the database data, no actual 
download necessary.
                        err = d.cluster.CreateImage(
                                project, imgInfo.Fingerprint, imgInfo.Filename, 
imgInfo.Size, false,
@@ -126,6 +141,7 @@ func (d *Daemon) ImageDownload(op *operations.Operation, 
server string, protocol
                        if err != nil {
                                return nil, err
                        }
+
                        err = d.cluster.CreateImageSource(id, server, protocol, 
certificate, alias)
                        if err != nil {
                                return nil, err
@@ -133,10 +149,31 @@ func (d *Daemon) ImageDownload(op *operations.Operation, 
server string, protocol
                }
        }
 
-       if err == nil {
-               logger.Debug("Image already exists in the db", log.Ctx{"image": 
fp})
+       if imgInfo != nil {
+               logger.Debugf("Image %q already exists in the DB", fp)
                info = imgInfo
 
+               if nodeAddress != "" {
+                       // The image is available from another node, let's try 
to import it.
+                       logger.Debugf("Transferring image %q from node %q", 
info.Fingerprint, nodeAddress)
+                       client, err := cluster.Connect(nodeAddress, 
d.endpoints.NetworkCert(), false)
+                       if err != nil {
+                               return nil, err
+                       }
+
+                       client = client.UseProject(project)
+
+                       err = imageImportFromNode(filepath.Join(d.os.VarDir, 
"images"), client, info.Fingerprint)
+                       if err != nil {
+                               return nil, errors.Wrapf(err, "Failed importing 
from node %q", nodeAddress)
+                       }
+
+                       err = d.cluster.AddImageToLocalNode(project, 
info.Fingerprint)
+                       if err != nil {
+                               return nil, errors.Wrapf(err, "Failed adding 
image to local node")
+                       }
+               }
+
                // If not requested in a particular pool, we're done.
                if storagePool == "" {
                        return info, nil
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to