[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