The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/1630
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) ===
From 25f9c226f5c7da23e5c1d2265a26b0bfa3bc04b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@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 <stgra...@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?= <stgra...@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 <stgra...@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)) }
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel