[lxc-devel] [lxd/master] Add --format and json output for image list command

ctrlrsf on Github lxc-bot at linuxcontainers.org
Tue May 17 18:35:49 UTC 2016


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 5644 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20160517/efcec008/attachment.bin>
-------------- next part --------------
From 39751b85e083f3fa629e9be23f02d3e8b8097f1e Mon Sep 17 00:00:00 2001
From: Rene Fragoso <ctrlrsf at gmail.com>
Date: Tue, 17 May 2016 14:23:17 -0400
Subject: [PATCH] Add --format and json output for image list command

Adds the --format option to the `lxc image list` command. Possible options are
table and json.

Image list filters still work regardless of output format.

--format table example:
```
$ lxc image list images: 'description=.*yakkety.*s390x.*' --format table
+-------------------------------+--------------+--------+-----------------------------------------+-------+---------+------------------------------+
|             ALIAS             | FINGERPRINT  | PUBLIC | DESCRIPTION               | ARCH  |  SIZE   |         UPLOAD DATE |
+-------------------------------+--------------+--------+-----------------------------------------+-------+---------+------------------------------+
| ubuntu/yakkety/s390x (1 more) | 03a93a03d6bb | yes    | Ubuntu yakkety (s390x) (20160517_03:49) | s390x | 73.19MB | May 17, 2016 at 4:26am (UTC) |
+-------------------------------+--------------+--------+-----------------------------------------+-------+---------+------------------------------+
|                               | 42f6c2bb9348 | yes    | Ubuntu yakkety (s390x) (20160515_03:49) | s390x | 73.09MB | May 15, 2016 at 5:20am (UTC) |
+-------------------------------+--------------+--------+-----------------------------------------+-------+---------+------------------------------+
|                               | a6539f9ece07 | yes    | Ubuntu yakkety (s390x) (20160515_09:20) | s390x | 73.19MB | May 16, 2016 at 6:22pm (UTC) |
+-------------------------------+--------------+--------+-----------------------------------------+-------+---------+------------------------------+
```

--format json example:
```
$ lxc image list images: 'description=.*yakkety.*s390x.*' --format json
[{"aliases":[],"architecture":"s390x","cached":false,"filename":"ubuntu-yakkety-s390x-default-20160515_03:49.tar.xz","fingerprint":"42f6c2bb9348e27a8a048ce9657574cc524473bfa801902f4461da1ca1a456ba","properties":{"architecture":"s390x","build":"20160515_03:49","description":"Ubuntu
yakkety (s390x)
(20160515_03:49)","distribution":"ubuntu","release":"yakkety"},"public":true,"size":76642122,"auto_update":false,"created_at":"2016-05-15T05:20:21Z","expires_at":"1970-01-01T00:00:00Z","last_used_at":"0001-01-01T00:00:00Z","uploaded_at":"2016-05-15T05:20:21Z"},{},{}]
[{"aliases":[],"architecture":"s390x","cached":false,"filename":"ubuntu-yakkety-s390x-default-20160515_03:49.tar.xz","fingerprint":"42f6c2bb9348e27a8a048ce9657574cc524473bfa801902f4461da1ca1a456ba","properties":{"architecture":"s390x","build":"20160515_03:49","description":"Ubuntu
yakkety (s390x)
(20160515_03:49)","distribution":"ubuntu","release":"yakkety"},"public":true,"size":76642122,"auto_update":false,"created_at":"2016-05-15T05:20:21Z","expires_at":"1970-01-01T00:00:00Z","last_used_at":"0001-01-01T00:00:00Z","uploaded_at":"2016-05-15T05:20:21Z"},{"aliases":[],"architecture":"s390x","cached":false,"filename":"ubuntu-yakkety-s390x-default-20160515_09:20.tar.xz","fingerprint":"a6539f9ece0734574e6ffdaf81e421975fbeb32ac2637b16fe2cbc5648c909fd","properties":{"architecture":"s390x","build":"20160515_09:20","description":"Ubuntu
yakkety (s390x)
(20160515_09:20)","distribution":"ubuntu","release":"yakkety"},"public":true,"size":76743878,"auto_update":false,"created_at":"2016-05-16T18:22:41Z","expires_at":"1970-01-01T00:00:00Z","last_used_at":"0001-01-01T00:00:00Z","uploaded_at":"2016-05-16T18:22:41Z"},{}]
[{"aliases":[],"architecture":"s390x","cached":false,"filename":"ubuntu-yakkety-s390x-default-20160515_03:49.tar.xz","fingerprint":"42f6c2bb9348e27a8a048ce9657574cc524473bfa801902f4461da1ca1a456ba","properties":{"architecture":"s390x","build":"20160515_03:49","description":"Ubuntu
yakkety (s390x)
(20160515_03:49)","distribution":"ubuntu","release":"yakkety"},"public":true,"size":76642122,"auto_update":false,"created_at":"2016-05-15T05:20:21Z","expires_at":"1970-01-01T00:00:00Z","last_used_at":"0001-01-01T00:00:00Z","uploaded_at":"2016-05-15T05:20:21Z"},{"aliases":[],"architecture":"s390x","cached":false,"filename":"ubuntu-yakkety-s390x-default-20160515_09:20.tar.xz","fingerprint":"a6539f9ece0734574e6ffdaf81e421975fbeb32ac2637b16fe2cbc5648c909fd","properties":{"architecture":"s390x","build":"20160515_09:20","description":"Ubuntu
yakkety (s390x)
(20160515_09:20)","distribution":"ubuntu","release":"yakkety"},"public":true,"size":76743878,"auto_update":false,"created_at":"2016-05-16T18:22:41Z","expires_at":"1970-01-01T00:00:00Z","last_used_at":"0001-01-01T00:00:00Z","uploaded_at":"2016-05-16T18:22:41Z"},{"aliases":[{"name":"ubuntu/yakkety/s390x/default","description":"Ubuntu
yakkety (s390x)
(default)"},{"name":"ubuntu/yakkety/s390x","description":"Ubuntu yakkety
(s390x)"}],"architecture":"s390x","cached":false,"filename":"ubuntu-yakkety-s390x-default-20160517_03:49.tar.xz","fingerprint":"03a93a03d6bb370a129518c0fd53aa6b199342d8ef40c643c43710972334c4df","properties":{"architecture":"s390x","build":"20160517_03:49","description":"Ubuntu
yakkety (s390x)
(20160517_03:49)","distribution":"ubuntu","release":"yakkety"},"public":true,"size":76740678,"auto_update":false,"created_at":"2016-05-17T04:26:27Z","expires_at":"1970-01-01T00:00:00Z","last_used_at":"0001-01-01T00:00:00Z","uploaded_at":"2016-05-17T04:26:27Z"}]
```

Closes https://github.com/lxc/lxd/issues/1951

Signed-off-by: Rene Fragoso <ctrlrsf at gmail.com>
---
 lxc/image.go | 100 ++++++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 64 insertions(+), 36 deletions(-)

diff --git a/lxc/image.go b/lxc/image.go
index 752b9c6..fad808e 100644
--- a/lxc/image.go
+++ b/lxc/image.go
@@ -1,6 +1,7 @@
 package main
 
 import (
+	"encoding/json"
 	"fmt"
 	"io/ioutil"
 	"os"
@@ -73,6 +74,7 @@ type imageCmd struct {
 	publicImage bool
 	copyAliases bool
 	autoUpdate  bool
+	format      string
 }
 
 func (c *imageCmd) showByDefault() bool {
@@ -126,7 +128,7 @@ lxc image export [remote:]<image>
 lxc image info [remote:]<image>
     Print everything LXD knows about a given image.
 
-lxc image list [remote:] [filter]
+lxc image list [remote:] [filter] [--format table|json]
     List images in the LXD image store. Filters may be of the
     <key>=<value> form for property based filtering, or part of the image
     hash or part of the image alias name.
@@ -155,6 +157,7 @@ func (c *imageCmd) flags() {
 	gnuflag.BoolVar(&c.copyAliases, "copy-aliases", false, i18n.G("Copy aliases from source"))
 	gnuflag.BoolVar(&c.autoUpdate, "auto-update", false, i18n.G("Keep the image up to date after initial copy"))
 	gnuflag.Var(&c.addAliases, "alias", i18n.G("New alias to define at target"))
+	gnuflag.StringVar(&c.format, "format", "table", i18n.G("Format"))
 }
 
 func (c *imageCmd) doImageAlias(config *lxd.Config, args []string) error {
@@ -446,11 +449,20 @@ func (c *imageCmd) run(config *lxd.Config, args []string) error {
 			return err
 		}
 
-		images, err := d.ListImages()
+		var images []shared.ImageInfo
+		allImages, err := d.ListImages()
 		if err != nil {
 			return err
 		}
 
+		for _, image := range allImages {
+			if !c.imageShouldShow(filters, &image) {
+				continue
+			}
+
+			images = append(images, image)
+		}
+
 		return c.showImages(images, filters)
 
 	case "edit":
@@ -572,46 +584,62 @@ func (c *imageCmd) findDescription(props map[string]string) string {
 }
 
 func (c *imageCmd) showImages(images []shared.ImageInfo, filters []string) error {
-	data := [][]string{}
-	for _, image := range images {
-		if !c.imageShouldShow(filters, &image) {
-			continue
-		}
+	switch c.format {
+	case listFormatTable:
+		data := [][]string{}
+		for _, image := range images {
+			if !c.imageShouldShow(filters, &image) {
+				continue
+			}
 
-		shortest := c.shortestAlias(image.Aliases)
-		if len(image.Aliases) > 1 {
-			shortest = fmt.Sprintf(i18n.G("%s (%d more)"), shortest, len(image.Aliases)-1)
-		}
-		fp := image.Fingerprint[0:12]
-		public := i18n.G("no")
-		description := c.findDescription(image.Properties)
+			shortest := c.shortestAlias(image.Aliases)
+			if len(image.Aliases) > 1 {
+				shortest = fmt.Sprintf(i18n.G("%s (%d more)"), shortest, len(image.Aliases)-1)
+			}
+			fp := image.Fingerprint[0:12]
+			public := i18n.G("no")
+			description := c.findDescription(image.Properties)
 
-		if image.Public {
-			public = i18n.G("yes")
+			if image.Public {
+				public = i18n.G("yes")
+			}
+
+			const layout = "Jan 2, 2006 at 3:04pm (MST)"
+			uploaded := image.UploadDate.UTC().Format(layout)
+			size := fmt.Sprintf("%.2fMB", float64(image.Size)/1024.0/1024.0)
+			data = append(data, []string{shortest, fp, public, description, image.Architecture, size, uploaded})
+		}
+
+		table := tablewriter.NewWriter(os.Stdout)
+		table.SetAutoWrapText(false)
+		table.SetAlignment(tablewriter.ALIGN_LEFT)
+		table.SetRowLine(true)
+		table.SetHeader([]string{
+			i18n.G("ALIAS"),
+			i18n.G("FINGERPRINT"),
+			i18n.G("PUBLIC"),
+			i18n.G("DESCRIPTION"),
+			i18n.G("ARCH"),
+			i18n.G("SIZE"),
+			i18n.G("UPLOAD DATE")})
+		sort.Sort(SortImage(data))
+		table.AppendBulk(data)
+		table.Render()
+	case listFormatJSON:
+		data := make([]*shared.ImageInfo, len(images))
+		for i := range images {
+			data[i] = &images[i]
+			enc := json.NewEncoder(os.Stdout)
+			err := enc.Encode(data)
+			if err != nil {
+				return err
+			}
 		}
 
-		const layout = "Jan 2, 2006 at 3:04pm (MST)"
-		uploaded := image.UploadDate.UTC().Format(layout)
-		size := fmt.Sprintf("%.2fMB", float64(image.Size)/1024.0/1024.0)
-		data = append(data, []string{shortest, fp, public, description, image.Architecture, size, uploaded})
+	default:
+		return fmt.Errorf("invalid format %q", c.format)
 	}
 
-	table := tablewriter.NewWriter(os.Stdout)
-	table.SetAutoWrapText(false)
-	table.SetAlignment(tablewriter.ALIGN_LEFT)
-	table.SetRowLine(true)
-	table.SetHeader([]string{
-		i18n.G("ALIAS"),
-		i18n.G("FINGERPRINT"),
-		i18n.G("PUBLIC"),
-		i18n.G("DESCRIPTION"),
-		i18n.G("ARCH"),
-		i18n.G("SIZE"),
-		i18n.G("UPLOAD DATE")})
-	sort.Sort(SortImage(data))
-	table.AppendBulk(data)
-	table.Render()
-
 	return nil
 }
 


More information about the lxc-devel mailing list