[lxc-devel] [lxd/master] Bugfixes
stgraber on Github
lxc-bot at linuxcontainers.org
Mon Mar 20 18:26:32 UTC 2017
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/20170320/e846bd4a/attachment.bin>
-------------- next part --------------
From 9ec18d41556aec884a571370855ce99993cd365b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Mon, 20 Mar 2017 13:58:03 -0400
Subject: [PATCH 1/2] init: Better render available storage backends
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/main_init.go | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/lxd/main_init.go b/lxd/main_init.go
index 1960220..e86d210 100644
--- a/lxd/main_init.go
+++ b/lxd/main_init.go
@@ -244,11 +244,7 @@ func cmdInit() error {
goto askForStorageAgain
}
- storagePoolDriverChoiceString := backendsAvailable[0]
- if len(backendsAvailable) > 1 {
- storagePoolDriverChoiceString = strings.Join(backendsAvailable, ",")
- }
- storageBackend = askChoice(fmt.Sprintf("Name of the storage backend to use (%s) [default=%s]: ", storagePoolDriverChoiceString, defaultStorage), supportedStoragePoolDrivers, defaultStorage)
+ storageBackend = askChoice(fmt.Sprintf("Name of the storage backend to use (%s) [default=%s]: ", strings.Join(backendsAvailable, ", "), defaultStorage), supportedStoragePoolDrivers, defaultStorage)
if !shared.StringInSlice(storageBackend, supportedStoragePoolDrivers) {
return fmt.Errorf("The requested backend '%s' isn't supported by lxd init.", storageBackend)
From e411eff44a2b9055e3e49f9831e2b76c0cd4f7bc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Mon, 20 Mar 2017 00:19:29 -0400
Subject: [PATCH 2/2] Don't attempt to live migration on copy
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This adds a "live" property to migration request allowing the client to
control whether to do a live migration or not, and to turn it off for
copies.
Closes #3086
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
client.go | 6 ++++--
doc/api-extensions.md | 4 ++++
lxc/copy.go | 8 ++++----
lxc/move.go | 2 +-
lxd/api_1.0.go | 1 +
lxd/container_post.go | 31 ++++++++++++++++++++++++-------
lxd/container_snapshot.go | 2 +-
lxd/migrate.go | 4 ++--
shared/api/container.go | 10 ++++++++--
9 files changed, 49 insertions(+), 19 deletions(-)
diff --git a/client.go b/client.go
index 0f2dd5f..a0a1050 100644
--- a/client.go
+++ b/client.go
@@ -1995,12 +1995,14 @@ func (c *Client) DeleteFile(container string, p string) error {
return nil
}
-func (c *Client) GetMigrationSourceWS(container string) (*api.Response, error) {
+func (c *Client) GetMigrationSourceWS(container string, stateful bool) (*api.Response, error) {
if c.Remote.Public {
return nil, fmt.Errorf("This function isn't supported by public remotes.")
}
- body := shared.Jmap{"migration": true}
+ body := shared.Jmap{
+ "migration": true,
+ "live": stateful}
url := fmt.Sprintf("containers/%s", container)
if shared.IsSnapshot(container) {
pieces := strings.SplitN(container, shared.SnapshotDelimiter, 2)
diff --git a/doc/api-extensions.md b/doc/api-extensions.md
index 702fac9..0b62c51 100644
--- a/doc/api-extensions.md
+++ b/doc/api-extensions.md
@@ -229,3 +229,7 @@ macvlan parent.
## image\_create\_aliases
Adds a new "aliases" field to POST /1.0/images allowing for aliases to
be set at image creation/import time.
+
+## container\_stateless\_copy
+This introduces a new "live" attribute in POST /1.0/containers/NAME.
+Setting it to false tells LXD not to attempt running state transfer.
diff --git a/lxc/copy.go b/lxc/copy.go
index 539d616..0e6445d 100644
--- a/lxc/copy.go
+++ b/lxc/copy.go
@@ -37,7 +37,7 @@ func (c *copyCmd) flags() {
gnuflag.BoolVar(&c.ephem, "e", false, i18n.G("Ephemeral container"))
}
-func (c *copyCmd) copyContainer(config *lxd.Config, sourceResource string, destResource string, keepVolatile bool, ephemeral int) error {
+func (c *copyCmd) copyContainer(config *lxd.Config, sourceResource string, destResource string, keepVolatile bool, ephemeral int, stateful bool) error {
sourceRemote, sourceName := config.ParseRemoteAndContainer(sourceResource)
destRemote, destName := config.ParseRemoteAndContainer(destResource)
@@ -178,7 +178,7 @@ func (c *copyCmd) copyContainer(config *lxd.Config, sourceResource string, destR
}
}
- sourceWSResponse, err := source.GetMigrationSourceWS(sourceName)
+ sourceWSResponse, err := source.GetMigrationSourceWS(sourceName, stateful)
if err != nil {
return err
}
@@ -259,8 +259,8 @@ func (c *copyCmd) run(config *lxd.Config, args []string) error {
}
if len(args) < 2 {
- return c.copyContainer(config, args[0], "", false, ephem)
+ return c.copyContainer(config, args[0], "", false, ephem, false)
}
- return c.copyContainer(config, args[0], args[1], false, ephem)
+ return c.copyContainer(config, args[0], args[1], false, ephem, false)
}
diff --git a/lxc/move.go b/lxc/move.go
index 112d2a7..69179be 100644
--- a/lxc/move.go
+++ b/lxc/move.go
@@ -61,7 +61,7 @@ func (c *moveCmd) run(config *lxd.Config, args []string) error {
// A move is just a copy followed by a delete; however, we want to
// keep the volatile entries around since we are moving the container.
- if err := cpy.copyContainer(config, args[0], args[1], true, -1); err != nil {
+ if err := cpy.copyContainer(config, args[0], args[1], true, -1, true); err != nil {
return err
}
diff --git a/lxd/api_1.0.go b/lxd/api_1.0.go
index a3fdd46..8edbd0e 100644
--- a/lxd/api_1.0.go
+++ b/lxd/api_1.0.go
@@ -97,6 +97,7 @@ func api10Get(d *Daemon, r *http.Request) Response {
"storage_lvm_thinpool_rename",
"network_vlan",
"image_create_aliases",
+ "container_stateless_copy",
},
APIStatus: "stable",
APIVersion: version.APIVersion,
diff --git a/lxd/container_post.go b/lxd/container_post.go
index 066a2a3..acfc5fa 100644
--- a/lxd/container_post.go
+++ b/lxd/container_post.go
@@ -1,12 +1,14 @@
package main
import (
+ "bytes"
"encoding/json"
"io/ioutil"
"net/http"
"github.com/gorilla/mux"
+ "github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
)
@@ -17,18 +19,33 @@ func containerPost(d *Daemon, r *http.Request) Response {
return SmartError(err)
}
- buf, err := ioutil.ReadAll(r.Body)
+ body, err := ioutil.ReadAll(r.Body)
if err != nil {
return InternalError(err)
}
- body := api.ContainerPost{}
- if err := json.Unmarshal(buf, &body); err != nil {
+ rdr1 := ioutil.NopCloser(bytes.NewBuffer(body))
+ rdr2 := ioutil.NopCloser(bytes.NewBuffer(body))
+
+ reqRaw := shared.Jmap{}
+ if err := json.NewDecoder(rdr1).Decode(&reqRaw); err != nil {
+ return BadRequest(err)
+ }
+
+ req := api.ContainerPost{}
+ if err := json.NewDecoder(rdr2).Decode(&req); err != nil {
return BadRequest(err)
}
- if body.Migration {
- ws, err := NewMigrationSource(c)
+ // Check if stateful (backward compatibility)
+ stateful := true
+ _, err = reqRaw.GetBool("live")
+ if err == nil {
+ stateful = req.Live
+ }
+
+ if req.Migration {
+ ws, err := NewMigrationSource(c, stateful)
if err != nil {
return InternalError(err)
}
@@ -45,13 +62,13 @@ func containerPost(d *Daemon, r *http.Request) Response {
}
// Check that the name isn't already in use
- id, _ := dbContainerId(d.db, body.Name)
+ id, _ := dbContainerId(d.db, req.Name)
if id > 0 {
return Conflict
}
run := func(*operation) error {
- return c.Rename(body.Name)
+ return c.Rename(req.Name)
}
resources := map[string][]string{}
diff --git a/lxd/container_snapshot.go b/lxd/container_snapshot.go
index 097b233..84dd133 100644
--- a/lxd/container_snapshot.go
+++ b/lxd/container_snapshot.go
@@ -204,7 +204,7 @@ func snapshotPost(d *Daemon, r *http.Request, sc container, containerName string
migration, err := raw.GetBool("migration")
if err == nil && migration {
- ws, err := NewMigrationSource(sc)
+ ws, err := NewMigrationSource(sc, false)
if err != nil {
return SmartError(err)
}
diff --git a/lxd/migrate.go b/lxd/migrate.go
index 93f3525..803a99b 100644
--- a/lxd/migrate.go
+++ b/lxd/migrate.go
@@ -152,7 +152,7 @@ type migrationSourceWs struct {
allConnected chan bool
}
-func NewMigrationSource(c container) (*migrationSourceWs, error) {
+func NewMigrationSource(c container, stateful bool) (*migrationSourceWs, error) {
ret := migrationSourceWs{migrationFields{container: c}, make(chan bool, 1)}
var err error
@@ -166,7 +166,7 @@ func NewMigrationSource(c container) (*migrationSourceWs, error) {
return nil, err
}
- if c.IsRunning() {
+ if stateful && c.IsRunning() {
_, err := exec.LookPath("criu")
if err != nil {
return nil, fmt.Errorf("Unable to perform container live migration. CRIU isn't installed on the source server.")
diff --git a/shared/api/container.go b/shared/api/container.go
index 33154bb..e198d59 100644
--- a/shared/api/container.go
+++ b/shared/api/container.go
@@ -14,8 +14,14 @@ type ContainersPost struct {
// ContainerPost represents the fields required to rename/move a LXD container
type ContainerPost struct {
- Migration bool `json:"migration" yaml:"migration"`
- Name string `json:"name" yaml:"name"`
+ // Used for renames
+ Name string `json:"name" yaml:"name"`
+
+ // Used for migration
+ Migration bool `json:"migration" yaml:"migration"`
+
+ // API extension: container_stateless_copy
+ Live bool `json:"live" yaml:"live"`
}
// ContainerPut represents the modifiable fields of a LXD container
More information about the lxc-devel
mailing list