[lxc-devel] [lxd/master] Bugfix and minor improvements

stgraber on Github lxc-bot at linuxcontainers.org
Mon Aug 15 21:34:35 UTC 2016


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/20160815/b7d2945f/attachment.bin>
-------------- next part --------------
From 1342bd8261349626122da0f3cf9663edaf952064 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Mon, 15 Aug 2016 15:10:35 -0400
Subject: [PATCH 1/5] Report download progress on 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.go    | 39 ++++++++++++++++++++++++++++++++++++++-
 lxc/image.go |  6 +++++-
 po/lxd.pot   | 37 +++++++++++++++++++++----------------
 3 files changed, 64 insertions(+), 18 deletions(-)

diff --git a/client.go b/client.go
index 84f9558..17dc0a6 100644
--- a/client.go
+++ b/client.go
@@ -886,7 +886,7 @@ func (c *Client) ExportImage(image string, target string) (string, error) {
 	return destpath, nil
 }
 
-func (c *Client) PostImageURL(imageFile string, public bool, aliases []string) (string, error) {
+func (c *Client) PostImageURL(imageFile string, public bool, aliases []string, progressHandler func(progress string)) (string, error) {
 	if c.Remote.Public {
 		return "", fmt.Errorf("This function isn't supported by public remotes.")
 	}
@@ -897,11 +897,48 @@ func (c *Client) PostImageURL(imageFile string, public bool, aliases []string) (
 		"url":  imageFile}
 	body := shared.Jmap{"public": public, "source": source}
 
+	operation := ""
+	handler := func(msg interface{}) {
+		if msg == nil {
+			return
+		}
+
+		event := msg.(map[string]interface{})
+		if event["type"].(string) != "operation" {
+			return
+		}
+
+		if event["metadata"] == nil {
+			return
+		}
+
+		md := event["metadata"].(map[string]interface{})
+		if !strings.HasSuffix(operation, md["id"].(string)) {
+			return
+		}
+
+		if md["metadata"] == nil {
+			return
+		}
+
+		opMd := md["metadata"].(map[string]interface{})
+		_, ok := opMd["download_progress"]
+		if ok {
+			progressHandler(opMd["download_progress"].(string))
+		}
+	}
+
+	if progressHandler != nil {
+		go c.Monitor([]string{"operation"}, handler)
+	}
+
 	resp, err := c.post("images", body, Async)
 	if err != nil {
 		return "", err
 	}
 
+	operation = resp.Operation
+
 	op, err := c.WaitFor(resp.Operation)
 	if err != nil {
 		return "", err
diff --git a/lxc/image.go b/lxc/image.go
index d878f22..1016852 100644
--- a/lxc/image.go
+++ b/lxc/image.go
@@ -424,7 +424,11 @@ func (c *imageCmd) run(config *lxd.Config, args []string) error {
 		}
 
 		if strings.HasPrefix(imageFile, "https://") {
-			fingerprint, err = d.PostImageURL(imageFile, c.publicImage, c.addAliases)
+			progressHandler := func(progress string) {
+				fmt.Printf(i18n.G("Importing the image: %s")+"\r", progress)
+			}
+
+			fingerprint, err = d.PostImageURL(imageFile, c.publicImage, c.addAliases, progressHandler)
 		} else if strings.HasPrefix(imageFile, "http://") {
 			return fmt.Errorf(i18n.G("Only https:// is supported for remote image import."))
 		} else {
diff --git a/po/lxd.pot b/po/lxd.pot
index b334194..dc1d89e 100644
--- a/po/lxd.pot
+++ b/po/lxd.pot
@@ -7,7 +7,7 @@
 msgid   ""
 msgstr  "Project-Id-Version: lxd\n"
         "Report-Msgid-Bugs-To: lxc-devel at lists.linuxcontainers.org\n"
-        "POT-Creation-Date: 2016-07-26 14:46+0200\n"
+        "POT-Creation-Date: 2016-08-15 15:10-0400\n"
         "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
         "Last-Translator: FULL NAME <EMAIL at ADDRESS>\n"
         "Language-Team: LANGUAGE <LL at li.org>\n"
@@ -77,7 +77,7 @@ msgid   "### This is a yaml representation of the profile.\n"
         "### Note that the name is shown but cannot be changed"
 msgstr  ""
 
-#: lxc/image.go:612
+#: lxc/image.go:616
 #, c-format
 msgid   "%s (%d more)"
 msgstr  ""
@@ -90,11 +90,11 @@ msgstr  ""
 msgid   "(none)"
 msgstr  ""
 
-#: lxc/image.go:633 lxc/image.go:675
+#: lxc/image.go:637 lxc/image.go:679
 msgid   "ALIAS"
 msgstr  ""
 
-#: lxc/image.go:637
+#: lxc/image.go:641
 msgid   "ARCH"
 msgstr  ""
 
@@ -187,7 +187,7 @@ msgstr  ""
 msgid   "Config key/value to apply to the new container"
 msgstr  ""
 
-#: lxc/config.go:531 lxc/config.go:596 lxc/image.go:729 lxc/profile.go:218
+#: lxc/config.go:531 lxc/config.go:596 lxc/image.go:733 lxc/profile.go:218
 #, c-format
 msgid   "Config parsing error: %s"
 msgstr  ""
@@ -259,7 +259,7 @@ msgstr  ""
 msgid   "Creating the container"
 msgstr  ""
 
-#: lxc/image.go:636 lxc/image.go:677
+#: lxc/image.go:640 lxc/image.go:681
 msgid   "DESCRIPTION"
 msgstr  ""
 
@@ -326,7 +326,7 @@ msgstr  ""
 msgid   "Expires: never"
 msgstr  ""
 
-#: lxc/config.go:273 lxc/image.go:634 lxc/image.go:676
+#: lxc/config.go:273 lxc/image.go:638 lxc/image.go:680
 msgid   "FINGERPRINT"
 msgstr  ""
 
@@ -393,11 +393,16 @@ msgstr  ""
 msgid   "Image copied successfully!"
 msgstr  ""
 
-#: lxc/image.go:437
+#: lxc/image.go:441
 #, c-format
 msgid   "Image imported with fingerprint: %s"
 msgstr  ""
 
+#: lxc/image.go:428
+#, c-format
+msgid   "Importing the image: %s"
+msgstr  ""
+
 #: lxc/init.go:73
 msgid   "Initialize a container from a particular image.\n"
         "\n"
@@ -781,7 +786,7 @@ msgstr  ""
 msgid   "Only https URLs are supported for simplestreams"
 msgstr  ""
 
-#: lxc/image.go:429
+#: lxc/image.go:433
 msgid   "Only https:// is supported for remote image import."
 msgstr  ""
 
@@ -789,7 +794,7 @@ msgstr  ""
 msgid   "Options:"
 msgstr  ""
 
-#: lxc/image.go:533
+#: lxc/image.go:537
 #, c-format
 msgid   "Output is in %s"
 msgstr  ""
@@ -814,7 +819,7 @@ msgstr  ""
 msgid   "PROTOCOL"
 msgstr  ""
 
-#: lxc/image.go:635 lxc/remote.go:379
+#: lxc/image.go:639 lxc/remote.go:379
 msgid   "PUBLIC"
 msgstr  ""
 
@@ -853,7 +858,7 @@ msgstr  ""
 msgid   "Press enter to open the editor again"
 msgstr  ""
 
-#: lxc/config.go:532 lxc/config.go:597 lxc/image.go:730
+#: lxc/config.go:532 lxc/config.go:597 lxc/image.go:734
 msgid   "Press enter to start the editor again"
 msgstr  ""
 
@@ -955,7 +960,7 @@ msgstr  ""
 msgid   "Retrieving image: %s"
 msgstr  ""
 
-#: lxc/image.go:638
+#: lxc/image.go:642
 msgid   "SIZE"
 msgstr  ""
 
@@ -1122,7 +1127,7 @@ msgstr  ""
 msgid   "Type: persistent"
 msgstr  ""
 
-#: lxc/image.go:639
+#: lxc/image.go:643
 msgid   "UPLOAD DATE"
 msgstr  ""
 
@@ -1218,7 +1223,7 @@ msgstr  ""
 msgid   "got bad version"
 msgstr  ""
 
-#: lxc/image.go:336 lxc/image.go:615
+#: lxc/image.go:336 lxc/image.go:619
 msgid   "no"
 msgstr  ""
 
@@ -1276,7 +1281,7 @@ msgstr  ""
 msgid   "wrong number of subcommand arguments"
 msgstr  ""
 
-#: lxc/delete.go:45 lxc/image.go:338 lxc/image.go:619
+#: lxc/delete.go:45 lxc/image.go:338 lxc/image.go:623
 msgid   "yes"
 msgstr  ""
 

From ff4b6590873744613a376c39fb2403d72f12edf0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Mon, 15 Aug 2016 15:20:24 -0400
Subject: [PATCH 2/5] Fix image import from URL
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

 - Support URLs containing an equals signs
 - Actually respect the provided properties

Closes #2272

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 client.go    | 14 ++++++++++++--
 lxc/image.go |  5 +++--
 2 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/client.go b/client.go
index 17dc0a6..f7a6c53 100644
--- a/client.go
+++ b/client.go
@@ -886,16 +886,26 @@ func (c *Client) ExportImage(image string, target string) (string, error) {
 	return destpath, nil
 }
 
-func (c *Client) PostImageURL(imageFile string, public bool, aliases []string, progressHandler func(progress string)) (string, error) {
+func (c *Client) PostImageURL(imageFile string, properties []string, public bool, aliases []string, progressHandler func(progress string)) (string, error) {
 	if c.Remote.Public {
 		return "", fmt.Errorf("This function isn't supported by public remotes.")
 	}
 
+	imgProperties := map[string]string{}
+	for _, entry := range properties {
+		fields := strings.SplitN(entry, "=", 2)
+		if len(fields) != 2 {
+			return "", fmt.Errorf("Invalid image property: %s", entry)
+		}
+
+		imgProperties[fields[0]] = fields[1]
+	}
+
 	source := shared.Jmap{
 		"type": "url",
 		"mode": "pull",
 		"url":  imageFile}
-	body := shared.Jmap{"public": public, "source": source}
+	body := shared.Jmap{"public": public, "properties": imgProperties, "source": source}
 
 	operation := ""
 	handler := func(msg interface{}) {
diff --git a/lxc/image.go b/lxc/image.go
index 1016852..488adab 100644
--- a/lxc/image.go
+++ b/lxc/image.go
@@ -408,7 +408,8 @@ func (c *imageCmd) run(config *lxd.Config, args []string) error {
 		}
 
 		if imageFile == "" {
-			return errArgs
+			imageFile = args[1]
+			properties = properties[1:]
 		}
 
 		d, err := lxd.NewClient(config, remote)
@@ -428,7 +429,7 @@ func (c *imageCmd) run(config *lxd.Config, args []string) error {
 				fmt.Printf(i18n.G("Importing the image: %s")+"\r", progress)
 			}
 
-			fingerprint, err = d.PostImageURL(imageFile, c.publicImage, c.addAliases, progressHandler)
+			fingerprint, err = d.PostImageURL(imageFile, properties, c.publicImage, c.addAliases, progressHandler)
 		} else if strings.HasPrefix(imageFile, "http://") {
 			return fmt.Errorf(i18n.G("Only https:// is supported for remote image import."))
 		} else {

From 8181bfca010ba05f7112f1bbc73842a40c05e0b2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Mon, 15 Aug 2016 15:52:11 -0400
Subject: [PATCH 3/5] Allow "lxc copy" to pick a random name
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Closes #2281

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxc/copy.go | 45 ++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 42 insertions(+), 3 deletions(-)

diff --git a/lxc/copy.go b/lxc/copy.go
index 74631c4..e920c76 100644
--- a/lxc/copy.go
+++ b/lxc/copy.go
@@ -38,7 +38,7 @@ func (c *copyCmd) copyContainer(config *lxd.Config, sourceResource string, destR
 		return fmt.Errorf(i18n.G("you must specify a source container name"))
 	}
 
-	if destName == "" {
+	if destName == "" && destResource != "" {
 		destName = sourceName
 	}
 
@@ -104,7 +104,27 @@ func (c *copyCmd) copyContainer(config *lxd.Config, sourceResource string, destR
 			return err
 		}
 
-		return source.WaitForSuccess(cp.Operation)
+		err = source.WaitForSuccess(cp.Operation)
+		if err != nil {
+			return err
+		}
+
+		if destResource == "" {
+			op, err := cp.MetadataAsOperation()
+			if err != nil {
+				return fmt.Errorf(i18n.G("didn't get any affected image, container or snapshot from server"))
+			}
+
+			containers, ok := op.Resources["containers"]
+			if !ok || len(containers) == 0 {
+				return fmt.Errorf(i18n.G("didn't get any affected image, container or snapshot from server"))
+			}
+
+			fields := strings.Split(containers[0], "/")
+			fmt.Printf(i18n.G("Container name is: %s")+"\n", fields[len(fields)-1])
+		}
+
+		return nil
 	}
 
 	dest, err := lxd.NewClient(config, destRemote)
@@ -177,6 +197,21 @@ func (c *copyCmd) copyContainer(config *lxd.Config, sourceResource string, destR
 			return err
 		}
 
+		if destResource == "" {
+			op, err := migration.MetadataAsOperation()
+			if err != nil {
+				return fmt.Errorf(i18n.G("didn't get any affected image, container or snapshot from server"))
+			}
+
+			containers, ok := op.Resources["containers"]
+			if !ok || len(containers) == 0 {
+				return fmt.Errorf(i18n.G("didn't get any affected image, container or snapshot from server"))
+			}
+
+			fields := strings.Split(containers[0], "/")
+			fmt.Printf(i18n.G("Container name is: %s")+"\n", fields[len(fields)-1])
+		}
+
 		return nil
 	}
 
@@ -184,7 +219,7 @@ func (c *copyCmd) copyContainer(config *lxd.Config, sourceResource string, destR
 }
 
 func (c *copyCmd) run(config *lxd.Config, args []string) error {
-	if len(args) != 2 {
+	if len(args) < 1 {
 		return errArgs
 	}
 
@@ -193,5 +228,9 @@ func (c *copyCmd) run(config *lxd.Config, args []string) error {
 		ephem = 1
 	}
 
+	if len(args) < 2 {
+		return c.copyContainer(config, args[0], "", false, ephem)
+	}
+
 	return c.copyContainer(config, args[0], args[1], false, ephem)
 }

From 71945c6192344fcf4b403a8af205b0eef2e1e06d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Mon, 15 Aug 2016 16:11:10 -0400
Subject: [PATCH 4/5] Allow additional profiles and config on copy
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Closes #2282

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxc/copy.go | 20 ++++++++++++++++++--
 po/lxd.pot  | 56 ++++++++++++++++++++++++++++----------------------------
 2 files changed, 46 insertions(+), 30 deletions(-)

diff --git a/lxc/copy.go b/lxc/copy.go
index e920c76..8e07479 100644
--- a/lxc/copy.go
+++ b/lxc/copy.go
@@ -11,7 +11,9 @@ import (
 )
 
 type copyCmd struct {
-	ephem bool
+	profArgs profileList
+	confArgs configList
+	ephem    bool
 }
 
 func (c *copyCmd) showByDefault() bool {
@@ -22,10 +24,14 @@ func (c *copyCmd) usage() string {
 	return i18n.G(
 		`Copy containers within or in between lxd instances.
 
-lxc copy [remote:]<source container> [remote:]<destination container> [--ephemeral|e]`)
+lxc copy [remote:]<source container> [remote:]<destination container> [--ephemeral|e] [--profile|-p <profile>...] [--config|-c <key=value>...]`)
 }
 
 func (c *copyCmd) flags() {
+	gnuflag.Var(&c.confArgs, "config", i18n.G("Config key/value to apply to the new container"))
+	gnuflag.Var(&c.confArgs, "c", i18n.G("Config key/value to apply to the new container"))
+	gnuflag.Var(&c.profArgs, "profile", i18n.G("Profile to apply to the new container"))
+	gnuflag.Var(&c.profArgs, "p", i18n.G("Profile to apply to the new container"))
 	gnuflag.BoolVar(&c.ephem, "ephemeral", false, i18n.G("Ephemeral container"))
 	gnuflag.BoolVar(&c.ephem, "e", false, i18n.G("Ephemeral container"))
 }
@@ -83,6 +89,16 @@ func (c *copyCmd) copyContainer(config *lxd.Config, sourceResource string, destR
 		status.Profiles = result.Profiles
 	}
 
+	if c.profArgs != nil {
+		status.Profiles = append(status.Profiles, c.profArgs...)
+	}
+
+	if configMap != nil {
+		for key, value := range configMap {
+			status.Config[key] = value
+		}
+	}
+
 	baseImage = status.Config["volatile.base_image"]
 
 	if !keepVolatile {
diff --git a/po/lxd.pot b/po/lxd.pot
index dc1d89e..1eadd99 100644
--- a/po/lxd.pot
+++ b/po/lxd.pot
@@ -7,7 +7,7 @@
 msgid   ""
 msgstr  "Project-Id-Version: lxd\n"
         "Report-Msgid-Bugs-To: lxc-devel at lists.linuxcontainers.org\n"
-        "POT-Creation-Date: 2016-08-15 15:10-0400\n"
+        "POT-Creation-Date: 2016-08-15 16:10-0400\n"
         "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
         "Last-Translator: FULL NAME <EMAIL at ADDRESS>\n"
         "Language-Team: LANGUAGE <LL at li.org>\n"
@@ -77,7 +77,7 @@ msgid   "### This is a yaml representation of the profile.\n"
         "### Note that the name is shown but cannot be changed"
 msgstr  ""
 
-#: lxc/image.go:616
+#: lxc/image.go:617
 #, c-format
 msgid   "%s (%d more)"
 msgstr  ""
@@ -90,11 +90,11 @@ msgstr  ""
 msgid   "(none)"
 msgstr  ""
 
-#: lxc/image.go:637 lxc/image.go:679
+#: lxc/image.go:638 lxc/image.go:680
 msgid   "ALIAS"
 msgstr  ""
 
-#: lxc/image.go:641
+#: lxc/image.go:642
 msgid   "ARCH"
 msgstr  ""
 
@@ -183,11 +183,11 @@ msgstr  ""
 msgid   "Columns"
 msgstr  ""
 
-#: lxc/init.go:134 lxc/init.go:135 lxc/launch.go:40 lxc/launch.go:41
+#: lxc/copy.go:31 lxc/copy.go:32 lxc/init.go:134 lxc/init.go:135 lxc/launch.go:40 lxc/launch.go:41
 msgid   "Config key/value to apply to the new container"
 msgstr  ""
 
-#: lxc/config.go:531 lxc/config.go:596 lxc/image.go:733 lxc/profile.go:218
+#: lxc/config.go:531 lxc/config.go:596 lxc/image.go:734 lxc/profile.go:218
 #, c-format
 msgid   "Config parsing error: %s"
 msgstr  ""
@@ -200,7 +200,7 @@ msgstr  ""
 msgid   "Container name is mandatory"
 msgstr  ""
 
-#: lxc/init.go:210
+#: lxc/copy.go:140 lxc/copy.go:228 lxc/init.go:210
 #, c-format
 msgid   "Container name is: %s"
 msgstr  ""
@@ -214,10 +214,10 @@ msgstr  ""
 msgid   "Copy aliases from source"
 msgstr  ""
 
-#: lxc/copy.go:22
+#: lxc/copy.go:24
 msgid   "Copy containers within or in between lxd instances.\n"
         "\n"
-        "lxc copy [remote:]<source container> [remote:]<destination container> [--ephemeral|e]"
+        "lxc copy [remote:]<source container> [remote:]<destination container> [--ephemeral|e] [--profile|-p <profile>...] [--config|-c <key=value>...]"
 msgstr  ""
 
 #: lxc/image.go:280
@@ -259,7 +259,7 @@ msgstr  ""
 msgid   "Creating the container"
 msgstr  ""
 
-#: lxc/image.go:640 lxc/image.go:681
+#: lxc/image.go:641 lxc/image.go:682
 msgid   "DESCRIPTION"
 msgstr  ""
 
@@ -301,7 +301,7 @@ msgstr  ""
 msgid   "Environment:"
 msgstr  ""
 
-#: lxc/copy.go:29 lxc/copy.go:30 lxc/init.go:138 lxc/init.go:139 lxc/launch.go:44 lxc/launch.go:45
+#: lxc/copy.go:35 lxc/copy.go:36 lxc/init.go:138 lxc/init.go:139 lxc/launch.go:44 lxc/launch.go:45
 msgid   "Ephemeral container"
 msgstr  ""
 
@@ -326,7 +326,7 @@ msgstr  ""
 msgid   "Expires: never"
 msgstr  ""
 
-#: lxc/config.go:273 lxc/image.go:638 lxc/image.go:680
+#: lxc/config.go:273 lxc/image.go:639 lxc/image.go:681
 msgid   "FINGERPRINT"
 msgstr  ""
 
@@ -393,12 +393,12 @@ msgstr  ""
 msgid   "Image copied successfully!"
 msgstr  ""
 
-#: lxc/image.go:441
+#: lxc/image.go:442
 #, c-format
 msgid   "Image imported with fingerprint: %s"
 msgstr  ""
 
-#: lxc/image.go:428
+#: lxc/image.go:429
 #, c-format
 msgid   "Importing the image: %s"
 msgstr  ""
@@ -786,7 +786,7 @@ msgstr  ""
 msgid   "Only https URLs are supported for simplestreams"
 msgstr  ""
 
-#: lxc/image.go:433
+#: lxc/image.go:434
 msgid   "Only https:// is supported for remote image import."
 msgstr  ""
 
@@ -794,7 +794,7 @@ msgstr  ""
 msgid   "Options:"
 msgstr  ""
 
-#: lxc/image.go:537
+#: lxc/image.go:538
 #, c-format
 msgid   "Output is in %s"
 msgstr  ""
@@ -819,7 +819,7 @@ msgstr  ""
 msgid   "PROTOCOL"
 msgstr  ""
 
-#: lxc/image.go:639 lxc/remote.go:379
+#: lxc/image.go:640 lxc/remote.go:379
 msgid   "PUBLIC"
 msgstr  ""
 
@@ -858,7 +858,7 @@ msgstr  ""
 msgid   "Press enter to open the editor again"
 msgstr  ""
 
-#: lxc/config.go:532 lxc/config.go:597 lxc/image.go:734
+#: lxc/config.go:532 lxc/config.go:597 lxc/image.go:735
 msgid   "Press enter to start the editor again"
 msgstr  ""
 
@@ -905,7 +905,7 @@ msgstr  ""
 msgid   "Profile %s removed from %s"
 msgstr  ""
 
-#: lxc/init.go:136 lxc/init.go:137 lxc/launch.go:42 lxc/launch.go:43
+#: lxc/copy.go:33 lxc/copy.go:34 lxc/init.go:136 lxc/init.go:137 lxc/launch.go:42 lxc/launch.go:43
 msgid   "Profile to apply to the new container"
 msgstr  ""
 
@@ -960,7 +960,7 @@ msgstr  ""
 msgid   "Retrieving image: %s"
 msgstr  ""
 
-#: lxc/image.go:642
+#: lxc/image.go:643
 msgid   "SIZE"
 msgstr  ""
 
@@ -1109,7 +1109,7 @@ msgstr  ""
 msgid   "To start your first container, try: lxc launch ubuntu:16.04"
 msgstr  ""
 
-#: lxc/image.go:420
+#: lxc/image.go:421
 #, c-format
 msgid   "Transferring image: %d%%"
 msgstr  ""
@@ -1127,7 +1127,7 @@ msgstr  ""
 msgid   "Type: persistent"
 msgstr  ""
 
-#: lxc/image.go:643
+#: lxc/image.go:644
 msgid   "UPLOAD DATE"
 msgstr  ""
 
@@ -1185,7 +1185,7 @@ msgstr  ""
 msgid   "bad result type from action"
 msgstr  ""
 
-#: lxc/copy.go:99
+#: lxc/copy.go:115
 msgid   "can't copy to the same container name"
 msgstr  ""
 
@@ -1197,7 +1197,7 @@ msgstr  ""
 msgid   "default"
 msgstr  ""
 
-#: lxc/init.go:200 lxc/init.go:205 lxc/launch.go:95 lxc/launch.go:100
+#: lxc/copy.go:131 lxc/copy.go:136 lxc/copy.go:219 lxc/copy.go:224 lxc/init.go:200 lxc/init.go:205 lxc/launch.go:95 lxc/launch.go:100
 msgid   "didn't get any affected image, container or snapshot from server"
 msgstr  ""
 
@@ -1223,11 +1223,11 @@ msgstr  ""
 msgid   "got bad version"
 msgstr  ""
 
-#: lxc/image.go:336 lxc/image.go:619
+#: lxc/image.go:336 lxc/image.go:620
 msgid   "no"
 msgstr  ""
 
-#: lxc/copy.go:122
+#: lxc/copy.go:158
 msgid   "not all the profiles from the source exist on the target"
 msgstr  ""
 
@@ -1281,11 +1281,11 @@ msgstr  ""
 msgid   "wrong number of subcommand arguments"
 msgstr  ""
 
-#: lxc/delete.go:45 lxc/image.go:338 lxc/image.go:623
+#: lxc/delete.go:45 lxc/image.go:338 lxc/image.go:624
 msgid   "yes"
 msgstr  ""
 
-#: lxc/copy.go:38
+#: lxc/copy.go:44
 msgid   "you must specify a source container name"
 msgstr  ""
 

From 16bac94c72f1d4ac2af2d2aeb91d5c3688947369 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Mon, 15 Aug 2016 17:33:18 -0400
Subject: [PATCH 5/5] Fix unix-char/unix-block in nested containers
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This comes with a number of limitations due to us not being able to
mknod the device, but it's better than what we have currently.

Closes #2279

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/container_lxc.go | 98 ++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 68 insertions(+), 30 deletions(-)

diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index cb2f2ca..8982e88 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -1096,15 +1096,17 @@ func (c *containerLXC) startCommon() (string, error) {
 				return "", err
 			}
 
-			// Add the new device cgroup rule
-			dType, dMajor, dMinor, err := deviceGetAttributes(devPath)
-			if err != nil {
-				return "", err
-			}
+			if c.IsPrivileged() && !runningInUserns && cgDevicesController {
+				// Add the new device cgroup rule
+				dType, dMajor, dMinor, err := deviceGetAttributes(devPath)
+				if err != nil {
+					return "", err
+				}
 
-			err = lxcSetConfigItem(c.c, "lxc.cgroup.devices.allow", fmt.Sprintf("%s %d:%d rwm", dType, dMajor, dMinor))
-			if err != nil {
-				return "", fmt.Errorf("Failed to add cgroup rule for device")
+				err = lxcSetConfigItem(c.c, "lxc.cgroup.devices.allow", fmt.Sprintf("%s %d:%d rwm", dType, dMajor, dMinor))
+				if err != nil {
+					return "", fmt.Errorf("Failed to add cgroup rule for device")
+				}
 			}
 		} else if m["type"] == "usb" {
 			if usbs == nil {
@@ -1121,9 +1123,11 @@ func (c *containerLXC) startCommon() (string, error) {
 					continue
 				}
 
-				err = lxcSetConfigItem(c.c, "lxc.cgroup.devices.allow", fmt.Sprintf("c %d:%d rwm", usb.major, usb.minor))
-				if err != nil {
-					return "", err
+				if c.IsPrivileged() && !runningInUserns && cgDevicesController {
+					err = lxcSetConfigItem(c.c, "lxc.cgroup.devices.allow", fmt.Sprintf("c %d:%d rwm", usb.major, usb.minor))
+					if err != nil {
+						return "", err
+					}
 				}
 
 				m["major"] = fmt.Sprintf("%d", usb.major)
@@ -3657,6 +3661,15 @@ func (c *containerLXC) createUnixDevice(m shared.Device) (string, error) {
 	devName := fmt.Sprintf("unix.%s", strings.Replace(tgtPath, "/", "-", -1))
 	devPath := filepath.Join(c.DevicesPath(), devName)
 
+	// Extra checks for nesting
+	if runningInUserns {
+		for key, value := range m {
+			if shared.StringInSlice(key, []string{"major", "minor", "mode", "uid", "gid"}) && value != "" {
+				return "", fmt.Errorf("The \"%s\" property may not be set when adding a device to a nested container", key)
+			}
+		}
+	}
+
 	// Get the major/minor of the device we want to create
 	if m["major"] == "" && m["minor"] == "" {
 		// If no major and minor are set, use those from the device on the host
@@ -3722,6 +3735,10 @@ func (c *containerLXC) createUnixDevice(m shared.Device) (string, error) {
 
 	// Clean any existing entry
 	if shared.PathExists(devPath) {
+		if runningInUserns {
+			syscall.Unmount(devPath, syscall.MNT_DETACH)
+		}
+
 		err = os.Remove(devPath)
 		if err != nil {
 			return "", fmt.Errorf("Failed to remove existing entry: %s", err)
@@ -3729,23 +3746,36 @@ func (c *containerLXC) createUnixDevice(m shared.Device) (string, error) {
 	}
 
 	// Create the new entry
-	if err := syscall.Mknod(devPath, uint32(mode), minor|(major<<8)); err != nil {
-		return "", fmt.Errorf("Failed to create device %s for %s: %s", devPath, m["path"], err)
-	}
+	if !runningInUserns {
+		if err := syscall.Mknod(devPath, uint32(mode), minor|(major<<8)); err != nil {
+			return "", fmt.Errorf("Failed to create device %s for %s: %s", devPath, m["path"], err)
+		}
 
-	if err := os.Chown(devPath, uid, gid); err != nil {
-		return "", fmt.Errorf("Failed to chown device %s: %s", devPath, err)
-	}
+		if err := os.Chown(devPath, uid, gid); err != nil {
+			return "", fmt.Errorf("Failed to chown device %s: %s", devPath, err)
+		}
 
-	// Needed as mknod respects the umask
-	if err := os.Chmod(devPath, mode); err != nil {
-		return "", fmt.Errorf("Failed to chmod device %s: %s", devPath, err)
-	}
+		// Needed as mknod respects the umask
+		if err := os.Chmod(devPath, mode); err != nil {
+			return "", fmt.Errorf("Failed to chmod device %s: %s", devPath, err)
+		}
 
-	if c.idmapset != nil {
-		if err := c.idmapset.ShiftFile(devPath); err != nil {
-			// uidshift failing is weird, but not a big problem.  Log and proceed
-			shared.Debugf("Failed to uidshift device %s: %s\n", m["path"], err)
+		if c.idmapset != nil {
+			if err := c.idmapset.ShiftFile(devPath); err != nil {
+				// uidshift failing is weird, but not a big problem.  Log and proceed
+				shared.Debugf("Failed to uidshift device %s: %s\n", m["path"], err)
+			}
+		}
+	} else {
+		f, err := os.Create(devPath)
+		if err != nil {
+			return "", err
+		}
+		f.Close()
+
+		err = deviceMountDisk(srcPath, devPath, false, false)
+		if err != nil {
+			return "", err
 		}
 	}
 
@@ -3777,8 +3807,10 @@ func (c *containerLXC) insertUnixDevice(name string, m shared.Device) error {
 		return fmt.Errorf("Failed to get device attributes: %s", err)
 	}
 
-	if err := c.CGroupSet("devices.allow", fmt.Sprintf("%s %d:%d rwm", dType, dMajor, dMinor)); err != nil {
-		return fmt.Errorf("Failed to add cgroup rule for device")
+	if c.IsPrivileged() && !runningInUserns && cgDevicesController {
+		if err := c.CGroupSet("devices.allow", fmt.Sprintf("%s %d:%d rwm", dType, dMajor, dMinor)); err != nil {
+			return fmt.Errorf("Failed to add cgroup rule for device")
+		}
 	}
 
 	return nil
@@ -3803,9 +3835,11 @@ func (c *containerLXC) removeUnixDevice(m shared.Device) error {
 		return err
 	}
 
-	err = c.CGroupSet("devices.deny", fmt.Sprintf("%s %d:%d rwm", dType, dMajor, dMinor))
-	if err != nil {
-		return err
+	if c.IsPrivileged() && !runningInUserns && cgDevicesController {
+		err = c.CGroupSet("devices.deny", fmt.Sprintf("%s %d:%d rwm", dType, dMajor, dMinor))
+		if err != nil {
+			return err
+		}
 	}
 
 	// Remove the bind-mount from the container
@@ -3824,6 +3858,10 @@ func (c *containerLXC) removeUnixDevice(m shared.Device) error {
 	}
 
 	// Remove the host side
+	if runningInUserns {
+		syscall.Unmount(devPath, syscall.MNT_DETACH)
+	}
+
 	err = os.Remove(devPath)
 	if err != nil {
 		return err


More information about the lxc-devel mailing list