[lxc-devel] [lxd/master] Support editing container metadata and templates over API

albertodonato on Github lxc-bot at linuxcontainers.org
Fri Jul 14 16:05:55 UTC 2017


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 475 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20170714/5352608d/attachment.bin>
-------------- next part --------------
From ab8d925a5cc34051f18522dc42c97ab753c4d0cf Mon Sep 17 00:00:00 2001
From: Alberto Donato <alberto.donato at canonical.com>
Date: Thu, 13 Jul 2017 10:41:36 +0200
Subject: [PATCH 1/3] Add API for editing containers metadata.yaml

Signed-off-by: Alberto Donato <alberto.donato at canonical.com>
---
 client/interfaces.go      |   3 ++
 client/lxd_containers.go  |  32 ++++++++++++
 doc/api-extensions.md     |   5 ++
 doc/rest-api.md           |  62 +++++++++++++++++++++++
 lxc/config.go             | 123 ++++++++++++++++++++++++++++++++++++++++++++++
 lxd/api_1.0.go            |   2 +
 lxd/container_lxc.go      |   6 +--
 lxd/container_metadata.go |  71 ++++++++++++++++++++++++++
 lxd/containers.go         |   6 +++
 lxd/images.go             |  21 ++------
 po/de.po                  |  85 +++++++++++++++++++++++++-------
 po/el.po                  |  67 ++++++++++++++++++-------
 po/fr.po                  |  85 +++++++++++++++++++++++++-------
 po/it.po                  |  67 ++++++++++++++++++-------
 po/ja.po                  |  67 ++++++++++++++++++-------
 po/lxd.pot                |  64 +++++++++++++++++-------
 po/nl.po                  |  67 ++++++++++++++++++-------
 po/ru.po                  |  85 +++++++++++++++++++++++++-------
 po/sr.po                  |  67 ++++++++++++++++++-------
 po/sv.po                  |  67 ++++++++++++++++++-------
 po/tr.po                  |  67 ++++++++++++++++++-------
 shared/api/image.go       |  15 ++++++
 test/main.sh              |   2 +
 test/suites/config.sh     |  17 +++++++
 24 files changed, 924 insertions(+), 229 deletions(-)
 create mode 100644 lxd/container_metadata.go

diff --git a/client/interfaces.go b/client/interfaces.go
index d146c1ddf..bf6075a45 100644
--- a/client/interfaces.go
+++ b/client/interfaces.go
@@ -86,6 +86,9 @@ type ContainerServer interface {
 	GetContainerLogfile(name string, filename string) (content io.ReadCloser, err error)
 	DeleteContainerLogfile(name string, filename string) (err error)
 
+	GetContainerMetadata(name string) (*api.ImageMetadata, string, error)
+	SetContainerMetadata(name string, ETag string, metadata api.ImageMetadata) error
+
 	// Event handling functions
 	GetEvents() (listener *EventListener, err error)
 
diff --git a/client/lxd_containers.go b/client/lxd_containers.go
index 9d4cb6bce..8706855bc 100644
--- a/client/lxd_containers.go
+++ b/client/lxd_containers.go
@@ -1261,3 +1261,35 @@ func (r *ProtocolLXD) DeleteContainerLogfile(name string, filename string) error
 
 	return nil
 }
+
+// GetContainerMetadata returns container metadata
+func (r *ProtocolLXD) GetContainerMetadata(name string) (*api.ImageMetadata, string, error) {
+	if !r.HasExtension("container_edit_metadata") {
+		return nil, "", fmt.Errorf("The server is missing the required \"container_edit_metadata\" API extension")
+	}
+
+	metadata := api.ImageMetadata{}
+
+	url := fmt.Sprintf("/containers/%s/metadata", name)
+	etag, err := r.queryStruct("GET", url, nil, "", &metadata)
+	if err != nil {
+		return nil, "", err
+	}
+
+	return &metadata, etag, err
+}
+
+// Set the content of the container metadata file.
+func (r *ProtocolLXD) SetContainerMetadata(name string, ETag string, metadata api.ImageMetadata) error {
+	if !r.HasExtension("container_edit_metadata") {
+		return fmt.Errorf("The server is missing the required \"container_edit_metadata\" API extension")
+	}
+
+	url := fmt.Sprintf("/containers/%s/metadata", name)
+	_, _, err := r.query("PUT", url, metadata, ETag)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
diff --git a/doc/api-extensions.md b/doc/api-extensions.md
index bc3dd2d61..b930d21f7 100644
--- a/doc/api-extensions.md
+++ b/doc/api-extensions.md
@@ -292,3 +292,8 @@ X-LXD-type can now be "symlink" with the request content being the target path.
 ## container\_push\_target
 This adds the "target" field to POST /1.0/containers/NAME which can be
 used to have the source LXD host connect to the target during migration.
+
+## container\_edit\_metadata
+This adds support for editing a container metadata.yaml and related templates
+via API, by accessing urls under /1.0/containers/NAME/metadata. It can be used
+to edit a container before publishing an image from it.
diff --git a/doc/rest-api.md b/doc/rest-api.md
index 354bf5929..c3bf9b5d2 100644
--- a/doc/rest-api.md
+++ b/doc/rest-api.md
@@ -190,6 +190,7 @@ won't work and PUT needs to be used instead.
          * /1.0/containers/\<name\>/state
          * /1.0/containers/\<name\>/logs
          * /1.0/containers/\<name\>/logs/\<logfile\>
+         * /1.0/containers/\<name\>/metadata
      * /1.0/events
      * /1.0/images
        * /1.0/images/\<fingerprint\>
@@ -1177,6 +1178,67 @@ Return:
 * Operation: Sync
 * Return: empty response or standard error
 
+## /1.0/containers/\<name\>/metadata
+### GET
+* Description: Container metadata
+* Authentication: trusted
+* Operation: Sync
+* Return: dict representing container metadata
+
+Return:
+
+    {
+        "architecture": "x86_64",
+        "creation_date": 1477146654,
+        "expiry_date": 0,
+        "properties": {
+            "architecture": "x86_64",
+            "description": "Busybox x86_64",
+            "name": "busybox-x86_64",
+            "os": "Busybox"
+        },
+        "templates": {
+            "/template": {
+                "when": [
+                    ""
+                ],
+                "create_only": false,
+                "template": "template.tpl",
+                "properties": {}
+            }
+        }
+    }
+
+### PUT (ETag supported)
+ * Description: Replaces container metadata
+ * Authentication: trusted
+ * Operation: sync
+ * Return: standard return value or standard error
+
+Input:
+
+    {
+        "architecture": "x86_64",
+        "creation_date": 1477146654,
+        "expiry_date": 0,
+        "properties": {
+            "architecture": "x86_64",
+            "description": "Busybox x86_64",
+            "name": "busybox-x86_64",
+            "os": "Busybox"
+        },
+        "templates": {
+            "/template": {
+                "when": [
+                    ""
+                ],
+                "create_only": false,
+                "template": "template.tpl",
+                "properties": {}
+            }
+        }
+    }
+
 ## /1.0/events
 This URL isn't a real REST API endpoint, instead doing a GET query on it
 will upgrade the connection to a websocket on which notifications will
diff --git a/lxc/config.go b/lxc/config.go
index 6bc2fd06d..6c949a7ae 100644
--- a/lxc/config.go
+++ b/lxc/config.go
@@ -56,6 +56,30 @@ func (c *configCmd) configEditHelp() string {
 ### Note that the name is shown but cannot be changed`)
 }
 
+func (c *configCmd) metadataEditHelp() string {
+	return i18n.G(
+		`### This is a yaml representation of the container metadata.
+### Any line starting with a '# will be ignored.
+###
+### A sample configuration looks like:
+###
+### architecture: x86_64
+### creation_date: 1477146654
+### expiry_date: 0
+### properties:
+###   architecture: x86_64
+###   description: Busybox x86_64
+###   name: busybox-x86_64
+###   os: Busybox
+### templates:
+###   /template:
+###     when:
+###     - ""
+###     create_only: false
+###     template: template.tpl
+###     properties: {}`)
+}
+
 func (c *configCmd) usage() string {
 	return i18n.G(
 		`Usage: lxc config <subcommand> [options]
@@ -79,6 +103,11 @@ lxc config show [<remote>:][container] [--expanded]
 lxc config edit [<remote>:][container]
     Edit configuration, either by launching external editor or reading STDIN.
 
+*Container metadata*
+
+lxc config metadata show [<remote>:][container]
+    Show the container metadata.yaml content.
+
 *Device management*
 
 lxc config device add [<remote>:]<container> <device> <type> [key=value...]
@@ -583,6 +612,41 @@ func (c *configCmd) run(conf *config.Config, args []string) error {
 
 		return c.doContainerConfigEdit(d, container)
 
+	case "metadata":
+		if len(args) < 3 {
+			return errArgs
+		}
+
+		remote, container, err := conf.ParseRemote(args[2])
+		if err != nil {
+			return err
+		}
+
+		d, err := conf.GetContainerServer(remote)
+		if err != nil {
+			return err
+		}
+
+		switch args[1] {
+		case "show":
+			metadata, _, err := d.GetContainerMetadata(container)
+			if err != nil {
+				return err
+			}
+			content, err := yaml.Marshal(metadata)
+			if err != nil {
+				return err
+			}
+			fmt.Printf("%s", content)
+			return nil
+
+		case "edit":
+			return c.doContainerMetadataEdit(d, container)
+
+		default:
+			return errArgs
+		}
+
 	default:
 		return errArgs
 	}
@@ -1120,3 +1184,62 @@ func (c *configCmd) deviceShow(conf *config.Config, which string, args []string)
 	fmt.Printf(string(data))
 	return nil
 }
+
+func (c *configCmd) doContainerMetadataEdit(client lxd.ContainerServer, name string) error {
+	if !termios.IsTerminal(int(syscall.Stdin)) {
+		metadata := api.ImageMetadata{}
+		content, err := ioutil.ReadAll(os.Stdin)
+		if err != nil {
+			return err
+		}
+
+		err = yaml.Unmarshal(content, &metadata)
+		if err != nil {
+			return err
+		}
+		return client.SetContainerMetadata(name, "", metadata)
+	}
+
+	metadata, etag, err := client.GetContainerMetadata(name)
+	if err != nil {
+		return err
+	}
+	origContent, err := yaml.Marshal(metadata)
+	if err != nil {
+		return err
+	}
+
+	// Spawn the editor
+	content, err := shared.TextEditor("", []byte(c.metadataEditHelp()+"\n\n"+string(origContent)))
+	if err != nil {
+		return err
+	}
+
+	for {
+		err = yaml.Unmarshal(content, &metadata)
+		if err == nil {
+			err = client.SetContainerMetadata(name, etag, *metadata)
+		}
+
+		// Respawn the editor
+		if err != nil {
+			fmt.Fprintf(os.Stderr, i18n.G("Config parsing error: %s")+"\n", err)
+			fmt.Println(i18n.G("Press enter to start the editor again"))
+
+			_, err := os.Stdin.Read(make([]byte, 1))
+			if err != nil {
+				return err
+			}
+
+			content, err = shared.TextEditor("", content)
+			if err != nil {
+				return err
+			}
+			continue
+		}
+
+		break
+	}
+
+	return nil
+}
diff --git a/lxd/api_1.0.go b/lxd/api_1.0.go
index 46f7b5459..dd125c0e7 100644
--- a/lxd/api_1.0.go
+++ b/lxd/api_1.0.go
@@ -26,6 +26,7 @@ var api10 = []Command{
 	containerSnapshotsCmd,
 	containerSnapshotCmd,
 	containerExecCmd,
+	containerMetadataCmd,
 	aliasCmd,
 	aliasesCmd,
 	eventsCmd,
@@ -112,6 +113,7 @@ func api10Get(d *Daemon, r *http.Request) Response {
 			"id_map_base",
 			"file_symlinks",
 			"container_push_target",
+			"container_edit_metadata",
 		},
 		APIStatus:  "stable",
 		APIVersion: version.APIVersion,
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index d5eebbf91..1920f8a19 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -4146,7 +4146,7 @@ func (c *containerLXC) Export(w io.Writer, properties map[string]string) error {
 		}
 
 		// Fill in the metadata
-		meta := imageMetadata{}
+		meta := api.ImageMetadata{}
 		meta.Architecture = arch
 		meta.CreationDate = time.Now().UTC().Unix()
 		meta.Properties = properties
@@ -4191,7 +4191,7 @@ func (c *containerLXC) Export(w io.Writer, properties map[string]string) error {
 				return err
 			}
 
-			metadata := new(imageMetadata)
+			metadata := new(api.ImageMetadata)
 			err = yaml.Unmarshal(content, &metadata)
 			if err != nil {
 				tw.Close()
@@ -4486,7 +4486,7 @@ func (c *containerLXC) templateApplyNow(trigger string) error {
 		return err
 	}
 
-	metadata := new(imageMetadata)
+	metadata := new(api.ImageMetadata)
 	err = yaml.Unmarshal(content, &metadata)
 
 	if err != nil {
diff --git a/lxd/container_metadata.go b/lxd/container_metadata.go
new file mode 100644
index 000000000..5b235bf3e
--- /dev/null
+++ b/lxd/container_metadata.go
@@ -0,0 +1,71 @@
+package main
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"net/http"
+	"os"
+	"path/filepath"
+
+	"gopkg.in/yaml.v2"
+
+	"github.com/gorilla/mux"
+
+	"github.com/lxc/lxd/shared/api"
+)
+
+func containerMetadataGet(d *Daemon, r *http.Request) Response {
+	name := mux.Vars(r)["name"]
+	metadataPath, err := getContainerMetadataPath(d, name)
+	if err != nil {
+		return SmartError(err)
+	}
+
+	metadataFile, err := os.Open(metadataPath)
+	if err != nil {
+		return InternalError(err)
+	}
+
+	data, err := ioutil.ReadAll(metadataFile)
+	if err != nil {
+		return InternalError(err)
+	}
+	metadata := api.ImageMetadata{}
+	err = yaml.Unmarshal([]byte(data), &metadata)
+	if err != nil {
+		return SmartError(err)
+	}
+	return SyncResponse(true, metadata)
+}
+
+func containerMetadataPut(d *Daemon, r *http.Request) Response {
+	name := mux.Vars(r)["name"]
+	metadataPath, err := getContainerMetadataPath(d, name)
+	if err != nil {
+		return SmartError(err)
+	}
+
+	metadata := api.ImageMetadata{}
+	if err := json.NewDecoder(r.Body).Decode(&metadata); err != nil {
+		return BadRequest(err)
+	}
+
+	data, err := yaml.Marshal(metadata)
+	if err != nil {
+		return BadRequest(err)
+	}
+	if err := ioutil.WriteFile(metadataPath, data, 0644); err != nil {
+		InternalError(err)
+	}
+
+	return EmptySyncResponse
+}
+
+// Return the path of the container metadata file
+func getContainerMetadataPath(d *Daemon, cname string) (string, error) {
+	c, err := containerLoadByName(d, cname)
+	if err != nil {
+		return "", err
+	}
+	return filepath.Join(c.Path(), "metadata.yaml"), nil
+}
diff --git a/lxd/containers.go b/lxd/containers.go
index 3345879ef..92d795ace 100644
--- a/lxd/containers.go
+++ b/lxd/containers.go
@@ -58,6 +58,12 @@ var containerExecCmd = Command{
 	post: containerExecPost,
 }
 
+var containerMetadataCmd = Command{
+	name: "containers/{name}/metadata",
+	get:  containerMetadataGet,
+	put:  containerMetadataPut,
+}
+
 type containerAutostartList []container
 
 func (slice containerAutostartList) Len() int {
diff --git a/lxd/images.go b/lxd/images.go
index 9b04cff4b..5d6029cb8 100644
--- a/lxd/images.go
+++ b/lxd/images.go
@@ -203,21 +203,6 @@ func compressFile(path string, compress string) (string, error) {
 	return outfile.Name(), nil
 }
 
-type templateEntry struct {
-	When       []string          `yaml:"when"`
-	CreateOnly bool              `yaml:"create_only"`
-	Template   string            `yaml:"template"`
-	Properties map[string]string `yaml:"properties"`
-}
-
-type imageMetadata struct {
-	Architecture string                    `yaml:"architecture"`
-	CreationDate int64                     `yaml:"creation_date"`
-	ExpiryDate   int64                     `yaml:"expiry_date"`
-	Properties   map[string]string         `yaml:"properties"`
-	Templates    map[string]*templateEntry `yaml:"templates"`
-}
-
 /*
  * This function takes a container or snapshot from the local image server and
  * exports it as an image.
@@ -435,7 +420,7 @@ func imgPostURLInfo(d *Daemon, req api.ImagesPost, op *operation) (*api.Image, e
 
 func getImgPostInfo(d *Daemon, r *http.Request, builddir string, post *os.File) (*api.Image, error) {
 	info := api.Image{}
-	var imageMeta *imageMetadata
+	var imageMeta *api.ImageMetadata
 	logger := logging.AddContext(logger.Log, log.Ctx{"function": "getImgPostInfo"})
 
 	public, _ := strconv.Atoi(r.Header.Get("X-LXD-public"))
@@ -776,7 +761,7 @@ func imagesPost(d *Daemon, r *http.Request) Response {
 	return OperationResponse(op)
 }
 
-func getImageMetadata(fname string) (*imageMetadata, error) {
+func getImageMetadata(fname string) (*api.ImageMetadata, error) {
 	metadataName := "metadata.yaml"
 
 	compressionArgs, _, err := detectCompression(fname)
@@ -800,7 +785,7 @@ func getImageMetadata(fname string) (*imageMetadata, error) {
 		return nil, fmt.Errorf("Could not extract image %s from tar: %v (%s)", metadataName, err, outputLines[0])
 	}
 
-	metadata := imageMetadata{}
+	metadata := api.ImageMetadata{}
 	err = yaml.Unmarshal([]byte(output), &metadata)
 
 	if err != nil {
diff --git a/po/de.po b/po/de.po
index 450a54e19..dfabdb852 100644
--- a/po/de.po
+++ b/po/de.po
@@ -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: 2017-07-12 00:41+0200\n"
+"POT-Creation-Date: 2017-07-14 08:35+0000\n"
 "PO-Revision-Date: 2017-02-14 17:11+0000\n"
 "Last-Translator: Tim Rose <tim at netlope.de>\n"
 "Language-Team: German <https://hosted.weblate.org/projects/linux-containers/"
@@ -114,6 +114,48 @@ msgstr ""
 "###\n"
 "### Der Name wird zwar angezeigt, lässt sich jedoch nicht ändern.\n"
 
+#: lxc/config.go:60
+#, fuzzy
+msgid ""
+"### This is a yaml representation of the container metadata.\n"
+"### Any line starting with a '# will be ignored.\n"
+"###\n"
+"### A sample configuration looks like:\n"
+"###\n"
+"### architecture: x86_64\n"
+"### creation_date: 1477146654\n"
+"### expiry_date: 0\n"
+"### properties:\n"
+"###   architecture: x86_64\n"
+"###   description: Busybox x86_64\n"
+"###   name: busybox-x86_64\n"
+"###   os: Busybox\n"
+"### templates:\n"
+"###   /template:\n"
+"###     when:\n"
+"###     - \"\"\n"
+"###     create_only: false\n"
+"###     template: template.tpl\n"
+"###     properties: {}"
+msgstr ""
+"### Dies ist eine Darstellung der Konfiguration in yaml.\n"
+"### Jede Zeile die mit '# beginnt wird ignoriert.\n"
+"###\n"
+"### Beispiel einer Konfiguration:\n"
+"### name: container1\n"
+"### profiles:\n"
+"### - default\n"
+"### config:\n"
+"###   volatile.eth0.hwaddr: 00:16:3e:e9:f8:7f\n"
+"### devices:\n"
+"###   homedir:\n"
+"###     path: /extra\n"
+"###     source: /home/user\n"
+"###     type: disk\n"
+"### ephemeral: false\n"
+"###\n"
+"### Der Name wird zwar angezeigt, lässt sich jedoch nicht ändern.\n"
+
 #: lxc/image.go:62
 #, fuzzy
 msgid ""
@@ -290,7 +332,7 @@ msgstr "Bytes empfangen"
 msgid "Bytes sent"
 msgstr "Bytes gesendet"
 
-#: lxc/config.go:349
+#: lxc/config.go:378
 msgid "COMMON NAME"
 msgstr ""
 
@@ -311,17 +353,17 @@ msgstr "ERSTELLT AM"
 msgid "Can't pull a directory without --recursive"
 msgstr ""
 
-#: lxc/config.go:156 lxc/network.go:542
+#: lxc/config.go:185 lxc/network.go:542
 #, c-format
 msgid "Can't read from stdin: %s"
 msgstr ""
 
-#: lxc/config.go:169
+#: lxc/config.go:198
 #, c-format
 msgid "Can't unset key '%s', it's not currently set"
 msgstr ""
 
-#: lxc/config.go:211 lxc/config.go:237
+#: lxc/config.go:240 lxc/config.go:266
 #, c-format
 msgid "Can't unset key '%s', it's not currently set."
 msgstr ""
@@ -352,7 +394,7 @@ msgstr ""
 msgid "Config key/value to apply to the new container"
 msgstr "kann nicht zum selben Container Namen kopieren"
 
-#: lxc/config.go:647 lxc/config.go:712 lxc/image.go:1120 lxc/network.go:418
+#: lxc/config.go:715 lxc/config.go:780 lxc/image.go:1120 lxc/network.go:418
 #: lxc/profile.go:267 lxc/storage.go:576 lxc/storage.go:935
 #, fuzzy, c-format
 msgid "Config parsing error: %s"
@@ -426,12 +468,12 @@ msgstr ""
 msgid "Define a compression algorithm: for image or none"
 msgstr ""
 
-#: lxc/config.go:803
+#: lxc/config.go:871
 #, fuzzy, c-format
 msgid "Device %s added to %s"
 msgstr "Gerät %s wurde zu %s hinzugefügt\n"
 
-#: lxc/config.go:1039
+#: lxc/config.go:1107
 #, fuzzy, c-format
 msgid "Device %s removed from %s"
 msgstr "Gerät %s wurde von %s entfernt\n"
@@ -462,7 +504,7 @@ msgstr " Prozessorauslastung:"
 msgid "EPHEMERAL"
 msgstr ""
 
-#: lxc/config.go:351
+#: lxc/config.go:380
 msgid "EXPIRY DATE"
 msgstr ""
 
@@ -506,7 +548,7 @@ msgstr ""
 msgid "Exporting the image: %s"
 msgstr ""
 
-#: lxc/config.go:348 lxc/image.go:229 lxc/image.go:1066
+#: lxc/config.go:377 lxc/image.go:229 lxc/image.go:1066
 msgid "FINGERPRINT"
 msgstr ""
 
@@ -573,7 +615,7 @@ msgstr ""
 msgid "IPV6"
 msgstr ""
 
-#: lxc/config.go:350
+#: lxc/config.go:379
 msgid "ISSUE DATE"
 msgstr ""
 
@@ -616,7 +658,7 @@ msgstr ""
 msgid "Invalid URL scheme \"%s\" in \"%s\""
 msgstr ""
 
-#: lxc/config.go:329
+#: lxc/config.go:358
 #, fuzzy
 msgid "Invalid certificate"
 msgstr "Akzeptiere Zertifikat"
@@ -758,7 +800,7 @@ msgstr "Profil %s erstellt\n"
 msgid "New alias to define at target"
 msgstr ""
 
-#: lxc/config.go:360
+#: lxc/config.go:389
 #, fuzzy
 msgid "No certificate provided to add"
 msgstr "Kein Zertifikat zum hinzufügen bereitgestellt"
@@ -773,7 +815,7 @@ msgstr "Kein Zertifikat für diese Verbindung"
 msgid "No device found for this storage volume."
 msgstr "Kein Zertifikat für diese Verbindung"
 
-#: lxc/config.go:392
+#: lxc/config.go:421
 msgid "No fingerprint specified."
 msgstr "Kein Fingerabdruck angegeben."
 
@@ -857,7 +899,7 @@ msgstr ""
 msgid "Press enter to open the editor again"
 msgstr ""
 
-#: lxc/config.go:648 lxc/config.go:713 lxc/image.go:1121
+#: lxc/config.go:716 lxc/config.go:781 lxc/image.go:1121
 msgid "Press enter to start the editor again"
 msgstr ""
 
@@ -1145,13 +1187,13 @@ msgstr ""
 msgid "The container you are starting doesn't have any network attached to it."
 msgstr ""
 
-#: lxc/config.go:770 lxc/config.go:787
+#: lxc/config.go:838 lxc/config.go:855
 #, fuzzy
 msgid "The device already exists"
 msgstr "entfernte Instanz %s existiert bereits"
 
-#: lxc/config.go:833 lxc/config.go:845 lxc/config.go:881 lxc/config.go:899
-#: lxc/config.go:945 lxc/config.go:962 lxc/config.go:1005 lxc/config.go:1023
+#: lxc/config.go:901 lxc/config.go:913 lxc/config.go:949 lxc/config.go:967
+#: lxc/config.go:1013 lxc/config.go:1030 lxc/config.go:1073 lxc/config.go:1091
 #, fuzzy
 msgid "The device doesn't exist"
 msgstr "entfernte Instanz %s existiert nicht"
@@ -1284,7 +1326,7 @@ msgstr ""
 "Benutzung: lxc [Unterbefehl] [Optionen]\n"
 "Verfügbare Befehle:\n"
 
-#: lxc/config.go:60
+#: lxc/config.go:84
 #, fuzzy
 msgid ""
 "Usage: lxc config <subcommand> [options]\n"
@@ -1309,6 +1351,11 @@ msgid ""
 "    Edit configuration, either by launching external editor or reading "
 "STDIN.\n"
 "\n"
+"*Container metadata*\n"
+"\n"
+"lxc config metadata show [<remote>:][container]\n"
+"    Show the container metadata.yaml content.\n"
+"\n"
 "*Device management*\n"
 "\n"
 "lxc config device add [<remote>:]<container> <device> <type> [key=value...]\n"
diff --git a/po/el.po b/po/el.po
index df3be41b5..51aa464c6 100644
--- a/po/el.po
+++ b/po/el.po
@@ -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: 2017-07-12 00:41+0200\n"
+"POT-Creation-Date: 2017-07-14 08:35+0000\n"
 "PO-Revision-Date: 2017-02-14 08:00+0000\n"
 "Last-Translator: Simos Xenitellis <simos.65 at gmail.com>\n"
 "Language-Team: Greek <https://hosted.weblate.org/projects/linux-containers/"
@@ -71,6 +71,30 @@ msgid ""
 "### Note that the name is shown but cannot be changed"
 msgstr ""
 
+#: lxc/config.go:60
+msgid ""
+"### This is a yaml representation of the container metadata.\n"
+"### Any line starting with a '# will be ignored.\n"
+"###\n"
+"### A sample configuration looks like:\n"
+"###\n"
+"### architecture: x86_64\n"
+"### creation_date: 1477146654\n"
+"### expiry_date: 0\n"
+"### properties:\n"
+"###   architecture: x86_64\n"
+"###   description: Busybox x86_64\n"
+"###   name: busybox-x86_64\n"
+"###   os: Busybox\n"
+"### templates:\n"
+"###   /template:\n"
+"###     when:\n"
+"###     - \"\"\n"
+"###     create_only: false\n"
+"###     template: template.tpl\n"
+"###     properties: {}"
+msgstr ""
+
 #: lxc/image.go:62
 msgid ""
 "### This is a yaml representation of the image properties.\n"
@@ -202,7 +226,7 @@ msgstr ""
 msgid "Bytes sent"
 msgstr ""
 
-#: lxc/config.go:349
+#: lxc/config.go:378
 msgid "COMMON NAME"
 msgstr ""
 
@@ -223,17 +247,17 @@ msgstr ""
 msgid "Can't pull a directory without --recursive"
 msgstr ""
 
-#: lxc/config.go:156 lxc/network.go:542
+#: lxc/config.go:185 lxc/network.go:542
 #, c-format
 msgid "Can't read from stdin: %s"
 msgstr ""
 
-#: lxc/config.go:169
+#: lxc/config.go:198
 #, c-format
 msgid "Can't unset key '%s', it's not currently set"
 msgstr ""
 
-#: lxc/config.go:211 lxc/config.go:237
+#: lxc/config.go:240 lxc/config.go:266
 #, c-format
 msgid "Can't unset key '%s', it's not currently set."
 msgstr ""
@@ -263,7 +287,7 @@ msgstr ""
 msgid "Config key/value to apply to the new container"
 msgstr ""
 
-#: lxc/config.go:647 lxc/config.go:712 lxc/image.go:1120 lxc/network.go:418
+#: lxc/config.go:715 lxc/config.go:780 lxc/image.go:1120 lxc/network.go:418
 #: lxc/profile.go:267 lxc/storage.go:576 lxc/storage.go:935
 #, c-format
 msgid "Config parsing error: %s"
@@ -335,12 +359,12 @@ msgstr ""
 msgid "Define a compression algorithm: for image or none"
 msgstr ""
 
-#: lxc/config.go:803
+#: lxc/config.go:871
 #, c-format
 msgid "Device %s added to %s"
 msgstr ""
 
-#: lxc/config.go:1039
+#: lxc/config.go:1107
 #, c-format
 msgid "Device %s removed from %s"
 msgstr ""
@@ -371,7 +395,7 @@ msgstr "  Χρήση CPU:"
 msgid "EPHEMERAL"
 msgstr ""
 
-#: lxc/config.go:351
+#: lxc/config.go:380
 msgid "EXPIRY DATE"
 msgstr ""
 
@@ -413,7 +437,7 @@ msgstr ""
 msgid "Exporting the image: %s"
 msgstr ""
 
-#: lxc/config.go:348 lxc/image.go:229 lxc/image.go:1066
+#: lxc/config.go:377 lxc/image.go:229 lxc/image.go:1066
 msgid "FINGERPRINT"
 msgstr ""
 
@@ -477,7 +501,7 @@ msgstr ""
 msgid "IPV6"
 msgstr ""
 
-#: lxc/config.go:350
+#: lxc/config.go:379
 msgid "ISSUE DATE"
 msgstr ""
 
@@ -519,7 +543,7 @@ msgstr ""
 msgid "Invalid URL scheme \"%s\" in \"%s\""
 msgstr ""
 
-#: lxc/config.go:329
+#: lxc/config.go:358
 msgid "Invalid certificate"
 msgstr ""
 
@@ -657,7 +681,7 @@ msgstr "  Χρήση δικτύου:"
 msgid "New alias to define at target"
 msgstr ""
 
-#: lxc/config.go:360
+#: lxc/config.go:389
 msgid "No certificate provided to add"
 msgstr ""
 
@@ -669,7 +693,7 @@ msgstr ""
 msgid "No device found for this storage volume."
 msgstr ""
 
-#: lxc/config.go:392
+#: lxc/config.go:421
 msgid "No fingerprint specified."
 msgstr ""
 
@@ -750,7 +774,7 @@ msgstr ""
 msgid "Press enter to open the editor again"
 msgstr ""
 
-#: lxc/config.go:648 lxc/config.go:713 lxc/image.go:1121
+#: lxc/config.go:716 lxc/config.go:781 lxc/image.go:1121
 msgid "Press enter to start the editor again"
 msgstr ""
 
@@ -1029,12 +1053,12 @@ msgstr ""
 msgid "The container you are starting doesn't have any network attached to it."
 msgstr ""
 
-#: lxc/config.go:770 lxc/config.go:787
+#: lxc/config.go:838 lxc/config.go:855
 msgid "The device already exists"
 msgstr ""
 
-#: lxc/config.go:833 lxc/config.go:845 lxc/config.go:881 lxc/config.go:899
-#: lxc/config.go:945 lxc/config.go:962 lxc/config.go:1005 lxc/config.go:1023
+#: lxc/config.go:901 lxc/config.go:913 lxc/config.go:949 lxc/config.go:967
+#: lxc/config.go:1013 lxc/config.go:1030 lxc/config.go:1073 lxc/config.go:1091
 msgid "The device doesn't exist"
 msgstr ""
 
@@ -1156,7 +1180,7 @@ msgstr ""
 msgid "Usage: lxc <command> [options]"
 msgstr ""
 
-#: lxc/config.go:60
+#: lxc/config.go:84
 msgid ""
 "Usage: lxc config <subcommand> [options]\n"
 "\n"
@@ -1180,6 +1204,11 @@ msgid ""
 "    Edit configuration, either by launching external editor or reading "
 "STDIN.\n"
 "\n"
+"*Container metadata*\n"
+"\n"
+"lxc config metadata show [<remote>:][container]\n"
+"    Show the container metadata.yaml content.\n"
+"\n"
 "*Device management*\n"
 "\n"
 "lxc config device add [<remote>:]<container> <device> <type> [key=value...]\n"
diff --git a/po/fr.po b/po/fr.po
index 7c88aa3a3..245a808f1 100644
--- a/po/fr.po
+++ b/po/fr.po
@@ -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: 2017-07-12 00:41+0200\n"
+"POT-Creation-Date: 2017-07-14 08:35+0000\n"
 "PO-Revision-Date: 2017-06-07 15:24+0000\n"
 "Last-Translator: Stéphane Graber <stgraber at stgraber.org>\n"
 "Language-Team: French <https://hosted.weblate.org/projects/linux-containers/"
@@ -109,6 +109,48 @@ msgstr ""
 "###\n"
 "### Notez que le nom est affiché mais ne peut être modifié"
 
+#: lxc/config.go:60
+#, fuzzy
+msgid ""
+"### This is a yaml representation of the container metadata.\n"
+"### Any line starting with a '# will be ignored.\n"
+"###\n"
+"### A sample configuration looks like:\n"
+"###\n"
+"### architecture: x86_64\n"
+"### creation_date: 1477146654\n"
+"### expiry_date: 0\n"
+"### properties:\n"
+"###   architecture: x86_64\n"
+"###   description: Busybox x86_64\n"
+"###   name: busybox-x86_64\n"
+"###   os: Busybox\n"
+"### templates:\n"
+"###   /template:\n"
+"###     when:\n"
+"###     - \"\"\n"
+"###     create_only: false\n"
+"###     template: template.tpl\n"
+"###     properties: {}"
+msgstr ""
+"### Ceci est une réprésentation yaml de la configuration.\n"
+"### Toute ligne commençant par un '# sera ignorée.\n"
+"###\n"
+"### Un exemple de configuration ressemble à :\n"
+"### name: container1\n"
+"### profiles:\n"
+"### - default\n"
+"### config:\n"
+"###   volatile.eth0.hwaddr: 00:16:3e:e9:f8:7f\n"
+"### devices:\n"
+"###   homedir:\n"
+"###     path: /extra\n"
+"###     source: /home/user\n"
+"###     type: disk\n"
+"### ephemeral: false\n"
+"###\n"
+"### Notez que le nom est affiché mais ne peut être modifié"
+
 #: lxc/image.go:62
 msgid ""
 "### This is a yaml representation of the image properties.\n"
@@ -280,7 +322,7 @@ msgstr "Octets reçus"
 msgid "Bytes sent"
 msgstr "Octets émis"
 
-#: lxc/config.go:349
+#: lxc/config.go:378
 msgid "COMMON NAME"
 msgstr "COMMON NAME"
 
@@ -301,18 +343,18 @@ msgstr "CRÉÉ À"
 msgid "Can't pull a directory without --recursive"
 msgstr "impossible de récupérer un répertoire sans --recursive"
 
-#: lxc/config.go:156 lxc/network.go:542
+#: lxc/config.go:185 lxc/network.go:542
 #, c-format
 msgid "Can't read from stdin: %s"
 msgstr "Impossible de lire depuis stdin : %s"
 
-#: lxc/config.go:169
+#: lxc/config.go:198
 #, fuzzy, c-format
 msgid "Can't unset key '%s', it's not currently set"
 msgstr ""
 "Impossible de désaffecter la clé '%s', elle n'est pas définie actuellement."
 
-#: lxc/config.go:211 lxc/config.go:237
+#: lxc/config.go:240 lxc/config.go:266
 #, c-format
 msgid "Can't unset key '%s', it's not currently set."
 msgstr ""
@@ -343,7 +385,7 @@ msgstr "Commandes:"
 msgid "Config key/value to apply to the new container"
 msgstr "Clé/valeur de configuration à appliquer au nouveau conteneur"
 
-#: lxc/config.go:647 lxc/config.go:712 lxc/image.go:1120 lxc/network.go:418
+#: lxc/config.go:715 lxc/config.go:780 lxc/image.go:1120 lxc/network.go:418
 #: lxc/profile.go:267 lxc/storage.go:576 lxc/storage.go:935
 #, c-format
 msgid "Config parsing error: %s"
@@ -416,12 +458,12 @@ msgstr "PILOTE"
 msgid "Define a compression algorithm: for image or none"
 msgstr "Définir un algorithme de compression : pour image ou aucun"
 
-#: lxc/config.go:803
+#: lxc/config.go:871
 #, c-format
 msgid "Device %s added to %s"
 msgstr "Périphérique %s ajouté à %s"
 
-#: lxc/config.go:1039
+#: lxc/config.go:1107
 #, c-format
 msgid "Device %s removed from %s"
 msgstr "Périphérique %s retiré de %s"
@@ -452,7 +494,7 @@ msgstr "  Disque utilisé :"
 msgid "EPHEMERAL"
 msgstr "ÉPHÉMÈRE"
 
-#: lxc/config.go:351
+#: lxc/config.go:380
 msgid "EXPIRY DATE"
 msgstr "DATE D'EXPIRATION"
 
@@ -494,7 +536,7 @@ msgstr "N'expire jamais"
 msgid "Exporting the image: %s"
 msgstr "Import de l'image : %s"
 
-#: lxc/config.go:348 lxc/image.go:229 lxc/image.go:1066
+#: lxc/config.go:377 lxc/image.go:229 lxc/image.go:1066
 msgid "FINGERPRINT"
 msgstr "EMPREINTE"
 
@@ -560,7 +602,7 @@ msgstr "IPv4"
 msgid "IPV6"
 msgstr "IPv6"
 
-#: lxc/config.go:350
+#: lxc/config.go:379
 msgid "ISSUE DATE"
 msgstr "DATE D'ÉMISSION"
 
@@ -607,7 +649,7 @@ msgstr "Image copiée avec succès !"
 msgid "Invalid URL scheme \"%s\" in \"%s\""
 msgstr "Schème d'URL invalide \"%s\" in \"%s\""
 
-#: lxc/config.go:329
+#: lxc/config.go:358
 msgid "Invalid certificate"
 msgstr "Certificat invalide"
 
@@ -747,7 +789,7 @@ msgstr "  Réseau utilisé :"
 msgid "New alias to define at target"
 msgstr "Nouvel alias à définir sur la cible"
 
-#: lxc/config.go:360
+#: lxc/config.go:389
 msgid "No certificate provided to add"
 msgstr "Un certificat à ajouter n'a pas été fourni"
 
@@ -760,7 +802,7 @@ msgstr "Aucun périphérique existant pour ce réseau"
 msgid "No device found for this storage volume."
 msgstr "Aucun périphérique existant pour ce réseau"
 
-#: lxc/config.go:392
+#: lxc/config.go:421
 msgid "No fingerprint specified."
 msgstr "Aucune empreinte n'a été indiquée."
 
@@ -842,7 +884,7 @@ msgstr "Pid : %d"
 msgid "Press enter to open the editor again"
 msgstr "Appuyer sur Entrée pour ouvrir à nouveau l'éditeur"
 
-#: lxc/config.go:648 lxc/config.go:713 lxc/image.go:1121
+#: lxc/config.go:716 lxc/config.go:781 lxc/image.go:1121
 msgid "Press enter to start the editor again"
 msgstr "Appuyer sur Entrée pour lancer à nouveau l'éditeur"
 
@@ -1130,13 +1172,13 @@ msgid "The container you are starting doesn't have any network attached to it."
 msgstr ""
 "Le conteneur que vous démarrez n'est attaché à aucune interface réseau."
 
-#: lxc/config.go:770 lxc/config.go:787
+#: lxc/config.go:838 lxc/config.go:855
 #, fuzzy
 msgid "The device already exists"
 msgstr "Le périphérique n'existe pas"
 
-#: lxc/config.go:833 lxc/config.go:845 lxc/config.go:881 lxc/config.go:899
-#: lxc/config.go:945 lxc/config.go:962 lxc/config.go:1005 lxc/config.go:1023
+#: lxc/config.go:901 lxc/config.go:913 lxc/config.go:949 lxc/config.go:967
+#: lxc/config.go:1013 lxc/config.go:1030 lxc/config.go:1073 lxc/config.go:1091
 msgid "The device doesn't exist"
 msgstr "Le périphérique n'existe pas"
 
@@ -1268,7 +1310,7 @@ msgstr ""
 msgid "Usage: lxc <command> [options]"
 msgstr "Utilisation : lxc <commande> [options]"
 
-#: lxc/config.go:60
+#: lxc/config.go:84
 #, fuzzy
 msgid ""
 "Usage: lxc config <subcommand> [options]\n"
@@ -1293,6 +1335,11 @@ msgid ""
 "    Edit configuration, either by launching external editor or reading "
 "STDIN.\n"
 "\n"
+"*Container metadata*\n"
+"\n"
+"lxc config metadata show [<remote>:][container]\n"
+"    Show the container metadata.yaml content.\n"
+"\n"
 "*Device management*\n"
 "\n"
 "lxc config device add [<remote>:]<container> <device> <type> [key=value...]\n"
diff --git a/po/it.po b/po/it.po
index 1d36629ca..edbba09c2 100644
--- a/po/it.po
+++ b/po/it.po
@@ -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: 2017-07-12 00:41+0200\n"
+"POT-Creation-Date: 2017-07-14 08:35+0000\n"
 "PO-Revision-Date: 2017-06-15 22:46+0000\n"
 "Last-Translator: Alberto Donato <alberto.donato at gmail.com>\n"
 "Language-Team: Italian <https://hosted.weblate.org/projects/linux-containers/"
@@ -85,6 +85,30 @@ msgid ""
 "### Note that the name is shown but cannot be changed"
 msgstr ""
 
+#: lxc/config.go:60
+msgid ""
+"### This is a yaml representation of the container metadata.\n"
+"### Any line starting with a '# will be ignored.\n"
+"###\n"
+"### A sample configuration looks like:\n"
+"###\n"
+"### architecture: x86_64\n"
+"### creation_date: 1477146654\n"
+"### expiry_date: 0\n"
+"### properties:\n"
+"###   architecture: x86_64\n"
+"###   description: Busybox x86_64\n"
+"###   name: busybox-x86_64\n"
+"###   os: Busybox\n"
+"### templates:\n"
+"###   /template:\n"
+"###     when:\n"
+"###     - \"\"\n"
+"###     create_only: false\n"
+"###     template: template.tpl\n"
+"###     properties: {}"
+msgstr ""
+
 #: lxc/image.go:62
 msgid ""
 "### This is a yaml representation of the image properties.\n"
@@ -223,7 +247,7 @@ msgstr "Bytes ricevuti"
 msgid "Bytes sent"
 msgstr "Byte inviati"
 
-#: lxc/config.go:349
+#: lxc/config.go:378
 msgid "COMMON NAME"
 msgstr ""
 
@@ -243,17 +267,17 @@ msgstr "CREATO IL"
 msgid "Can't pull a directory without --recursive"
 msgstr ""
 
-#: lxc/config.go:156 lxc/network.go:542
+#: lxc/config.go:185 lxc/network.go:542
 #, c-format
 msgid "Can't read from stdin: %s"
 msgstr ""
 
-#: lxc/config.go:169
+#: lxc/config.go:198
 #, c-format
 msgid "Can't unset key '%s', it's not currently set"
 msgstr ""
 
-#: lxc/config.go:211 lxc/config.go:237
+#: lxc/config.go:240 lxc/config.go:266
 #, c-format
 msgid "Can't unset key '%s', it's not currently set."
 msgstr ""
@@ -283,7 +307,7 @@ msgstr ""
 msgid "Config key/value to apply to the new container"
 msgstr ""
 
-#: lxc/config.go:647 lxc/config.go:712 lxc/image.go:1120 lxc/network.go:418
+#: lxc/config.go:715 lxc/config.go:780 lxc/image.go:1120 lxc/network.go:418
 #: lxc/profile.go:267 lxc/storage.go:576 lxc/storage.go:935
 #, c-format
 msgid "Config parsing error: %s"
@@ -355,12 +379,12 @@ msgstr ""
 msgid "Define a compression algorithm: for image or none"
 msgstr ""
 
-#: lxc/config.go:803
+#: lxc/config.go:871
 #, c-format
 msgid "Device %s added to %s"
 msgstr ""
 
-#: lxc/config.go:1039
+#: lxc/config.go:1107
 #, c-format
 msgid "Device %s removed from %s"
 msgstr ""
@@ -390,7 +414,7 @@ msgstr ""
 msgid "EPHEMERAL"
 msgstr ""
 
-#: lxc/config.go:351
+#: lxc/config.go:380
 msgid "EXPIRY DATE"
 msgstr ""
 
@@ -432,7 +456,7 @@ msgstr ""
 msgid "Exporting the image: %s"
 msgstr ""
 
-#: lxc/config.go:348 lxc/image.go:229 lxc/image.go:1066
+#: lxc/config.go:377 lxc/image.go:229 lxc/image.go:1066
 msgid "FINGERPRINT"
 msgstr ""
 
@@ -496,7 +520,7 @@ msgstr ""
 msgid "IPV6"
 msgstr ""
 
-#: lxc/config.go:350
+#: lxc/config.go:379
 msgid "ISSUE DATE"
 msgstr ""
 
@@ -538,7 +562,7 @@ msgstr ""
 msgid "Invalid URL scheme \"%s\" in \"%s\""
 msgstr ""
 
-#: lxc/config.go:329
+#: lxc/config.go:358
 msgid "Invalid certificate"
 msgstr ""
 
@@ -674,7 +698,7 @@ msgstr ""
 msgid "New alias to define at target"
 msgstr ""
 
-#: lxc/config.go:360
+#: lxc/config.go:389
 msgid "No certificate provided to add"
 msgstr ""
 
@@ -686,7 +710,7 @@ msgstr ""
 msgid "No device found for this storage volume."
 msgstr ""
 
-#: lxc/config.go:392
+#: lxc/config.go:421
 msgid "No fingerprint specified."
 msgstr ""
 
@@ -767,7 +791,7 @@ msgstr ""
 msgid "Press enter to open the editor again"
 msgstr ""
 
-#: lxc/config.go:648 lxc/config.go:713 lxc/image.go:1121
+#: lxc/config.go:716 lxc/config.go:781 lxc/image.go:1121
 msgid "Press enter to start the editor again"
 msgstr ""
 
@@ -1046,13 +1070,13 @@ msgstr ""
 msgid "The container you are starting doesn't have any network attached to it."
 msgstr ""
 
-#: lxc/config.go:770 lxc/config.go:787
+#: lxc/config.go:838 lxc/config.go:855
 #, fuzzy
 msgid "The device already exists"
 msgstr "il remote %s esiste già"
 
-#: lxc/config.go:833 lxc/config.go:845 lxc/config.go:881 lxc/config.go:899
-#: lxc/config.go:945 lxc/config.go:962 lxc/config.go:1005 lxc/config.go:1023
+#: lxc/config.go:901 lxc/config.go:913 lxc/config.go:949 lxc/config.go:967
+#: lxc/config.go:1013 lxc/config.go:1030 lxc/config.go:1073 lxc/config.go:1091
 msgid "The device doesn't exist"
 msgstr ""
 
@@ -1174,7 +1198,7 @@ msgstr ""
 msgid "Usage: lxc <command> [options]"
 msgstr ""
 
-#: lxc/config.go:60
+#: lxc/config.go:84
 msgid ""
 "Usage: lxc config <subcommand> [options]\n"
 "\n"
@@ -1198,6 +1222,11 @@ msgid ""
 "    Edit configuration, either by launching external editor or reading "
 "STDIN.\n"
 "\n"
+"*Container metadata*\n"
+"\n"
+"lxc config metadata show [<remote>:][container]\n"
+"    Show the container metadata.yaml content.\n"
+"\n"
 "*Device management*\n"
 "\n"
 "lxc config device add [<remote>:]<container> <device> <type> [key=value...]\n"
diff --git a/po/ja.po b/po/ja.po
index 557f50af6..3a66645b6 100644
--- a/po/ja.po
+++ b/po/ja.po
@@ -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: 2017-07-12 00:41+0200\n"
+"POT-Creation-Date: 2017-07-14 08:35+0000\n"
 "PO-Revision-Date: 2017-03-23 12:03+0000\n"
 "Last-Translator: KATOH Yasufumi <karma at jazz.email.ne.jp>\n"
 "Language-Team: Japanese <https://hosted.weblate.org/projects/linux-"
@@ -71,6 +71,30 @@ msgid ""
 "### Note that the name is shown but cannot be changed"
 msgstr ""
 
+#: lxc/config.go:60
+msgid ""
+"### This is a yaml representation of the container metadata.\n"
+"### Any line starting with a '# will be ignored.\n"
+"###\n"
+"### A sample configuration looks like:\n"
+"###\n"
+"### architecture: x86_64\n"
+"### creation_date: 1477146654\n"
+"### expiry_date: 0\n"
+"### properties:\n"
+"###   architecture: x86_64\n"
+"###   description: Busybox x86_64\n"
+"###   name: busybox-x86_64\n"
+"###   os: Busybox\n"
+"### templates:\n"
+"###   /template:\n"
+"###     when:\n"
+"###     - \"\"\n"
+"###     create_only: false\n"
+"###     template: template.tpl\n"
+"###     properties: {}"
+msgstr ""
+
 #: lxc/image.go:62
 msgid ""
 "### This is a yaml representation of the image properties.\n"
@@ -202,7 +226,7 @@ msgstr "受信バイト数"
 msgid "Bytes sent"
 msgstr "送信バイト数"
 
-#: lxc/config.go:349
+#: lxc/config.go:378
 msgid "COMMON NAME"
 msgstr ""
 
@@ -224,17 +248,17 @@ msgid "Can't pull a directory without --recursive"
 msgstr ""
 "ディレクトリを pull する場合は --recursive オプションを使用してください"
 
-#: lxc/config.go:156 lxc/network.go:542
+#: lxc/config.go:185 lxc/network.go:542
 #, c-format
 msgid "Can't read from stdin: %s"
 msgstr "標準入力から読み込めません: %s"
 
-#: lxc/config.go:169
+#: lxc/config.go:198
 #, fuzzy, c-format
 msgid "Can't unset key '%s', it's not currently set"
 msgstr "キー '%s' が指定されていないので削除できません。"
 
-#: lxc/config.go:211 lxc/config.go:237
+#: lxc/config.go:240 lxc/config.go:266
 #, c-format
 msgid "Can't unset key '%s', it's not currently set."
 msgstr "キー '%s' が指定されていないので削除できません。"
@@ -264,7 +288,7 @@ msgstr "コマンド:"
 msgid "Config key/value to apply to the new container"
 msgstr "新しいコンテナに適用するキー/値の設定"
 
-#: lxc/config.go:647 lxc/config.go:712 lxc/image.go:1120 lxc/network.go:418
+#: lxc/config.go:715 lxc/config.go:780 lxc/image.go:1120 lxc/network.go:418
 #: lxc/profile.go:267 lxc/storage.go:576 lxc/storage.go:935
 #, c-format
 msgid "Config parsing error: %s"
@@ -337,12 +361,12 @@ msgstr ""
 msgid "Define a compression algorithm: for image or none"
 msgstr "圧縮アルゴリズムを指定します: 圧縮アルゴリズム名 or none"
 
-#: lxc/config.go:803
+#: lxc/config.go:871
 #, c-format
 msgid "Device %s added to %s"
 msgstr "デバイス %s が %s に追加されました"
 
-#: lxc/config.go:1039
+#: lxc/config.go:1107
 #, c-format
 msgid "Device %s removed from %s"
 msgstr "デバイス %s が %s から削除されました"
@@ -372,7 +396,7 @@ msgstr "ディスク使用量:"
 msgid "EPHEMERAL"
 msgstr ""
 
-#: lxc/config.go:351
+#: lxc/config.go:380
 msgid "EXPIRY DATE"
 msgstr ""
 
@@ -414,7 +438,7 @@ msgstr "失効日時: 失効しない"
 msgid "Exporting the image: %s"
 msgstr "イメージのインポート中: %s"
 
-#: lxc/config.go:348 lxc/image.go:229 lxc/image.go:1066
+#: lxc/config.go:377 lxc/image.go:229 lxc/image.go:1066
 msgid "FINGERPRINT"
 msgstr ""
 
@@ -480,7 +504,7 @@ msgstr "IPV4"
 msgid "IPV6"
 msgstr "IPV6"
 
-#: lxc/config.go:350
+#: lxc/config.go:379
 msgid "ISSUE DATE"
 msgstr ""
 
@@ -524,7 +548,7 @@ msgstr "イメージのコピーが成功しました!"
 msgid "Invalid URL scheme \"%s\" in \"%s\""
 msgstr "不正な URL スキーム \"%s\" (\"%s\" 内)"
 
-#: lxc/config.go:329
+#: lxc/config.go:358
 msgid "Invalid certificate"
 msgstr "不正な証明書です"
 
@@ -663,7 +687,7 @@ msgstr "ネットワーク使用状況:"
 msgid "New alias to define at target"
 msgstr "新しいエイリアスを定義する"
 
-#: lxc/config.go:360
+#: lxc/config.go:389
 msgid "No certificate provided to add"
 msgstr "追加すべき証明書が提供されていません"
 
@@ -675,7 +699,7 @@ msgstr "このネットワークに対するデバイスがありません"
 msgid "No device found for this storage volume."
 msgstr "このストレージボリュームに対するデバイスがありません。"
 
-#: lxc/config.go:392
+#: lxc/config.go:421
 msgid "No fingerprint specified."
 msgstr "フィンガープリントが指定されていません。"
 
@@ -756,7 +780,7 @@ msgstr "Pid: %d"
 msgid "Press enter to open the editor again"
 msgstr "再度エディタを開くためには Enter キーを押します"
 
-#: lxc/config.go:648 lxc/config.go:713 lxc/image.go:1121
+#: lxc/config.go:716 lxc/config.go:781 lxc/image.go:1121
 msgid "Press enter to start the editor again"
 msgstr "再度エディタを起動するには Enter キーを押します"
 
@@ -1038,13 +1062,13 @@ msgstr ""
 msgid "The container you are starting doesn't have any network attached to it."
 msgstr "起動しようとしたコンテナに接続されているネットワークがありません。"
 
-#: lxc/config.go:770 lxc/config.go:787
+#: lxc/config.go:838 lxc/config.go:855
 #, fuzzy
 msgid "The device already exists"
 msgstr "リモート %s は既に存在します"
 
-#: lxc/config.go:833 lxc/config.go:845 lxc/config.go:881 lxc/config.go:899
-#: lxc/config.go:945 lxc/config.go:962 lxc/config.go:1005 lxc/config.go:1023
+#: lxc/config.go:901 lxc/config.go:913 lxc/config.go:949 lxc/config.go:967
+#: lxc/config.go:1013 lxc/config.go:1030 lxc/config.go:1073 lxc/config.go:1091
 msgid "The device doesn't exist"
 msgstr "デバイスが存在しません"
 
@@ -1180,7 +1204,7 @@ msgstr ""
 msgid "Usage: lxc <command> [options]"
 msgstr "使い方: lxc <コマンド> [オプション]"
 
-#: lxc/config.go:60
+#: lxc/config.go:84
 #, fuzzy
 msgid ""
 "Usage: lxc config <subcommand> [options]\n"
@@ -1205,6 +1229,11 @@ msgid ""
 "    Edit configuration, either by launching external editor or reading "
 "STDIN.\n"
 "\n"
+"*Container metadata*\n"
+"\n"
+"lxc config metadata show [<remote>:][container]\n"
+"    Show the container metadata.yaml content.\n"
+"\n"
 "*Device management*\n"
 "\n"
 "lxc config device add [<remote>:]<container> <device> <type> [key=value...]\n"
diff --git a/po/lxd.pot b/po/lxd.pot
index dbfa7c209..bfa5ca373 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: 2017-07-12 00:41+0200\n"
+        "POT-Creation-Date: 2017-07-14 10:35+0200\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"
@@ -65,6 +65,29 @@ msgid   "### This is a yaml representation of the configuration.\n"
         "### Note that the name is shown but cannot be changed"
 msgstr  ""
 
+#: lxc/config.go:60
+msgid   "### This is a yaml representation of the container metadata.\n"
+        "### Any line starting with a '# will be ignored.\n"
+        "###\n"
+        "### A sample configuration looks like:\n"
+        "###\n"
+        "### architecture: x86_64\n"
+        "### creation_date: 1477146654\n"
+        "### expiry_date: 0\n"
+        "### properties:\n"
+        "###   architecture: x86_64\n"
+        "###   description: Busybox x86_64\n"
+        "###   name: busybox-x86_64\n"
+        "###   os: Busybox\n"
+        "### templates:\n"
+        "###   /template:\n"
+        "###     when:\n"
+        "###     - \"\"\n"
+        "###     create_only: false\n"
+        "###     template: template.tpl\n"
+        "###     properties: {}"
+msgstr  ""
+
 #: lxc/image.go:62
 msgid   "### This is a yaml representation of the image properties.\n"
         "### Any line starting with a '# will be ignored.\n"
@@ -193,7 +216,7 @@ msgstr  ""
 msgid   "Bytes sent"
 msgstr  ""
 
-#: lxc/config.go:349
+#: lxc/config.go:378
 msgid   "COMMON NAME"
 msgstr  ""
 
@@ -213,17 +236,17 @@ msgstr  ""
 msgid   "Can't pull a directory without --recursive"
 msgstr  ""
 
-#: lxc/config.go:156 lxc/network.go:542
+#: lxc/config.go:185 lxc/network.go:542
 #, c-format
 msgid   "Can't read from stdin: %s"
 msgstr  ""
 
-#: lxc/config.go:169
+#: lxc/config.go:198
 #, c-format
 msgid   "Can't unset key '%s', it's not currently set"
 msgstr  ""
 
-#: lxc/config.go:211 lxc/config.go:237
+#: lxc/config.go:240 lxc/config.go:266
 #, c-format
 msgid   "Can't unset key '%s', it's not currently set."
 msgstr  ""
@@ -253,7 +276,7 @@ msgstr  ""
 msgid   "Config key/value to apply to the new container"
 msgstr  ""
 
-#: lxc/config.go:647 lxc/config.go:712 lxc/image.go:1120 lxc/network.go:418 lxc/profile.go:267 lxc/storage.go:576 lxc/storage.go:935
+#: lxc/config.go:715 lxc/config.go:780 lxc/image.go:1120 lxc/network.go:418 lxc/profile.go:267 lxc/storage.go:576 lxc/storage.go:935
 #, c-format
 msgid   "Config parsing error: %s"
 msgstr  ""
@@ -323,12 +346,12 @@ msgstr  ""
 msgid   "Define a compression algorithm: for image or none"
 msgstr  ""
 
-#: lxc/config.go:803
+#: lxc/config.go:871
 #, c-format
 msgid   "Device %s added to %s"
 msgstr  ""
 
-#: lxc/config.go:1039
+#: lxc/config.go:1107
 #, c-format
 msgid   "Device %s removed from %s"
 msgstr  ""
@@ -358,7 +381,7 @@ msgstr  ""
 msgid   "EPHEMERAL"
 msgstr  ""
 
-#: lxc/config.go:351
+#: lxc/config.go:380
 msgid   "EXPIRY DATE"
 msgstr  ""
 
@@ -400,7 +423,7 @@ msgstr  ""
 msgid   "Exporting the image: %s"
 msgstr  ""
 
-#: lxc/config.go:348 lxc/image.go:229 lxc/image.go:1066
+#: lxc/config.go:377 lxc/image.go:229 lxc/image.go:1066
 msgid   "FINGERPRINT"
 msgstr  ""
 
@@ -464,7 +487,7 @@ msgstr  ""
 msgid   "IPV6"
 msgstr  ""
 
-#: lxc/config.go:350
+#: lxc/config.go:379
 msgid   "ISSUE DATE"
 msgstr  ""
 
@@ -506,7 +529,7 @@ msgstr  ""
 msgid   "Invalid URL scheme \"%s\" in \"%s\""
 msgstr  ""
 
-#: lxc/config.go:329
+#: lxc/config.go:358
 msgid   "Invalid certificate"
 msgstr  ""
 
@@ -641,7 +664,7 @@ msgstr  ""
 msgid   "New alias to define at target"
 msgstr  ""
 
-#: lxc/config.go:360
+#: lxc/config.go:389
 msgid   "No certificate provided to add"
 msgstr  ""
 
@@ -653,7 +676,7 @@ msgstr  ""
 msgid   "No device found for this storage volume."
 msgstr  ""
 
-#: lxc/config.go:392
+#: lxc/config.go:421
 msgid   "No fingerprint specified."
 msgstr  ""
 
@@ -734,7 +757,7 @@ msgstr  ""
 msgid   "Press enter to open the editor again"
 msgstr  ""
 
-#: lxc/config.go:648 lxc/config.go:713 lxc/image.go:1121
+#: lxc/config.go:716 lxc/config.go:781 lxc/image.go:1121
 msgid   "Press enter to start the editor again"
 msgstr  ""
 
@@ -1011,11 +1034,11 @@ msgstr  ""
 msgid   "The container you are starting doesn't have any network attached to it."
 msgstr  ""
 
-#: lxc/config.go:770 lxc/config.go:787
+#: lxc/config.go:838 lxc/config.go:855
 msgid   "The device already exists"
 msgstr  ""
 
-#: lxc/config.go:833 lxc/config.go:845 lxc/config.go:881 lxc/config.go:899 lxc/config.go:945 lxc/config.go:962 lxc/config.go:1005 lxc/config.go:1023
+#: lxc/config.go:901 lxc/config.go:913 lxc/config.go:949 lxc/config.go:967 lxc/config.go:1013 lxc/config.go:1030 lxc/config.go:1073 lxc/config.go:1091
 msgid   "The device doesn't exist"
 msgstr  ""
 
@@ -1135,7 +1158,7 @@ msgstr  ""
 msgid   "Usage: lxc <command> [options]"
 msgstr  ""
 
-#: lxc/config.go:60
+#: lxc/config.go:84
 msgid   "Usage: lxc config <subcommand> [options]\n"
         "\n"
         "Change container or server configuration options.\n"
@@ -1157,6 +1180,11 @@ msgid   "Usage: lxc config <subcommand> [options]\n"
         "lxc config edit [<remote>:][container]\n"
         "    Edit configuration, either by launching external editor or reading STDIN.\n"
         "\n"
+        "*Container metadata*\n"
+        "\n"
+        "lxc config metadata show [<remote>:][container]\n"
+        "    Show the container metadata.yaml content.\n"
+        "\n"
         "*Device management*\n"
         "\n"
         "lxc config device add [<remote>:]<container> <device> <type> [key=value...]\n"
diff --git a/po/nl.po b/po/nl.po
index a005e30f2..101f50f7f 100644
--- a/po/nl.po
+++ b/po/nl.po
@@ -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: 2017-07-12 00:41+0200\n"
+"POT-Creation-Date: 2017-07-14 08:35+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -68,6 +68,30 @@ msgid ""
 "### Note that the name is shown but cannot be changed"
 msgstr ""
 
+#: lxc/config.go:60
+msgid ""
+"### This is a yaml representation of the container metadata.\n"
+"### Any line starting with a '# will be ignored.\n"
+"###\n"
+"### A sample configuration looks like:\n"
+"###\n"
+"### architecture: x86_64\n"
+"### creation_date: 1477146654\n"
+"### expiry_date: 0\n"
+"### properties:\n"
+"###   architecture: x86_64\n"
+"###   description: Busybox x86_64\n"
+"###   name: busybox-x86_64\n"
+"###   os: Busybox\n"
+"### templates:\n"
+"###   /template:\n"
+"###     when:\n"
+"###     - \"\"\n"
+"###     create_only: false\n"
+"###     template: template.tpl\n"
+"###     properties: {}"
+msgstr ""
+
 #: lxc/image.go:62
 msgid ""
 "### This is a yaml representation of the image properties.\n"
@@ -199,7 +223,7 @@ msgstr ""
 msgid "Bytes sent"
 msgstr ""
 
-#: lxc/config.go:349
+#: lxc/config.go:378
 msgid "COMMON NAME"
 msgstr ""
 
@@ -219,17 +243,17 @@ msgstr ""
 msgid "Can't pull a directory without --recursive"
 msgstr ""
 
-#: lxc/config.go:156 lxc/network.go:542
+#: lxc/config.go:185 lxc/network.go:542
 #, c-format
 msgid "Can't read from stdin: %s"
 msgstr ""
 
-#: lxc/config.go:169
+#: lxc/config.go:198
 #, c-format
 msgid "Can't unset key '%s', it's not currently set"
 msgstr ""
 
-#: lxc/config.go:211 lxc/config.go:237
+#: lxc/config.go:240 lxc/config.go:266
 #, c-format
 msgid "Can't unset key '%s', it's not currently set."
 msgstr ""
@@ -259,7 +283,7 @@ msgstr ""
 msgid "Config key/value to apply to the new container"
 msgstr ""
 
-#: lxc/config.go:647 lxc/config.go:712 lxc/image.go:1120 lxc/network.go:418
+#: lxc/config.go:715 lxc/config.go:780 lxc/image.go:1120 lxc/network.go:418
 #: lxc/profile.go:267 lxc/storage.go:576 lxc/storage.go:935
 #, c-format
 msgid "Config parsing error: %s"
@@ -331,12 +355,12 @@ msgstr ""
 msgid "Define a compression algorithm: for image or none"
 msgstr ""
 
-#: lxc/config.go:803
+#: lxc/config.go:871
 #, c-format
 msgid "Device %s added to %s"
 msgstr ""
 
-#: lxc/config.go:1039
+#: lxc/config.go:1107
 #, c-format
 msgid "Device %s removed from %s"
 msgstr ""
@@ -366,7 +390,7 @@ msgstr ""
 msgid "EPHEMERAL"
 msgstr ""
 
-#: lxc/config.go:351
+#: lxc/config.go:380
 msgid "EXPIRY DATE"
 msgstr ""
 
@@ -408,7 +432,7 @@ msgstr ""
 msgid "Exporting the image: %s"
 msgstr ""
 
-#: lxc/config.go:348 lxc/image.go:229 lxc/image.go:1066
+#: lxc/config.go:377 lxc/image.go:229 lxc/image.go:1066
 msgid "FINGERPRINT"
 msgstr ""
 
@@ -472,7 +496,7 @@ msgstr ""
 msgid "IPV6"
 msgstr ""
 
-#: lxc/config.go:350
+#: lxc/config.go:379
 msgid "ISSUE DATE"
 msgstr ""
 
@@ -514,7 +538,7 @@ msgstr ""
 msgid "Invalid URL scheme \"%s\" in \"%s\""
 msgstr ""
 
-#: lxc/config.go:329
+#: lxc/config.go:358
 msgid "Invalid certificate"
 msgstr ""
 
@@ -650,7 +674,7 @@ msgstr ""
 msgid "New alias to define at target"
 msgstr ""
 
-#: lxc/config.go:360
+#: lxc/config.go:389
 msgid "No certificate provided to add"
 msgstr ""
 
@@ -662,7 +686,7 @@ msgstr ""
 msgid "No device found for this storage volume."
 msgstr ""
 
-#: lxc/config.go:392
+#: lxc/config.go:421
 msgid "No fingerprint specified."
 msgstr ""
 
@@ -743,7 +767,7 @@ msgstr ""
 msgid "Press enter to open the editor again"
 msgstr ""
 
-#: lxc/config.go:648 lxc/config.go:713 lxc/image.go:1121
+#: lxc/config.go:716 lxc/config.go:781 lxc/image.go:1121
 msgid "Press enter to start the editor again"
 msgstr ""
 
@@ -1022,12 +1046,12 @@ msgstr ""
 msgid "The container you are starting doesn't have any network attached to it."
 msgstr ""
 
-#: lxc/config.go:770 lxc/config.go:787
+#: lxc/config.go:838 lxc/config.go:855
 msgid "The device already exists"
 msgstr ""
 
-#: lxc/config.go:833 lxc/config.go:845 lxc/config.go:881 lxc/config.go:899
-#: lxc/config.go:945 lxc/config.go:962 lxc/config.go:1005 lxc/config.go:1023
+#: lxc/config.go:901 lxc/config.go:913 lxc/config.go:949 lxc/config.go:967
+#: lxc/config.go:1013 lxc/config.go:1030 lxc/config.go:1073 lxc/config.go:1091
 msgid "The device doesn't exist"
 msgstr ""
 
@@ -1149,7 +1173,7 @@ msgstr ""
 msgid "Usage: lxc <command> [options]"
 msgstr ""
 
-#: lxc/config.go:60
+#: lxc/config.go:84
 msgid ""
 "Usage: lxc config <subcommand> [options]\n"
 "\n"
@@ -1173,6 +1197,11 @@ msgid ""
 "    Edit configuration, either by launching external editor or reading "
 "STDIN.\n"
 "\n"
+"*Container metadata*\n"
+"\n"
+"lxc config metadata show [<remote>:][container]\n"
+"    Show the container metadata.yaml content.\n"
+"\n"
 "*Device management*\n"
 "\n"
 "lxc config device add [<remote>:]<container> <device> <type> [key=value...]\n"
diff --git a/po/ru.po b/po/ru.po
index 148c7b953..68104bb71 100644
--- a/po/ru.po
+++ b/po/ru.po
@@ -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: 2017-07-12 00:41+0200\n"
+"POT-Creation-Date: 2017-07-14 08:35+0000\n"
 "PO-Revision-Date: 2017-06-06 13:55+0000\n"
 "Last-Translator: Александр Киль <shorrey at gmail.com>\n"
 "Language-Team: Russian <https://hosted.weblate.org/projects/linux-containers/"
@@ -106,6 +106,48 @@ msgstr ""
 "###\n"
 "### Обратите внимание, что имя отображается, но не может быть изменено"
 
+#: lxc/config.go:60
+#, fuzzy
+msgid ""
+"### This is a yaml representation of the container metadata.\n"
+"### Any line starting with a '# will be ignored.\n"
+"###\n"
+"### A sample configuration looks like:\n"
+"###\n"
+"### architecture: x86_64\n"
+"### creation_date: 1477146654\n"
+"### expiry_date: 0\n"
+"### properties:\n"
+"###   architecture: x86_64\n"
+"###   description: Busybox x86_64\n"
+"###   name: busybox-x86_64\n"
+"###   os: Busybox\n"
+"### templates:\n"
+"###   /template:\n"
+"###     when:\n"
+"###     - \"\"\n"
+"###     create_only: false\n"
+"###     template: template.tpl\n"
+"###     properties: {}"
+msgstr ""
+"### Это представление конфигурации в формате YAML. \n"
+"### Любая строка начинающаяся с '#' будет игнорироваться.\n"
+"###\n"
+"### Пример конфигурации:\n"
+"### name: container1\n"
+"### profiles:\n"
+"### - default\n"
+"### config:\n"
+"###   volatile.eth0.hwaddr: 00:16:3e:e9:f8:7f\n"
+"### devices:\n"
+"###   homedir:\n"
+"###     path: /extra\n"
+"###     source: /home/user\n"
+"###     type: disk\n"
+"### ephemeral: false\n"
+"###\n"
+"### Обратите внимание, что имя отображается, но не может быть изменено"
+
 #: lxc/image.go:62
 msgid ""
 "### This is a yaml representation of the image properties.\n"
@@ -271,7 +313,7 @@ msgstr "Получено байтов"
 msgid "Bytes sent"
 msgstr "Отправлено байтов"
 
-#: lxc/config.go:349
+#: lxc/config.go:378
 msgid "COMMON NAME"
 msgstr "ОБЩЕЕ ИМЯ"
 
@@ -292,17 +334,17 @@ msgstr "СОЗДАН"
 msgid "Can't pull a directory without --recursive"
 msgstr ""
 
-#: lxc/config.go:156 lxc/network.go:542
+#: lxc/config.go:185 lxc/network.go:542
 #, c-format
 msgid "Can't read from stdin: %s"
 msgstr "Невозможно прочитать из стандартного ввода: %s"
 
-#: lxc/config.go:169
+#: lxc/config.go:198
 #, c-format
 msgid "Can't unset key '%s', it's not currently set"
 msgstr ""
 
-#: lxc/config.go:211 lxc/config.go:237
+#: lxc/config.go:240 lxc/config.go:266
 #, c-format
 msgid "Can't unset key '%s', it's not currently set."
 msgstr ""
@@ -332,7 +374,7 @@ msgstr ""
 msgid "Config key/value to apply to the new container"
 msgstr ""
 
-#: lxc/config.go:647 lxc/config.go:712 lxc/image.go:1120 lxc/network.go:418
+#: lxc/config.go:715 lxc/config.go:780 lxc/image.go:1120 lxc/network.go:418
 #: lxc/profile.go:267 lxc/storage.go:576 lxc/storage.go:935
 #, c-format
 msgid "Config parsing error: %s"
@@ -404,12 +446,12 @@ msgstr ""
 msgid "Define a compression algorithm: for image or none"
 msgstr ""
 
-#: lxc/config.go:803
+#: lxc/config.go:871
 #, c-format
 msgid "Device %s added to %s"
 msgstr ""
 
-#: lxc/config.go:1039
+#: lxc/config.go:1107
 #, c-format
 msgid "Device %s removed from %s"
 msgstr ""
@@ -440,7 +482,7 @@ msgstr " Использование диска:"
 msgid "EPHEMERAL"
 msgstr ""
 
-#: lxc/config.go:351
+#: lxc/config.go:380
 msgid "EXPIRY DATE"
 msgstr ""
 
@@ -482,7 +524,7 @@ msgstr ""
 msgid "Exporting the image: %s"
 msgstr "Копирование образа: %s"
 
-#: lxc/config.go:348 lxc/image.go:229 lxc/image.go:1066
+#: lxc/config.go:377 lxc/image.go:229 lxc/image.go:1066
 msgid "FINGERPRINT"
 msgstr ""
 
@@ -546,7 +588,7 @@ msgstr ""
 msgid "IPV6"
 msgstr ""
 
-#: lxc/config.go:350
+#: lxc/config.go:379
 msgid "ISSUE DATE"
 msgstr ""
 
@@ -588,7 +630,7 @@ msgstr ""
 msgid "Invalid URL scheme \"%s\" in \"%s\""
 msgstr ""
 
-#: lxc/config.go:329
+#: lxc/config.go:358
 msgid "Invalid certificate"
 msgstr ""
 
@@ -726,7 +768,7 @@ msgstr " Использование сети:"
 msgid "New alias to define at target"
 msgstr ""
 
-#: lxc/config.go:360
+#: lxc/config.go:389
 msgid "No certificate provided to add"
 msgstr ""
 
@@ -738,7 +780,7 @@ msgstr ""
 msgid "No device found for this storage volume."
 msgstr ""
 
-#: lxc/config.go:392
+#: lxc/config.go:421
 msgid "No fingerprint specified."
 msgstr ""
 
@@ -819,7 +861,7 @@ msgstr ""
 msgid "Press enter to open the editor again"
 msgstr ""
 
-#: lxc/config.go:648 lxc/config.go:713 lxc/image.go:1121
+#: lxc/config.go:716 lxc/config.go:781 lxc/image.go:1121
 msgid "Press enter to start the editor again"
 msgstr ""
 
@@ -1098,12 +1140,12 @@ msgstr ""
 msgid "The container you are starting doesn't have any network attached to it."
 msgstr ""
 
-#: lxc/config.go:770 lxc/config.go:787
+#: lxc/config.go:838 lxc/config.go:855
 msgid "The device already exists"
 msgstr ""
 
-#: lxc/config.go:833 lxc/config.go:845 lxc/config.go:881 lxc/config.go:899
-#: lxc/config.go:945 lxc/config.go:962 lxc/config.go:1005 lxc/config.go:1023
+#: lxc/config.go:901 lxc/config.go:913 lxc/config.go:949 lxc/config.go:967
+#: lxc/config.go:1013 lxc/config.go:1030 lxc/config.go:1073 lxc/config.go:1091
 msgid "The device doesn't exist"
 msgstr ""
 
@@ -1228,7 +1270,7 @@ msgstr ""
 msgid "Usage: lxc <command> [options]"
 msgstr ""
 
-#: lxc/config.go:60
+#: lxc/config.go:84
 msgid ""
 "Usage: lxc config <subcommand> [options]\n"
 "\n"
@@ -1252,6 +1294,11 @@ msgid ""
 "    Edit configuration, either by launching external editor or reading "
 "STDIN.\n"
 "\n"
+"*Container metadata*\n"
+"\n"
+"lxc config metadata show [<remote>:][container]\n"
+"    Show the container metadata.yaml content.\n"
+"\n"
 "*Device management*\n"
 "\n"
 "lxc config device add [<remote>:]<container> <device> <type> [key=value...]\n"
diff --git a/po/sr.po b/po/sr.po
index 47ae3c04f..f8a7d4290 100644
--- a/po/sr.po
+++ b/po/sr.po
@@ -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: 2017-07-12 00:41+0200\n"
+"POT-Creation-Date: 2017-07-14 08:35+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -68,6 +68,30 @@ msgid ""
 "### Note that the name is shown but cannot be changed"
 msgstr ""
 
+#: lxc/config.go:60
+msgid ""
+"### This is a yaml representation of the container metadata.\n"
+"### Any line starting with a '# will be ignored.\n"
+"###\n"
+"### A sample configuration looks like:\n"
+"###\n"
+"### architecture: x86_64\n"
+"### creation_date: 1477146654\n"
+"### expiry_date: 0\n"
+"### properties:\n"
+"###   architecture: x86_64\n"
+"###   description: Busybox x86_64\n"
+"###   name: busybox-x86_64\n"
+"###   os: Busybox\n"
+"### templates:\n"
+"###   /template:\n"
+"###     when:\n"
+"###     - \"\"\n"
+"###     create_only: false\n"
+"###     template: template.tpl\n"
+"###     properties: {}"
+msgstr ""
+
 #: lxc/image.go:62
 msgid ""
 "### This is a yaml representation of the image properties.\n"
@@ -199,7 +223,7 @@ msgstr ""
 msgid "Bytes sent"
 msgstr ""
 
-#: lxc/config.go:349
+#: lxc/config.go:378
 msgid "COMMON NAME"
 msgstr ""
 
@@ -219,17 +243,17 @@ msgstr ""
 msgid "Can't pull a directory without --recursive"
 msgstr ""
 
-#: lxc/config.go:156 lxc/network.go:542
+#: lxc/config.go:185 lxc/network.go:542
 #, c-format
 msgid "Can't read from stdin: %s"
 msgstr ""
 
-#: lxc/config.go:169
+#: lxc/config.go:198
 #, c-format
 msgid "Can't unset key '%s', it's not currently set"
 msgstr ""
 
-#: lxc/config.go:211 lxc/config.go:237
+#: lxc/config.go:240 lxc/config.go:266
 #, c-format
 msgid "Can't unset key '%s', it's not currently set."
 msgstr ""
@@ -259,7 +283,7 @@ msgstr ""
 msgid "Config key/value to apply to the new container"
 msgstr ""
 
-#: lxc/config.go:647 lxc/config.go:712 lxc/image.go:1120 lxc/network.go:418
+#: lxc/config.go:715 lxc/config.go:780 lxc/image.go:1120 lxc/network.go:418
 #: lxc/profile.go:267 lxc/storage.go:576 lxc/storage.go:935
 #, c-format
 msgid "Config parsing error: %s"
@@ -331,12 +355,12 @@ msgstr ""
 msgid "Define a compression algorithm: for image or none"
 msgstr ""
 
-#: lxc/config.go:803
+#: lxc/config.go:871
 #, c-format
 msgid "Device %s added to %s"
 msgstr ""
 
-#: lxc/config.go:1039
+#: lxc/config.go:1107
 #, c-format
 msgid "Device %s removed from %s"
 msgstr ""
@@ -366,7 +390,7 @@ msgstr ""
 msgid "EPHEMERAL"
 msgstr ""
 
-#: lxc/config.go:351
+#: lxc/config.go:380
 msgid "EXPIRY DATE"
 msgstr ""
 
@@ -408,7 +432,7 @@ msgstr ""
 msgid "Exporting the image: %s"
 msgstr ""
 
-#: lxc/config.go:348 lxc/image.go:229 lxc/image.go:1066
+#: lxc/config.go:377 lxc/image.go:229 lxc/image.go:1066
 msgid "FINGERPRINT"
 msgstr ""
 
@@ -472,7 +496,7 @@ msgstr ""
 msgid "IPV6"
 msgstr ""
 
-#: lxc/config.go:350
+#: lxc/config.go:379
 msgid "ISSUE DATE"
 msgstr ""
 
@@ -514,7 +538,7 @@ msgstr ""
 msgid "Invalid URL scheme \"%s\" in \"%s\""
 msgstr ""
 
-#: lxc/config.go:329
+#: lxc/config.go:358
 msgid "Invalid certificate"
 msgstr ""
 
@@ -650,7 +674,7 @@ msgstr ""
 msgid "New alias to define at target"
 msgstr ""
 
-#: lxc/config.go:360
+#: lxc/config.go:389
 msgid "No certificate provided to add"
 msgstr ""
 
@@ -662,7 +686,7 @@ msgstr ""
 msgid "No device found for this storage volume."
 msgstr ""
 
-#: lxc/config.go:392
+#: lxc/config.go:421
 msgid "No fingerprint specified."
 msgstr ""
 
@@ -743,7 +767,7 @@ msgstr ""
 msgid "Press enter to open the editor again"
 msgstr ""
 
-#: lxc/config.go:648 lxc/config.go:713 lxc/image.go:1121
+#: lxc/config.go:716 lxc/config.go:781 lxc/image.go:1121
 msgid "Press enter to start the editor again"
 msgstr ""
 
@@ -1022,12 +1046,12 @@ msgstr ""
 msgid "The container you are starting doesn't have any network attached to it."
 msgstr ""
 
-#: lxc/config.go:770 lxc/config.go:787
+#: lxc/config.go:838 lxc/config.go:855
 msgid "The device already exists"
 msgstr ""
 
-#: lxc/config.go:833 lxc/config.go:845 lxc/config.go:881 lxc/config.go:899
-#: lxc/config.go:945 lxc/config.go:962 lxc/config.go:1005 lxc/config.go:1023
+#: lxc/config.go:901 lxc/config.go:913 lxc/config.go:949 lxc/config.go:967
+#: lxc/config.go:1013 lxc/config.go:1030 lxc/config.go:1073 lxc/config.go:1091
 msgid "The device doesn't exist"
 msgstr ""
 
@@ -1149,7 +1173,7 @@ msgstr ""
 msgid "Usage: lxc <command> [options]"
 msgstr ""
 
-#: lxc/config.go:60
+#: lxc/config.go:84
 msgid ""
 "Usage: lxc config <subcommand> [options]\n"
 "\n"
@@ -1173,6 +1197,11 @@ msgid ""
 "    Edit configuration, either by launching external editor or reading "
 "STDIN.\n"
 "\n"
+"*Container metadata*\n"
+"\n"
+"lxc config metadata show [<remote>:][container]\n"
+"    Show the container metadata.yaml content.\n"
+"\n"
 "*Device management*\n"
 "\n"
 "lxc config device add [<remote>:]<container> <device> <type> [key=value...]\n"
diff --git a/po/sv.po b/po/sv.po
index fe126ed67..a5c7c37aa 100644
--- a/po/sv.po
+++ b/po/sv.po
@@ -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: 2017-07-12 00:41+0200\n"
+"POT-Creation-Date: 2017-07-14 08:35+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -68,6 +68,30 @@ msgid ""
 "### Note that the name is shown but cannot be changed"
 msgstr ""
 
+#: lxc/config.go:60
+msgid ""
+"### This is a yaml representation of the container metadata.\n"
+"### Any line starting with a '# will be ignored.\n"
+"###\n"
+"### A sample configuration looks like:\n"
+"###\n"
+"### architecture: x86_64\n"
+"### creation_date: 1477146654\n"
+"### expiry_date: 0\n"
+"### properties:\n"
+"###   architecture: x86_64\n"
+"###   description: Busybox x86_64\n"
+"###   name: busybox-x86_64\n"
+"###   os: Busybox\n"
+"### templates:\n"
+"###   /template:\n"
+"###     when:\n"
+"###     - \"\"\n"
+"###     create_only: false\n"
+"###     template: template.tpl\n"
+"###     properties: {}"
+msgstr ""
+
 #: lxc/image.go:62
 msgid ""
 "### This is a yaml representation of the image properties.\n"
@@ -199,7 +223,7 @@ msgstr ""
 msgid "Bytes sent"
 msgstr ""
 
-#: lxc/config.go:349
+#: lxc/config.go:378
 msgid "COMMON NAME"
 msgstr ""
 
@@ -219,17 +243,17 @@ msgstr ""
 msgid "Can't pull a directory without --recursive"
 msgstr ""
 
-#: lxc/config.go:156 lxc/network.go:542
+#: lxc/config.go:185 lxc/network.go:542
 #, c-format
 msgid "Can't read from stdin: %s"
 msgstr ""
 
-#: lxc/config.go:169
+#: lxc/config.go:198
 #, c-format
 msgid "Can't unset key '%s', it's not currently set"
 msgstr ""
 
-#: lxc/config.go:211 lxc/config.go:237
+#: lxc/config.go:240 lxc/config.go:266
 #, c-format
 msgid "Can't unset key '%s', it's not currently set."
 msgstr ""
@@ -259,7 +283,7 @@ msgstr ""
 msgid "Config key/value to apply to the new container"
 msgstr ""
 
-#: lxc/config.go:647 lxc/config.go:712 lxc/image.go:1120 lxc/network.go:418
+#: lxc/config.go:715 lxc/config.go:780 lxc/image.go:1120 lxc/network.go:418
 #: lxc/profile.go:267 lxc/storage.go:576 lxc/storage.go:935
 #, c-format
 msgid "Config parsing error: %s"
@@ -331,12 +355,12 @@ msgstr ""
 msgid "Define a compression algorithm: for image or none"
 msgstr ""
 
-#: lxc/config.go:803
+#: lxc/config.go:871
 #, c-format
 msgid "Device %s added to %s"
 msgstr ""
 
-#: lxc/config.go:1039
+#: lxc/config.go:1107
 #, c-format
 msgid "Device %s removed from %s"
 msgstr ""
@@ -366,7 +390,7 @@ msgstr ""
 msgid "EPHEMERAL"
 msgstr ""
 
-#: lxc/config.go:351
+#: lxc/config.go:380
 msgid "EXPIRY DATE"
 msgstr ""
 
@@ -408,7 +432,7 @@ msgstr ""
 msgid "Exporting the image: %s"
 msgstr ""
 
-#: lxc/config.go:348 lxc/image.go:229 lxc/image.go:1066
+#: lxc/config.go:377 lxc/image.go:229 lxc/image.go:1066
 msgid "FINGERPRINT"
 msgstr ""
 
@@ -472,7 +496,7 @@ msgstr ""
 msgid "IPV6"
 msgstr ""
 
-#: lxc/config.go:350
+#: lxc/config.go:379
 msgid "ISSUE DATE"
 msgstr ""
 
@@ -514,7 +538,7 @@ msgstr ""
 msgid "Invalid URL scheme \"%s\" in \"%s\""
 msgstr ""
 
-#: lxc/config.go:329
+#: lxc/config.go:358
 msgid "Invalid certificate"
 msgstr ""
 
@@ -650,7 +674,7 @@ msgstr ""
 msgid "New alias to define at target"
 msgstr ""
 
-#: lxc/config.go:360
+#: lxc/config.go:389
 msgid "No certificate provided to add"
 msgstr ""
 
@@ -662,7 +686,7 @@ msgstr ""
 msgid "No device found for this storage volume."
 msgstr ""
 
-#: lxc/config.go:392
+#: lxc/config.go:421
 msgid "No fingerprint specified."
 msgstr ""
 
@@ -743,7 +767,7 @@ msgstr ""
 msgid "Press enter to open the editor again"
 msgstr ""
 
-#: lxc/config.go:648 lxc/config.go:713 lxc/image.go:1121
+#: lxc/config.go:716 lxc/config.go:781 lxc/image.go:1121
 msgid "Press enter to start the editor again"
 msgstr ""
 
@@ -1022,12 +1046,12 @@ msgstr ""
 msgid "The container you are starting doesn't have any network attached to it."
 msgstr ""
 
-#: lxc/config.go:770 lxc/config.go:787
+#: lxc/config.go:838 lxc/config.go:855
 msgid "The device already exists"
 msgstr ""
 
-#: lxc/config.go:833 lxc/config.go:845 lxc/config.go:881 lxc/config.go:899
-#: lxc/config.go:945 lxc/config.go:962 lxc/config.go:1005 lxc/config.go:1023
+#: lxc/config.go:901 lxc/config.go:913 lxc/config.go:949 lxc/config.go:967
+#: lxc/config.go:1013 lxc/config.go:1030 lxc/config.go:1073 lxc/config.go:1091
 msgid "The device doesn't exist"
 msgstr ""
 
@@ -1149,7 +1173,7 @@ msgstr ""
 msgid "Usage: lxc <command> [options]"
 msgstr ""
 
-#: lxc/config.go:60
+#: lxc/config.go:84
 msgid ""
 "Usage: lxc config <subcommand> [options]\n"
 "\n"
@@ -1173,6 +1197,11 @@ msgid ""
 "    Edit configuration, either by launching external editor or reading "
 "STDIN.\n"
 "\n"
+"*Container metadata*\n"
+"\n"
+"lxc config metadata show [<remote>:][container]\n"
+"    Show the container metadata.yaml content.\n"
+"\n"
 "*Device management*\n"
 "\n"
 "lxc config device add [<remote>:]<container> <device> <type> [key=value...]\n"
diff --git a/po/tr.po b/po/tr.po
index ffc13f253..7fe893057 100644
--- a/po/tr.po
+++ b/po/tr.po
@@ -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: 2017-07-12 00:41+0200\n"
+"POT-Creation-Date: 2017-07-14 08:35+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -68,6 +68,30 @@ msgid ""
 "### Note that the name is shown but cannot be changed"
 msgstr ""
 
+#: lxc/config.go:60
+msgid ""
+"### This is a yaml representation of the container metadata.\n"
+"### Any line starting with a '# will be ignored.\n"
+"###\n"
+"### A sample configuration looks like:\n"
+"###\n"
+"### architecture: x86_64\n"
+"### creation_date: 1477146654\n"
+"### expiry_date: 0\n"
+"### properties:\n"
+"###   architecture: x86_64\n"
+"###   description: Busybox x86_64\n"
+"###   name: busybox-x86_64\n"
+"###   os: Busybox\n"
+"### templates:\n"
+"###   /template:\n"
+"###     when:\n"
+"###     - \"\"\n"
+"###     create_only: false\n"
+"###     template: template.tpl\n"
+"###     properties: {}"
+msgstr ""
+
 #: lxc/image.go:62
 msgid ""
 "### This is a yaml representation of the image properties.\n"
@@ -199,7 +223,7 @@ msgstr ""
 msgid "Bytes sent"
 msgstr ""
 
-#: lxc/config.go:349
+#: lxc/config.go:378
 msgid "COMMON NAME"
 msgstr ""
 
@@ -219,17 +243,17 @@ msgstr ""
 msgid "Can't pull a directory without --recursive"
 msgstr ""
 
-#: lxc/config.go:156 lxc/network.go:542
+#: lxc/config.go:185 lxc/network.go:542
 #, c-format
 msgid "Can't read from stdin: %s"
 msgstr ""
 
-#: lxc/config.go:169
+#: lxc/config.go:198
 #, c-format
 msgid "Can't unset key '%s', it's not currently set"
 msgstr ""
 
-#: lxc/config.go:211 lxc/config.go:237
+#: lxc/config.go:240 lxc/config.go:266
 #, c-format
 msgid "Can't unset key '%s', it's not currently set."
 msgstr ""
@@ -259,7 +283,7 @@ msgstr ""
 msgid "Config key/value to apply to the new container"
 msgstr ""
 
-#: lxc/config.go:647 lxc/config.go:712 lxc/image.go:1120 lxc/network.go:418
+#: lxc/config.go:715 lxc/config.go:780 lxc/image.go:1120 lxc/network.go:418
 #: lxc/profile.go:267 lxc/storage.go:576 lxc/storage.go:935
 #, c-format
 msgid "Config parsing error: %s"
@@ -331,12 +355,12 @@ msgstr ""
 msgid "Define a compression algorithm: for image or none"
 msgstr ""
 
-#: lxc/config.go:803
+#: lxc/config.go:871
 #, c-format
 msgid "Device %s added to %s"
 msgstr ""
 
-#: lxc/config.go:1039
+#: lxc/config.go:1107
 #, c-format
 msgid "Device %s removed from %s"
 msgstr ""
@@ -366,7 +390,7 @@ msgstr ""
 msgid "EPHEMERAL"
 msgstr ""
 
-#: lxc/config.go:351
+#: lxc/config.go:380
 msgid "EXPIRY DATE"
 msgstr ""
 
@@ -408,7 +432,7 @@ msgstr ""
 msgid "Exporting the image: %s"
 msgstr ""
 
-#: lxc/config.go:348 lxc/image.go:229 lxc/image.go:1066
+#: lxc/config.go:377 lxc/image.go:229 lxc/image.go:1066
 msgid "FINGERPRINT"
 msgstr ""
 
@@ -472,7 +496,7 @@ msgstr ""
 msgid "IPV6"
 msgstr ""
 
-#: lxc/config.go:350
+#: lxc/config.go:379
 msgid "ISSUE DATE"
 msgstr ""
 
@@ -514,7 +538,7 @@ msgstr ""
 msgid "Invalid URL scheme \"%s\" in \"%s\""
 msgstr ""
 
-#: lxc/config.go:329
+#: lxc/config.go:358
 msgid "Invalid certificate"
 msgstr ""
 
@@ -650,7 +674,7 @@ msgstr ""
 msgid "New alias to define at target"
 msgstr ""
 
-#: lxc/config.go:360
+#: lxc/config.go:389
 msgid "No certificate provided to add"
 msgstr ""
 
@@ -662,7 +686,7 @@ msgstr ""
 msgid "No device found for this storage volume."
 msgstr ""
 
-#: lxc/config.go:392
+#: lxc/config.go:421
 msgid "No fingerprint specified."
 msgstr ""
 
@@ -743,7 +767,7 @@ msgstr ""
 msgid "Press enter to open the editor again"
 msgstr ""
 
-#: lxc/config.go:648 lxc/config.go:713 lxc/image.go:1121
+#: lxc/config.go:716 lxc/config.go:781 lxc/image.go:1121
 msgid "Press enter to start the editor again"
 msgstr ""
 
@@ -1022,12 +1046,12 @@ msgstr ""
 msgid "The container you are starting doesn't have any network attached to it."
 msgstr ""
 
-#: lxc/config.go:770 lxc/config.go:787
+#: lxc/config.go:838 lxc/config.go:855
 msgid "The device already exists"
 msgstr ""
 
-#: lxc/config.go:833 lxc/config.go:845 lxc/config.go:881 lxc/config.go:899
-#: lxc/config.go:945 lxc/config.go:962 lxc/config.go:1005 lxc/config.go:1023
+#: lxc/config.go:901 lxc/config.go:913 lxc/config.go:949 lxc/config.go:967
+#: lxc/config.go:1013 lxc/config.go:1030 lxc/config.go:1073 lxc/config.go:1091
 msgid "The device doesn't exist"
 msgstr ""
 
@@ -1149,7 +1173,7 @@ msgstr ""
 msgid "Usage: lxc <command> [options]"
 msgstr ""
 
-#: lxc/config.go:60
+#: lxc/config.go:84
 msgid ""
 "Usage: lxc config <subcommand> [options]\n"
 "\n"
@@ -1173,6 +1197,11 @@ msgid ""
 "    Edit configuration, either by launching external editor or reading "
 "STDIN.\n"
 "\n"
+"*Container metadata*\n"
+"\n"
+"lxc config metadata show [<remote>:][container]\n"
+"    Show the container metadata.yaml content.\n"
+"\n"
 "*Device management*\n"
 "\n"
 "lxc config device add [<remote>:]<container> <device> <type> [key=value...]\n"
diff --git a/shared/api/image.go b/shared/api/image.go
index 814c0981d..c1335dfc1 100644
--- a/shared/api/image.go
+++ b/shared/api/image.go
@@ -102,3 +102,18 @@ type ImageAliasesEntry struct {
 
 	Name string `json:"name" yaml:"name"`
 }
+
+type TemplateEntry struct {
+	When       []string          `json:"when" yaml:"when"`
+	CreateOnly bool              `json:"create_only" yaml:"create_only"`
+	Template   string            `json:"template" yaml:"template"`
+	Properties map[string]string `json:"properties" yaml:"properties"`
+}
+
+type ImageMetadata struct {
+	Architecture string                    `json:"architecture" yaml:"architecture"`
+	CreationDate int64                     `json:"creation_date" yaml:"creation_date"`
+	ExpiryDate   int64                     `json:"expiry_date" yaml:"expiry_date"`
+	Properties   map[string]string         `json:"properties" yaml:"properties"`
+	Templates    map[string]*TemplateEntry `json:"templates" yaml:"templates"`
+}
diff --git a/test/main.sh b/test/main.sh
index 9fc18d525..a332e5554 100755
--- a/test/main.sh
+++ b/test/main.sh
@@ -616,6 +616,8 @@ run_test test_snap_restore "snapshot restores"
 run_test test_config_profiles "profiles and configuration"
 run_test test_config_edit "container configuration edit"
 run_test test_config_edit_container_snapshot_pool_config "container and snapshot volume configuration edit"
+run_test test_metadata_show "container metadata show"
+run_test test_metadata_edit "contaimer metadata edit"
 run_test test_server_config "server configuration"
 run_test test_filemanip "file manipulations"
 run_test test_network "network management"
diff --git a/test/suites/config.sh b/test/suites/config.sh
index 1a943a72f..5c0c269bf 100644
--- a/test/suites/config.sh
+++ b/test/suites/config.sh
@@ -260,3 +260,20 @@ test_config_edit_container_snapshot_pool_config() {
     lxc storage volume show "$storage_pool" container/c1/s1 | grep -q 'description: baz'
     lxc delete c1
 }
+
+test_metadata_show() {
+    ensure_import_testimage
+
+    lxc init testimage c
+    # metadata for the container are printed
+    lxc config metadata show c | grep -q Busybox
+}
+
+test_metadata_edit() {
+    ensure_import_testimage
+
+    lxc init testimage c
+    lxc config metadata show c | sed 's/Busybox/BB/' | lxc config metadata edit c
+    # metadata have been updated
+    lxc config metadata show c | grep -q BB
+}

From 81842f9d495054ec9a9b8e3bd69f3b98f1088362 Mon Sep 17 00:00:00 2001
From: Alberto Donato <alberto.donato at canonical.com>
Date: Fri, 14 Jul 2017 11:53:41 +0200
Subject: [PATCH 2/3] Add API for managing container template files

Signed-off-by: Alberto Donato <alberto.donato at canonical.com>
---
 doc/rest-api.md           |  50 ++++++++++++++++
 lxd/api_1.0.go            |   2 +
 lxd/container_metadata.go | 149 +++++++++++++++++++++++++++++++++++++++++++++-
 lxd/containers.go         |  13 ++++
 test/main.sh              |   4 ++
 test/suites/config.sh     |  37 +++++++++++-
 6 files changed, 252 insertions(+), 3 deletions(-)

diff --git a/doc/rest-api.md b/doc/rest-api.md
index c3bf9b5d2..a4519e0db 100644
--- a/doc/rest-api.md
+++ b/doc/rest-api.md
@@ -191,6 +191,8 @@ won't work and PUT needs to be used instead.
          * /1.0/containers/\<name\>/logs
          * /1.0/containers/\<name\>/logs/\<logfile\>
          * /1.0/containers/\<name\>/metadata
+         * /1.0/containers/\<name\>/metadata/templates
+         * /1.0/containers/\<name\>/metadata/templates/\<template\>
      * /1.0/events
      * /1.0/images
        * /1.0/images/\<fingerprint\>
@@ -1239,6 +1241,54 @@ Input:
         }
     }
 
+## /1.0/containers/\<name\>/metadata/templates
+### GET
+* Description: List container templates
+* Authentication: trusted
+* Operation: Sync
+* Return: a list with container template names
+
+Return:
+
+    [
+        "template.tpl",
+        "hosts.tpl"
+    ]
+
+## POST
+* Description: Add a continer template
+* Authentication: trusted
+* Operation: Sync
+* Return: standard return value or standard error
+
+Input:
+ * Standard http file upload.
+ * The request must contain the `X-LXD-filename` header, which is used as name
+   of the created template file.
+
+
+## /1.0/containers/\<name\>/metadata/templates/\<template\>
+### GET
+* Description: Content of a container template
+* Authentication: trusted
+* Operation: Sync
+* Return: the content of the template
+
+### PUT
+* Description: Replace content of a template
+* Authentication: trusted
+* Operation: Sync
+* Return: standard return value or standard error
+
+Input:
+ * Standard http file upload.
+
+### DELETE
+* Description: Delete a container template
+* Authentication: trusted
+* Operation: Sync
+* Return: standard return value or standard error
+
 ## /1.0/events
 This URL isn't a real REST API endpoint, instead doing a GET query on it
 will upgrade the connection to a websocket on which notifications will
diff --git a/lxd/api_1.0.go b/lxd/api_1.0.go
index dd125c0e7..9828ebb63 100644
--- a/lxd/api_1.0.go
+++ b/lxd/api_1.0.go
@@ -27,6 +27,8 @@ var api10 = []Command{
 	containerSnapshotCmd,
 	containerExecCmd,
 	containerMetadataCmd,
+	containerMetadataTemplatesCmd,
+	containerMetadataTemplateCmd,
 	aliasCmd,
 	aliasesCmd,
 	eventsCmd,
diff --git a/lxd/container_metadata.go b/lxd/container_metadata.go
index 5b235bf3e..d2754b27f 100644
--- a/lxd/container_metadata.go
+++ b/lxd/container_metadata.go
@@ -2,15 +2,18 @@ package main
 
 import (
 	"encoding/json"
+	"fmt"
 	"io/ioutil"
 	"net/http"
 	"os"
 	"path/filepath"
+	"strings"
 
 	"gopkg.in/yaml.v2"
 
 	"github.com/gorilla/mux"
 
+	"github.com/lxc/lxd/shared"
 	"github.com/lxc/lxd/shared/api"
 )
 
@@ -31,7 +34,7 @@ func containerMetadataGet(d *Daemon, r *http.Request) Response {
 		return InternalError(err)
 	}
 	metadata := api.ImageMetadata{}
-	err = yaml.Unmarshal([]byte(data), &metadata)
+	err = yaml.Unmarshal(data, &metadata)
 	if err != nil {
 		return SmartError(err)
 	}
@@ -61,6 +64,129 @@ func containerMetadataPut(d *Daemon, r *http.Request) Response {
 	return EmptySyncResponse
 }
 
+// Return a list of templates used in a container
+func containerMetadataTemplatesGet(d *Daemon, r *http.Request) Response {
+	name := mux.Vars(r)["name"]
+	templatesPath, err := getContainerTemplatesPath(d, name)
+	if err != nil {
+		return SmartError(err)
+	}
+
+	filesInfo, err := ioutil.ReadDir(templatesPath)
+	if err != nil {
+		return InternalError(err)
+	}
+
+	templates := []string{}
+	for _, info := range filesInfo {
+		if !info.IsDir() {
+			templates = append(templates, info.Name())
+		}
+	}
+	return SyncResponse(true, templates)
+}
+
+// Add a container template file
+func containerMetadataTemplatesPost(d *Daemon, r *http.Request) Response {
+	name := mux.Vars(r)["name"]
+	templateName := r.Header.Get("X-LXD-filename")
+	if templateName == "" {
+		return BadRequest(fmt.Errorf("Missing X-LXD-filename header"))
+	}
+	templatePath, err := getContainerTemplatePath(d, name, templateName)
+	if err != nil {
+		return SmartError(err)
+	}
+
+	if shared.PathExists(templatePath) {
+		return BadRequest(fmt.Errorf("Template already exists"))
+	}
+
+	data, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		return SmartError(err)
+	}
+
+	template, err := os.OpenFile(templatePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
+	if err != nil {
+		return SmartError(err)
+	}
+	defer template.Close()
+	_, err = template.Write(data)
+	if err != nil {
+		return SmartError(err)
+	}
+
+	return EmptySyncResponse
+}
+
+// Return the content of a container template
+func containerMetadataTemplateGet(d *Daemon, r *http.Request) Response {
+	name := mux.Vars(r)["name"]
+	templateName := mux.Vars(r)["template"]
+	templatePath, err := getContainerTemplatePath(d, name, templateName)
+	if err != nil {
+		return SmartError(err)
+	}
+	if !shared.PathExists(templatePath) {
+		return NotFound
+	}
+
+	files := make([]fileResponseEntry, 1)
+	files[0].identifier = templateName
+	files[0].path = templatePath
+	files[0].filename = templateName
+	return FileResponse(r, files, nil, false)
+}
+
+// Update the content of a container template
+func containerMetadataTemplatePut(d *Daemon, r *http.Request) Response {
+	name := mux.Vars(r)["name"]
+	templateName := mux.Vars(r)["template"]
+	templatePath, err := getContainerTemplatePath(d, name, templateName)
+	if err != nil {
+		return SmartError(err)
+	}
+	if !shared.PathExists(templatePath) {
+		return NotFound
+	}
+
+	data, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		return SmartError(err)
+	}
+	template, err := os.OpenFile(templatePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
+	if err != nil {
+		return SmartError(err)
+	}
+	defer template.Close()
+	_, err = template.Write(data)
+	if err != nil {
+		return SmartError(err)
+	}
+
+	return EmptySyncResponse
+}
+
+// Delete a container template
+func containerMetadataTemplateDelete(d *Daemon, r *http.Request) Response {
+	name := mux.Vars(r)["name"]
+	templateName := mux.Vars(r)["template"]
+	templatePath, err := getContainerTemplatePath(d, name, templateName)
+	if err != nil {
+		return SmartError(err)
+	}
+	if !shared.PathExists(templatePath) {
+		return NotFound
+	}
+
+	err = os.Remove(templatePath)
+	if err != nil {
+		return InternalError(err)
+	}
+	return EmptySyncResponse
+}
+
 // Return the path of the container metadata file
 func getContainerMetadataPath(d *Daemon, cname string) (string, error) {
 	c, err := containerLoadByName(d, cname)
@@ -69,3 +195,24 @@ func getContainerMetadataPath(d *Daemon, cname string) (string, error) {
 	}
 	return filepath.Join(c.Path(), "metadata.yaml"), nil
 }
+
+// Return the path of the container templates dir
+func getContainerTemplatesPath(d *Daemon, cname string) (string, error) {
+	c, err := containerLoadByName(d, cname)
+	if err != nil {
+		return "", err
+	}
+	return filepath.Join(c.Path(), "templates"), nil
+}
+
+// Return
+func getContainerTemplatePath(d *Daemon, cname string, filename string) (string, error) {
+	if strings.Contains(filename, "/") {
+		return "", fmt.Errorf("Invalid template filename")
+	}
+	templatesPath, err := getContainerTemplatesPath(d, cname)
+	if err != nil {
+		return "", err
+	}
+	return filepath.Join(templatesPath, filename), nil
+}
diff --git a/lxd/containers.go b/lxd/containers.go
index 92d795ace..49179c562 100644
--- a/lxd/containers.go
+++ b/lxd/containers.go
@@ -64,6 +64,19 @@ var containerMetadataCmd = Command{
 	put:  containerMetadataPut,
 }
 
+var containerMetadataTemplatesCmd = Command{
+	name: "containers/{name}/metadata/templates",
+	get:  containerMetadataTemplatesGet,
+	post: containerMetadataTemplatesPost,
+}
+
+var containerMetadataTemplateCmd = Command{
+	name:   "containers/{name}/metadata/templates/{template}",
+	get:    containerMetadataTemplateGet,
+	put:    containerMetadataTemplatePut,
+	delete: containerMetadataTemplateDelete,
+}
+
 type containerAutostartList []container
 
 func (slice containerAutostartList) Len() int {
diff --git a/test/main.sh b/test/main.sh
index a332e5554..30c7fcda2 100755
--- a/test/main.sh
+++ b/test/main.sh
@@ -618,6 +618,10 @@ run_test test_config_edit "container configuration edit"
 run_test test_config_edit_container_snapshot_pool_config "container and snapshot volume configuration edit"
 run_test test_metadata_show "container metadata show"
 run_test test_metadata_edit "contaimer metadata edit"
+run_test test_metadata_template_list "contaimer template list"
+run_test test_metadata_template_content "contaimer template content"
+run_test test_metadata_template_add "container template add"
+run_test test_metadata_template_remove "container template remove"
 run_test test_server_config "server configuration"
 run_test test_filemanip "file manipulations"
 run_test test_network "network management"
diff --git a/test/suites/config.sh b/test/suites/config.sh
index 5c0c269bf..1f9b09056 100644
--- a/test/suites/config.sh
+++ b/test/suites/config.sh
@@ -263,17 +263,50 @@ test_config_edit_container_snapshot_pool_config() {
 
 test_metadata_show() {
     ensure_import_testimage
-
     lxc init testimage c
+
     # metadata for the container are printed
     lxc config metadata show c | grep -q Busybox
 }
 
 test_metadata_edit() {
     ensure_import_testimage
-
     lxc init testimage c
+
     lxc config metadata show c | sed 's/Busybox/BB/' | lxc config metadata edit c
     # metadata have been updated
     lxc config metadata show c | grep -q BB
 }
+
+test_metadata_template_list() {
+    ensure_import_testimage
+    lxc init testimage c
+
+    # the GET response contains the template
+    curl -s --unix-socket "${LXD_DIR}/unix.socket" lxd/1.0/containers/c/metadata/templates | grep -q template.tpl
+}
+
+test_metadata_template_content() {
+    ensure_import_testimage
+    lxc init testimage c
+
+    curl -s --unix-socket "${LXD_DIR}/unix.socket" lxd/1.0/containers/c/metadata/templates/template.tpl | grep -q "name:"
+}
+
+test_metadata_template_add() {
+    ensure_import_testimage
+    lxc init testimage c
+
+    curl -s --unix-socket "${LXD_DIR}/unix.socket" lxd/1.0/containers/c/metadata/templates -H "X-LXD-filename: my.tpl" -d "some content"
+    curl -s --unix-socket "${LXD_DIR}/unix.socket" lxd/1.0/containers/c/metadata/templates/my.tpl | grep -q "some content"
+}
+
+test_metadata_template_remove() {
+    ensure_import_testimage
+    lxc init testimage c
+
+    curl -s --unix-socket "${LXD_DIR}/unix.socket" lxd/1.0/containers/c/metadata/templates -H "X-LXD-filename: my.tpl" -d "some content"
+    curl -s --unix-socket "${LXD_DIR}/unix.socket" lxd/1.0/containers/c/metadata/templates/my.tpl -X DELETE
+    # the template is no longer there
+    ! (curl -s --unix-socket "${LXD_DIR}/unix.socket" lxd/1.0/containers/c/metadata/templates | grep my.tpl)
+}

From 30146950fe626175c49021d76c0c77ae3ba15739 Mon Sep 17 00:00:00 2001
From: Alberto Donato <alberto.donato at canonical.com>
Date: Fri, 14 Jul 2017 17:56:36 +0200
Subject: [PATCH 3/3] Expose all template operations under /metadata/templates

Signed-off-by: Alberto Donato <alberto.donato at canonical.com>
---
 doc/rest-api.md           |  23 ++++-----
 lxd/api_1.0.go            |   1 -
 lxd/container_metadata.go | 120 ++++++++++++++++++----------------------------
 lxd/containers.go         |  15 ++----
 test/suites/config.sh     |  12 ++---
 5 files changed, 66 insertions(+), 105 deletions(-)

diff --git a/doc/rest-api.md b/doc/rest-api.md
index a4519e0db..81eaaf0dd 100644
--- a/doc/rest-api.md
+++ b/doc/rest-api.md
@@ -192,7 +192,6 @@ won't work and PUT needs to be used instead.
          * /1.0/containers/\<name\>/logs/\<logfile\>
          * /1.0/containers/\<name\>/metadata
          * /1.0/containers/\<name\>/metadata/templates
-         * /1.0/containers/\<name\>/metadata/templates/\<template\>
      * /1.0/events
      * /1.0/images
        * /1.0/images/\<fingerprint\>
@@ -1255,7 +1254,13 @@ Return:
         "hosts.tpl"
     ]
 
-## POST
+### GET (?path=\<template\>)
+* Description: Content of a container template
+* Authentication: trusted
+* Operation: Sync
+* Return: the content of the template
+
+## POST (?path=\<template\>)
 * Description: Add a continer template
 * Authentication: trusted
 * Operation: Sync
@@ -1263,18 +1268,8 @@ Return:
 
 Input:
  * Standard http file upload.
- * The request must contain the `X-LXD-filename` header, which is used as name
-   of the created template file.
-
-
-## /1.0/containers/\<name\>/metadata/templates/\<template\>
-### GET
-* Description: Content of a container template
-* Authentication: trusted
-* Operation: Sync
-* Return: the content of the template
 
-### PUT
+### PUT (?path=\<template\>)
 * Description: Replace content of a template
 * Authentication: trusted
 * Operation: Sync
@@ -1283,7 +1278,7 @@ Input:
 Input:
  * Standard http file upload.
 
-### DELETE
+### DELETE (?path=\<template\>)
 * Description: Delete a container template
 * Authentication: trusted
 * Operation: Sync
diff --git a/lxd/api_1.0.go b/lxd/api_1.0.go
index 9828ebb63..9adfc2c2f 100644
--- a/lxd/api_1.0.go
+++ b/lxd/api_1.0.go
@@ -28,7 +28,6 @@ var api10 = []Command{
 	containerExecCmd,
 	containerMetadataCmd,
 	containerMetadataTemplatesCmd,
-	containerMetadataTemplateCmd,
 	aliasCmd,
 	aliasesCmd,
 	eventsCmd,
diff --git a/lxd/container_metadata.go b/lxd/container_metadata.go
index d2754b27f..e38995cb1 100644
--- a/lxd/container_metadata.go
+++ b/lxd/container_metadata.go
@@ -3,6 +3,7 @@ package main
 import (
 	"encoding/json"
 	"fmt"
+	"io"
 	"io/ioutil"
 	"net/http"
 	"os"
@@ -64,114 +65,85 @@ func containerMetadataPut(d *Daemon, r *http.Request) Response {
 	return EmptySyncResponse
 }
 
-// Return a list of templates used in a container
+// Return a list of templates used in a container or the content of a template
 func containerMetadataTemplatesGet(d *Daemon, r *http.Request) Response {
 	name := mux.Vars(r)["name"]
-	templatesPath, err := getContainerTemplatesPath(d, name)
-	if err != nil {
-		return SmartError(err)
-	}
+	templateName := r.FormValue("path")
 
-	filesInfo, err := ioutil.ReadDir(templatesPath)
-	if err != nil {
-		return InternalError(err)
-	}
+	if templateName == "" {
+		// List templates
+		templatesPath, err := getContainerTemplatesPath(d, name)
+		if err != nil {
+			return SmartError(err)
+		}
+
+		filesInfo, err := ioutil.ReadDir(templatesPath)
+		if err != nil {
+			return InternalError(err)
+		}
 
-	templates := []string{}
-	for _, info := range filesInfo {
-		if !info.IsDir() {
-			templates = append(templates, info.Name())
+		templates := []string{}
+		for _, info := range filesInfo {
+			if !info.IsDir() {
+				templates = append(templates, info.Name())
+			}
+		}
+		return SyncResponse(true, templates)
+	} else {
+		// Return the content of the template
+		templatePath, err := getContainerTemplatePath(d, name, templateName)
+		if err != nil {
+			return SmartError(err)
 		}
+		if !shared.PathExists(templatePath) {
+			return NotFound
+		}
+
+		files := make([]fileResponseEntry, 1)
+		files[0].identifier = templateName
+		files[0].path = templatePath
+		files[0].filename = templateName
+		return FileResponse(r, files, nil, false)
 	}
-	return SyncResponse(true, templates)
 }
 
 // Add a container template file
-func containerMetadataTemplatesPost(d *Daemon, r *http.Request) Response {
+func containerMetadataTemplatesPostPut(d *Daemon, r *http.Request) Response {
 	name := mux.Vars(r)["name"]
-	templateName := r.Header.Get("X-LXD-filename")
+	templateName := r.FormValue("path")
 	if templateName == "" {
-		return BadRequest(fmt.Errorf("Missing X-LXD-filename header"))
+		return BadRequest(fmt.Errorf("missing path argument"))
 	}
 	templatePath, err := getContainerTemplatePath(d, name, templateName)
 	if err != nil {
 		return SmartError(err)
 	}
 
-	if shared.PathExists(templatePath) {
+	if r.Method == "POST" && shared.PathExists(templatePath) {
 		return BadRequest(fmt.Errorf("Template already exists"))
 	}
 
-	data, err := ioutil.ReadAll(r.Body)
-	if err != nil {
-		return SmartError(err)
-	}
-
 	template, err := os.OpenFile(templatePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
 	if err != nil {
 		return SmartError(err)
 	}
 	defer template.Close()
-	_, err = template.Write(data)
-	if err != nil {
-		return SmartError(err)
-	}
-
-	return EmptySyncResponse
-}
 
-// Return the content of a container template
-func containerMetadataTemplateGet(d *Daemon, r *http.Request) Response {
-	name := mux.Vars(r)["name"]
-	templateName := mux.Vars(r)["template"]
-	templatePath, err := getContainerTemplatePath(d, name, templateName)
+	_, err = io.Copy(template, r.Body)
 	if err != nil {
-		return SmartError(err)
-	}
-	if !shared.PathExists(templatePath) {
-		return NotFound
-	}
-
-	files := make([]fileResponseEntry, 1)
-	files[0].identifier = templateName
-	files[0].path = templatePath
-	files[0].filename = templateName
-	return FileResponse(r, files, nil, false)
-}
-
-// Update the content of a container template
-func containerMetadataTemplatePut(d *Daemon, r *http.Request) Response {
-	name := mux.Vars(r)["name"]
-	templateName := mux.Vars(r)["template"]
-	templatePath, err := getContainerTemplatePath(d, name, templateName)
-	if err != nil {
-		return SmartError(err)
-	}
-	if !shared.PathExists(templatePath) {
-		return NotFound
-	}
-
-	data, err := ioutil.ReadAll(r.Body)
-	if err != nil {
-		return SmartError(err)
-	}
-	template, err := os.OpenFile(templatePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
-	if err != nil {
-		return SmartError(err)
-	}
-	defer template.Close()
-	_, err = template.Write(data)
-	if err != nil {
-		return SmartError(err)
+		return InternalError(err)
 	}
 
 	return EmptySyncResponse
 }
 
 // Delete a container template
-func containerMetadataTemplateDelete(d *Daemon, r *http.Request) Response {
+func containerMetadataTemplatesDelete(d *Daemon, r *http.Request) Response {
 	name := mux.Vars(r)["name"]
-	templateName := mux.Vars(r)["template"]
+	templateName := r.FormValue("path")
+	if templateName == "" {
+		return BadRequest(fmt.Errorf("missing path argument"))
+	}
 	templatePath, err := getContainerTemplatePath(d, name, templateName)
 	if err != nil {
 		return SmartError(err)
diff --git a/lxd/containers.go b/lxd/containers.go
index 49179c562..a48a4b51d 100644
--- a/lxd/containers.go
+++ b/lxd/containers.go
@@ -65,16 +65,11 @@ var containerMetadataCmd = Command{
 }
 
 var containerMetadataTemplatesCmd = Command{
-	name: "containers/{name}/metadata/templates",
-	get:  containerMetadataTemplatesGet,
-	post: containerMetadataTemplatesPost,
-}
-
-var containerMetadataTemplateCmd = Command{
-	name:   "containers/{name}/metadata/templates/{template}",
-	get:    containerMetadataTemplateGet,
-	put:    containerMetadataTemplatePut,
-	delete: containerMetadataTemplateDelete,
+	name:   "containers/{name}/metadata/templates",
+	get:    containerMetadataTemplatesGet,
+	post:   containerMetadataTemplatesPostPut,
+	put:    containerMetadataTemplatesPostPut,
+	delete: containerMetadataTemplatesDelete,
 }
 
 type containerAutostartList []container
diff --git a/test/suites/config.sh b/test/suites/config.sh
index 1f9b09056..8e8ecd2b8 100644
--- a/test/suites/config.sh
+++ b/test/suites/config.sh
@@ -290,23 +290,23 @@ test_metadata_template_content() {
     ensure_import_testimage
     lxc init testimage c
 
-    curl -s --unix-socket "${LXD_DIR}/unix.socket" lxd/1.0/containers/c/metadata/templates/template.tpl | grep -q "name:"
+    curl -s --unix-socket "${LXD_DIR}/unix.socket" "lxd/1.0/containers/c/metadata/templates?path=template.tpl" | grep -q "name:"
 }
 
 test_metadata_template_add() {
     ensure_import_testimage
     lxc init testimage c
 
-    curl -s --unix-socket "${LXD_DIR}/unix.socket" lxd/1.0/containers/c/metadata/templates -H "X-LXD-filename: my.tpl" -d "some content"
-    curl -s --unix-socket "${LXD_DIR}/unix.socket" lxd/1.0/containers/c/metadata/templates/my.tpl | grep -q "some content"
+    curl -s --unix-socket "${LXD_DIR}/unix.socket" "lxd/1.0/containers/c/metadata/templates?path=my.tpl" -H 'Content-type: application/octet-stream' -d "some content"
+    curl -s --unix-socket "${LXD_DIR}/unix.socket" "lxd/1.0/containers/c/metadata/templates?path=my.tpl" | grep -q "some content"
 }
 
 test_metadata_template_remove() {
     ensure_import_testimage
     lxc init testimage c
 
-    curl -s --unix-socket "${LXD_DIR}/unix.socket" lxd/1.0/containers/c/metadata/templates -H "X-LXD-filename: my.tpl" -d "some content"
-    curl -s --unix-socket "${LXD_DIR}/unix.socket" lxd/1.0/containers/c/metadata/templates/my.tpl -X DELETE
+    curl -s --unix-socket "${LXD_DIR}/unix.socket" "lxd/1.0/containers/c/metadata/templates?path=my.tpl" -H 'Content-type: application/octet-stream' -d "some content"
+    curl -s --unix-socket "${LXD_DIR}/unix.socket" "lxd/1.0/containers/c/metadata/templates?path=my.tpl" -X DELETE
     # the template is no longer there
-    ! (curl -s --unix-socket "${LXD_DIR}/unix.socket" lxd/1.0/containers/c/metadata/templates | grep my.tpl)
+    ! (curl -s --unix-socket "${LXD_DIR}/unix.socket" lxd/1.0/containers/c/metadata/templates | grep -q my.tpl)
 }


More information about the lxc-devel mailing list