[lxc-devel] [lxd/master] Update architecture API

stgraber on Github lxc-bot at linuxcontainers.org
Sun Feb 21 20:51:07 UTC 2016


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 301 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20160221/5e979105/attachment.bin>
-------------- next part --------------
From 25f9c226f5c7da23e5c1d2265a26b0bfa3bc04b8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Sun, 21 Feb 2016 14:11:28 -0500
Subject: [PATCH 1/2] Return architecture name rather than ID
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Makes it significantly easier to deal with the API.

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 client.go              |  6 +++---
 lxc/image.go           |  6 ++----
 lxd/api_1.0.go         | 12 +++++++++++-
 lxd/container_lxc.go   |  5 ++++-
 lxd/container_put.go   |  9 +++++++--
 lxd/containers_post.go | 23 +++++++++++++++++++----
 lxd/daemon_images.go   |  2 +-
 lxd/db_images.go       | 21 ++++++++++++++++++---
 lxd/images.go          |  4 ++--
 shared/container.go    |  2 +-
 shared/image.go        |  2 +-
 shared/server.go       |  2 +-
 specs/rest-api.md      | 26 +++++++++++++-------------
 13 files changed, 83 insertions(+), 37 deletions(-)

diff --git a/client.go b/client.go
index 00b7190..afedc25 100644
--- a/client.go
+++ b/client.go
@@ -1083,7 +1083,7 @@ func (c *Client) Init(name string, imgremote string, image string, profiles *[]s
 			return nil, err
 		}
 
-		if len(architectures) != 0 && !shared.IntInSlice(imageinfo.Architecture, architectures) {
+		if len(architectures) != 0 && !shared.StringInSlice(imageinfo.Architecture, architectures) {
 			return nil, fmt.Errorf("The image architecture is incompatible with the target server")
 		}
 
@@ -1122,7 +1122,7 @@ func (c *Client) Init(name string, imgremote string, image string, profiles *[]s
 			return nil, fmt.Errorf("can't get info for image '%s': %s", image, err)
 		}
 
-		if len(architectures) != 0 && !shared.IntInSlice(imageinfo.Architecture, architectures) {
+		if len(architectures) != 0 && !shared.StringInSlice(imageinfo.Architecture, architectures) {
 			return nil, fmt.Errorf("The image architecture is incompatible with the target server")
 		}
 		source["fingerprint"] = fingerprint
@@ -1487,7 +1487,7 @@ func (c *Client) GetMigrationSourceWS(container string) (*Response, error) {
 	return c.post(url, body, Async)
 }
 
-func (c *Client) MigrateFrom(name string, operation string, certificate string, secrets map[string]string, architecture int, config map[string]string, devices shared.Devices, profiles []string, baseImage string, ephemeral bool) (*Response, error) {
+func (c *Client) MigrateFrom(name string, operation string, certificate string, secrets map[string]string, architecture string, config map[string]string, devices shared.Devices, profiles []string, baseImage string, ephemeral bool) (*Response, error) {
 	source := shared.Jmap{
 		"type":        "migration",
 		"mode":        "pull",
diff --git a/lxc/image.go b/lxc/image.go
index 05c78d5..182f08e 100644
--- a/lxc/image.go
+++ b/lxc/image.go
@@ -295,8 +295,7 @@ func (c *imageCmd) run(config *lxd.Config, args []string) error {
 		}
 
 		fmt.Printf(i18n.G("Size: %.2fMB")+"\n", float64(info.Size)/1024.0/1024.0)
-		arch, _ := shared.ArchitectureName(info.Architecture)
-		fmt.Printf(i18n.G("Architecture: %s")+"\n", arch)
+		fmt.Printf(i18n.G("Architecture: %s")+"\n", info.Architecture)
 		fmt.Printf(i18n.G("Public: %s")+"\n", public)
 		fmt.Printf(i18n.G("Timestamps:") + "\n")
 		const layout = "2006/01/02 15:04 UTC"
@@ -544,9 +543,8 @@ func (c *imageCmd) showImages(images []shared.ImageInfo, filters []string) error
 
 		const layout = "Jan 2, 2006 at 3:04pm (MST)"
 		uploaded := image.UploadDate.UTC().Format(layout)
-		arch, _ := shared.ArchitectureName(image.Architecture)
 		size := fmt.Sprintf("%.2fMB", float64(image.Size)/1024.0/1024.0)
-		data = append(data, []string{shortest, fp, public, description, arch, size, uploaded})
+		data = append(data, []string{shortest, fp, public, description, image.Architecture, size, uploaded})
 	}
 
 	table := tablewriter.NewWriter(os.Stdout)
diff --git a/lxd/api_1.0.go b/lxd/api_1.0.go
index 29b57e7..6ca360f 100644
--- a/lxd/api_1.0.go
+++ b/lxd/api_1.0.go
@@ -94,9 +94,19 @@ func api10Get(d *Daemon, r *http.Request) Response {
 			certificate = string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: d.tlsConfig.Certificates[0].Certificate[0]}))
 		}
 
+		architectures := []string{}
+
+		for _, architecture := range d.architectures {
+			architectureName, err := shared.ArchitectureName(architecture)
+			if err != nil {
+				return InternalError(err)
+			}
+			architectures = append(architectures, architectureName)
+		}
+
 		env := shared.Jmap{
 			"addresses":           addresses,
-			"architectures":       d.architectures,
+			"architectures":       architectures,
 			"certificate":         certificate,
 			"driver":              "lxc",
 			"driver_version":      lxc.Version(),
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 0701841..c3afead 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -1351,8 +1351,11 @@ func (c *containerLXC) Render() (*shared.ContainerInfo, error) {
 	// FIXME: Render shouldn't directly access the go-lxc struct
 	statusCode := shared.FromLXCState(int(c.c.State()))
 
+	// Ignore err as the arch string on error is correct (unknown)
+	architectureName, _ := shared.ArchitectureName(c.architecture)
+
 	return &shared.ContainerInfo{
-		Architecture:    c.architecture,
+		Architecture:    architectureName,
 		Config:          c.localConfig,
 		CreationDate:    c.creationDate,
 		Devices:         c.localDevices,
diff --git a/lxd/container_put.go b/lxd/container_put.go
index 3d4778a..747a234 100644
--- a/lxd/container_put.go
+++ b/lxd/container_put.go
@@ -13,7 +13,7 @@ import (
 )
 
 type containerPutReq struct {
-	Architecture int               `json:"architecture"`
+	Architecture string            `json:"architecture"`
 	Config       map[string]string `json:"config"`
 	Devices      shared.Devices    `json:"devices"`
 	Ephemeral    bool              `json:"ephemeral"`
@@ -37,13 +37,18 @@ func containerPut(d *Daemon, r *http.Request) Response {
 		return BadRequest(err)
 	}
 
+	architecture, err := shared.ArchitectureId(configRaw.Architecture)
+	if err != nil {
+		architecture = 0
+	}
+
 	var do = func(*operation) error { return nil }
 
 	if configRaw.Restore == "" {
 		// Update container configuration
 		do = func(op *operation) error {
 			args := containerArgs{
-				Architecture: configRaw.Architecture,
+				Architecture: architecture,
 				Config:       configRaw.Config,
 				Devices:      configRaw.Devices,
 				Ephemeral:    configRaw.Ephemeral,
diff --git a/lxd/containers_post.go b/lxd/containers_post.go
index f736469..6b90ecc 100644
--- a/lxd/containers_post.go
+++ b/lxd/containers_post.go
@@ -44,7 +44,7 @@ type containerImageSource struct {
 }
 
 type containerPostReq struct {
-	Architecture int                  `json:"architecture"`
+	Architecture string               `json:"architecture"`
 	Config       map[string]string    `json:"config"`
 	Devices      shared.Devices       `json:"devices"`
 	Ephemeral    bool                 `json:"ephemeral"`
@@ -93,8 +93,13 @@ func createFromImage(d *Daemon, req *containerPostReq) Response {
 
 		hash = imgInfo.Fingerprint
 
+		architecture, err := shared.ArchitectureId(imgInfo.Architecture)
+		if err != nil {
+			architecture = 0
+		}
+
 		args := containerArgs{
-			Architecture: imgInfo.Architecture,
+			Architecture: architecture,
 			BaseImage:    hash,
 			Config:       req.Config,
 			Ctype:        cTypeRegular,
@@ -120,8 +125,13 @@ func createFromImage(d *Daemon, req *containerPostReq) Response {
 }
 
 func createFromNone(d *Daemon, req *containerPostReq) Response {
+	architecture, err := shared.ArchitectureId(req.Architecture)
+	if err != nil {
+		architecture = 0
+	}
+
 	args := containerArgs{
-		Architecture: req.Architecture,
+		Architecture: architecture,
 		Config:       req.Config,
 		Ctype:        cTypeRegular,
 		Devices:      req.Devices,
@@ -151,9 +161,14 @@ func createFromMigration(d *Daemon, req *containerPostReq) Response {
 		return NotImplemented
 	}
 
+	architecture, err := shared.ArchitectureId(req.Architecture)
+	if err != nil {
+		architecture = 0
+	}
+
 	run := func(op *operation) error {
 		args := containerArgs{
-			Architecture: req.Architecture,
+			Architecture: architecture,
 			BaseImage:    req.Source.BaseImage,
 			Config:       req.Config,
 			Ctype:        cTypeRegular,
diff --git a/lxd/daemon_images.go b/lxd/daemon_images.go
index 655a0f9..2ae6a31 100644
--- a/lxd/daemon_images.go
+++ b/lxd/daemon_images.go
@@ -288,7 +288,7 @@ func (d *Daemon) ImageDownload(op *operation, server string, certificate string,
 			return err
 		}
 
-		info.Architecture, _ = shared.ArchitectureId(imageMeta.Architecture)
+		info.Architecture = imageMeta.Architecture
 		info.CreationDate = time.Unix(imageMeta.CreationDate, 0)
 		info.ExpiryDate = time.Unix(imageMeta.ExpiryDate, 0)
 		info.Properties = imageMeta.Properties
diff --git a/lxd/db_images.go b/lxd/db_images.go
index 6aa3603..70f58d3 100644
--- a/lxd/db_images.go
+++ b/lxd/db_images.go
@@ -43,10 +43,11 @@ func dbImageGet(db *sql.DB, fingerprint string, public bool, strictMatching bool
 	// The object we'll actually return
 	image := shared.ImageInfo{}
 	id := -1
+	arch := -1
 
 	// These two humongous things will be filled by the call to DbQueryRowScan
 	outfmt := []interface{}{&id, &image.Fingerprint, &image.Filename,
-		&image.Size, &image.Public, &image.Architecture,
+		&image.Size, &image.Public, &arch,
 		&create, &expire, &upload}
 
 	var query string
@@ -88,11 +89,15 @@ func dbImageGet(db *sql.DB, fingerprint string, public bool, strictMatching bool
 	} else {
 		image.CreationDate = time.Time{}
 	}
+
 	if expire != nil {
 		image.ExpiryDate = *expire
 	} else {
 		image.ExpiryDate = time.Time{}
 	}
+
+	image.Architecture, _ = shared.ArchitectureName(arch)
+
 	// The upload date is enforced by NOT NULL in the schema, so it can never be nil.
 	image.UploadDate = *upload
 
@@ -232,7 +237,12 @@ func dbImageExpiryGet(db *sql.DB) (string, error) {
 	}
 }
 
-func dbImageUpdate(db *sql.DB, id int, fname string, sz int64, public bool, arch int, creationDate time.Time, expiryDate time.Time, properties map[string]string) error {
+func dbImageUpdate(db *sql.DB, id int, fname string, sz int64, public bool, architecture string, creationDate time.Time, expiryDate time.Time, properties map[string]string) error {
+	arch, err := shared.ArchitectureId(architecture)
+	if err != nil {
+		arch = 0
+	}
+
 	tx, err := dbBegin(db)
 	if err != nil {
 		return err
@@ -279,7 +289,12 @@ func dbImageUpdate(db *sql.DB, id int, fname string, sz int64, public bool, arch
 	return nil
 }
 
-func dbImageInsert(db *sql.DB, fp string, fname string, sz int64, public bool, arch int, creationDate time.Time, expiryDate time.Time, properties map[string]string) error {
+func dbImageInsert(db *sql.DB, fp string, fname string, sz int64, public bool, architecture string, creationDate time.Time, expiryDate time.Time, properties map[string]string) error {
+	arch, err := shared.ArchitectureId(architecture)
+	if err != nil {
+		arch = 0
+	}
+
 	tx, err := dbBegin(db)
 	if err != nil {
 		return err
diff --git a/lxd/images.go b/lxd/images.go
index 54a676f..0f63f31 100644
--- a/lxd/images.go
+++ b/lxd/images.go
@@ -262,7 +262,7 @@ func imgPostContInfo(d *Daemon, r *http.Request, req imagePostReq,
 		return info, err
 	}
 
-	info.Architecture = c.Architecture()
+	info.Architecture, _ = shared.ArchitectureName(c.Architecture())
 	info.Properties = req.Properties
 
 	return info, nil
@@ -583,7 +583,7 @@ func getImgPostInfo(d *Daemon, r *http.Request,
 		}
 	}
 
-	info.Architecture, _ = shared.ArchitectureId(imageMeta.Architecture)
+	info.Architecture = imageMeta.Architecture
 	info.CreationDate = time.Unix(imageMeta.CreationDate, 0)
 	info.ExpiryDate = time.Unix(imageMeta.ExpiryDate, 0)
 
diff --git a/shared/container.go b/shared/container.go
index 9ff9d51..438be1d 100644
--- a/shared/container.go
+++ b/shared/container.go
@@ -31,7 +31,7 @@ type SnapshotInfo struct {
 }
 
 type ContainerInfo struct {
-	Architecture    int               `json:"architecture"`
+	Architecture    string            `json:"architecture"`
 	Config          map[string]string `json:"config"`
 	CreationDate    time.Time         `json:"created_at"`
 	Devices         Devices           `json:"devices"`
diff --git a/shared/image.go b/shared/image.go
index 78445be..c56c997 100644
--- a/shared/image.go
+++ b/shared/image.go
@@ -21,7 +21,7 @@ type ImageAlias struct {
 
 type ImageInfo struct {
 	Aliases      []ImageAlias      `json:"aliases"`
-	Architecture int               `json:"architecture"`
+	Architecture string            `json:"architecture"`
 	Fingerprint  string            `json:"fingerprint"`
 	Filename     string            `json:"filename"`
 	Properties   map[string]string `json:"properties"`
diff --git a/shared/server.go b/shared/server.go
index 37794a9..e557c9d 100644
--- a/shared/server.go
+++ b/shared/server.go
@@ -2,7 +2,7 @@ package shared
 
 type ServerStateEnvironment struct {
 	Addresses          []string `json:"addresses"`
-	Architectures      []int    `json:"architectures"`
+	Architectures      []string `json:"architectures"`
 	Certificate        string   `json:"certificate"`
 	Driver             string   `json:"driver"`
 	DriverVersion      string   `json:"driver_version"`
diff --git a/specs/rest-api.md b/specs/rest-api.md
index 06bf957..2afe7c0 100644
--- a/specs/rest-api.md
+++ b/specs/rest-api.md
@@ -230,8 +230,8 @@ Return value (if trusted):
                 "[1234::1234]:8443"
             ],
             "architectures": [
-                2,
-                1
+                "x86_64",
+                "i686"
             ],
             "certificate": "PEM certificate",
             "driver": "lxc",
@@ -365,7 +365,7 @@ Input (container based on a local image with the "ubuntu/devel" alias):
 
     {
         "name": "my-new-container",                                         # 64 chars max, ASCII, no slash, no colon and no comma
-        "architecture": 2,
+        "architecture": "x86_64",
         "profiles": ["default"],                                            # List of profiles
         "ephemeral": true,                                                  # Whether to destroy the container on shutdown
         "config": {"limits.cpu": "2"},                                      # Config override.
@@ -377,7 +377,7 @@ Input (container based on a local image identified by its fingerprint):
 
     {
         "name": "my-new-container",                                         # 64 chars max, ASCII, no slash, no colon and no comma
-        "architecture": 2,
+        "architecture": "x86_64",
         "profiles": ["default"],                                            # List of profiles
         "ephemeral": true,                                                  # Whether to destroy the container on shutdown
         "config": {"limits.cpu": "2"},                                      # Config override.
@@ -389,7 +389,7 @@ Input (container based on most recent match based on image properties):
 
     {
         "name": "my-new-container",                                         # 64 chars max, ASCII, no slash, no colon and no comma
-        "architecture": 2,
+        "architecture": "x86_64",
         "profiles": ["default"],                                            # List of profiles
         "ephemeral": true,                                                  # Whether to destroy the container on shutdown
         "config": {"limits.cpu": "2"},                                      # Config override.
@@ -405,7 +405,7 @@ Input (container without a pre-populated rootfs, useful when attaching to an exi
 
     {
         "name": "my-new-container",                                         # 64 chars max, ASCII, no slash, no colon and no comma
-        "architecture": 2,
+        "architecture": "x86_64",
         "profiles": ["default"],                                            # List of profiles
         "ephemeral": true,                                                  # Whether to destroy the container on shutdown
         "config": {"limits.cpu": "2"},                                      # Config override.
@@ -416,7 +416,7 @@ Input (using a public remote image):
 
     {
         "name": "my-new-container",                                         # 64 chars max, ASCII, no slash, no colon and no comma
-        "architecture": 2,
+        "architecture": "x86_64",
         "profiles": ["default"],                                            # List of profiles
         "ephemeral": true,                                                  # Whether to destroy the container on shutdown
         "config": {"limits.cpu": "2"},                                      # Config override.
@@ -432,7 +432,7 @@ Input (using a private remote image after having obtained a secret for that imag
 
     {
         "name": "my-new-container",                                         # 64 chars max, ASCII, no slash, no colon and no comma
-        "architecture": 2,
+        "architecture": "x86_64",
         "profiles": ["default"],                                            # List of profiles
         "ephemeral": true,                                                  # Whether to destroy the container on shutdown
         "config": {"limits.cpu": "2"},                                      # Config override.
@@ -448,7 +448,7 @@ Input (using a remote container, sent over the migration websocket):
 
     {
         "name": "my-new-container",                                                     # 64 chars max, ASCII, no slash, no colon and no comma
-        "architecture": 2,
+        "architecture": "x86_64",
         "profiles": ["default"],                                                        # List of profiles
         "ephemeral": true,                                                              # Whether to destroy the container on shutdown
         "config": {"limits.cpu": "2"},                                                  # Config override.
@@ -466,7 +466,7 @@ Input (using a local container):
 
     {
         "name": "my-new-container",                                                     # 64 chars max, ASCII, no slash, no colon and no comma
-        "architecture": 2,
+        "architecture": "x86_64",
         "profiles": ["default"],                                                        # List of profiles
         "ephemeral": true,                                                              # Whether to destroy the container on shutdown
         "config": {"limits.cpu": "2"},                                                  # Config override.
@@ -485,7 +485,7 @@ Input (using a local container):
 Output:
 
     {
-        "architecture": 2,
+        "architecture": "x86_64",
         "config": {
             "limits.cpu": "3",
             "volatile.base_image": "97d97a3d1d053840ca19c86cdd0596cf1be060c5157d31407f2a4f9f350c78cc",
@@ -534,7 +534,7 @@ Output:
 Input (update container configuration):
 
     {
-        "architecture": 2,
+        "architecture": "x86_64",
         "config": {
             "limits.cpu": "4",
             "volatile.base_image": "97d97a3d1d053840ca19c86cdd0596cf1be060c5157d31407f2a4f9f350c78cc",
@@ -1006,7 +1006,7 @@ Output:
                 "description": "",
             }
         ],
-        "architecture": 2,
+        "architecture": "x86_64",
         "fingerprint": "54c8caac1f61901ed86c68f24af5f5d3672bdc62c71d04f06df3a59e95684473",
         "filename": "ubuntu-trusty-14.04-amd64-server-20160201.tar.xz",
         "properties": {

From 1be4efab1765d8697f149260a8f7f9b9bf2c900b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Sun, 21 Feb 2016 14:12:27 -0500
Subject: [PATCH 2/2] Show the container architecture in lxc info
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxc/info.go | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lxc/info.go b/lxc/info.go
index f4d115d..1cd1840 100644
--- a/lxc/info.go
+++ b/lxc/info.go
@@ -84,6 +84,7 @@ func (c *infoCmd) containerInfo(d *lxd.Client, name string, showLog bool) error
 	const layout = "2006/01/02 15:04 UTC"
 
 	fmt.Printf(i18n.G("Name: %s")+"\n", ct.Name)
+	fmt.Printf(i18n.G("Architecture: %s")+"\n", ct.Architecture)
 	if ct.CreationDate.UTC().Unix() != 0 {
 		fmt.Printf(i18n.G("Created: %s")+"\n", ct.CreationDate.UTC().Format(layout))
 	}


More information about the lxc-devel mailing list