[lxc-devel] [lxd/master] Last beta2 changes
stgraber on Github
lxc-bot at linuxcontainers.org
Wed Feb 10 21:31:35 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/20160210/bd18d551/attachment.bin>
-------------- next part --------------
From a3f49ffaecb82e280134e517494cb74251a1e7b8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Wed, 10 Feb 2016 11:24:41 -0500
Subject: [PATCH 1/6] Remove backward compatibility code
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This has been around for a long time now and nobody should be using
those old versions anymore, so lets clean things up before we get to
2.0.
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
client.go | 63 ++++++++++++++++++---------------------------------------
lxc/copy.go | 52 ++++++++---------------------------------------
lxc/image.go | 6 ++----
lxd/images.go | 5 +----
lxd/migrate.go | 15 ++------------
shared/image.go | 30 ++++++++++-----------------
shared/util.go | 16 ---------------
7 files changed, 44 insertions(+), 143 deletions(-)
diff --git a/client.go b/client.go
index 6bb9550..136b96c 100644
--- a/client.go
+++ b/client.go
@@ -530,8 +530,7 @@ func (c *Client) CopyImage(image string, dest *Client, copy_aliases bool, aliase
"server": c.BaseURL,
"fingerprint": fingerprint}
- // FIXME: InterfaceToBool is there for backward compatibility
- if !shared.InterfaceToBool(info.Public) {
+ if !info.Public {
var secret string
resp, err := c.post("images/"+fingerprint+"/secret", nil, Async)
@@ -540,19 +539,13 @@ func (c *Client) CopyImage(image string, dest *Client, copy_aliases bool, aliase
}
op, err := resp.MetadataAsOperation()
- if err == nil && op.Metadata != nil {
- secret, err = op.Metadata.GetString("secret")
- if err != nil {
- return err
- }
- } else {
- // FIXME: This is a backward compatibility codepath
- md := secretMd{}
- if err := json.Unmarshal(resp.Metadata, &md); err != nil {
- return err
- }
+ if err != nil {
+ return err
+ }
- secret = md.Secret
+ secret, err = op.Metadata.GetString("secret")
+ if err != nil {
+ return err
}
source["secret"] = secret
@@ -1158,8 +1151,7 @@ func (c *Client) Init(name string, imgremote string, image string, profiles *[]s
return nil, fmt.Errorf("The image architecture is incompatible with the target server")
}
- // FIXME: InterfaceToBool is there for backward compatibility
- if !shared.InterfaceToBool(imageinfo.Public) {
+ if !imageinfo.Public {
var secret string
resp, err := tmpremote.post("images/"+fingerprint+"/secret", nil, Async)
@@ -1168,19 +1160,13 @@ func (c *Client) Init(name string, imgremote string, image string, profiles *[]s
}
op, err := resp.MetadataAsOperation()
- if err == nil && op.Metadata != nil {
- secret, err = op.Metadata.GetString("secret")
- if err != nil {
- return nil, err
- }
- } else {
- // FIXME: This is a backward compatibility codepath
- md := secretMd{}
- if err := json.Unmarshal(resp.Metadata, &md); err != nil {
- return nil, err
- }
+ if err != nil {
+ return nil, err
+ }
- secret = md.Secret
+ secret, err = op.Metadata.GetString("secret")
+ if err != nil {
+ return nil, err
}
source["secret"] = secret
@@ -1332,22 +1318,13 @@ func (c *Client) Exec(name string, cmd []string, env map[string]string,
var fds shared.Jmap
op, err := resp.MetadataAsOperation()
- if err == nil && op.Metadata != nil {
- fds, err = op.Metadata.GetMap("fds")
- if err != nil {
- return -1, err
- }
- } else {
- // FIXME: This is a backward compatibility codepath
- md := execMd{}
- if err := json.Unmarshal(resp.Metadata, &md); err != nil {
- return -1, err
- }
+ if err != nil {
+ return -1, err
+ }
- fds, err = shared.ParseMetadata(md.FDs)
- if err != nil {
- return -1, err
- }
+ fds, err = op.Metadata.GetMap("fds")
+ if err != nil {
+ return -1, err
}
if controlHandler != nil {
diff --git a/lxc/copy.go b/lxc/copy.go
index a07480e..0f3d20d 100644
--- a/lxc/copy.go
+++ b/lxc/copy.go
@@ -1,7 +1,6 @@
package main
import (
- "encoding/json"
"fmt"
"strings"
@@ -122,15 +121,12 @@ func copyContainer(config *lxd.Config, sourceResource string, destResource strin
secrets := map[string]string{}
op, err := sourceWSResponse.MetadataAsOperation()
- if err == nil && op.Metadata != nil {
- for k, v := range *op.Metadata {
- secrets[k] = v.(string)
- }
- } else {
- // FIXME: This is a backward compatibility codepath
- if err := json.Unmarshal(sourceWSResponse.Metadata, &secrets); err != nil {
- return err
- }
+ if err != nil {
+ return err
+ }
+
+ for k, v := range *op.Metadata {
+ secrets[k] = v.(string)
}
addresses, err := source.Addresses()
@@ -146,55 +142,23 @@ func copyContainer(config *lxd.Config, sourceResource string, destResource strin
* course, if all the errors are websocket errors, let's just
* report that.
*/
- var realError error
-
for _, addr := range addresses {
var migration *lxd.Response
sourceWSUrl := "https://" + addr + sourceWSResponse.Operation
migration, err = dest.MigrateFrom(destName, sourceWSUrl, secrets, status.Architecture, status.Config, status.Devices, status.Profiles, baseImage, ephemeral == 1)
if err != nil {
- if !strings.Contains(err.Error(), "websocket: bad handshake") {
- realError = err
- }
- shared.Debugf("intermediate error: %s", err)
continue
}
if err = dest.WaitForSuccess(migration.Operation); err != nil {
- if !strings.Contains(err.Error(), "websocket: bad handshake") {
- realError = err
- }
- shared.Debugf("intermediate error: %s", err)
- // FIXME: This is a backward compatibility codepath
- sourceWSUrl := "wss://" + addr + sourceWSResponse.Operation + "/websocket"
-
- migration, err = dest.MigrateFrom(destName, sourceWSUrl, secrets, status.Architecture, status.Config, status.Devices, status.Profiles, baseImage, ephemeral == 1)
- if err != nil {
- if !strings.Contains(err.Error(), "websocket: bad handshake") {
- realError = err
- }
- shared.Debugf("intermediate error: %s", err)
- continue
- }
-
- if err = dest.WaitForSuccess(migration.Operation); err != nil {
- if !strings.Contains(err.Error(), "websocket: bad handshake") {
- realError = err
- }
- shared.Debugf("intermediate error: %s", err)
- continue
- }
+ return err
}
return nil
}
- if realError != nil {
- return realError
- } else {
- return err
- }
+ return err
}
}
diff --git a/lxc/image.go b/lxc/image.go
index 9ace054..2be6fe9 100644
--- a/lxc/image.go
+++ b/lxc/image.go
@@ -255,8 +255,7 @@ func (c *imageCmd) run(config *lxd.Config, args []string) error {
fmt.Printf(i18n.G("Fingerprint: %s")+"\n", info.Fingerprint)
public := i18n.G("no")
- // FIXME: InterfaceToBool is there for backward compatibility
- if shared.InterfaceToBool(info) {
+ if info.Public {
public = i18n.G("yes")
}
@@ -504,8 +503,7 @@ func showImages(images []shared.ImageInfo, filters []string) error {
public := i18n.G("no")
description := findDescription(image.Properties)
- // FIXME: InterfaceToBool is there for backward compatibility
- if shared.InterfaceToBool(image.Public) {
+ if image.Public {
public = i18n.G("yes")
}
diff --git a/lxd/images.go b/lxd/images.go
index c69f8b9..a24de23 100644
--- a/lxd/images.go
+++ b/lxd/images.go
@@ -660,10 +660,7 @@ func imageBuildFromInfo(d *Daemon, info shared.ImageInfo) (metadata map[string]s
info.Fingerprint,
info.Filename,
info.Size,
-
- // FIXME: InterfaceToBool is there for backward compatibility
- shared.InterfaceToBool(info.Public),
-
+ info.Public,
info.Architecture,
info.CreationDate,
info.ExpiryDate,
diff --git a/lxd/migrate.go b/lxd/migrate.go
index 46f2efd..254ad4d 100644
--- a/lxd/migrate.go
+++ b/lxd/migrate.go
@@ -446,20 +446,9 @@ func (c *migrationSink) connectWithSecret(secret string) (*websocket.Conn, error
query := url.Values{"secret": []string{secret}}
// The URL is a https URL to the operation, mangle to be a wss URL to the secret
- url := c.url
- if strings.HasPrefix(url, "https://") {
- url = fmt.Sprintf("wss://%s", strings.TrimPrefix(url, "https://"))
- }
-
- // FIXME: This is a backward compatibility codepath
- if !strings.HasSuffix(url, "/websocket") {
- url = fmt.Sprintf("%s/websocket", url)
- }
-
- // Append the secret suffix
- url = fmt.Sprintf("%s?%s", url, query.Encode())
+ wsUrl := fmt.Sprintf("wss://%s/websocket?%s", strings.TrimPrefix(c.url, "https://"), query.Encode())
- return lxd.WebsocketDial(c.dialer, url)
+ return lxd.WebsocketDial(c.dialer, wsUrl)
}
func (c *migrationSink) do() error {
diff --git a/shared/image.go b/shared/image.go
index 692ed3c..c3d3073 100644
--- a/shared/image.go
+++ b/shared/image.go
@@ -15,14 +15,11 @@ type ImageInfo struct {
Fingerprint string `json:"fingerprint"`
Filename string `json:"filename"`
Properties map[string]string `json:"properties"`
-
- // FIXME: This is an interface{] instead of a bool for backward compatibility
- Public interface{} `json:"public"`
-
- Size int64 `json:"size"`
- CreationDate int64 `json:"created_at"`
- ExpiryDate int64 `json:"expires_at"`
- UploadDate int64 `json:"uploaded_at"`
+ Public bool `json:"public"`
+ Size int64 `json:"size"`
+ CreationDate int64 `json:"created_at"`
+ ExpiryDate int64 `json:"expires_at"`
+ UploadDate int64 `json:"uploaded_at"`
}
/*
@@ -37,21 +34,16 @@ type BriefImageInfo struct {
func (i *ImageInfo) BriefInfo() BriefImageInfo {
retstate := BriefImageInfo{
Properties: i.Properties,
-
- // FIXME: InterfaceToBool is there for backward compatibility
- Public: InterfaceToBool(i.Public)}
+ Public: i.Public}
return retstate
}
type ImageBaseInfo struct {
- Id int
- Fingerprint string
- Filename string
- Size int64
-
- // FIXME: This is an interface{] instead of a bool for backward compatibility
- Public interface{}
-
+ Id int
+ Fingerprint string
+ Filename string
+ Size int64
+ Public bool
Architecture int
CreationDate int64
ExpiryDate int64
diff --git a/shared/util.go b/shared/util.go
index 3615789..c3c6a29 100644
--- a/shared/util.go
+++ b/shared/util.go
@@ -501,22 +501,6 @@ func ValidHostname(name string) bool {
return true
}
-// FIXME: InterfaceToBool is there for backward compatibility
-func InterfaceToBool(value interface{}) bool {
- switch t := value.(type) {
- case bool:
- return t
- case float32:
- return t == 1
- case float64:
- return t == 1
- case int:
- return t == 1
- default:
- return false
- }
-}
-
func TextEditor(inPath string, inContent []byte) ([]byte, error) {
var f *os.File
var err error
From 6cec2158e513dade1af838be3ced08b0e8a1da6e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Wed, 10 Feb 2016 14:08:33 -0500
Subject: [PATCH 2/6] Fail when unsetting a key that's not currentl set
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Closes #1477
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
lxc/config.go | 40 ++++++++++++++++++++++++---
po/lxd.pot | 86 +++++++++++++++++++++++++++++++++--------------------------
2 files changed, 84 insertions(+), 42 deletions(-)
diff --git a/lxc/config.go b/lxc/config.go
index 19709bb..1f95535 100644
--- a/lxc/config.go
+++ b/lxc/config.go
@@ -90,7 +90,7 @@ To set the server trust password:
lxc config set core.trust_password blah`)
}
-func doSet(config *lxd.Config, args []string) error {
+func doSet(config *lxd.Config, args []string, unset bool) error {
if len(args) != 4 {
return errArgs
}
@@ -108,11 +108,23 @@ func doSet(config *lxd.Config, args []string) error {
if !terminal.IsTerminal(int(syscall.Stdin)) && value == "-" {
buf, err := ioutil.ReadAll(os.Stdin)
if err != nil {
- return fmt.Errorf("Can't read from stdin: %s", err)
+ return fmt.Errorf(i18n.G("Can't read from stdin: %s"), err)
}
value = string(buf[:])
}
+ if unset {
+ st, err := d.ContainerStatus(container)
+ if err != nil {
+ return err
+ }
+
+ _, ok := st.Config[key]
+ if !ok {
+ return fmt.Errorf(i18n.G("Can't unset key '%s', it's not currently set."), key)
+ }
+ }
+
return d.SetContainerConfig(container, key, value)
}
@@ -135,6 +147,16 @@ func (c *configCmd) run(config *lxd.Config, args []string) error {
return err
}
+ ss, err := c.ServerStatus()
+ if err != nil {
+ return err
+ }
+
+ _, ok := ss.Config[args[1]]
+ if !ok {
+ return fmt.Errorf(i18n.G("Can't unset key '%s', it's not currently set."), args[1])
+ }
+
_, err = c.SetServerConfig(args[1], "")
return err
}
@@ -147,13 +169,23 @@ func (c *configCmd) run(config *lxd.Config, args []string) error {
return err
}
+ ss, err := c.ServerStatus()
+ if err != nil {
+ return err
+ }
+
+ _, ok := ss.Config[args[1]]
+ if !ok {
+ return fmt.Errorf(i18n.G("Can't unset key '%s', it's not currently set."), args[1])
+ }
+
_, err = c.SetServerConfig(args[2], "")
return err
}
// Deal with container
args = append(args, "")
- return doSet(config, args)
+ return doSet(config, args, true)
case "set":
if len(args) < 3 {
@@ -184,7 +216,7 @@ func (c *configCmd) run(config *lxd.Config, args []string) error {
}
// Deal with container
- return doSet(config, args)
+ return doSet(config, args, false)
case "trust":
if len(args) < 2 {
diff --git a/po/lxd.pot b/po/lxd.pot
index 5baf553..f423d71 100644
--- a/po/lxd.pot
+++ b/po/lxd.pot
@@ -7,7 +7,7 @@
msgid ""
msgstr "Project-Id-Version: lxd\n"
"Report-Msgid-Bugs-To: lxc-devel at lists.linuxcontainers.org\n"
- "POT-Creation-Date: 2016-02-09 15:53-0700\n"
+ "POT-Creation-Date: 2016-02-10 14:08-0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL at ADDRESS>\n"
"Language-Team: LANGUAGE <LL at li.org>\n"
@@ -65,7 +65,7 @@ msgid "### This is a yaml representation of the profile.\n"
"### Note that the name is shown but cannot be changed"
msgstr ""
-#: lxc/image.go:501
+#: lxc/image.go:500
#, c-format
msgid "%s (%d more)"
msgstr ""
@@ -78,11 +78,11 @@ msgstr ""
msgid "(none)"
msgstr ""
-#: lxc/image.go:522 lxc/image.go:544
+#: lxc/image.go:520 lxc/image.go:542
msgid "ALIAS"
msgstr ""
-#: lxc/image.go:526
+#: lxc/image.go:524
msgid "ARCH"
msgstr ""
@@ -95,7 +95,7 @@ msgstr ""
msgid "Admin password for %s: "
msgstr ""
-#: lxc/image.go:282
+#: lxc/image.go:281
msgid "Aliases:"
msgstr ""
@@ -103,7 +103,7 @@ msgstr ""
msgid "An environment variable of the form HOME=/home/foo"
msgstr ""
-#: lxc/image.go:265
+#: lxc/image.go:264
#, c-format
msgid "Architecture: %s"
msgstr ""
@@ -112,10 +112,20 @@ msgstr ""
msgid "Available commands:"
msgstr ""
-#: lxc/config.go:232
+#: lxc/config.go:264
msgid "COMMON NAME"
msgstr ""
+#: lxc/config.go:111
+#, c-format
+msgid "Can't read from stdin: %s"
+msgstr ""
+
+#: lxc/config.go:124 lxc/config.go:157 lxc/config.go:179
+#, c-format
+msgid "Can't unset key '%s', it's not currently set."
+msgstr ""
+
#: lxc/profile.go:329
msgid "Cannot provide container name to list"
msgstr ""
@@ -144,7 +154,7 @@ msgstr ""
msgid "Config key/value to apply to the new container"
msgstr ""
-#: lxc/config.go:458 lxc/config.go:523 lxc/image.go:599 lxc/profile.go:185
+#: lxc/config.go:490 lxc/config.go:555 lxc/image.go:597 lxc/profile.go:185
#, c-format
msgid "Config parsing error: %s"
msgstr ""
@@ -171,7 +181,7 @@ msgstr ""
msgid "Copy aliases from source"
msgstr ""
-#: lxc/copy.go:23
+#: lxc/copy.go:22
msgid "Copy containers within or in between lxd instances.\n"
"\n"
"lxc copy [remote:]<source container> [remote:]<destination container> [--ephemeral|e]"
@@ -198,7 +208,7 @@ msgid "Create a read-only snapshot of a container.\n"
"lxc snapshot u1 snap0"
msgstr ""
-#: lxc/image.go:270
+#: lxc/image.go:269
#, c-format
msgid "Created: %s"
msgstr ""
@@ -212,7 +222,7 @@ msgstr ""
msgid "Creating the container"
msgstr ""
-#: lxc/image.go:525
+#: lxc/image.go:523
msgid "DESCRIPTION"
msgstr ""
@@ -224,12 +234,12 @@ msgid "Delete containers or container snapshots.\n"
"Destroy containers or snapshots with any attached data (configuration, snapshots, ...)."
msgstr ""
-#: lxc/config.go:571
+#: lxc/config.go:603
#, c-format
msgid "Device %s added to %s"
msgstr ""
-#: lxc/config.go:599
+#: lxc/config.go:631
#, c-format
msgid "Device %s removed from %s"
msgstr ""
@@ -238,7 +248,7 @@ msgstr ""
msgid "EPHEMERAL"
msgstr ""
-#: lxc/config.go:234
+#: lxc/config.go:266
msgid "EXPIRY DATE"
msgstr ""
@@ -254,7 +264,7 @@ msgstr ""
msgid "Environment:"
msgstr ""
-#: lxc/copy.go:30 lxc/copy.go:31 lxc/init.go:136 lxc/init.go:137 lxc/launch.go:40 lxc/launch.go:41
+#: lxc/copy.go:29 lxc/copy.go:30 lxc/init.go:136 lxc/init.go:137 lxc/launch.go:40 lxc/launch.go:41
msgid "Ephemeral container"
msgstr ""
@@ -268,16 +278,16 @@ msgid "Execute the specified command in a container.\n"
"lxc exec [remote:]container [--mode=auto|interactive|non-interactive] [--env EDITOR=/usr/bin/vim]... <command>"
msgstr ""
-#: lxc/image.go:274
+#: lxc/image.go:273
#, c-format
msgid "Expires: %s"
msgstr ""
-#: lxc/image.go:276
+#: lxc/image.go:275
msgid "Expires: never"
msgstr ""
-#: lxc/config.go:231 lxc/image.go:523 lxc/image.go:545
+#: lxc/config.go:263 lxc/image.go:521 lxc/image.go:543
msgid "FINGERPRINT"
msgstr ""
@@ -316,7 +326,7 @@ msgstr ""
msgid "IPV6"
msgstr ""
-#: lxc/config.go:233
+#: lxc/config.go:265
msgid "ISSUE DATE"
msgstr ""
@@ -328,7 +338,7 @@ msgstr ""
msgid "Image copied successfully!"
msgstr ""
-#: lxc/image.go:340
+#: lxc/image.go:339
#, c-format
msgid "Image imported with fingerprint: %s"
msgstr ""
@@ -627,15 +637,15 @@ msgstr ""
msgid "New alias to define at target"
msgstr ""
-#: lxc/config.go:245
+#: lxc/config.go:277
msgid "No certificate provided to add"
msgstr ""
-#: lxc/config.go:268
+#: lxc/config.go:300
msgid "No fingerprint specified."
msgstr ""
-#: lxc/image.go:332
+#: lxc/image.go:331
msgid "Only https:// is supported for remote image import."
msgstr ""
@@ -643,7 +653,7 @@ msgstr ""
msgid "Options:"
msgstr ""
-#: lxc/image.go:426
+#: lxc/image.go:425
#, c-format
msgid "Output is in %s"
msgstr ""
@@ -656,7 +666,7 @@ msgstr ""
msgid "PID"
msgstr ""
-#: lxc/image.go:524 lxc/remote.go:273
+#: lxc/image.go:522 lxc/remote.go:273
msgid "PUBLIC"
msgstr ""
@@ -682,7 +692,7 @@ msgstr ""
msgid "Press enter to open the editor again"
msgstr ""
-#: lxc/config.go:459 lxc/config.go:524 lxc/image.go:600
+#: lxc/config.go:491 lxc/config.go:556 lxc/image.go:598
msgid "Press enter to start the editor again"
msgstr ""
@@ -733,7 +743,7 @@ msgstr ""
msgid "Profiles: %s"
msgstr ""
-#: lxc/image.go:278
+#: lxc/image.go:277
msgid "Properties:"
msgstr ""
@@ -741,7 +751,7 @@ msgstr ""
msgid "Public image server"
msgstr ""
-#: lxc/image.go:266
+#: lxc/image.go:265
#, c-format
msgid "Public: %s"
msgstr ""
@@ -761,7 +771,7 @@ msgstr ""
msgid "Retrieving image: %s"
msgstr ""
-#: lxc/image.go:527
+#: lxc/image.go:525
msgid "SIZE"
msgstr ""
@@ -814,7 +824,7 @@ msgstr ""
msgid "Show the container's last 100 log lines?"
msgstr ""
-#: lxc/image.go:263
+#: lxc/image.go:262
#, c-format
msgid "Size: %.2fMB"
msgstr ""
@@ -845,7 +855,7 @@ msgstr ""
msgid "Time to wait for the container before killing it."
msgstr ""
-#: lxc/image.go:267
+#: lxc/image.go:266
msgid "Timestamps:"
msgstr ""
@@ -862,7 +872,7 @@ msgstr ""
msgid "Type: persistent"
msgstr ""
-#: lxc/image.go:528
+#: lxc/image.go:526
msgid "UPLOAD DATE"
msgstr ""
@@ -870,7 +880,7 @@ msgstr ""
msgid "URL"
msgstr ""
-#: lxc/image.go:272
+#: lxc/image.go:271
#, c-format
msgid "Uploaded: %s"
msgstr ""
@@ -912,7 +922,7 @@ msgstr ""
msgid "bad result type from action"
msgstr ""
-#: lxc/copy.go:79
+#: lxc/copy.go:78
msgid "can't copy to the same container name"
msgstr ""
@@ -942,11 +952,11 @@ msgstr ""
msgid "got bad version"
msgstr ""
-#: lxc/image.go:256 lxc/image.go:504
+#: lxc/image.go:256 lxc/image.go:503
msgid "no"
msgstr ""
-#: lxc/copy.go:101
+#: lxc/copy.go:100
msgid "not all the profiles from the source exist on the target"
msgstr ""
@@ -982,11 +992,11 @@ msgstr ""
msgid "wrong number of subcommand arguments"
msgstr ""
-#: lxc/image.go:260 lxc/image.go:509
+#: lxc/image.go:259 lxc/image.go:507
msgid "yes"
msgstr ""
-#: lxc/copy.go:39
+#: lxc/copy.go:38
msgid "you must specify a source container name"
msgstr ""
From 7959797f3fd9698bc4552b8183c47465ff112f9e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Wed, 10 Feb 2016 14:40:32 -0500
Subject: [PATCH 3/6] Implement interactive mode in delete
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Closes #781
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
lxc/delete.go | 44 ++++++++++++++++++++++++++++++++++++--------
po/lxd.pot | 29 +++++++++++++++++++++++++----
test/main.sh | 2 +-
test/suites/basic.sh | 4 ++--
test/suites/filemanip.sh | 2 +-
5 files changed, 65 insertions(+), 16 deletions(-)
diff --git a/lxc/delete.go b/lxc/delete.go
index d241aea..d09498d 100644
--- a/lxc/delete.go
+++ b/lxc/delete.go
@@ -1,14 +1,21 @@
package main
import (
+ "bufio"
"fmt"
+ "os"
+ "strings"
"github.com/lxc/lxd"
"github.com/lxc/lxd/i18n"
"github.com/lxc/lxd/shared"
+ "github.com/lxc/lxd/shared/gnuflag"
)
-type deleteCmd struct{}
+type deleteCmd struct {
+ force bool
+ interactive bool
+}
func (c *deleteCmd) showByDefault() bool {
return true
@@ -23,9 +30,24 @@ lxc delete [remote:]<container>[/<snapshot>] [remote:][<container>[/<snapshot>].
Destroy containers or snapshots with any attached data (configuration, snapshots, ...).`)
}
-func (c *deleteCmd) flags() {}
+func (c *deleteCmd) flags() {
+ gnuflag.BoolVar(&c.force, "f", false, i18n.G("Force the removal of stopped containers."))
+ gnuflag.BoolVar(&c.force, "force", false, i18n.G("Force the removal of stopped containers."))
+ gnuflag.BoolVar(&c.interactive, "i", false, i18n.G("Require user confirmation."))
+ gnuflag.BoolVar(&c.interactive, "interactive", false, i18n.G("Require user confirmation."))
+}
+
+func (c *deleteCmd) doDelete(d *lxd.Client, name string) error {
+ if c.interactive {
+ reader := bufio.NewReader(os.Stdin)
+ fmt.Printf(i18n.G("Remove %s (yes/no): "), name)
+ input, _ := reader.ReadString('\n')
+ input = strings.TrimSuffix(input, "\n")
+ if !shared.StringInSlice(strings.ToLower(input), []string{i18n.G("yes")}) {
+ return fmt.Errorf(i18n.G("User aborted delete operation."))
+ }
+ }
-func doDelete(d *lxd.Client, name string) error {
resp, err := d.Delete(name)
if err != nil {
return err
@@ -47,14 +69,20 @@ func (c *deleteCmd) run(config *lxd.Config, args []string) error {
return err
}
- ct, err := d.ContainerStatus(name)
+ if shared.IsSnapshot(name) {
+ return c.doDelete(d, name)
+ }
+ ct, err := d.ContainerStatus(name)
if err != nil {
- // Could be a snapshot
- return doDelete(d, name)
+ return err
}
if ct.Status.StatusCode != 0 && ct.Status.StatusCode != shared.Stopped {
+ if !c.force {
+ return fmt.Errorf(i18n.G("The container is currently running, stop it first or pass --force."))
+ }
+
resp, err := d.Action(name, shared.Stop, -1, true)
if err != nil {
return err
@@ -73,10 +101,10 @@ func (c *deleteCmd) run(config *lxd.Config, args []string) error {
return nil
}
}
- if err := doDelete(d, name); err != nil {
+
+ if err := c.doDelete(d, name); err != nil {
return err
}
}
return nil
-
}
diff --git a/po/lxd.pot b/po/lxd.pot
index f423d71..2afd38d 100644
--- a/po/lxd.pot
+++ b/po/lxd.pot
@@ -7,7 +7,7 @@
msgid ""
msgstr "Project-Id-Version: lxd\n"
"Report-Msgid-Bugs-To: lxc-devel at lists.linuxcontainers.org\n"
- "POT-Creation-Date: 2016-02-10 14:08-0500\n"
+ "POT-Creation-Date: 2016-02-10 14:55-0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL at ADDRESS>\n"
"Language-Team: LANGUAGE <LL at li.org>\n"
@@ -226,7 +226,7 @@ msgstr ""
msgid "DESCRIPTION"
msgstr ""
-#: lxc/delete.go:18
+#: lxc/delete.go:25
msgid "Delete containers or container snapshots.\n"
"\n"
"lxc delete [remote:]<container>[/<snapshot>] [remote:][<container>[/<snapshot>]...]\n"
@@ -310,6 +310,10 @@ msgstr ""
msgid "Force the container to shutdown."
msgstr ""
+#: lxc/delete.go:34 lxc/delete.go:35
+msgid "Force the removal of stopped containers."
+msgstr ""
+
#: lxc/main.go:56
msgid "Force using the local unix socket."
msgstr ""
@@ -766,6 +770,15 @@ msgstr ""
msgid "Remote admin password"
msgstr ""
+#: lxc/delete.go:43
+#, c-format
+msgid "Remove %s (yes/no): "
+msgstr ""
+
+#: lxc/delete.go:36 lxc/delete.go:37
+msgid "Require user confirmation."
+msgstr ""
+
#: lxc/init.go:244
#, c-format
msgid "Retrieving image: %s"
@@ -843,10 +856,14 @@ msgstr ""
msgid "Status: %s"
msgstr ""
-#: lxc/delete.go:69
+#: lxc/delete.go:97
msgid "Stopping container failed!"
msgstr ""
+#: lxc/delete.go:83
+msgid "The container is currently running, stop it first or pass --force."
+msgstr ""
+
#: lxc/publish.go:57
msgid "There is no \"image name\". Did you want an alias?"
msgstr ""
@@ -894,6 +911,10 @@ msgstr ""
msgid "Usage: lxc [subcommand] [options]"
msgstr ""
+#: lxc/delete.go:47
+msgid "User aborted delete operation."
+msgstr ""
+
#: lxc/restore.go:35
msgid "Whether or not to restore the container's running state from snapshot (if available)"
msgstr ""
@@ -992,7 +1013,7 @@ msgstr ""
msgid "wrong number of subcommand arguments"
msgstr ""
-#: lxc/image.go:259 lxc/image.go:507
+#: lxc/delete.go:46 lxc/image.go:259 lxc/image.go:507
msgid "yes"
msgstr ""
diff --git a/test/main.sh b/test/main.sh
index 55e05d6..e13bd2b 100755
--- a/test/main.sh
+++ b/test/main.sh
@@ -183,7 +183,7 @@ kill_lxd() {
# Delete all containers
echo "==> Deleting all containers"
for container in $(lxc list --force-local | tail -n+3 | grep "^| " | cut -d' ' -f2); do
- lxc delete "${container}" --force-local || true
+ lxc delete "${container}" --force-local -f || true
done
# Delete all images
diff --git a/test/suites/basic.sh b/test/suites/basic.sh
index 6b55f13..0a1e31a 100644
--- a/test/suites/basic.sh
+++ b/test/suites/basic.sh
@@ -211,10 +211,10 @@ test_basic_usage() {
lxc launch testimage deleterunning
my_curl -X DELETE "https://${LXD_ADDR}/1.0/containers/deleterunning" | grep "container is running"
- lxc delete deleterunning
+ lxc delete deleterunning -f
# cleanup
- lxc delete foo
+ lxc delete foo -f
# check that an apparmor profile is created for this container, that it is
# unloaded on stop, and that it is deleted when the container is deleted
diff --git a/test/suites/filemanip.sh b/test/suites/filemanip.sh
index a8c2cb8..dd2317c 100644
--- a/test/suites/filemanip.sh
+++ b/test/suites/filemanip.sh
@@ -10,5 +10,5 @@ test_filemanip() {
[ ! -f /tmp/main.sh ]
[ -f "${LXD_DIR}/containers/filemanip/rootfs/tmp/main.sh" ]
- lxc delete filemanip
+ lxc delete filemanip -f
}
From 21d3b9b3dfe4c98ecff990fd2fe7e29d36404bb0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Wed, 10 Feb 2016 15:15:10 -0500
Subject: [PATCH 4/6] specs: Re-sync database spec with reality
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>
---
specs/database.md | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/specs/database.md b/specs/database.md
index 6f5162d..2632fd5 100644
--- a/specs/database.md
+++ b/specs/database.md
@@ -109,8 +109,8 @@ id | INTEGER | SERIAL | NOT NULL | SERIAL
name | VARCHAR(255) | - | NOT NULL | Container name
architecture | INTEGER | - | NOT NULL | Container architecture
type | INTEGER | 0 | NOT NULL | Container type (0 = container, 1 = container snapshot)
-power\_state | INTEGER | 0 | NOT NULL | Container power state (0 = off, 1 = on)
ephemeral | INTEGER | 0 | NOT NULL | Whether the container is ephemeral (0 = persistent, 1 = ephemeral)
+creation\_date | DATETIME | - | | Image creation date (user supplied, 0 = unknown)
Index: UNIQUE ON id AND name
@@ -190,31 +190,31 @@ last\_use\_date | DATETIME | - | | Last time
Index: UNIQUE ON id AND fingerprint
-## images\_properties
+## images\_aliases
Column | Type | Default | Constraint | Description
:----- | :--- | :------ | :--------- | :----------
id | INTEGER | SERIAL | NOT NULL | SERIAL
+name | VARCHAR(255) | - | NOT NULL | Alias name
image\_id | INTEGER | - | NOT NULL | images.id FK
-type | INTEGER | 0 | NOT NULL | Property type (0 = string, 1 = text)
-key | VARCHAR(255) | - | NOT NULL | Property name
-value | TEXT | - | | Property value (NULL for unset)
+description | VARCHAR(255) | - | | Description of the alias
-Index: UNIQUE ON id
+Index: UNIQUE ON id AND name
Foreign keys: image\_id REFERENCES images(id)
-## images\_aliases
+## images\_properties
Column | Type | Default | Constraint | Description
:----- | :--- | :------ | :--------- | :----------
id | INTEGER | SERIAL | NOT NULL | SERIAL
-name | VARCHAR(255) | - | NOT NULL | Alias name
image\_id | INTEGER | - | NOT NULL | images.id FK
-description | VARCHAR(255) | - | | Description of the alias
+type | INTEGER | 0 | NOT NULL | Property type (0 = string, 1 = text)
+key | VARCHAR(255) | - | NOT NULL | Property name
+value | TEXT | - | | Property value (NULL for unset)
-Index: UNIQUE ON id AND name
+Index: UNIQUE ON id
Foreign keys: image\_id REFERENCES images(id)
From e63445b6f9acbd14d4aab29278724b1c0401e388 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Wed, 10 Feb 2016 16:00:59 -0500
Subject: [PATCH 5/6] Record a creation time for containers and snapshots
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>
---
lxd/container.go | 2 ++
lxd/container_lxc.go | 7 +++++++
lxd/container_snapshot.go | 27 ++++++++++++---------------
lxd/db.go | 3 ++-
lxd/db_containers.go | 12 ++++++++----
lxd/db_images.go | 4 ++--
lxd/db_update.go | 14 ++++++++++++++
shared/container.go | 7 +++++++
specs/rest-api.md | 3 +++
test/suites/basic.sh | 2 +-
10 files changed, 58 insertions(+), 23 deletions(-)
diff --git a/lxd/container.go b/lxd/container.go
index 87dd19d..272b7f2 100644
--- a/lxd/container.go
+++ b/lxd/container.go
@@ -296,6 +296,7 @@ type containerArgs struct {
Architecture int
BaseImage string
Config map[string]string
+ CreationDate *time.Time
Ctype containerType
Devices shared.Devices
Ephemeral bool
@@ -350,6 +351,7 @@ type container interface {
Id() int
Name() string
Architecture() int
+ CreationDate() *time.Time
ExpandedConfig() map[string]string
ExpandedDevices() shared.Devices
LocalConfig() map[string]string
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 073b9b7..3a22f74 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -86,6 +86,7 @@ func containerLXCCreate(d *Daemon, args containerArgs) (container, error) {
ephemeral: args.Ephemeral,
architecture: args.Architecture,
cType: args.Ctype,
+ creationDate: args.CreationDate,
profiles: args.Profiles,
localConfig: args.Config,
localDevices: args.Devices}
@@ -181,6 +182,7 @@ func containerLXCLoad(d *Daemon, args containerArgs) (container, error) {
ephemeral: args.Ephemeral,
architecture: args.Architecture,
cType: args.Ctype,
+ creationDate: args.CreationDate,
profiles: args.Profiles,
localConfig: args.Config,
localDevices: args.Devices}
@@ -206,6 +208,7 @@ type containerLXC struct {
// Properties
architecture int
cType containerType
+ creationDate *time.Time
ephemeral bool
id int
name string
@@ -1362,6 +1365,7 @@ func (c *containerLXC) RenderState() (*shared.ContainerState, error) {
return &shared.ContainerState{
Architecture: c.architecture,
Config: c.localConfig,
+ CreationDate: c.creationDate.Unix(),
Devices: c.localDevices,
Ephemeral: c.ephemeral,
ExpandedConfig: c.expandedConfig,
@@ -3825,6 +3829,9 @@ func (c *containerLXC) Architecture() int {
return c.architecture
}
+func (c *containerLXC) CreationDate() *time.Time {
+ return c.creationDate
+}
func (c *containerLXC) ExpandedConfig() map[string]string {
return c.expandedConfig
}
diff --git a/lxd/container_snapshot.go b/lxd/container_snapshot.go
index dfff877..063364e 100644
--- a/lxd/container_snapshot.go
+++ b/lxd/container_snapshot.go
@@ -10,8 +10,6 @@ import (
"github.com/gorilla/mux"
"github.com/lxc/lxd/shared"
-
- log "gopkg.in/inconshreveable/log15.v2"
)
func containerSnapshotsGet(d *Daemon, r *http.Request) Response {
@@ -22,13 +20,12 @@ func containerSnapshotsGet(d *Daemon, r *http.Request) Response {
}
cname := mux.Vars(r)["name"]
- // Makes sure the requested container exists.
- _, err = containerLoadByName(d, cname)
+ c, err := containerLoadByName(d, cname)
if err != nil {
return SmartError(err)
}
- results, err := dbContainerGetSnapshots(d.db, cname)
+ snaps, err := c.Snapshots()
if err != nil {
return SmartError(err)
}
@@ -36,19 +33,16 @@ func containerSnapshotsGet(d *Daemon, r *http.Request) Response {
resultString := []string{}
resultMap := []shared.Jmap{}
- for _, name := range results {
- sc, err := containerLoadByName(d, name)
- if err != nil {
- shared.Log.Error("Failed to load snapshot", log.Ctx{"snapshot": name})
- continue
- }
-
- snapName := strings.SplitN(name, shared.SnapshotDelimiter, 2)[1]
+ for _, snap := range snaps {
+ snapName := strings.SplitN(snap.Name(), shared.SnapshotDelimiter, 2)[1]
if recursion == 0 {
url := fmt.Sprintf("/%s/containers/%s/snapshots/%s", shared.APIVersion, cname, snapName)
resultString = append(resultString, url)
} else {
- body := shared.Jmap{"name": snapName, "stateful": shared.PathExists(sc.StatePath())}
+ body := shared.Jmap{
+ "name": snapName,
+ "creation_date": snap.CreationDate().Unix(),
+ "stateful": shared.PathExists(snap.StatePath())}
resultMap = append(resultMap, body)
}
}
@@ -189,7 +183,10 @@ func snapshotHandler(d *Daemon, r *http.Request) Response {
}
func snapshotGet(sc container, name string) Response {
- body := shared.Jmap{"name": name, "stateful": shared.PathExists(sc.StatePath())}
+ body := shared.Jmap{
+ "name": name,
+ "creation_date": sc.CreationDate().Unix(),
+ "stateful": shared.PathExists(sc.StatePath())}
return SyncResponse(true, body)
}
diff --git a/lxd/db.go b/lxd/db.go
index 9b5606c..646d076 100644
--- a/lxd/db.go
+++ b/lxd/db.go
@@ -34,7 +34,7 @@ type Profile struct {
// Profiles will contain a list of all Profiles.
type Profiles []Profile
-const DB_CURRENT_VERSION int = 21
+const DB_CURRENT_VERSION int = 22
// CURRENT_SCHEMA contains the current SQLite SQL Schema.
const CURRENT_SCHEMA string = `
@@ -58,6 +58,7 @@ CREATE TABLE IF NOT EXISTS containers (
architecture INTEGER NOT NULL,
type INTEGER NOT NULL,
ephemeral INTEGER NOT NULL DEFAULT 0,
+ creation_date DATETIME,
UNIQUE (name)
);
CREATE TABLE IF NOT EXISTS containers_config (
diff --git a/lxd/db_containers.go b/lxd/db_containers.go
index a1092e8..c8a1e53 100644
--- a/lxd/db_containers.go
+++ b/lxd/db_containers.go
@@ -3,6 +3,7 @@ package main
import (
"database/sql"
"fmt"
+ "time"
"github.com/lxc/lxd/shared"
@@ -65,9 +66,9 @@ func dbContainerGet(db *sql.DB, name string) (containerArgs, error) {
args.Name = name
ephemInt := -1
- q := "SELECT id, architecture, type, ephemeral FROM containers WHERE name=?"
+ q := "SELECT id, architecture, type, ephemeral, creation_date FROM containers WHERE name=?"
arg1 := []interface{}{name}
- arg2 := []interface{}{&args.Id, &args.Architecture, &args.Ctype, &ephemInt}
+ arg2 := []interface{}{&args.Id, &args.Architecture, &args.Ctype, &ephemInt, &args.CreationDate}
err := dbQueryRowScan(db, q, arg1, arg2)
if err != nil {
return args, err
@@ -123,14 +124,17 @@ func dbContainerCreate(db *sql.DB, args containerArgs) (int, error) {
ephemInt = 1
}
- str := fmt.Sprintf("INSERT INTO containers (name, architecture, type, ephemeral) VALUES (?, ?, ?, ?)")
+ now := time.Now().UTC()
+ args.CreationDate = &now
+
+ str := fmt.Sprintf("INSERT INTO containers (name, architecture, type, ephemeral, creation_date) VALUES (?, ?, ?, ?, ?)")
stmt, err := tx.Prepare(str)
if err != nil {
tx.Rollback()
return 0, err
}
defer stmt.Close()
- result, err := stmt.Exec(args.Name, args.Architecture, args.Ctype, ephemInt)
+ result, err := stmt.Exec(args.Name, args.Architecture, args.Ctype, ephemInt, args.CreationDate.Unix())
if err != nil {
tx.Rollback()
return 0, err
diff --git a/lxd/db_images.go b/lxd/db_images.go
index 3f42e2b..2cd41c7 100644
--- a/lxd/db_images.go
+++ b/lxd/db_images.go
@@ -150,9 +150,9 @@ func dbImageSetPublic(db *sql.DB, id int, public bool) error {
return err
}
-// Insert an alias into the database.
+// Insert an alias ento the database.
func dbImageAliasAdd(db *sql.DB, name string, imageID int, desc string) error {
- stmt := `INSERT into images_aliases (name, image_id, description) values (?, ?, ?)`
+ stmt := `INSERT INTO images_aliases (name, image_id, description) values (?, ?, ?)`
_, err := dbExec(db, stmt, name, imageID, desc)
return err
}
diff --git a/lxd/db_update.go b/lxd/db_update.go
index 6a7a8fe..0e39f84 100644
--- a/lxd/db_update.go
+++ b/lxd/db_update.go
@@ -15,6 +15,14 @@ import (
log "gopkg.in/inconshreveable/log15.v2"
)
+func dbUpdateFromV21(db *sql.DB) error {
+ stmt := `
+ALTER TABLE containers ADD COLUMN creation_date DATETIME NOT NULL DEFAULT 0;
+INSERT INTO schema (version, updated_at) VALUES (?, strftime("%s"));`
+ _, err := db.Exec(stmt, 22)
+ return err
+}
+
func dbUpdateFromV20(d *Daemon) error {
cNames, err := dbContainersList(d.db, cTypeRegular)
if err != nil {
@@ -900,6 +908,12 @@ func dbUpdate(d *Daemon, prevVersion int) error {
return err
}
}
+ if prevVersion < 22 {
+ err = dbUpdateFromV21(db)
+ if err != nil {
+ return err
+ }
+ }
return nil
}
diff --git a/shared/container.go b/shared/container.go
index cb75ec3..d4bb6da 100644
--- a/shared/container.go
+++ b/shared/container.go
@@ -24,9 +24,16 @@ type ContainerExecControl struct {
Args map[string]string `json:"args"`
}
+type SnapshotState struct {
+ CreationDate int64 `json:"creation_date"`
+ Name string `json:"name"`
+ Stateful bool `json:"stateful"`
+}
+
type ContainerState struct {
Architecture int `json:"architecture"`
Config map[string]string `json:"config"`
+ CreationDate int64 `json:"creation_date"`
Devices Devices `json:"devices"`
Ephemeral bool `json:"ephemeral"`
ExpandedConfig map[string]string `json:"expanded_config"`
diff --git a/specs/rest-api.md b/specs/rest-api.md
index 017ece0..0ca83db 100644
--- a/specs/rest-api.md
+++ b/specs/rest-api.md
@@ -385,6 +385,8 @@ Output:
'profiles': ["default"],
'architecture': 2,
'config': {"limits.cpu": "3"},
+ 'ephemeral': false,
+ 'creation_date': 1455136027,
'expanded_config': {"limits.cpu": "3"} # the result of expanding profiles and adding the container's local config
'devices': {
'rootfs': {
@@ -572,6 +574,7 @@ Input:
Return:
{
+ 'creation_date': 1455139453,
'name': "my-snapshot",
'stateful': true
}
diff --git a/test/suites/basic.sh b/test/suites/basic.sh
index 0a1e31a..c24d53a 100644
--- a/test/suites/basic.sh
+++ b/test/suites/basic.sh
@@ -44,7 +44,7 @@ test_basic_usage() {
# Test container creation
lxc init testimage foo
- lxc list | grep foo | grep STOPPED
+ lxc list | grep foo | grep STOPPED || bash
lxc list fo | grep foo | grep STOPPED
# Test container rename
From 87408f9b9c49fda54df4a494e8d5fdb7f1d60e03 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Wed, 10 Feb 2016 16:01:16 -0500
Subject: [PATCH 6/6] Rework snapshot rendering
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- Don't print the awkward list in "lxc list" anymore.
- Update "lxc info" to show:
- Snapshot name
- Snapshot creation date (if known)
- Snapshot type (stateful or stateless)
Closes #1560
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
client.go | 16 +++-------------
lxc/info.go | 22 +++++++++++++++++++++-
lxc/list.go | 15 ++-------------
po/lxd.pot | 61 +++++++++++++++++++++++++++++++++++++------------------------
4 files changed, 63 insertions(+), 51 deletions(-)
diff --git a/client.go b/client.go
index 136b96c..45eb1a2 100644
--- a/client.go
+++ b/client.go
@@ -1624,30 +1624,20 @@ func (c *Client) Snapshot(container string, snapshotName string, stateful bool)
return c.post(fmt.Sprintf("containers/%s/snapshots", container), body, Async)
}
-func (c *Client) ListSnapshots(container string) ([]string, error) {
+func (c *Client) ListSnapshots(container string) ([]shared.SnapshotState, error) {
qUrl := fmt.Sprintf("containers/%s/snapshots?recursion=1", container)
resp, err := c.get(qUrl)
if err != nil {
return nil, err
}
- var result []shared.Jmap
+ var result []shared.SnapshotState
if err := json.Unmarshal(resp.Metadata, &result); err != nil {
return nil, err
}
- names := []string{}
-
- for _, snapjmap := range result {
- name, err := snapjmap.GetString("name")
- if err != nil {
- continue
- }
- names = append(names, name)
- }
-
- return names, nil
+ return result, nil
}
func (c *Client) GetServerConfigString() ([]string, error) {
diff --git a/lxc/info.go b/lxc/info.go
index 6116341..ba644e1 100644
--- a/lxc/info.go
+++ b/lxc/info.go
@@ -4,6 +4,7 @@ import (
"fmt"
"io/ioutil"
"strings"
+ "time"
"gopkg.in/yaml.v2"
@@ -76,7 +77,13 @@ func containerInfo(d *lxd.Client, name string, showLog bool) error {
return err
}
+ const layout = "2006/01/02 15:04 UTC"
+
fmt.Printf(i18n.G("Name: %s")+"\n", ct.Name)
+ if ct.CreationDate != 0 {
+ fmt.Printf(i18n.G("Created: %s")+"\n", time.Unix(ct.CreationDate, 0).UTC().Format(layout))
+ }
+
fmt.Printf(i18n.G("Status: %s")+"\n", ct.Status.Status)
if ct.Ephemeral {
fmt.Printf(i18n.G("Type: ephemeral") + "\n")
@@ -109,11 +116,24 @@ func containerInfo(d *lxd.Client, name string, showLog bool) error {
if err != nil {
return nil
}
+
for _, snap := range snaps {
if first_snapshot {
fmt.Println(i18n.G("Snapshots:"))
}
- fmt.Printf(" %s\n", snap)
+ fmt.Printf(" %s", snap.Name)
+
+ if snap.CreationDate != 0 {
+ fmt.Printf(" ("+i18n.G("taken at %s")+")", time.Unix(snap.CreationDate, 0).UTC().Format(layout))
+ }
+
+ if snap.Stateful {
+ fmt.Printf(" (" + i18n.G("stateful") + ")")
+ } else {
+ fmt.Printf(" (" + i18n.G("stateless") + ")")
+ }
+ fmt.Printf("\n")
+
first_snapshot = false
}
diff --git a/lxc/list.go b/lxc/list.go
index 349aeef..ee25e73 100644
--- a/lxc/list.go
+++ b/lxc/list.go
@@ -149,7 +149,7 @@ func shouldShow(filters []string, state *shared.ContainerState) bool {
return true
}
-func listContainers(cinfos []shared.ContainerInfo, filters []string, columns []Column, listsnaps bool) error {
+func listContainers(cinfos []shared.ContainerInfo, filters []string, columns []Column) error {
headers := []string{}
for _, column := range columns {
headers = append(headers, column.Name)
@@ -175,17 +175,6 @@ func listContainers(cinfos []shared.ContainerInfo, filters []string, columns []C
table.AppendBulk(data)
table.Render()
- if listsnaps && len(cinfos) == 1 {
- csnaps := cinfos[0].Snaps
- first_snapshot := true
- for _, snap := range csnaps {
- if first_snapshot {
- fmt.Println(i18n.G("Snapshots:"))
- }
- fmt.Printf(" %s\n", snap)
- first_snapshot = false
- }
- }
return nil
}
@@ -250,7 +239,7 @@ func (c *listCmd) run(config *lxd.Config, args []string) error {
}
}
- return listContainers(cts, filters, columns, len(cts) == 1)
+ return listContainers(cts, filters, columns)
}
func nameColumnData(cinfo shared.ContainerInfo) string {
diff --git a/po/lxd.pot b/po/lxd.pot
index 2afd38d..07753b4 100644
--- a/po/lxd.pot
+++ b/po/lxd.pot
@@ -7,7 +7,7 @@
msgid ""
msgstr "Project-Id-Version: lxd\n"
"Report-Msgid-Bugs-To: lxc-devel at lists.linuxcontainers.org\n"
- "POT-Creation-Date: 2016-02-10 14:55-0500\n"
+ "POT-Creation-Date: 2016-02-10 16:04-0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL at ADDRESS>\n"
"Language-Team: LANGUAGE <LL at li.org>\n"
@@ -74,7 +74,7 @@ msgstr ""
msgid "'/' not allowed in snapshot name"
msgstr ""
-#: lxc/info.go:102 lxc/profile.go:221
+#: lxc/info.go:109 lxc/profile.go:221
msgid "(none)"
msgstr ""
@@ -208,7 +208,7 @@ msgid "Create a read-only snapshot of a container.\n"
"lxc snapshot u1 snap0"
msgstr ""
-#: lxc/image.go:269
+#: lxc/image.go:269 lxc/info.go:84
#, c-format
msgid "Created: %s"
msgstr ""
@@ -244,7 +244,7 @@ msgstr ""
msgid "Device %s removed from %s"
msgstr ""
-#: lxc/list.go:239
+#: lxc/list.go:228
msgid "EPHEMERAL"
msgstr ""
@@ -322,11 +322,11 @@ msgstr ""
msgid "Generating a client certificate. This may take a minute..."
msgstr ""
-#: lxc/list.go:237
+#: lxc/list.go:226
msgid "IPV4"
msgstr ""
-#: lxc/list.go:238
+#: lxc/list.go:227
msgid "IPV6"
msgstr ""
@@ -347,7 +347,7 @@ msgstr ""
msgid "Image imported with fingerprint: %s"
msgstr ""
-#: lxc/info.go:88
+#: lxc/info.go:95
#, c-format
msgid "Init: %d"
msgstr ""
@@ -380,7 +380,7 @@ msgstr ""
msgid "Invalid target %s"
msgstr ""
-#: lxc/info.go:90
+#: lxc/info.go:97
msgid "Ips:"
msgstr ""
@@ -402,7 +402,7 @@ msgid "Launch a container from a particular image.\n"
"lxc launch ubuntu u1"
msgstr ""
-#: lxc/info.go:24
+#: lxc/info.go:25
msgid "List information on containers.\n"
"\n"
"This will support remotes and images as well, but only containers for now.\n"
@@ -433,7 +433,7 @@ msgid "Lists the available resources.\n"
"* p - pid of container init process"
msgstr ""
-#: lxc/info.go:131
+#: lxc/info.go:151
msgid "Log:"
msgstr ""
@@ -624,15 +624,15 @@ msgid "Move containers within or in between lxd instances.\n"
" Rename a local container.\n"
msgstr ""
-#: lxc/list.go:235 lxc/remote.go:271
+#: lxc/list.go:224 lxc/remote.go:271
msgid "NAME"
msgstr ""
-#: lxc/list.go:304 lxc/remote.go:257
+#: lxc/list.go:293 lxc/remote.go:257
msgid "NO"
msgstr ""
-#: lxc/info.go:79
+#: lxc/info.go:82
#, c-format
msgid "Name: %s"
msgstr ""
@@ -666,7 +666,7 @@ msgstr ""
msgid "Override the terminal mode (auto, interactive or non-interactive)"
msgstr ""
-#: lxc/list.go:241
+#: lxc/list.go:230
msgid "PID"
msgstr ""
@@ -718,7 +718,7 @@ msgid "Prints the version number of LXD.\n"
"lxc version"
msgstr ""
-#: lxc/info.go:89
+#: lxc/info.go:96
#, c-format
msgid "Processcount: %d"
msgstr ""
@@ -742,7 +742,7 @@ msgstr ""
msgid "Profile to apply to the new container"
msgstr ""
-#: lxc/info.go:86
+#: lxc/info.go:93
#, c-format
msgid "Profiles: %s"
msgstr ""
@@ -788,11 +788,11 @@ msgstr ""
msgid "SIZE"
msgstr ""
-#: lxc/list.go:240
+#: lxc/list.go:229
msgid "SNAPSHOTS"
msgstr ""
-#: lxc/list.go:236
+#: lxc/list.go:225
msgid "STATE"
msgstr ""
@@ -833,7 +833,7 @@ msgstr ""
msgid "Show all commands (not just interesting ones)"
msgstr ""
-#: lxc/info.go:33
+#: lxc/info.go:34
msgid "Show the container's last 100 log lines?"
msgstr ""
@@ -842,7 +842,7 @@ msgstr ""
msgid "Size: %.2fMB"
msgstr ""
-#: lxc/info.go:114 lxc/list.go:183
+#: lxc/info.go:122
msgid "Snapshots:"
msgstr ""
@@ -851,7 +851,7 @@ msgstr ""
msgid "Starting %s"
msgstr ""
-#: lxc/info.go:80
+#: lxc/info.go:87
#, c-format
msgid "Status: %s"
msgstr ""
@@ -881,11 +881,11 @@ msgstr ""
msgid "Try `lxc info --show-log %s` for more info"
msgstr ""
-#: lxc/info.go:82
+#: lxc/info.go:89
msgid "Type: ephemeral"
msgstr ""
-#: lxc/info.go:84
+#: lxc/info.go:91
msgid "Type: persistent"
msgstr ""
@@ -927,7 +927,7 @@ msgstr ""
msgid "Whether to show the expanded configuration"
msgstr ""
-#: lxc/list.go:302 lxc/remote.go:259
+#: lxc/list.go:291 lxc/remote.go:259
msgid "YES"
msgstr ""
@@ -1005,6 +1005,19 @@ msgstr ""
msgid "remote %s exists as <%s>"
msgstr ""
+#: lxc/info.go:131
+msgid "stateful"
+msgstr ""
+
+#: lxc/info.go:133
+msgid "stateless"
+msgstr ""
+
+#: lxc/info.go:127
+#, c-format
+msgid "taken at %s"
+msgstr ""
+
#: lxc/exec.go:158
msgid "unreachable return reached"
msgstr ""
More information about the lxc-devel
mailing list