[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