[lxc-devel] [lxd/master] Fix VM image import/export

stgraber on Github lxc-bot at linuxcontainers.org
Tue Nov 26 17:51:31 UTC 2019


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/20191126/5aec0a34/attachment-0001.bin>
-------------- next part --------------
From 5c5df500b40acfcea087041b3387586aa0c1f4a7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 26 Nov 2019 12:02:58 -0500
Subject: [PATCH 1/7] lxd/images: Fix image pruning with 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/images.go | 24 ++++++++++++++++++++++++
 lxd/images.go    |  2 +-
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/lxd/db/images.go b/lxd/db/images.go
index 2db6855437..a3043e2677 100644
--- a/lxd/db/images.go
+++ b/lxd/db/images.go
@@ -22,6 +22,30 @@ var ImageSourceProtocol = map[int]string{
 	2: "simplestreams",
 }
 
+// ImagesGetLocal returns the names of all local images.
+func (c *Cluster) ImagesGetLocal() ([]string, error) {
+	q := `
+SELECT images.fingerprint
+  FROM images_nodes
+  JOIN images ON images.id = images_nodes.image_id
+ WHERE node_id = ?
+`
+	var fp string
+	inargs := []interface{}{c.nodeID}
+	outfmt := []interface{}{fp}
+	dbResults, err := queryScan(c.db, q, inargs, outfmt)
+	if err != nil {
+		return []string{}, err
+	}
+
+	results := []string{}
+	for _, r := range dbResults {
+		results = append(results, r[0].(string))
+	}
+
+	return results, nil
+}
+
 // ImagesGet returns the names of all images (optionally only the public ones).
 func (c *Cluster) ImagesGet(project string, public bool) ([]string, error) {
 	err := c.Transaction(func(tx *ClusterTx) error {
diff --git a/lxd/images.go b/lxd/images.go
index cf989c4011..d848430086 100644
--- a/lxd/images.go
+++ b/lxd/images.go
@@ -1244,7 +1244,7 @@ func pruneExpiredImagesTask(d *Daemon) (task.Func, task.Schedule) {
 func pruneLeftoverImages(d *Daemon) {
 	opRun := func(op *operations.Operation) error {
 		// Get all images
-		images, err := d.cluster.ImagesGet("default", false)
+		images, err := d.cluster.ImagesGetLocal()
 		if err != nil {
 			return errors.Wrap(err, "Unable to retrieve the list of images")
 		}

From f7570e32d492bb716994c87fc291c77befecffd3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 26 Nov 2019 12:34:01 -0500
Subject: [PATCH 2/7] lxd/images: Fix VM image export
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/images.go | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/lxd/images.go b/lxd/images.go
index d848430086..ce41f0975e 100644
--- a/lxd/images.go
+++ b/lxd/images.go
@@ -1953,7 +1953,11 @@ func imageExport(d *Daemon, r *http.Request) response.Response {
 		}
 		filename = fmt.Sprintf("%s%s", imgInfo.Fingerprint, ext)
 
-		files[1].Identifier = "rootfs"
+		if imgInfo.Type == "virtual-machine" {
+			files[1].Identifier = "rootfs.img"
+		} else {
+			files[1].Identifier = "rootfs"
+		}
 		files[1].Path = rootfsPath
 		files[1].Filename = filename
 

From 8109ecbcde60714ec0348500953cad0bdd027195 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 26 Nov 2019 12:34:10 -0500
Subject: [PATCH 3/7] client: Fix VM image export
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>
---
 client/lxd_images.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/client/lxd_images.go b/client/lxd_images.go
index 519bd9f428..71cf9e8f63 100644
--- a/client/lxd_images.go
+++ b/client/lxd_images.go
@@ -226,7 +226,7 @@ func lxdDownloadImage(fingerprint string, uri string, userAgent string, client *
 			return nil, err
 		}
 
-		if part.FormName() != "rootfs" {
+		if !shared.StringInSlice(part.FormName(), []string{"rootfs", "rootfs.img"}) {
 			return nil, fmt.Errorf("Invalid multipart image")
 		}
 

From 464514e8b5f3a15809b38d85f5ec7fcdb60b48ec Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 26 Nov 2019 12:36:21 -0500
Subject: [PATCH 4/7] shared: Un-restrict archive.go
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>
---
 shared/{archive_linux.go => archive.go} | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename shared/{archive_linux.go => archive.go} (100%)

diff --git a/shared/archive_linux.go b/shared/archive.go
similarity index 100%
rename from shared/archive_linux.go
rename to shared/archive.go

From 11b34d5208d528303c2b51c75ec5fea0c5ff80c4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 26 Nov 2019 12:47:43 -0500
Subject: [PATCH 5/7] shared: Add qcow2
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>
---
 shared/archive.go | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/shared/archive.go b/shared/archive.go
index a77a09b70a..08b1652138 100644
--- a/shared/archive.go
+++ b/shared/archive.go
@@ -50,8 +50,9 @@ func DetectCompressionFile(f io.ReadSeeker) ([]string, string, []string, error)
 	case bytes.Equal(header[257:262], []byte{'u', 's', 't', 'a', 'r'}):
 		return []string{"-xf"}, ".tar", []string{}, nil
 	case bytes.Equal(header[0:4], []byte{'h', 's', 'q', 's'}):
-		return []string{"-xf"}, ".squashfs",
-			[]string{"sqfs2tar", "--no-skip"}, nil
+		return []string{"-xf"}, ".squashfs", []string{"sqfs2tar", "--no-skip"}, nil
+	case bytes.Equal(header[0:3], []byte{'Q', 'F', 'I'}):
+		return []string{""}, ".qcow2", []string{"qemu-img", "convert", "-O", "raw"}, nil
 	default:
 		return nil, "", nil, fmt.Errorf("Unsupported compression")
 	}

From 40aa10b48adc5bd72e5c02ec2c2eb2d98fab195b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 26 Nov 2019 12:50:03 -0500
Subject: [PATCH 6/7] client: Fix VM image import
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>
---
 client/interfaces.go | 3 +++
 client/lxd_images.go | 6 +++++-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/client/interfaces.go b/client/interfaces.go
index fb954734f9..b034c1b871 100644
--- a/client/interfaces.go
+++ b/client/interfaces.go
@@ -336,6 +336,9 @@ type ImageCreateArgs struct {
 
 	// Progress handler (called with upload progress)
 	ProgressHandler func(progress ioprogress.ProgressData)
+
+	// Type of the image (container or virtual-machine)
+	Type string
 }
 
 // The ImageFileRequest struct is used for an image download request.
diff --git a/client/lxd_images.go b/client/lxd_images.go
index 71cf9e8f63..b46213f0cc 100644
--- a/client/lxd_images.go
+++ b/client/lxd_images.go
@@ -387,7 +387,11 @@ func (r *ProtocolLXD) CreateImage(image api.ImagesPost, args *ImageCreateArgs) (
 		}
 
 		// Rootfs file
-		fw, err = w.CreateFormFile("rootfs", args.RootfsName)
+		if args.Type == "virtual-machine" {
+			fw, err = w.CreateFormFile("rootfs.img", args.RootfsName)
+		} else {
+			fw, err = w.CreateFormFile("rootfs", args.RootfsName)
+		}
 		if err != nil {
 			return nil, err
 		}

From dc67b895d9a7ffc22b280c04d1c41926d192b2e6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 26 Nov 2019 12:50:12 -0500
Subject: [PATCH 7/7] lxc/image: Detect type on import
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>
---
 lxc/image.go | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/lxc/image.go b/lxc/image.go
index 47db1ae9ed..7195093d46 100644
--- a/lxc/image.go
+++ b/lxc/image.go
@@ -726,6 +726,7 @@ func (c *cmdImageImport) Run(cmd *cobra.Command, args []string) error {
 		Quiet:  c.global.flagQuiet,
 	}
 
+	imageType := "container"
 	if strings.HasPrefix(imageFile, "https://") {
 		image.Source = &api.ImagesPostSource{}
 		image.Source.Type = "url"
@@ -734,8 +735,8 @@ func (c *cmdImageImport) Run(cmd *cobra.Command, args []string) error {
 		image.Source.URL = imageFile
 		createArgs = nil
 	} else {
-		var meta io.ReadCloser
-		var rootfs io.ReadCloser
+		var meta *os.File
+		var rootfs *os.File
 
 		// Open meta
 		if shared.IsDir(imageFile) {
@@ -760,6 +761,16 @@ func (c *cmdImageImport) Run(cmd *cobra.Command, args []string) error {
 				return err
 			}
 			defer rootfs.Close()
+
+			_, ext, _, err := shared.DetectCompressionFile(rootfs)
+			if err != nil {
+				return err
+			}
+			rootfs.Seek(0, 0)
+
+			if ext == ".qcow2" {
+				imageType = "virtual-machine"
+			}
 		}
 
 		createArgs = &lxd.ImageCreateArgs{
@@ -768,6 +779,7 @@ func (c *cmdImageImport) Run(cmd *cobra.Command, args []string) error {
 			RootfsFile:      rootfs,
 			RootfsName:      filepath.Base(rootfsFile),
 			ProgressHandler: progress.UpdateProgress,
+			Type:            imageType,
 		}
 		image.Filename = createArgs.MetaName
 	}


More information about the lxc-devel mailing list