[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