[lxc-devel] [lxd/master] [RFC] lxd: add SetExportProperties()

brauner on Github lxc-bot at linuxcontainers.org
Wed Oct 26 12:34:17 UTC 2016


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 1685 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20161026/5c4d7b34/attachment.bin>
-------------- next part --------------
From 4c0e69151dc0fd1f88d7916130eefc606ec64707 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at canonical.com>
Date: Wed, 26 Oct 2016 14:19:35 +0200
Subject: [PATCH] lxd: add SetExportProperties()

lxc publish c --alias=test description=test age=32

leads to the following calls
- client.go:ImageFromContainer()
- lxd/images.go:imagesPost()
- lxd/images.go:imgPostContInfo()

imgPostContInfo() in turn will call Export() and Export() takes care of actually
publishing the image. After Export() returns it will have created the img
tarfile. If we want to change the properties after that we would have to
recreate the tar archive just to update the metadata.yaml file which is wildly
inefficient. And I'm not aware of an easy way to replace existing files in a tar
archive. My proposal is thus to have a new function SetExportProperties() that
allows users to specifiy properties that an image created from a container is
supposed to receive. In lxd/images.go:imgPostContInfo() we can then do:

	// Set properties the user wants the exported image to have.
	if len(req.Properties) != 0 {
		c.SetExportProperties(req.Properties)
	}

prior to

	if err := c.Export(tarfile); err != nil {
		tarfile.Close()
		return info, err
	}
	tarfile.Close()

which means that the published image will have the requested properties at the
time of the publish operation. So when you export the image you will receive an
updated metadata.yaml file containing the properties requested.

Signed-off-by: Christian Brauner <christian.brauner at canonical.com>
---
 lxd/container.go     |  1 +
 lxd/container_lxc.go | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 lxd/images.go        |  7 +++++++
 3 files changed, 54 insertions(+)

diff --git a/lxd/container.go b/lxd/container.go
index 78df78b..b131b42 100644
--- a/lxd/container.go
+++ b/lxd/container.go
@@ -407,6 +407,7 @@ type container interface {
 	LastIdmapSet() (*shared.IdmapSet, error)
 	TemplateApply(trigger string) error
 	Daemon() *Daemon
+	SetExportProperties(properties map[string]string)
 }
 
 // Loader functions
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index e269cb7..b607829 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -281,6 +281,7 @@ type containerLXC struct {
 	id           int
 	name         string
 	stateful     bool
+	properties   map[string]string
 
 	// Config
 	expandedConfig  map[string]string
@@ -3196,6 +3197,9 @@ func (c *containerLXC) Export(w io.Writer) error {
 		meta := imageMetadata{}
 		meta.Architecture = arch
 		meta.CreationDate = time.Now().UTC().Unix()
+		if c.properties != nil {
+			meta.Properties = c.properties
+		}
 
 		data, err := yaml.Marshal(&meta)
 		if err != nil {
@@ -3228,6 +3232,44 @@ func (c *containerLXC) Export(w io.Writer) error {
 			return err
 		}
 	} else {
+		if c.properties != nil {
+			// Parse the metadata
+			content, err := ioutil.ReadFile(fnam)
+			if err != nil {
+				tw.Close()
+				return err
+			}
+
+			metadata := new(imageMetadata)
+			err = yaml.Unmarshal(content, &metadata)
+			metadata.Properties = c.properties
+
+			// Generate a new metadata.yaml
+			tempDir, err := ioutil.TempDir("", "lxd_lxd_metadata_")
+			if err != nil {
+				tw.Close()
+				shared.LogError("Failed exporting container", ctxMap)
+				return err
+			}
+			defer os.RemoveAll(tempDir)
+
+			data, err := yaml.Marshal(&metadata)
+			if err != nil {
+				tw.Close()
+				shared.LogError("Failed exporting container", ctxMap)
+				return err
+			}
+
+			// Write the actual file
+			fnam = filepath.Join(tempDir, "metadata.yaml")
+			err = ioutil.WriteFile(fnam, data, 0644)
+			if err != nil {
+				tw.Close()
+				shared.LogError("Failed exporting container", ctxMap)
+				return err
+			}
+		}
+
 		// Include metadata.yaml in the tarball
 		fi, err := os.Lstat(fnam)
 		if err != nil {
@@ -5529,3 +5571,7 @@ func (c *containerLXC) StatePath() string {
 	}
 	return filepath.Join(c.Path(), "state")
 }
+
+func (c *containerLXC) SetExportProperties(properties map[string]string) {
+	c.properties = properties
+}
diff --git a/lxd/images.go b/lxd/images.go
index daae70b..45a0127 100644
--- a/lxd/images.go
+++ b/lxd/images.go
@@ -1,6 +1,7 @@
 package main
 
 import (
+	// "archive/tar"
 	"bytes"
 	"crypto/sha256"
 	"encoding/json"
@@ -13,6 +14,7 @@ import (
 	"net/url"
 	"os"
 	"os/exec"
+	// "path/filepath"
 	"strconv"
 	"strings"
 	"sync"
@@ -270,6 +272,11 @@ func imgPostContInfo(d *Daemon, r *http.Request, req imagePostReq,
 	}
 	defer os.Remove(tarfile.Name())
 
+	// Set properties the user wants the exported image to have.
+	if len(req.Properties) != 0 {
+		c.SetExportProperties(req.Properties)
+	}
+
 	if err := c.Export(tarfile); err != nil {
 		tarfile.Close()
 		return info, err


More information about the lxc-devel mailing list