[lxc-devel] [lxd/master] migration: stateless incremental containers

brauner on Github lxc-bot at linuxcontainers.org
Wed Sep 27 18:05:50 UTC 2017


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 532 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20170927/540815f6/attachment.bin>
-------------- next part --------------
From e9b04a39f689c1498a773f54c5f190c794b89c9c Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Wed, 27 Sep 2017 17:56:13 +0200
Subject: [PATCH 1/3] migration: stateless incremental containers

This adds a new criu migration type "NONE" which can be used to perform mock
live migration. Any step but actually calling criu will be performed.

Closes #3798.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/migrate.go    |  27 ++++++++++++--
 lxd/migrate.pb.go | 103 +++++++++++++++++++++++++++++++++++++++++++-----------
 lxd/migrate.proto |   1 +
 3 files changed, 108 insertions(+), 23 deletions(-)

diff --git a/lxd/migrate.go b/lxd/migrate.go
index 59fa03faa..555fb0714 100644
--- a/lxd/migrate.go
+++ b/lxd/migrate.go
@@ -360,6 +360,9 @@ func (s *migrationSourceWs) Do(migrateOp *operation) error {
 	criuType := CRIUType_CRIU_RSYNC.Enum()
 	if !s.live {
 		criuType = nil
+		if s.container.IsRunning() {
+			criuType = CRIUType_NONE.Enum()
+		}
 	}
 
 	// Storage needs to start unconditionally now, since we need to
@@ -470,6 +473,7 @@ func (s *migrationSourceWs) Do(migrateOp *operation) error {
 
 	restoreSuccess := make(chan bool, 1)
 	dumpSuccess := make(chan error, 1)
+
 	if s.live {
 		if header.Criu == nil {
 			return abort(fmt.Errorf("Got no CRIU socket type for live migration"))
@@ -589,7 +593,9 @@ func (s *migrationSourceWs) Do(migrateOp *operation) error {
 		if err != nil {
 			return abort(err)
 		}
+	}
 
+	if s.live || (header.Criu != nil && *header.Criu == CRIUType_NONE) {
 		err = driver.SendAfterCheckpoint(s.fsConn, bwlimit)
 		if err != nil {
 			return abort(err)
@@ -827,8 +833,12 @@ func (c *migrationSink) Do(migrateOp *operation) error {
 	}
 
 	criuType := CRIUType_CRIU_RSYNC.Enum()
-	if !live {
-		criuType = nil
+	if header.Criu != nil && *header.Criu == CRIUType_NONE {
+		criuType = CRIUType_NONE.Enum()
+	} else {
+		if !live {
+			criuType = nil
+		}
 	}
 
 	mySink := c.src.container.Storage().MigrationSink
@@ -898,7 +908,18 @@ func (c *migrationSink) Do(migrateOp *operation) error {
 				fsConn = c.src.fsConn
 			}
 
-			err = mySink(live, c.src.container, snapshots, fsConn, srcIdmap, migrateOp, c.src.containerOnly)
+			sendFinalFsDelta := false
+			if live {
+				sendFinalFsDelta = true
+			}
+
+			if criuType != nil && *criuType == CRIUType_NONE {
+				sendFinalFsDelta = true
+			}
+
+			err = mySink(sendFinalFsDelta, c.src.container,
+				snapshots, fsConn, srcIdmap, migrateOp,
+				c.src.containerOnly)
 			if err != nil {
 				fsTransfer <- err
 				return
diff --git a/lxd/migrate.pb.go b/lxd/migrate.pb.go
index 69dafcb77..93dce20cf 100644
--- a/lxd/migrate.pb.go
+++ b/lxd/migrate.pb.go
@@ -1,6 +1,5 @@
-// Code generated by protoc-gen-go.
+// Code generated by protoc-gen-go. DO NOT EDIT.
 // source: lxd/migrate.proto
-// DO NOT EDIT!
 
 /*
 Package main is a generated protocol buffer package.
@@ -19,12 +18,20 @@ It has these top-level messages:
 package main
 
 import proto "github.com/golang/protobuf/proto"
+import fmt "fmt"
 import math "math"
 
 // Reference imports to suppress errors if they are not otherwise used.
 var _ = proto.Marshal
+var _ = fmt.Errorf
 var _ = math.Inf
 
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
+
 type MigrationFSType int32
 
 const (
@@ -63,21 +70,25 @@ func (x *MigrationFSType) UnmarshalJSON(data []byte) error {
 	*x = MigrationFSType(value)
 	return nil
 }
+func (MigrationFSType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
 
 type CRIUType int32
 
 const (
 	CRIUType_CRIU_RSYNC CRIUType = 0
 	CRIUType_PHAUL      CRIUType = 1
+	CRIUType_NONE       CRIUType = 2
 )
 
 var CRIUType_name = map[int32]string{
 	0: "CRIU_RSYNC",
 	1: "PHAUL",
+	2: "NONE",
 }
 var CRIUType_value = map[string]int32{
 	"CRIU_RSYNC": 0,
 	"PHAUL":      1,
+	"NONE":       2,
 }
 
 func (x CRIUType) Enum() *CRIUType {
@@ -96,6 +107,7 @@ func (x *CRIUType) UnmarshalJSON(data []byte) error {
 	*x = CRIUType(value)
 	return nil
 }
+func (CRIUType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
 
 type IDMapType struct {
 	Isuid            *bool  `protobuf:"varint,1,req,name=isuid" json:"isuid,omitempty"`
@@ -106,9 +118,10 @@ type IDMapType struct {
 	XXX_unrecognized []byte `json:"-"`
 }
 
-func (m *IDMapType) Reset()         { *m = IDMapType{} }
-func (m *IDMapType) String() string { return proto.CompactTextString(m) }
-func (*IDMapType) ProtoMessage()    {}
+func (m *IDMapType) Reset()                    { *m = IDMapType{} }
+func (m *IDMapType) String() string            { return proto.CompactTextString(m) }
+func (*IDMapType) ProtoMessage()               {}
+func (*IDMapType) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
 
 func (m *IDMapType) GetIsuid() bool {
 	if m != nil && m.Isuid != nil {
@@ -151,9 +164,10 @@ type Config struct {
 	XXX_unrecognized []byte  `json:"-"`
 }
 
-func (m *Config) Reset()         { *m = Config{} }
-func (m *Config) String() string { return proto.CompactTextString(m) }
-func (*Config) ProtoMessage()    {}
+func (m *Config) Reset()                    { *m = Config{} }
+func (m *Config) String() string            { return proto.CompactTextString(m) }
+func (*Config) ProtoMessage()               {}
+func (*Config) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
 
 func (m *Config) GetKey() string {
 	if m != nil && m.Key != nil {
@@ -175,9 +189,10 @@ type Device struct {
 	XXX_unrecognized []byte    `json:"-"`
 }
 
-func (m *Device) Reset()         { *m = Device{} }
-func (m *Device) String() string { return proto.CompactTextString(m) }
-func (*Device) ProtoMessage()    {}
+func (m *Device) Reset()                    { *m = Device{} }
+func (m *Device) String() string            { return proto.CompactTextString(m) }
+func (*Device) ProtoMessage()               {}
+func (*Device) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
 
 func (m *Device) GetName() string {
 	if m != nil && m.Name != nil {
@@ -204,9 +219,10 @@ type Snapshot struct {
 	XXX_unrecognized []byte    `json:"-"`
 }
 
-func (m *Snapshot) Reset()         { *m = Snapshot{} }
-func (m *Snapshot) String() string { return proto.CompactTextString(m) }
-func (*Snapshot) ProtoMessage()    {}
+func (m *Snapshot) Reset()                    { *m = Snapshot{} }
+func (m *Snapshot) String() string            { return proto.CompactTextString(m) }
+func (*Snapshot) ProtoMessage()               {}
+func (*Snapshot) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
 
 func (m *Snapshot) GetName() string {
 	if m != nil && m.Name != nil {
@@ -266,9 +282,10 @@ type MigrationHeader struct {
 	XXX_unrecognized []byte           `json:"-"`
 }
 
-func (m *MigrationHeader) Reset()         { *m = MigrationHeader{} }
-func (m *MigrationHeader) String() string { return proto.CompactTextString(m) }
-func (*MigrationHeader) ProtoMessage()    {}
+func (m *MigrationHeader) Reset()                    { *m = MigrationHeader{} }
+func (m *MigrationHeader) String() string            { return proto.CompactTextString(m) }
+func (*MigrationHeader) ProtoMessage()               {}
+func (*MigrationHeader) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
 
 func (m *MigrationHeader) GetFs() MigrationFSType {
 	if m != nil && m.Fs != nil {
@@ -312,9 +329,10 @@ type MigrationControl struct {
 	XXX_unrecognized []byte  `json:"-"`
 }
 
-func (m *MigrationControl) Reset()         { *m = MigrationControl{} }
-func (m *MigrationControl) String() string { return proto.CompactTextString(m) }
-func (*MigrationControl) ProtoMessage()    {}
+func (m *MigrationControl) Reset()                    { *m = MigrationControl{} }
+func (m *MigrationControl) String() string            { return proto.CompactTextString(m) }
+func (*MigrationControl) ProtoMessage()               {}
+func (*MigrationControl) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
 
 func (m *MigrationControl) GetSuccess() bool {
 	if m != nil && m.Success != nil {
@@ -331,6 +349,51 @@ func (m *MigrationControl) GetMessage() string {
 }
 
 func init() {
+	proto.RegisterType((*IDMapType)(nil), "main.IDMapType")
+	proto.RegisterType((*Config)(nil), "main.Config")
+	proto.RegisterType((*Device)(nil), "main.Device")
+	proto.RegisterType((*Snapshot)(nil), "main.Snapshot")
+	proto.RegisterType((*MigrationHeader)(nil), "main.MigrationHeader")
+	proto.RegisterType((*MigrationControl)(nil), "main.MigrationControl")
 	proto.RegisterEnum("main.MigrationFSType", MigrationFSType_name, MigrationFSType_value)
 	proto.RegisterEnum("main.CRIUType", CRIUType_name, CRIUType_value)
 }
+
+func init() { proto.RegisterFile("lxd/migrate.proto", fileDescriptor0) }
+
+var fileDescriptor0 = []byte{
+	// 523 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x52, 0x4d, 0x6f, 0xd3, 0x40,
+	0x10, 0xc5, 0x5f, 0xa9, 0x3d, 0x09, 0xa9, 0x59, 0x01, 0x5a, 0x21, 0x0e, 0x91, 0xd5, 0x4a, 0x51,
+	0x85, 0xd2, 0x2a, 0x37, 0x8e, 0x24, 0x21, 0x6a, 0x25, 0x1a, 0xd0, 0xa6, 0x3d, 0xc0, 0x05, 0xad,
+	0xec, 0x89, 0xb3, 0xc2, 0x5f, 0xf2, 0xda, 0x15, 0x3d, 0xf1, 0x33, 0xf9, 0x2f, 0x9c, 0xd0, 0xae,
+	0x3f, 0x9a, 0x48, 0x70, 0x9b, 0xf7, 0xe6, 0x79, 0x9e, 0xe7, 0xed, 0xc0, 0x8b, 0xe4, 0x67, 0x74,
+	0x99, 0x8a, 0xb8, 0xe4, 0x15, 0xce, 0x8a, 0x32, 0xaf, 0x72, 0x62, 0xa7, 0x5c, 0x64, 0xc1, 0x2f,
+	0xf0, 0x6e, 0x56, 0xb7, 0xbc, 0xb8, 0x7b, 0x2c, 0x90, 0xbc, 0x04, 0x47, 0xc8, 0x5a, 0x44, 0xd4,
+	0x98, 0x98, 0x53, 0x97, 0x35, 0xa0, 0x61, 0x63, 0x11, 0x51, 0xb3, 0x63, 0x63, 0x11, 0x91, 0xd7,
+	0x30, 0xd8, 0xe7, 0xb2, 0x12, 0x11, 0xb5, 0x26, 0xe6, 0xd4, 0x61, 0x2d, 0x22, 0x04, 0xec, 0x4c,
+	0x8a, 0x88, 0xda, 0x9a, 0xd5, 0x35, 0x79, 0x03, 0x6e, 0xca, 0x8b, 0x92, 0x67, 0x31, 0x52, 0x47,
+	0xf3, 0x3d, 0x0e, 0xae, 0x60, 0xb0, 0xcc, 0xb3, 0x9d, 0x88, 0x89, 0x0f, 0xd6, 0x0f, 0x7c, 0xd4,
+	0xde, 0x1e, 0x53, 0xa5, 0x72, 0x7e, 0xe0, 0x49, 0x8d, 0xda, 0xd9, 0x63, 0x0d, 0x08, 0x16, 0x30,
+	0x58, 0xe1, 0x83, 0x08, 0x51, 0x7b, 0xf1, 0x14, 0xdb, 0x4f, 0x74, 0x4d, 0xce, 0x60, 0x10, 0xea,
+	0x79, 0xd4, 0x9c, 0x58, 0xd3, 0xe1, 0x7c, 0x34, 0x53, 0x7b, 0xce, 0x1a, 0x0f, 0xd6, 0xf6, 0x82,
+	0x3f, 0x06, 0xb8, 0xdb, 0x8c, 0x17, 0x72, 0x9f, 0x57, 0xff, 0x1c, 0x33, 0x83, 0x61, 0x92, 0x87,
+	0x3c, 0x59, 0xfe, 0x7f, 0xd6, 0xa1, 0x40, 0xad, 0x58, 0x94, 0xf9, 0x4e, 0x24, 0x28, 0xa9, 0x35,
+	0xb1, 0xa6, 0x1e, 0xeb, 0x31, 0x79, 0x0b, 0x1e, 0x16, 0x7b, 0x4c, 0xb1, 0xe4, 0x89, 0xce, 0xc5,
+	0x65, 0x4f, 0x04, 0xb9, 0x82, 0x91, 0x1e, 0xd4, 0xec, 0x24, 0xa9, 0x73, 0x68, 0xd5, 0x90, 0xec,
+	0x48, 0x41, 0x02, 0x18, 0xf1, 0x32, 0xdc, 0x8b, 0x0a, 0xc3, 0xaa, 0x2e, 0x91, 0x0e, 0x74, 0xa4,
+	0x47, 0x9c, 0xfa, 0x1f, 0x59, 0xf1, 0x0a, 0x77, 0x75, 0x42, 0x4f, 0xb4, 0x65, 0x8f, 0x83, 0xdf,
+	0x06, 0x9c, 0xde, 0xea, 0x5b, 0x10, 0x79, 0x76, 0x8d, 0x3c, 0xc2, 0x92, 0x9c, 0x83, 0xb9, 0x93,
+	0x3a, 0x81, 0xf1, 0xfc, 0x55, 0xe3, 0xdd, 0x4b, 0xd6, 0x5b, 0x75, 0x1d, 0xcc, 0xdc, 0x29, 0x6b,
+	0x3b, 0x2c, 0x45, 0x4d, 0xcd, 0x89, 0x31, 0x1d, 0xcf, 0xc7, 0x6d, 0x1e, 0xec, 0xe6, 0x5e, 0x2b,
+	0x74, 0x8f, 0x9c, 0x83, 0x23, 0xa2, 0x94, 0x17, 0x3a, 0x87, 0xe1, 0xfc, 0xb4, 0x11, 0xf5, 0x57,
+	0xc6, 0x9a, 0x2e, 0x39, 0x83, 0xe7, 0xb2, 0x7d, 0x81, 0x0d, 0x4f, 0x51, 0x52, 0x5b, 0xc7, 0x76,
+	0x4c, 0x92, 0x77, 0xe0, 0x75, 0x44, 0x17, 0x4d, 0xeb, 0xda, 0x3d, 0x1f, 0x7b, 0x12, 0x04, 0x6b,
+	0xf0, 0xfb, 0xbf, 0x5e, 0xe6, 0x59, 0x55, 0xe6, 0x09, 0xa1, 0x70, 0x22, 0xeb, 0x30, 0x44, 0x29,
+	0xdb, 0xb3, 0xee, 0xa0, 0xea, 0xa4, 0x28, 0x25, 0x8f, 0x51, 0xef, 0xe3, 0xb1, 0x0e, 0x5e, 0xbc,
+	0x3f, 0x08, 0xa8, 0xd9, 0x9e, 0x78, 0xe0, 0xb0, 0xed, 0xd7, 0xcd, 0xd2, 0x7f, 0xa6, 0xca, 0xc5,
+	0x1d, 0x5b, 0x6f, 0x7d, 0x83, 0x9c, 0x80, 0xf5, 0x6d, 0xbd, 0xf5, 0x4d, 0x55, 0xb0, 0xc5, 0xca,
+	0xb7, 0x2e, 0x2e, 0xc1, 0xed, 0xf2, 0x20, 0x63, 0x00, 0x55, 0x7f, 0x3f, 0xf8, 0xf0, 0xcb, 0xf5,
+	0x87, 0xfb, 0x4f, 0xbe, 0x41, 0x5c, 0xb0, 0x37, 0x9f, 0x37, 0x1f, 0x7d, 0xf3, 0x6f, 0x00, 0x00,
+	0x00, 0xff, 0xff, 0xe4, 0xf2, 0xc3, 0xd0, 0x9b, 0x03, 0x00, 0x00,
+}
diff --git a/lxd/migrate.proto b/lxd/migrate.proto
index 6cdee4eff..172a940be 100644
--- a/lxd/migrate.proto
+++ b/lxd/migrate.proto
@@ -10,6 +10,7 @@ enum MigrationFSType {
 enum CRIUType {
 	CRIU_RSYNC	= 0;
 	PHAUL		= 1;
+	NONE		= 2;
 }
 
 message IDMapType {

From 51de6151d7286583309bd67f9a4e125c4f43ed19 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Wed, 27 Sep 2017 20:04:47 +0200
Subject: [PATCH 2/3] tests: add stateless live migration tests

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 test/suites/migration.sh | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/test/suites/migration.sh b/test/suites/migration.sh
index 057346c75..16b1d0bbd 100644
--- a/test/suites/migration.sh
+++ b/test/suites/migration.sh
@@ -122,6 +122,23 @@ migration() {
   lxc_remote list l1: | grep RUNNING | grep nonlive2
   lxc_remote delete l1:nonlive2 l2:nonlive2 --force
 
+  lxc_remote launch testimage cccp
+  lxc_remote copy l1:cccp l2:udssr --stateless
+  lxc_remote delete l2:udssr --force
+  lxc_remote copy l1:cccp l2:udssr --stateless --mode=push
+  lxc_remote delete l2:udssr --force
+  lxc_remote copy l1:cccp l2:udssr --stateless --mode=relay
+  lxc_remote delete l2:udssr --force
+
+  lxc_remote move l1:cccp l2:udssr --stateless
+  lxc_remote delete l2:udssr --force
+  lxc_remote launch testimage cccp
+  lxc_remote move l1:cccp l2:udssr --stateless --mode=push
+  lxc_remote delete l2:udssr --force
+  lxc_remote launch testimage cccp
+  lxc_remote move l1:cccp l2:udssr --stateless --mode=relay
+  lxc_remote delete l2:udssr --force
+
   lxc_remote start l2:nonlive
   lxc_remote list l2: | grep RUNNING | grep nonlive
   lxc_remote delete l2:nonlive --force

From 7fd48765a83f5a82561b3cb0f4043ca73df1f60d Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Wed, 27 Sep 2017 19:33:08 +0200
Subject: [PATCH 3/3] migration: fix lvm stateful restores

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/container_lxc.go |  1 +
 lxd/storage_lvm.go   | 15 ++++++++++++---
 2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index a7fa9ba99..a21ef563a 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -2766,6 +2766,7 @@ func (c *containerLXC) Restore(sourceContainer container, stateful bool) error {
 	// If the container wasn't running but was stateful, should we restore
 	// it as running?
 	if stateful == true {
+		logger.Errorf("0000: %s", c.StatePath())
 		if !shared.PathExists(c.StatePath()) {
 			return fmt.Errorf("Stateful snapshot restore requested by snapshot is stateless")
 		}
diff --git a/lxd/storage_lvm.go b/lxd/storage_lvm.go
index ece80e331..59514baf8 100644
--- a/lxd/storage_lvm.go
+++ b/lxd/storage_lvm.go
@@ -1293,15 +1293,24 @@ func (s *storageLvm) ContainerRestore(target container, source container) error
 		}
 
 		poolName := s.getOnDiskPoolName()
-		err = s.removeLV(poolName, storagePoolVolumeAPIEndpointContainers, targetLvmName)
+		err = s.removeLV(poolName,
+			storagePoolVolumeAPIEndpointContainers, targetLvmName)
 		if err != nil {
-			logger.Errorf(fmt.Sprintf("Failed to remove \"%s\": %s.", targetLvmName, err))
+			logger.Errorf("Failed to remove \"%s\": %s",
+				targetLvmName, err)
 		}
 
-		_, err = s.createSnapshotLV(poolName, sourceLvmName, storagePoolVolumeAPIEndpointContainers, targetLvmName, storagePoolVolumeAPIEndpointContainers, false, true)
+		_, err = s.createSnapshotLV(poolName, sourceLvmName,
+			storagePoolVolumeAPIEndpointContainers, targetLvmName,
+			storagePoolVolumeAPIEndpointContainers, false, true)
 		if err != nil {
 			return fmt.Errorf("Error creating snapshot LV: %v", err)
 		}
+
+		_, err = target.Storage().ContainerMount(target)
+		if err != nil {
+			return err
+		}
 	} else {
 		ourMount, err := target.Storage().ContainerMount(target)
 		if err != nil {


More information about the lxc-devel mailing list