[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