[lxc-devel] [lxd/master] VM: Migration

tomponline on Github lxc-bot at linuxcontainers.org
Tue Mar 10 16:47:06 UTC 2020


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 454 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200310/1f8f5fd0/attachment-0001.bin>
-------------- next part --------------
From 1b02a8ab5f5000db19195c2b4ae248718a07a796 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 10 Mar 2020 10:01:18 +0000
Subject: [PATCH 01/12] lxd/migraration: Adds BLOCK_AND_RSYNC migration
 transport type

Will be used for migrating VMs as they have both config volumes (that will use RSYNC) and block volumes.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/migration/migrate.pb.go | 710 ++++++++++++++++++++++++------------
 lxd/migration/migrate.proto |   1 +
 2 files changed, 487 insertions(+), 224 deletions(-)

diff --git a/lxd/migration/migrate.pb.go b/lxd/migration/migrate.pb.go
index c7e83a97d6..379acefa4f 100644
--- a/lxd/migration/migrate.pb.go
+++ b/lxd/migration/migrate.pb.go
@@ -1,31 +1,13 @@
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // source: lxd/migration/migrate.proto
 
-/*
-Package migration is a generated protocol buffer package.
-
-It is generated from these files:
-	lxd/migration/migrate.proto
-
-It has these top-level messages:
-	IDMapType
-	Config
-	Device
-	Snapshot
-	RsyncFeatures
-	ZfsFeatures
-	MigrationHeader
-	MigrationControl
-	MigrationSync
-	DumpStatsEntry
-	RestoreStatsEntry
-	StatsEntry
-*/
 package migration
 
-import proto "github.com/golang/protobuf/proto"
-import fmt "fmt"
-import math "math"
+import (
+	fmt "fmt"
+	proto "github.com/golang/protobuf/proto"
+	math "math"
+)
 
 // Reference imports to suppress errors if they are not otherwise used.
 var _ = proto.Marshal
@@ -36,15 +18,16 @@ var _ = math.Inf
 // 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
+const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
 
 type MigrationFSType int32
 
 const (
-	MigrationFSType_RSYNC MigrationFSType = 0
-	MigrationFSType_BTRFS MigrationFSType = 1
-	MigrationFSType_ZFS   MigrationFSType = 2
-	MigrationFSType_RBD   MigrationFSType = 3
+	MigrationFSType_RSYNC           MigrationFSType = 0
+	MigrationFSType_BTRFS           MigrationFSType = 1
+	MigrationFSType_ZFS             MigrationFSType = 2
+	MigrationFSType_RBD             MigrationFSType = 3
+	MigrationFSType_BLOCK_AND_RSYNC MigrationFSType = 4
 )
 
 var MigrationFSType_name = map[int32]string{
@@ -52,12 +35,15 @@ var MigrationFSType_name = map[int32]string{
 	1: "BTRFS",
 	2: "ZFS",
 	3: "RBD",
+	4: "BLOCK_AND_RSYNC",
 }
+
 var MigrationFSType_value = map[string]int32{
-	"RSYNC": 0,
-	"BTRFS": 1,
-	"ZFS":   2,
-	"RBD":   3,
+	"RSYNC":           0,
+	"BTRFS":           1,
+	"ZFS":             2,
+	"RBD":             3,
+	"BLOCK_AND_RSYNC": 4,
 }
 
 func (x MigrationFSType) Enum() *MigrationFSType {
@@ -65,9 +51,11 @@ func (x MigrationFSType) Enum() *MigrationFSType {
 	*p = x
 	return p
 }
+
 func (x MigrationFSType) String() string {
 	return proto.EnumName(MigrationFSType_name, int32(x))
 }
+
 func (x *MigrationFSType) UnmarshalJSON(data []byte) error {
 	value, err := proto.UnmarshalJSONEnum(MigrationFSType_value, data, "MigrationFSType")
 	if err != nil {
@@ -76,7 +64,10 @@ func (x *MigrationFSType) UnmarshalJSON(data []byte) error {
 	*x = MigrationFSType(value)
 	return nil
 }
-func (MigrationFSType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
+
+func (MigrationFSType) EnumDescriptor() ([]byte, []int) {
+	return fileDescriptor_fe8772548dc4b615, []int{0}
+}
 
 type CRIUType int32
 
@@ -91,6 +82,7 @@ var CRIUType_name = map[int32]string{
 	1: "PHAUL",
 	2: "NONE",
 }
+
 var CRIUType_value = map[string]int32{
 	"CRIU_RSYNC": 0,
 	"PHAUL":      1,
@@ -102,9 +94,11 @@ func (x CRIUType) Enum() *CRIUType {
 	*p = x
 	return p
 }
+
 func (x CRIUType) String() string {
 	return proto.EnumName(CRIUType_name, int32(x))
 }
+
 func (x *CRIUType) UnmarshalJSON(data []byte) error {
 	value, err := proto.UnmarshalJSONEnum(CRIUType_value, data, "CRIUType")
 	if err != nil {
@@ -113,21 +107,46 @@ func (x *CRIUType) UnmarshalJSON(data []byte) error {
 	*x = CRIUType(value)
 	return nil
 }
-func (CRIUType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
+
+func (CRIUType) EnumDescriptor() ([]byte, []int) {
+	return fileDescriptor_fe8772548dc4b615, []int{1}
+}
 
 type IDMapType struct {
-	Isuid            *bool  `protobuf:"varint,1,req,name=isuid" json:"isuid,omitempty"`
-	Isgid            *bool  `protobuf:"varint,2,req,name=isgid" json:"isgid,omitempty"`
-	Hostid           *int32 `protobuf:"varint,3,req,name=hostid" json:"hostid,omitempty"`
-	Nsid             *int32 `protobuf:"varint,4,req,name=nsid" json:"nsid,omitempty"`
-	Maprange         *int32 `protobuf:"varint,5,req,name=maprange" json:"maprange,omitempty"`
-	XXX_unrecognized []byte `json:"-"`
+	Isuid                *bool    `protobuf:"varint,1,req,name=isuid" json:"isuid,omitempty"`
+	Isgid                *bool    `protobuf:"varint,2,req,name=isgid" json:"isgid,omitempty"`
+	Hostid               *int32   `protobuf:"varint,3,req,name=hostid" json:"hostid,omitempty"`
+	Nsid                 *int32   `protobuf:"varint,4,req,name=nsid" json:"nsid,omitempty"`
+	Maprange             *int32   `protobuf:"varint,5,req,name=maprange" json:"maprange,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *IDMapType) Reset()         { *m = IDMapType{} }
+func (m *IDMapType) String() string { return proto.CompactTextString(m) }
+func (*IDMapType) ProtoMessage()    {}
+func (*IDMapType) Descriptor() ([]byte, []int) {
+	return fileDescriptor_fe8772548dc4b615, []int{0}
+}
+
+func (m *IDMapType) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_IDMapType.Unmarshal(m, b)
+}
+func (m *IDMapType) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_IDMapType.Marshal(b, m, deterministic)
+}
+func (m *IDMapType) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_IDMapType.Merge(m, src)
+}
+func (m *IDMapType) XXX_Size() int {
+	return xxx_messageInfo_IDMapType.Size(m)
+}
+func (m *IDMapType) XXX_DiscardUnknown() {
+	xxx_messageInfo_IDMapType.DiscardUnknown(m)
 }
 
-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} }
+var xxx_messageInfo_IDMapType proto.InternalMessageInfo
 
 func (m *IDMapType) GetIsuid() bool {
 	if m != nil && m.Isuid != nil {
@@ -165,15 +184,37 @@ func (m *IDMapType) GetMaprange() int32 {
 }
 
 type Config struct {
-	Key              *string `protobuf:"bytes,1,req,name=key" json:"key,omitempty"`
-	Value            *string `protobuf:"bytes,2,req,name=value" json:"value,omitempty"`
-	XXX_unrecognized []byte  `json:"-"`
+	Key                  *string  `protobuf:"bytes,1,req,name=key" json:"key,omitempty"`
+	Value                *string  `protobuf:"bytes,2,req,name=value" json:"value,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
 }
 
-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) Reset()         { *m = Config{} }
+func (m *Config) String() string { return proto.CompactTextString(m) }
+func (*Config) ProtoMessage()    {}
+func (*Config) Descriptor() ([]byte, []int) {
+	return fileDescriptor_fe8772548dc4b615, []int{1}
+}
+
+func (m *Config) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_Config.Unmarshal(m, b)
+}
+func (m *Config) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_Config.Marshal(b, m, deterministic)
+}
+func (m *Config) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Config.Merge(m, src)
+}
+func (m *Config) XXX_Size() int {
+	return xxx_messageInfo_Config.Size(m)
+}
+func (m *Config) XXX_DiscardUnknown() {
+	xxx_messageInfo_Config.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Config proto.InternalMessageInfo
 
 func (m *Config) GetKey() string {
 	if m != nil && m.Key != nil {
@@ -190,15 +231,37 @@ func (m *Config) GetValue() string {
 }
 
 type Device struct {
-	Name             *string   `protobuf:"bytes,1,req,name=name" json:"name,omitempty"`
-	Config           []*Config `protobuf:"bytes,2,rep,name=config" json:"config,omitempty"`
-	XXX_unrecognized []byte    `json:"-"`
+	Name                 *string   `protobuf:"bytes,1,req,name=name" json:"name,omitempty"`
+	Config               []*Config `protobuf:"bytes,2,rep,name=config" json:"config,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}  `json:"-"`
+	XXX_unrecognized     []byte    `json:"-"`
+	XXX_sizecache        int32     `json:"-"`
 }
 
-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) Reset()         { *m = Device{} }
+func (m *Device) String() string { return proto.CompactTextString(m) }
+func (*Device) ProtoMessage()    {}
+func (*Device) Descriptor() ([]byte, []int) {
+	return fileDescriptor_fe8772548dc4b615, []int{2}
+}
+
+func (m *Device) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_Device.Unmarshal(m, b)
+}
+func (m *Device) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_Device.Marshal(b, m, deterministic)
+}
+func (m *Device) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Device.Merge(m, src)
+}
+func (m *Device) XXX_Size() int {
+	return xxx_messageInfo_Device.Size(m)
+}
+func (m *Device) XXX_DiscardUnknown() {
+	xxx_messageInfo_Device.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Device proto.InternalMessageInfo
 
 func (m *Device) GetName() string {
 	if m != nil && m.Name != nil {
@@ -215,22 +278,44 @@ func (m *Device) GetConfig() []*Config {
 }
 
 type Snapshot struct {
-	Name             *string   `protobuf:"bytes,1,req,name=name" json:"name,omitempty"`
-	LocalConfig      []*Config `protobuf:"bytes,2,rep,name=localConfig" json:"localConfig,omitempty"`
-	Profiles         []string  `protobuf:"bytes,3,rep,name=profiles" json:"profiles,omitempty"`
-	Ephemeral        *bool     `protobuf:"varint,4,req,name=ephemeral" json:"ephemeral,omitempty"`
-	LocalDevices     []*Device `protobuf:"bytes,5,rep,name=localDevices" json:"localDevices,omitempty"`
-	Architecture     *int32    `protobuf:"varint,6,req,name=architecture" json:"architecture,omitempty"`
-	Stateful         *bool     `protobuf:"varint,7,req,name=stateful" json:"stateful,omitempty"`
-	CreationDate     *int64    `protobuf:"varint,8,opt,name=creation_date,json=creationDate" json:"creation_date,omitempty"`
-	LastUsedDate     *int64    `protobuf:"varint,9,opt,name=last_used_date,json=lastUsedDate" json:"last_used_date,omitempty"`
-	XXX_unrecognized []byte    `json:"-"`
-}
-
-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} }
+	Name                 *string   `protobuf:"bytes,1,req,name=name" json:"name,omitempty"`
+	LocalConfig          []*Config `protobuf:"bytes,2,rep,name=localConfig" json:"localConfig,omitempty"`
+	Profiles             []string  `protobuf:"bytes,3,rep,name=profiles" json:"profiles,omitempty"`
+	Ephemeral            *bool     `protobuf:"varint,4,req,name=ephemeral" json:"ephemeral,omitempty"`
+	LocalDevices         []*Device `protobuf:"bytes,5,rep,name=localDevices" json:"localDevices,omitempty"`
+	Architecture         *int32    `protobuf:"varint,6,req,name=architecture" json:"architecture,omitempty"`
+	Stateful             *bool     `protobuf:"varint,7,req,name=stateful" json:"stateful,omitempty"`
+	CreationDate         *int64    `protobuf:"varint,8,opt,name=creation_date,json=creationDate" json:"creation_date,omitempty"`
+	LastUsedDate         *int64    `protobuf:"varint,9,opt,name=last_used_date,json=lastUsedDate" json:"last_used_date,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}  `json:"-"`
+	XXX_unrecognized     []byte    `json:"-"`
+	XXX_sizecache        int32     `json:"-"`
+}
+
+func (m *Snapshot) Reset()         { *m = Snapshot{} }
+func (m *Snapshot) String() string { return proto.CompactTextString(m) }
+func (*Snapshot) ProtoMessage()    {}
+func (*Snapshot) Descriptor() ([]byte, []int) {
+	return fileDescriptor_fe8772548dc4b615, []int{3}
+}
+
+func (m *Snapshot) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_Snapshot.Unmarshal(m, b)
+}
+func (m *Snapshot) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_Snapshot.Marshal(b, m, deterministic)
+}
+func (m *Snapshot) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Snapshot.Merge(m, src)
+}
+func (m *Snapshot) XXX_Size() int {
+	return xxx_messageInfo_Snapshot.Size(m)
+}
+func (m *Snapshot) XXX_DiscardUnknown() {
+	xxx_messageInfo_Snapshot.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Snapshot proto.InternalMessageInfo
 
 func (m *Snapshot) GetName() string {
 	if m != nil && m.Name != nil {
@@ -296,17 +381,39 @@ func (m *Snapshot) GetLastUsedDate() int64 {
 }
 
 type RsyncFeatures struct {
-	Xattrs           *bool  `protobuf:"varint,1,opt,name=xattrs" json:"xattrs,omitempty"`
-	Delete           *bool  `protobuf:"varint,2,opt,name=delete" json:"delete,omitempty"`
-	Compress         *bool  `protobuf:"varint,3,opt,name=compress" json:"compress,omitempty"`
-	Bidirectional    *bool  `protobuf:"varint,4,opt,name=bidirectional" json:"bidirectional,omitempty"`
-	XXX_unrecognized []byte `json:"-"`
+	Xattrs               *bool    `protobuf:"varint,1,opt,name=xattrs" json:"xattrs,omitempty"`
+	Delete               *bool    `protobuf:"varint,2,opt,name=delete" json:"delete,omitempty"`
+	Compress             *bool    `protobuf:"varint,3,opt,name=compress" json:"compress,omitempty"`
+	Bidirectional        *bool    `protobuf:"varint,4,opt,name=bidirectional" json:"bidirectional,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
 }
 
-func (m *RsyncFeatures) Reset()                    { *m = RsyncFeatures{} }
-func (m *RsyncFeatures) String() string            { return proto.CompactTextString(m) }
-func (*RsyncFeatures) ProtoMessage()               {}
-func (*RsyncFeatures) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
+func (m *RsyncFeatures) Reset()         { *m = RsyncFeatures{} }
+func (m *RsyncFeatures) String() string { return proto.CompactTextString(m) }
+func (*RsyncFeatures) ProtoMessage()    {}
+func (*RsyncFeatures) Descriptor() ([]byte, []int) {
+	return fileDescriptor_fe8772548dc4b615, []int{4}
+}
+
+func (m *RsyncFeatures) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_RsyncFeatures.Unmarshal(m, b)
+}
+func (m *RsyncFeatures) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_RsyncFeatures.Marshal(b, m, deterministic)
+}
+func (m *RsyncFeatures) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_RsyncFeatures.Merge(m, src)
+}
+func (m *RsyncFeatures) XXX_Size() int {
+	return xxx_messageInfo_RsyncFeatures.Size(m)
+}
+func (m *RsyncFeatures) XXX_DiscardUnknown() {
+	xxx_messageInfo_RsyncFeatures.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_RsyncFeatures proto.InternalMessageInfo
 
 func (m *RsyncFeatures) GetXattrs() bool {
 	if m != nil && m.Xattrs != nil {
@@ -337,14 +444,36 @@ func (m *RsyncFeatures) GetBidirectional() bool {
 }
 
 type ZfsFeatures struct {
-	Compress         *bool  `protobuf:"varint,1,opt,name=compress" json:"compress,omitempty"`
-	XXX_unrecognized []byte `json:"-"`
+	Compress             *bool    `protobuf:"varint,1,opt,name=compress" json:"compress,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
 }
 
-func (m *ZfsFeatures) Reset()                    { *m = ZfsFeatures{} }
-func (m *ZfsFeatures) String() string            { return proto.CompactTextString(m) }
-func (*ZfsFeatures) ProtoMessage()               {}
-func (*ZfsFeatures) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
+func (m *ZfsFeatures) Reset()         { *m = ZfsFeatures{} }
+func (m *ZfsFeatures) String() string { return proto.CompactTextString(m) }
+func (*ZfsFeatures) ProtoMessage()    {}
+func (*ZfsFeatures) Descriptor() ([]byte, []int) {
+	return fileDescriptor_fe8772548dc4b615, []int{5}
+}
+
+func (m *ZfsFeatures) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_ZfsFeatures.Unmarshal(m, b)
+}
+func (m *ZfsFeatures) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_ZfsFeatures.Marshal(b, m, deterministic)
+}
+func (m *ZfsFeatures) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_ZfsFeatures.Merge(m, src)
+}
+func (m *ZfsFeatures) XXX_Size() int {
+	return xxx_messageInfo_ZfsFeatures.Size(m)
+}
+func (m *ZfsFeatures) XXX_DiscardUnknown() {
+	xxx_messageInfo_ZfsFeatures.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_ZfsFeatures proto.InternalMessageInfo
 
 func (m *ZfsFeatures) GetCompress() bool {
 	if m != nil && m.Compress != nil {
@@ -354,22 +483,44 @@ func (m *ZfsFeatures) GetCompress() bool {
 }
 
 type MigrationHeader struct {
-	Fs               *MigrationFSType `protobuf:"varint,1,req,name=fs,enum=migration.MigrationFSType" json:"fs,omitempty"`
-	Criu             *CRIUType        `protobuf:"varint,2,opt,name=criu,enum=migration.CRIUType" json:"criu,omitempty"`
-	Idmap            []*IDMapType     `protobuf:"bytes,3,rep,name=idmap" json:"idmap,omitempty"`
-	SnapshotNames    []string         `protobuf:"bytes,4,rep,name=snapshotNames" json:"snapshotNames,omitempty"`
-	Snapshots        []*Snapshot      `protobuf:"bytes,5,rep,name=snapshots" json:"snapshots,omitempty"`
-	Predump          *bool            `protobuf:"varint,7,opt,name=predump" json:"predump,omitempty"`
-	RsyncFeatures    *RsyncFeatures   `protobuf:"bytes,8,opt,name=rsyncFeatures" json:"rsyncFeatures,omitempty"`
-	Refresh          *bool            `protobuf:"varint,9,opt,name=refresh" json:"refresh,omitempty"`
-	ZfsFeatures      *ZfsFeatures     `protobuf:"bytes,10,opt,name=zfsFeatures" json:"zfsFeatures,omitempty"`
-	XXX_unrecognized []byte           `json:"-"`
-}
-
-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{6} }
+	Fs                   *MigrationFSType `protobuf:"varint,1,req,name=fs,enum=migration.MigrationFSType" json:"fs,omitempty"`
+	Criu                 *CRIUType        `protobuf:"varint,2,opt,name=criu,enum=migration.CRIUType" json:"criu,omitempty"`
+	Idmap                []*IDMapType     `protobuf:"bytes,3,rep,name=idmap" json:"idmap,omitempty"`
+	SnapshotNames        []string         `protobuf:"bytes,4,rep,name=snapshotNames" json:"snapshotNames,omitempty"`
+	Snapshots            []*Snapshot      `protobuf:"bytes,5,rep,name=snapshots" json:"snapshots,omitempty"`
+	Predump              *bool            `protobuf:"varint,7,opt,name=predump" json:"predump,omitempty"`
+	RsyncFeatures        *RsyncFeatures   `protobuf:"bytes,8,opt,name=rsyncFeatures" json:"rsyncFeatures,omitempty"`
+	Refresh              *bool            `protobuf:"varint,9,opt,name=refresh" json:"refresh,omitempty"`
+	ZfsFeatures          *ZfsFeatures     `protobuf:"bytes,10,opt,name=zfsFeatures" json:"zfsFeatures,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}         `json:"-"`
+	XXX_unrecognized     []byte           `json:"-"`
+	XXX_sizecache        int32            `json:"-"`
+}
+
+func (m *MigrationHeader) Reset()         { *m = MigrationHeader{} }
+func (m *MigrationHeader) String() string { return proto.CompactTextString(m) }
+func (*MigrationHeader) ProtoMessage()    {}
+func (*MigrationHeader) Descriptor() ([]byte, []int) {
+	return fileDescriptor_fe8772548dc4b615, []int{6}
+}
+
+func (m *MigrationHeader) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_MigrationHeader.Unmarshal(m, b)
+}
+func (m *MigrationHeader) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_MigrationHeader.Marshal(b, m, deterministic)
+}
+func (m *MigrationHeader) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_MigrationHeader.Merge(m, src)
+}
+func (m *MigrationHeader) XXX_Size() int {
+	return xxx_messageInfo_MigrationHeader.Size(m)
+}
+func (m *MigrationHeader) XXX_DiscardUnknown() {
+	xxx_messageInfo_MigrationHeader.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_MigrationHeader proto.InternalMessageInfo
 
 func (m *MigrationHeader) GetFs() MigrationFSType {
 	if m != nil && m.Fs != nil {
@@ -437,14 +588,36 @@ func (m *MigrationHeader) GetZfsFeatures() *ZfsFeatures {
 type MigrationControl struct {
 	Success *bool `protobuf:"varint,1,req,name=success" json:"success,omitempty"`
 	// optional failure message if sending a failure
-	Message          *string `protobuf:"bytes,2,opt,name=message" json:"message,omitempty"`
-	XXX_unrecognized []byte  `json:"-"`
+	Message              *string  `protobuf:"bytes,2,opt,name=message" json:"message,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
 }
 
-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{7} }
+func (m *MigrationControl) Reset()         { *m = MigrationControl{} }
+func (m *MigrationControl) String() string { return proto.CompactTextString(m) }
+func (*MigrationControl) ProtoMessage()    {}
+func (*MigrationControl) Descriptor() ([]byte, []int) {
+	return fileDescriptor_fe8772548dc4b615, []int{7}
+}
+
+func (m *MigrationControl) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_MigrationControl.Unmarshal(m, b)
+}
+func (m *MigrationControl) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_MigrationControl.Marshal(b, m, deterministic)
+}
+func (m *MigrationControl) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_MigrationControl.Merge(m, src)
+}
+func (m *MigrationControl) XXX_Size() int {
+	return xxx_messageInfo_MigrationControl.Size(m)
+}
+func (m *MigrationControl) XXX_DiscardUnknown() {
+	xxx_messageInfo_MigrationControl.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_MigrationControl proto.InternalMessageInfo
 
 func (m *MigrationControl) GetSuccess() bool {
 	if m != nil && m.Success != nil {
@@ -461,14 +634,36 @@ func (m *MigrationControl) GetMessage() string {
 }
 
 type MigrationSync struct {
-	FinalPreDump     *bool  `protobuf:"varint,1,req,name=finalPreDump" json:"finalPreDump,omitempty"`
-	XXX_unrecognized []byte `json:"-"`
+	FinalPreDump         *bool    `protobuf:"varint,1,req,name=finalPreDump" json:"finalPreDump,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *MigrationSync) Reset()         { *m = MigrationSync{} }
+func (m *MigrationSync) String() string { return proto.CompactTextString(m) }
+func (*MigrationSync) ProtoMessage()    {}
+func (*MigrationSync) Descriptor() ([]byte, []int) {
+	return fileDescriptor_fe8772548dc4b615, []int{8}
 }
 
-func (m *MigrationSync) Reset()                    { *m = MigrationSync{} }
-func (m *MigrationSync) String() string            { return proto.CompactTextString(m) }
-func (*MigrationSync) ProtoMessage()               {}
-func (*MigrationSync) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} }
+func (m *MigrationSync) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_MigrationSync.Unmarshal(m, b)
+}
+func (m *MigrationSync) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_MigrationSync.Marshal(b, m, deterministic)
+}
+func (m *MigrationSync) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_MigrationSync.Merge(m, src)
+}
+func (m *MigrationSync) XXX_Size() int {
+	return xxx_messageInfo_MigrationSync.Size(m)
+}
+func (m *MigrationSync) XXX_DiscardUnknown() {
+	xxx_messageInfo_MigrationSync.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_MigrationSync proto.InternalMessageInfo
 
 func (m *MigrationSync) GetFinalPreDump() bool {
 	if m != nil && m.FinalPreDump != nil {
@@ -479,24 +674,46 @@ func (m *MigrationSync) GetFinalPreDump() bool {
 
 // This one contains statistics about dump/restore process
 type DumpStatsEntry struct {
-	FreezingTime       *uint32 `protobuf:"varint,1,req,name=freezing_time,json=freezingTime" json:"freezing_time,omitempty"`
-	FrozenTime         *uint32 `protobuf:"varint,2,req,name=frozen_time,json=frozenTime" json:"frozen_time,omitempty"`
-	MemdumpTime        *uint32 `protobuf:"varint,3,req,name=memdump_time,json=memdumpTime" json:"memdump_time,omitempty"`
-	MemwriteTime       *uint32 `protobuf:"varint,4,req,name=memwrite_time,json=memwriteTime" json:"memwrite_time,omitempty"`
-	PagesScanned       *uint64 `protobuf:"varint,5,req,name=pages_scanned,json=pagesScanned" json:"pages_scanned,omitempty"`
-	PagesSkippedParent *uint64 `protobuf:"varint,6,req,name=pages_skipped_parent,json=pagesSkippedParent" json:"pages_skipped_parent,omitempty"`
-	PagesWritten       *uint64 `protobuf:"varint,7,req,name=pages_written,json=pagesWritten" json:"pages_written,omitempty"`
-	IrmapResolve       *uint32 `protobuf:"varint,8,opt,name=irmap_resolve,json=irmapResolve" json:"irmap_resolve,omitempty"`
-	PagesLazy          *uint64 `protobuf:"varint,9,req,name=pages_lazy,json=pagesLazy" json:"pages_lazy,omitempty"`
-	PagePipes          *uint64 `protobuf:"varint,10,opt,name=page_pipes,json=pagePipes" json:"page_pipes,omitempty"`
-	PagePipeBufs       *uint64 `protobuf:"varint,11,opt,name=page_pipe_bufs,json=pagePipeBufs" json:"page_pipe_bufs,omitempty"`
-	XXX_unrecognized   []byte  `json:"-"`
-}
-
-func (m *DumpStatsEntry) Reset()                    { *m = DumpStatsEntry{} }
-func (m *DumpStatsEntry) String() string            { return proto.CompactTextString(m) }
-func (*DumpStatsEntry) ProtoMessage()               {}
-func (*DumpStatsEntry) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} }
+	FreezingTime         *uint32  `protobuf:"varint,1,req,name=freezing_time,json=freezingTime" json:"freezing_time,omitempty"`
+	FrozenTime           *uint32  `protobuf:"varint,2,req,name=frozen_time,json=frozenTime" json:"frozen_time,omitempty"`
+	MemdumpTime          *uint32  `protobuf:"varint,3,req,name=memdump_time,json=memdumpTime" json:"memdump_time,omitempty"`
+	MemwriteTime         *uint32  `protobuf:"varint,4,req,name=memwrite_time,json=memwriteTime" json:"memwrite_time,omitempty"`
+	PagesScanned         *uint64  `protobuf:"varint,5,req,name=pages_scanned,json=pagesScanned" json:"pages_scanned,omitempty"`
+	PagesSkippedParent   *uint64  `protobuf:"varint,6,req,name=pages_skipped_parent,json=pagesSkippedParent" json:"pages_skipped_parent,omitempty"`
+	PagesWritten         *uint64  `protobuf:"varint,7,req,name=pages_written,json=pagesWritten" json:"pages_written,omitempty"`
+	IrmapResolve         *uint32  `protobuf:"varint,8,opt,name=irmap_resolve,json=irmapResolve" json:"irmap_resolve,omitempty"`
+	PagesLazy            *uint64  `protobuf:"varint,9,req,name=pages_lazy,json=pagesLazy" json:"pages_lazy,omitempty"`
+	PagePipes            *uint64  `protobuf:"varint,10,opt,name=page_pipes,json=pagePipes" json:"page_pipes,omitempty"`
+	PagePipeBufs         *uint64  `protobuf:"varint,11,opt,name=page_pipe_bufs,json=pagePipeBufs" json:"page_pipe_bufs,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *DumpStatsEntry) Reset()         { *m = DumpStatsEntry{} }
+func (m *DumpStatsEntry) String() string { return proto.CompactTextString(m) }
+func (*DumpStatsEntry) ProtoMessage()    {}
+func (*DumpStatsEntry) Descriptor() ([]byte, []int) {
+	return fileDescriptor_fe8772548dc4b615, []int{9}
+}
+
+func (m *DumpStatsEntry) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_DumpStatsEntry.Unmarshal(m, b)
+}
+func (m *DumpStatsEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_DumpStatsEntry.Marshal(b, m, deterministic)
+}
+func (m *DumpStatsEntry) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_DumpStatsEntry.Merge(m, src)
+}
+func (m *DumpStatsEntry) XXX_Size() int {
+	return xxx_messageInfo_DumpStatsEntry.Size(m)
+}
+func (m *DumpStatsEntry) XXX_DiscardUnknown() {
+	xxx_messageInfo_DumpStatsEntry.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_DumpStatsEntry proto.InternalMessageInfo
 
 func (m *DumpStatsEntry) GetFreezingTime() uint32 {
 	if m != nil && m.FreezingTime != nil {
@@ -576,18 +793,40 @@ func (m *DumpStatsEntry) GetPagePipeBufs() uint64 {
 }
 
 type RestoreStatsEntry struct {
-	PagesCompared    *uint64 `protobuf:"varint,1,req,name=pages_compared,json=pagesCompared" json:"pages_compared,omitempty"`
-	PagesSkippedCow  *uint64 `protobuf:"varint,2,req,name=pages_skipped_cow,json=pagesSkippedCow" json:"pages_skipped_cow,omitempty"`
-	ForkingTime      *uint32 `protobuf:"varint,3,req,name=forking_time,json=forkingTime" json:"forking_time,omitempty"`
-	RestoreTime      *uint32 `protobuf:"varint,4,req,name=restore_time,json=restoreTime" json:"restore_time,omitempty"`
-	PagesRestored    *uint64 `protobuf:"varint,5,opt,name=pages_restored,json=pagesRestored" json:"pages_restored,omitempty"`
-	XXX_unrecognized []byte  `json:"-"`
+	PagesCompared        *uint64  `protobuf:"varint,1,req,name=pages_compared,json=pagesCompared" json:"pages_compared,omitempty"`
+	PagesSkippedCow      *uint64  `protobuf:"varint,2,req,name=pages_skipped_cow,json=pagesSkippedCow" json:"pages_skipped_cow,omitempty"`
+	ForkingTime          *uint32  `protobuf:"varint,3,req,name=forking_time,json=forkingTime" json:"forking_time,omitempty"`
+	RestoreTime          *uint32  `protobuf:"varint,4,req,name=restore_time,json=restoreTime" json:"restore_time,omitempty"`
+	PagesRestored        *uint64  `protobuf:"varint,5,opt,name=pages_restored,json=pagesRestored" json:"pages_restored,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
 }
 
-func (m *RestoreStatsEntry) Reset()                    { *m = RestoreStatsEntry{} }
-func (m *RestoreStatsEntry) String() string            { return proto.CompactTextString(m) }
-func (*RestoreStatsEntry) ProtoMessage()               {}
-func (*RestoreStatsEntry) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} }
+func (m *RestoreStatsEntry) Reset()         { *m = RestoreStatsEntry{} }
+func (m *RestoreStatsEntry) String() string { return proto.CompactTextString(m) }
+func (*RestoreStatsEntry) ProtoMessage()    {}
+func (*RestoreStatsEntry) Descriptor() ([]byte, []int) {
+	return fileDescriptor_fe8772548dc4b615, []int{10}
+}
+
+func (m *RestoreStatsEntry) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_RestoreStatsEntry.Unmarshal(m, b)
+}
+func (m *RestoreStatsEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_RestoreStatsEntry.Marshal(b, m, deterministic)
+}
+func (m *RestoreStatsEntry) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_RestoreStatsEntry.Merge(m, src)
+}
+func (m *RestoreStatsEntry) XXX_Size() int {
+	return xxx_messageInfo_RestoreStatsEntry.Size(m)
+}
+func (m *RestoreStatsEntry) XXX_DiscardUnknown() {
+	xxx_messageInfo_RestoreStatsEntry.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_RestoreStatsEntry proto.InternalMessageInfo
 
 func (m *RestoreStatsEntry) GetPagesCompared() uint64 {
 	if m != nil && m.PagesCompared != nil {
@@ -625,15 +864,37 @@ func (m *RestoreStatsEntry) GetPagesRestored() uint64 {
 }
 
 type StatsEntry struct {
-	Dump             *DumpStatsEntry    `protobuf:"bytes,1,opt,name=dump" json:"dump,omitempty"`
-	Restore          *RestoreStatsEntry `protobuf:"bytes,2,opt,name=restore" json:"restore,omitempty"`
-	XXX_unrecognized []byte             `json:"-"`
+	Dump                 *DumpStatsEntry    `protobuf:"bytes,1,opt,name=dump" json:"dump,omitempty"`
+	Restore              *RestoreStatsEntry `protobuf:"bytes,2,opt,name=restore" json:"restore,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}           `json:"-"`
+	XXX_unrecognized     []byte             `json:"-"`
+	XXX_sizecache        int32              `json:"-"`
+}
+
+func (m *StatsEntry) Reset()         { *m = StatsEntry{} }
+func (m *StatsEntry) String() string { return proto.CompactTextString(m) }
+func (*StatsEntry) ProtoMessage()    {}
+func (*StatsEntry) Descriptor() ([]byte, []int) {
+	return fileDescriptor_fe8772548dc4b615, []int{11}
+}
+
+func (m *StatsEntry) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_StatsEntry.Unmarshal(m, b)
+}
+func (m *StatsEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_StatsEntry.Marshal(b, m, deterministic)
+}
+func (m *StatsEntry) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_StatsEntry.Merge(m, src)
+}
+func (m *StatsEntry) XXX_Size() int {
+	return xxx_messageInfo_StatsEntry.Size(m)
+}
+func (m *StatsEntry) XXX_DiscardUnknown() {
+	xxx_messageInfo_StatsEntry.DiscardUnknown(m)
 }
 
-func (m *StatsEntry) Reset()                    { *m = StatsEntry{} }
-func (m *StatsEntry) String() string            { return proto.CompactTextString(m) }
-func (*StatsEntry) ProtoMessage()               {}
-func (*StatsEntry) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} }
+var xxx_messageInfo_StatsEntry proto.InternalMessageInfo
 
 func (m *StatsEntry) GetDump() *DumpStatsEntry {
 	if m != nil {
@@ -650,6 +911,8 @@ func (m *StatsEntry) GetRestore() *RestoreStatsEntry {
 }
 
 func init() {
+	proto.RegisterEnum("migration.MigrationFSType", MigrationFSType_name, MigrationFSType_value)
+	proto.RegisterEnum("migration.CRIUType", CRIUType_name, CRIUType_value)
 	proto.RegisterType((*IDMapType)(nil), "migration.IDMapType")
 	proto.RegisterType((*Config)(nil), "migration.Config")
 	proto.RegisterType((*Device)(nil), "migration.Device")
@@ -662,78 +925,77 @@ func init() {
 	proto.RegisterType((*DumpStatsEntry)(nil), "migration.dump_stats_entry")
 	proto.RegisterType((*RestoreStatsEntry)(nil), "migration.restore_stats_entry")
 	proto.RegisterType((*StatsEntry)(nil), "migration.stats_entry")
-	proto.RegisterEnum("migration.MigrationFSType", MigrationFSType_name, MigrationFSType_value)
-	proto.RegisterEnum("migration.CRIUType", CRIUType_name, CRIUType_value)
 }
 
-func init() { proto.RegisterFile("lxd/migration/migrate.proto", fileDescriptor0) }
-
-var fileDescriptor0 = []byte{
-	// 1047 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x55, 0xdb, 0x6e, 0xdb, 0x46,
-	0x10, 0xad, 0x6e, 0xb6, 0x38, 0x92, 0x1c, 0x65, 0x63, 0x04, 0x44, 0xd2, 0x8b, 0xca, 0xa4, 0xa8,
-	0xe2, 0x07, 0x3b, 0x55, 0x50, 0x20, 0x7d, 0x29, 0x50, 0xcb, 0x75, 0x13, 0x20, 0x71, 0x8d, 0x95,
-	0x8d, 0xa2, 0x7d, 0x21, 0x36, 0xe4, 0x50, 0x5e, 0x98, 0x37, 0xec, 0x52, 0xb6, 0xe5, 0x97, 0xa2,
-	0x9f, 0xd1, 0x0f, 0xe8, 0xf7, 0xf4, 0xa9, 0xff, 0x53, 0xec, 0x2c, 0x49, 0x53, 0x4e, 0x81, 0xbe,
-	0xed, 0x9c, 0x39, 0x3c, 0xb3, 0x3b, 0x37, 0xc2, 0xd3, 0xf8, 0x26, 0x3c, 0x48, 0xe4, 0x52, 0x89,
-	0x42, 0x66, 0x69, 0x79, 0xc2, 0xfd, 0x5c, 0x65, 0x45, 0xc6, 0x9c, 0xda, 0xe1, 0xfd, 0x0e, 0xce,
-	0xdb, 0xa3, 0xf7, 0x22, 0x3f, 0x5b, 0xe7, 0xc8, 0x76, 0xa1, 0x27, 0xf5, 0x4a, 0x86, 0x6e, 0x6b,
-	0xd2, 0x9e, 0xf6, 0xb9, 0x35, 0x2c, 0xba, 0x94, 0xa1, 0xdb, 0xae, 0xd0, 0xa5, 0x0c, 0xd9, 0x63,
-	0xd8, 0xba, 0xc8, 0x74, 0x21, 0x43, 0xb7, 0x33, 0x69, 0x4f, 0x7b, 0xbc, 0xb4, 0x18, 0x83, 0x6e,
-	0xaa, 0x65, 0xe8, 0x76, 0x09, 0xa5, 0x33, 0x7b, 0x02, 0xfd, 0x44, 0xe4, 0x4a, 0xa4, 0x4b, 0x74,
-	0x7b, 0x84, 0xd7, 0xb6, 0xf7, 0x12, 0xb6, 0xe6, 0x59, 0x1a, 0xc9, 0x25, 0x1b, 0x43, 0xe7, 0x12,
-	0xd7, 0x14, 0xdb, 0xe1, 0xe6, 0x68, 0x22, 0x5f, 0x89, 0x78, 0x85, 0x14, 0xd9, 0xe1, 0xd6, 0xf0,
-	0x7e, 0x82, 0xad, 0x23, 0xbc, 0x92, 0x01, 0x52, 0x2c, 0x91, 0x60, 0xf9, 0x09, 0x9d, 0xd9, 0x0b,
-	0xd8, 0x0a, 0x48, 0xcf, 0x6d, 0x4f, 0x3a, 0xd3, 0xc1, 0xec, 0xe1, 0x7e, 0xfd, 0xd8, 0x7d, 0x1b,
-	0x88, 0x97, 0x04, 0xef, 0xef, 0x36, 0xf4, 0x17, 0xa9, 0xc8, 0xf5, 0x45, 0x56, 0xfc, 0xa7, 0xd6,
-	0x2b, 0x18, 0xc4, 0x59, 0x20, 0xe2, 0xf9, 0xff, 0x08, 0x36, 0x59, 0xe6, 0xb1, 0xb9, 0xca, 0x22,
-	0x19, 0xa3, 0x76, 0x3b, 0x93, 0xce, 0xd4, 0xe1, 0xb5, 0xcd, 0x3e, 0x05, 0x07, 0xf3, 0x0b, 0x4c,
-	0x50, 0x89, 0x98, 0x32, 0xd4, 0xe7, 0x77, 0x00, 0xfb, 0x16, 0x86, 0x24, 0x64, 0x5f, 0xa7, 0xdd,
-	0xde, 0x47, 0xf1, 0xac, 0x87, 0x6f, 0xd0, 0x98, 0x07, 0x43, 0xa1, 0x82, 0x0b, 0x59, 0x60, 0x50,
-	0xac, 0x14, 0xba, 0x5b, 0x94, 0xe1, 0x0d, 0xcc, 0x5c, 0x4a, 0x17, 0xa2, 0xc0, 0x68, 0x15, 0xbb,
-	0xdb, 0x14, 0xb7, 0xb6, 0xd9, 0x33, 0x18, 0x05, 0x0a, 0x29, 0x80, 0x1f, 0x8a, 0x02, 0xdd, 0xfe,
-	0xa4, 0x35, 0xed, 0xf0, 0x61, 0x05, 0x1e, 0x89, 0x02, 0xd9, 0x73, 0xd8, 0x89, 0x85, 0x2e, 0xfc,
-	0x95, 0xc6, 0xd0, 0xb2, 0x1c, 0xcb, 0x32, 0xe8, 0xb9, 0xc6, 0xd0, 0xb0, 0xbc, 0x3f, 0x5a, 0x30,
-	0x52, 0x7a, 0x9d, 0x06, 0xc7, 0x28, 0x4c, 0x5c, 0x6d, 0xda, 0xe4, 0x46, 0x14, 0x85, 0xd2, 0x6e,
-	0x6b, 0xd2, 0x9a, 0xf6, 0x79, 0x69, 0x19, 0x3c, 0xc4, 0x18, 0x0b, 0x53, 0x5b, 0xc2, 0xad, 0x65,
-	0x2e, 0x1a, 0x64, 0x49, 0xae, 0x50, 0x9b, 0xec, 0x19, 0x4f, 0x6d, 0xb3, 0xe7, 0x30, 0xfa, 0x20,
-	0x43, 0xa9, 0x30, 0x30, 0xd7, 0xa2, 0x0c, 0x1a, 0xc2, 0x26, 0xe8, 0xbd, 0x80, 0xc1, 0x6d, 0xa4,
-	0xeb, 0x0b, 0x34, 0x05, 0x5b, 0x9b, 0x82, 0xde, 0x9f, 0x1d, 0x78, 0xf0, 0xbe, 0x4a, 0xee, 0x1b,
-	0x14, 0x21, 0x2a, 0xb6, 0x07, 0xed, 0x48, 0x53, 0x17, 0xec, 0xcc, 0x9e, 0x34, 0x52, 0x5f, 0xf3,
-	0x8e, 0x17, 0x66, 0x56, 0x78, 0x3b, 0xd2, 0xec, 0x6b, 0xe8, 0x06, 0x4a, 0xae, 0xe8, 0x09, 0x3b,
-	0xb3, 0x47, 0xcd, 0xc6, 0xe0, 0x6f, 0xcf, 0x89, 0x46, 0x04, 0xb6, 0x07, 0x3d, 0x19, 0x26, 0x22,
-	0xa7, 0x86, 0x18, 0xcc, 0x76, 0x1b, 0xcc, 0x7a, 0xfa, 0xb8, 0xa5, 0x98, 0x57, 0xea, 0xb2, 0x29,
-	0x4f, 0x44, 0x82, 0xda, 0xed, 0x52, 0x13, 0x6d, 0x82, 0xec, 0x1b, 0x70, 0x2a, 0xa0, 0x6a, 0x94,
-	0x66, 0xfc, 0xaa, 0xad, 0xf9, 0x1d, 0x8b, 0xb9, 0xb0, 0x9d, 0x2b, 0x0c, 0x57, 0x49, 0xee, 0x6e,
-	0x53, 0x22, 0x2a, 0x93, 0x7d, 0x7f, 0xaf, 0x6a, 0xd4, 0x01, 0x83, 0x99, 0xdb, 0x10, 0xdc, 0xf0,
-	0xf3, 0x7b, 0x45, 0x76, 0x61, 0x5b, 0x61, 0xa4, 0x50, 0x5f, 0x50, 0x57, 0xf4, 0x79, 0x65, 0xb2,
-	0xd7, 0x1b, 0xc5, 0x70, 0x81, 0x74, 0x1f, 0x37, 0x74, 0x1b, 0x5e, 0xde, 0xa4, 0x7a, 0xc7, 0x30,
-	0xae, 0x53, 0x3e, 0xcf, 0xd2, 0x42, 0x65, 0xb1, 0x89, 0xa3, 0x57, 0x41, 0x60, 0x4b, 0x69, 0x9a,
-	0xb8, 0x32, 0x8d, 0x27, 0x41, 0xad, 0xc5, 0xd2, 0xf6, 0x93, 0xc3, 0x2b, 0xd3, 0x7b, 0x05, 0xa3,
-	0x5a, 0x67, 0xb1, 0x4e, 0x03, 0x33, 0x2e, 0x91, 0x4c, 0x45, 0x7c, 0xaa, 0xf0, 0xc8, 0xe4, 0xc2,
-	0x2a, 0x6d, 0x60, 0xde, 0x5f, 0x1d, 0x18, 0x9b, 0xcc, 0xf8, 0x66, 0x48, 0xb4, 0x8f, 0x69, 0xa1,
-	0xd6, 0x66, 0x4e, 0x22, 0x85, 0x78, 0x2b, 0xd3, 0xa5, 0x5f, 0xc8, 0x72, 0x55, 0x8c, 0xf8, 0xb0,
-	0x02, 0xcf, 0x64, 0x82, 0xec, 0x0b, 0x18, 0x44, 0x2a, 0xbb, 0xc5, 0xd4, 0x52, 0xda, 0x44, 0x01,
-	0x0b, 0x11, 0xe1, 0x4b, 0x18, 0x26, 0x98, 0x90, 0x38, 0x31, 0x3a, 0xc4, 0x18, 0x94, 0x18, 0x51,
-	0x9e, 0xc1, 0x28, 0xc1, 0xe4, 0x5a, 0xc9, 0x02, 0x2d, 0xa7, 0x6b, 0x03, 0x55, 0x60, 0x45, 0xca,
-	0xc5, 0x12, 0xb5, 0xaf, 0x03, 0x91, 0xa6, 0x18, 0xd2, 0x62, 0xed, 0xf2, 0x21, 0x81, 0x0b, 0x8b,
-	0xb1, 0x97, 0xb0, 0x5b, 0x92, 0x2e, 0x65, 0x9e, 0x63, 0xe8, 0xe7, 0x42, 0x61, 0x5a, 0xd0, 0x8a,
-	0xe8, 0x72, 0x66, 0xb9, 0xd6, 0x75, 0x4a, 0x9e, 0x3b, 0x59, 0x13, 0xa9, 0xc0, 0x94, 0xb6, 0x45,
-	0x25, 0xfb, 0x8b, 0xc5, 0x0c, 0x49, 0xaa, 0x44, 0xe4, 0xbe, 0x42, 0x9d, 0xc5, 0x57, 0x76, 0x63,
-	0x8c, 0xf8, 0x90, 0x40, 0x6e, 0x31, 0xf6, 0x19, 0x80, 0x55, 0x8a, 0xc5, 0xed, 0xda, 0x75, 0x48,
-	0xc6, 0x21, 0xe4, 0x9d, 0xb8, 0x5d, 0x57, 0x6e, 0x3f, 0x97, 0x79, 0xd9, 0x18, 0xa5, 0xfb, 0xd4,
-	0x00, 0x66, 0xdf, 0xd4, 0x6e, 0xff, 0xc3, 0x2a, 0xd2, 0xee, 0x80, 0x28, 0xc3, 0x8a, 0x72, 0xb8,
-	0x8a, 0xb4, 0xf7, 0x4f, 0x0b, 0x1e, 0x29, 0xd4, 0x45, 0xa6, 0x70, 0xa3, 0x54, 0x5f, 0xd9, 0xaf,
-	0xb5, 0x6f, 0x46, 0x5d, 0x28, 0xb4, 0x7f, 0xb4, 0x2e, 0xb7, 0x6f, 0x9b, 0x97, 0x20, 0xdb, 0x83,
-	0x87, 0x9b, 0xe9, 0x09, 0xb2, 0x6b, 0x2a, 0x59, 0x97, 0x3f, 0x68, 0xe6, 0x66, 0x9e, 0x5d, 0x9b,
-	0xba, 0x45, 0x99, 0xba, 0xac, 0x8b, 0x5f, 0xd6, 0xad, 0xc4, 0xaa, 0xd2, 0x56, 0x97, 0x69, 0x94,
-	0x6d, 0x50, 0x62, 0x44, 0xa9, 0x2f, 0x56, 0x82, 0xa6, 0x6c, 0xad, 0xfa, 0x62, 0xbc, 0x04, 0xbd,
-	0x1b, 0x18, 0x34, 0x9f, 0x73, 0x00, 0xdd, 0xd0, 0xb6, 0xaa, 0x19, 0x9f, 0xa7, 0x8d, 0xf1, 0xb9,
-	0xdf, 0xa4, 0x9c, 0x88, 0xec, 0xb5, 0x19, 0x48, 0xd2, 0xa2, 0x71, 0x18, 0xcc, 0x3e, 0x6f, 0x8e,
-	0xf2, 0xc7, 0x09, 0xe3, 0x15, 0x7d, 0xef, 0xbb, 0xc6, 0x46, 0xb4, 0x9b, 0x8e, 0x39, 0xd0, 0xe3,
-	0x8b, 0x5f, 0x4f, 0xe6, 0xe3, 0x4f, 0xcc, 0xf1, 0xf0, 0x8c, 0x1f, 0x2f, 0xc6, 0x2d, 0xb6, 0x0d,
-	0x9d, 0xdf, 0x8e, 0x17, 0xe3, 0xb6, 0x39, 0xf0, 0xc3, 0xa3, 0x71, 0x67, 0xef, 0x00, 0xfa, 0xd5,
-	0xda, 0x63, 0x3b, 0x00, 0xe6, 0xec, 0x37, 0x3e, 0x3c, 0x7d, 0xf3, 0xc3, 0xf9, 0xbb, 0x71, 0x8b,
-	0xf5, 0xa1, 0x7b, 0xf2, 0xf3, 0xc9, 0x8f, 0xe3, 0xf6, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xcf,
-	0xd6, 0xdc, 0x0b, 0xa4, 0x08, 0x00, 0x00,
+func init() { proto.RegisterFile("lxd/migration/migrate.proto", fileDescriptor_fe8772548dc4b615) }
+
+var fileDescriptor_fe8772548dc4b615 = []byte{
+	// 1063 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x55, 0xdd, 0x6e, 0xdb, 0x36,
+	0x14, 0x9e, 0x6d, 0x39, 0xb1, 0x8e, 0xec, 0xc4, 0x65, 0x82, 0x42, 0x68, 0xf7, 0xe3, 0xa9, 0x1d,
+	0xe6, 0xe6, 0x22, 0xe9, 0x5c, 0x0c, 0xe8, 0xd5, 0x80, 0xc6, 0x5e, 0xd6, 0x62, 0xa9, 0x1b, 0xd0,
+	0x09, 0x86, 0xed, 0x46, 0x60, 0xa5, 0x23, 0x87, 0x88, 0xfe, 0x40, 0xca, 0x49, 0x9c, 0x9b, 0x61,
+	0x8f, 0xb1, 0x07, 0xd8, 0xf3, 0xec, 0x6a, 0xef, 0x33, 0x90, 0x94, 0x14, 0x39, 0x1d, 0xb0, 0x3b,
+	0x9e, 0xef, 0x7c, 0xfa, 0x0e, 0x79, 0xfe, 0x04, 0x4f, 0xe3, 0xdb, 0xf0, 0x28, 0xe1, 0x4b, 0xc1,
+	0x0a, 0x9e, 0xa5, 0xe5, 0x09, 0x0f, 0x73, 0x91, 0x15, 0x19, 0xb1, 0x6b, 0x87, 0xf7, 0x3b, 0xd8,
+	0xef, 0x66, 0xef, 0x59, 0x7e, 0xbe, 0xce, 0x91, 0xec, 0x43, 0x97, 0xcb, 0x15, 0x0f, 0xdd, 0xd6,
+	0xa8, 0x3d, 0xee, 0x51, 0x63, 0x18, 0x74, 0xc9, 0x43, 0xb7, 0x5d, 0xa1, 0x4b, 0x1e, 0x92, 0xc7,
+	0xb0, 0x75, 0x99, 0xc9, 0x82, 0x87, 0x6e, 0x67, 0xd4, 0x1e, 0x77, 0x69, 0x69, 0x11, 0x02, 0x56,
+	0x2a, 0x79, 0xe8, 0x5a, 0x1a, 0xd5, 0x67, 0xf2, 0x04, 0x7a, 0x09, 0xcb, 0x05, 0x4b, 0x97, 0xe8,
+	0x76, 0x35, 0x5e, 0xdb, 0xde, 0x4b, 0xd8, 0x9a, 0x66, 0x69, 0xc4, 0x97, 0x64, 0x08, 0x9d, 0x2b,
+	0x5c, 0xeb, 0xd8, 0x36, 0x55, 0x47, 0x15, 0xf9, 0x9a, 0xc5, 0x2b, 0xd4, 0x91, 0x6d, 0x6a, 0x0c,
+	0xef, 0x27, 0xd8, 0x9a, 0xe1, 0x35, 0x0f, 0x50, 0xc7, 0x62, 0x09, 0x96, 0x9f, 0xe8, 0x33, 0x79,
+	0x01, 0x5b, 0x81, 0xd6, 0x73, 0xdb, 0xa3, 0xce, 0xd8, 0x99, 0x3c, 0x3a, 0xac, 0x1f, 0x7b, 0x68,
+	0x02, 0xd1, 0x92, 0xe0, 0xfd, 0xdd, 0x86, 0xde, 0x22, 0x65, 0xb9, 0xbc, 0xcc, 0x8a, 0xff, 0xd4,
+	0x7a, 0x05, 0x4e, 0x9c, 0x05, 0x2c, 0x9e, 0xfe, 0x8f, 0x60, 0x93, 0xa5, 0x1e, 0x9b, 0x8b, 0x2c,
+	0xe2, 0x31, 0x4a, 0xb7, 0x33, 0xea, 0x8c, 0x6d, 0x5a, 0xdb, 0xe4, 0x73, 0xb0, 0x31, 0xbf, 0xc4,
+	0x04, 0x05, 0x8b, 0x75, 0x86, 0x7a, 0xf4, 0x1e, 0x20, 0xdf, 0x43, 0x5f, 0x0b, 0x99, 0xd7, 0x49,
+	0xb7, 0xfb, 0x49, 0x3c, 0xe3, 0xa1, 0x1b, 0x34, 0xe2, 0x41, 0x9f, 0x89, 0xe0, 0x92, 0x17, 0x18,
+	0x14, 0x2b, 0x81, 0xee, 0x96, 0xce, 0xf0, 0x06, 0xa6, 0x2e, 0x25, 0x0b, 0x56, 0x60, 0xb4, 0x8a,
+	0xdd, 0x6d, 0x1d, 0xb7, 0xb6, 0xc9, 0x33, 0x18, 0x04, 0x02, 0x75, 0x00, 0x3f, 0x64, 0x05, 0xba,
+	0xbd, 0x51, 0x6b, 0xdc, 0xa1, 0xfd, 0x0a, 0x9c, 0xb1, 0x02, 0xc9, 0x73, 0xd8, 0x89, 0x99, 0x2c,
+	0xfc, 0x95, 0xc4, 0xd0, 0xb0, 0x6c, 0xc3, 0x52, 0xe8, 0x85, 0xc4, 0x50, 0xb1, 0xbc, 0x3f, 0x5a,
+	0x30, 0x10, 0x72, 0x9d, 0x06, 0x27, 0xc8, 0x54, 0x5c, 0xa9, 0xda, 0xe4, 0x96, 0x15, 0x85, 0x90,
+	0x6e, 0x6b, 0xd4, 0x1a, 0xf7, 0x68, 0x69, 0x29, 0x3c, 0xc4, 0x18, 0x0b, 0x55, 0x5b, 0x8d, 0x1b,
+	0x4b, 0x5d, 0x34, 0xc8, 0x92, 0x5c, 0xa0, 0x54, 0xd9, 0x53, 0x9e, 0xda, 0x26, 0xcf, 0x61, 0xf0,
+	0x91, 0x87, 0x5c, 0x60, 0xa0, 0xae, 0xa5, 0x33, 0xa8, 0x08, 0x9b, 0xa0, 0xf7, 0x02, 0x9c, 0xbb,
+	0x48, 0xd6, 0x17, 0x68, 0x0a, 0xb6, 0x36, 0x05, 0xbd, 0x3f, 0x3b, 0xb0, 0xfb, 0xbe, 0x4a, 0xee,
+	0x5b, 0x64, 0x21, 0x0a, 0x72, 0x00, 0xed, 0x48, 0xea, 0x2e, 0xd8, 0x99, 0x3c, 0x69, 0xa4, 0xbe,
+	0xe6, 0x9d, 0x2c, 0xd4, 0xac, 0xd0, 0x76, 0x24, 0xc9, 0xb7, 0x60, 0x05, 0x82, 0xaf, 0xf4, 0x13,
+	0x76, 0x26, 0x7b, 0xcd, 0xc6, 0xa0, 0xef, 0x2e, 0x34, 0x4d, 0x13, 0xc8, 0x01, 0x74, 0x79, 0x98,
+	0xb0, 0x5c, 0x37, 0x84, 0x33, 0xd9, 0x6f, 0x30, 0xeb, 0xe9, 0xa3, 0x86, 0xa2, 0x5e, 0x29, 0xcb,
+	0xa6, 0x9c, 0xb3, 0x04, 0xa5, 0x6b, 0xe9, 0x26, 0xda, 0x04, 0xc9, 0x77, 0x60, 0x57, 0x40, 0xd5,
+	0x28, 0xcd, 0xf8, 0x55, 0x5b, 0xd3, 0x7b, 0x16, 0x71, 0x61, 0x3b, 0x17, 0x18, 0xae, 0x92, 0xdc,
+	0xdd, 0xd6, 0x89, 0xa8, 0x4c, 0xf2, 0xc3, 0x83, 0xaa, 0xe9, 0x0e, 0x70, 0x26, 0x6e, 0x43, 0x70,
+	0xc3, 0x4f, 0x1f, 0x14, 0xd9, 0x85, 0x6d, 0x81, 0x91, 0x40, 0x79, 0xa9, 0xbb, 0xa2, 0x47, 0x2b,
+	0x93, 0xbc, 0xde, 0x28, 0x86, 0x0b, 0x5a, 0xf7, 0x71, 0x43, 0xb7, 0xe1, 0xa5, 0x4d, 0xaa, 0x77,
+	0x02, 0xc3, 0x3a, 0xe5, 0xd3, 0x2c, 0x2d, 0x44, 0x16, 0xab, 0x38, 0x72, 0x15, 0x04, 0xa6, 0x94,
+	0xaa, 0x89, 0x2b, 0x53, 0x79, 0x12, 0x94, 0x92, 0x2d, 0x4d, 0x3f, 0xd9, 0xb4, 0x32, 0xbd, 0x57,
+	0x30, 0xa8, 0x75, 0x16, 0xeb, 0x34, 0x50, 0xe3, 0x12, 0xf1, 0x94, 0xc5, 0x67, 0x02, 0x67, 0x2a,
+	0x17, 0x46, 0x69, 0x03, 0xf3, 0xfe, 0xea, 0xc0, 0x50, 0x65, 0xc6, 0x57, 0x43, 0x22, 0x7d, 0x4c,
+	0x0b, 0xb1, 0x56, 0x73, 0x12, 0x09, 0xc4, 0x3b, 0x9e, 0x2e, 0xfd, 0x82, 0x97, 0xab, 0x62, 0x40,
+	0xfb, 0x15, 0x78, 0xce, 0x13, 0x24, 0x5f, 0x81, 0x13, 0x89, 0xec, 0x0e, 0x53, 0x43, 0x69, 0x6b,
+	0x0a, 0x18, 0x48, 0x13, 0xbe, 0x86, 0x7e, 0x82, 0x89, 0x16, 0xd7, 0x8c, 0x8e, 0x66, 0x38, 0x25,
+	0xa6, 0x29, 0xcf, 0x60, 0x90, 0x60, 0x72, 0x23, 0x78, 0x81, 0x86, 0x63, 0x99, 0x40, 0x15, 0x58,
+	0x91, 0x72, 0xb6, 0x44, 0xe9, 0xcb, 0x80, 0xa5, 0x29, 0x86, 0x7a, 0xb1, 0x5a, 0xb4, 0xaf, 0xc1,
+	0x85, 0xc1, 0xc8, 0x4b, 0xd8, 0x2f, 0x49, 0x57, 0x3c, 0xcf, 0x31, 0xf4, 0x73, 0x26, 0x30, 0x2d,
+	0xf4, 0x8a, 0xb0, 0x28, 0x31, 0x5c, 0xe3, 0x3a, 0xd3, 0x9e, 0x7b, 0x59, 0x15, 0xa9, 0xc0, 0x54,
+	0x6f, 0x8b, 0x4a, 0xf6, 0x17, 0x83, 0x29, 0x12, 0x17, 0x09, 0xcb, 0x7d, 0x81, 0x32, 0x8b, 0xaf,
+	0xcd, 0xc6, 0x18, 0xd0, 0xbe, 0x06, 0xa9, 0xc1, 0xc8, 0x17, 0x00, 0x46, 0x29, 0x66, 0x77, 0x6b,
+	0xd7, 0xd6, 0x32, 0xb6, 0x46, 0x4e, 0xd9, 0xdd, 0xba, 0x72, 0xfb, 0x39, 0xcf, 0xcb, 0xc6, 0x28,
+	0xdd, 0x67, 0x0a, 0x50, 0xfb, 0xa6, 0x76, 0xfb, 0x1f, 0x57, 0x91, 0x74, 0x1d, 0x4d, 0xe9, 0x57,
+	0x94, 0xe3, 0x55, 0x24, 0xbd, 0x7f, 0x5a, 0xb0, 0x27, 0x50, 0x16, 0x99, 0xc0, 0x8d, 0x52, 0x7d,
+	0x63, 0xbe, 0x96, 0xbe, 0x1a, 0x75, 0x26, 0xd0, 0xfc, 0xd1, 0x2c, 0x6a, 0xde, 0x36, 0x2d, 0x41,
+	0x72, 0x00, 0x8f, 0x36, 0xd3, 0x13, 0x64, 0x37, 0xba, 0x64, 0x16, 0xdd, 0x6d, 0xe6, 0x66, 0x9a,
+	0xdd, 0xa8, 0xba, 0x45, 0x99, 0xb8, 0xaa, 0x8b, 0x5f, 0xd6, 0xad, 0xc4, 0xaa, 0xd2, 0x56, 0x97,
+	0x69, 0x94, 0xcd, 0x29, 0x31, 0x4d, 0xa9, 0x2f, 0x56, 0x82, 0xaa, 0x6c, 0xad, 0xfa, 0x62, 0xb4,
+	0x04, 0xbd, 0x5b, 0x70, 0x9a, 0xcf, 0x39, 0x02, 0x2b, 0x34, 0xad, 0xaa, 0xc6, 0xe7, 0x69, 0x63,
+	0x7c, 0x1e, 0x36, 0x29, 0xd5, 0x44, 0xf2, 0x5a, 0x0d, 0xa4, 0xd6, 0xd2, 0xe3, 0xe0, 0x4c, 0xbe,
+	0x6c, 0x8e, 0xf2, 0xa7, 0x09, 0xa3, 0x15, 0xfd, 0x60, 0xde, 0xd8, 0x88, 0x66, 0xd3, 0x11, 0x1b,
+	0xba, 0x74, 0xf1, 0xeb, 0x7c, 0x3a, 0xfc, 0x4c, 0x1d, 0x8f, 0xcf, 0xe9, 0xc9, 0x62, 0xd8, 0x22,
+	0xdb, 0xd0, 0xf9, 0xed, 0x64, 0x31, 0x6c, 0xab, 0x03, 0x3d, 0x9e, 0x0d, 0x3b, 0x64, 0x0f, 0x76,
+	0x8f, 0x4f, 0x3f, 0x4c, 0x7f, 0xf6, 0xdf, 0xcc, 0x67, 0xbe, 0xf9, 0xc2, 0x3a, 0x38, 0x82, 0x5e,
+	0xb5, 0x0b, 0xc9, 0x0e, 0x80, 0x3a, 0xfb, 0x0d, 0xb5, 0xb3, 0xb7, 0x6f, 0x2e, 0x4e, 0x87, 0x2d,
+	0xd2, 0x03, 0x6b, 0xfe, 0x61, 0xfe, 0xe3, 0xb0, 0xfd, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc9,
+	0x83, 0x44, 0xf9, 0xb9, 0x08, 0x00, 0x00,
 }
diff --git a/lxd/migration/migrate.proto b/lxd/migration/migrate.proto
index df01b51e5c..a337d90cef 100644
--- a/lxd/migration/migrate.proto
+++ b/lxd/migration/migrate.proto
@@ -8,6 +8,7 @@ enum MigrationFSType {
 	BTRFS		= 1;
 	ZFS		= 2;
 	RBD		= 3;
+	BLOCK_AND_RSYNC	= 4;
 }
 
 enum CRIUType {

From 28a9b0f29655514331df0e272a0f4c336786fd77 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 10 Mar 2020 10:53:14 +0000
Subject: [PATCH 02/12] lxd/storage/drivers/driver/common: Updates
 MigrationTypes to support block volumes for VMs

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/drivers/driver_common.go | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/lxd/storage/drivers/driver_common.go b/lxd/storage/drivers/driver_common.go
index cb850dccd2..051eb73033 100644
--- a/lxd/storage/drivers/driver_common.go
+++ b/lxd/storage/drivers/driver_common.go
@@ -131,9 +131,17 @@ func (d *common) validateVolume(vol Volume, driverRules map[string]func(value st
 // MigrationType returns the type of transfer methods to be used when doing migrations between pools
 // in preference order.
 func (d *common) MigrationTypes(contentType ContentType, refresh bool) []migration.Type {
+	var transportType migration.MigrationFSType
+
+	if contentType == ContentTypeBlock {
+		transportType = migration.MigrationFSType_BLOCK_AND_RSYNC
+	} else {
+		transportType = migration.MigrationFSType_RSYNC
+	}
+
 	return []migration.Type{
 		{
-			FSType:   migration.MigrationFSType_RSYNC,
+			FSType:   transportType,
 			Features: []string{"xattrs", "delete", "compress", "bidirectional"},
 		},
 	}

From a5d172942a0750915ab3c6856346ca9a8024319a Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 10 Mar 2020 11:00:29 +0000
Subject: [PATCH 03/12] lxd/storage/drivers/driver/dir/volumes: Updates
 migration to support VMs

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/drivers/driver_dir_volumes.go | 12 ++----------
 1 file changed, 2 insertions(+), 10 deletions(-)

diff --git a/lxd/storage/drivers/driver_dir_volumes.go b/lxd/storage/drivers/driver_dir_volumes.go
index eed421f8f1..7d21cd5844 100644
--- a/lxd/storage/drivers/driver_dir_volumes.go
+++ b/lxd/storage/drivers/driver_dir_volumes.go
@@ -129,11 +129,7 @@ func (d *dir) CreateVolumeFromCopy(vol Volume, srcVol Volume, copySnapshots bool
 
 // CreateVolumeFromMigration creates a volume being sent via a migration.
 func (d *dir) CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, volTargetArgs migration.VolumeTargetArgs, preFiller *VolumeFiller, op *operations.Operation) error {
-	if vol.contentType != ContentTypeFS {
-		return ErrNotSupported
-	}
-
-	if volTargetArgs.MigrationType.FSType != migration.MigrationFSType_RSYNC {
+	if volTargetArgs.MigrationType.FSType != migration.MigrationFSType_RSYNC && volTargetArgs.MigrationType.FSType != migration.MigrationFSType_BLOCK_AND_RSYNC {
 		return ErrNotSupported
 	}
 
@@ -306,11 +302,7 @@ func (d *dir) RenameVolume(vol Volume, newVolName string, op *operations.Operati
 
 // MigrateVolume sends a volume for migration.
 func (d *dir) MigrateVolume(vol Volume, conn io.ReadWriteCloser, volSrcArgs *migration.VolumeSourceArgs, op *operations.Operation) error {
-	if vol.contentType != ContentTypeFS {
-		return ErrNotSupported
-	}
-
-	if volSrcArgs.MigrationType.FSType != migration.MigrationFSType_RSYNC {
+	if volSrcArgs.MigrationType.FSType != migration.MigrationFSType_RSYNC && volSrcArgs.MigrationType.FSType != migration.MigrationFSType_BLOCK_AND_RSYNC {
 		return ErrNotSupported
 	}
 

From ebdd97ec50edc996c0011e38b64f2da52b0285f6 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 10 Mar 2020 13:41:49 +0000
Subject: [PATCH 04/12] lxd/rsync: Adds support for passing arguments to rsync
 send command

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/rsync/rsync.go | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/lxd/rsync/rsync.go b/lxd/rsync/rsync.go
index 716a8db525..6b18c743e1 100644
--- a/lxd/rsync/rsync.go
+++ b/lxd/rsync/rsync.go
@@ -74,7 +74,7 @@ func LocalCopy(source string, dest string, bwlimit string, xattrs bool) (string,
 	return msg, nil
 }
 
-func sendSetup(name string, path string, bwlimit string, execPath string, features []string) (*exec.Cmd, net.Conn, io.ReadCloser, error) {
+func sendSetup(name string, path string, bwlimit string, execPath string, features []string, rsyncArgs ...string) (*exec.Cmd, net.Conn, io.ReadCloser, error) {
 	/*
 	 * The way rsync works, it invokes a subprocess that does the actual
 	 * talking (given to it by a -E argument). Since there isn't an easy
@@ -129,6 +129,10 @@ func sendSetup(name string, path string, bwlimit string, execPath string, featur
 		args = append(args, rsyncFeatureArgs(features)...)
 	}
 
+	if len(rsyncArgs) > 0 {
+		args = append(args, rsyncArgs...)
+	}
+
 	args = append(args, []string{
 		path,
 		"localhost:/tmp/foo",
@@ -182,8 +186,8 @@ func sendSetup(name string, path string, bwlimit string, execPath string, featur
 
 // Send sets up the sending half of an rsync, to recursively send the
 // directory pointed to by path over the websocket.
-func Send(name string, path string, conn io.ReadWriteCloser, tracker *ioprogress.ProgressTracker, features []string, bwlimit string, execPath string) error {
-	cmd, netcatConn, stderr, err := sendSetup(name, path, bwlimit, execPath, features)
+func Send(name string, path string, conn io.ReadWriteCloser, tracker *ioprogress.ProgressTracker, features []string, bwlimit string, execPath string, rsyncArgs ...string) error {
+	cmd, netcatConn, stderr, err := sendSetup(name, path, bwlimit, execPath, features, rsyncArgs...)
 	if err != nil {
 		return err
 	}

From 1c18fcc2ac3bf116a81b632095cf892f1647ab28 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 10 Mar 2020 13:42:17 +0000
Subject: [PATCH 05/12] lxd/storage/drivers: Switches to ErrNotSupported for
 non-block volume paths

ErrNotImplemented suggests it will be implemented one day, which isn't true.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/drivers/driver_ceph_volumes.go   | 2 +-
 lxd/storage/drivers/driver_cephfs_volumes.go | 2 +-
 lxd/storage/drivers/driver_lvm_volumes.go    | 2 +-
 lxd/storage/drivers/generic_vfs.go           | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/lxd/storage/drivers/driver_ceph_volumes.go b/lxd/storage/drivers/driver_ceph_volumes.go
index 031d2a1f97..6ec379e6be 100644
--- a/lxd/storage/drivers/driver_ceph_volumes.go
+++ b/lxd/storage/drivers/driver_ceph_volumes.go
@@ -732,7 +732,7 @@ func (d *ceph) GetVolumeDiskPath(vol Volume) (string, error) {
 		return d.getRBDMappedDevPath(vol)
 	}
 
-	return "", ErrNotImplemented
+	return "", ErrNotSupported
 }
 
 // MountVolume simulates mounting a volume.
diff --git a/lxd/storage/drivers/driver_cephfs_volumes.go b/lxd/storage/drivers/driver_cephfs_volumes.go
index 852f967167..74fbf36e3f 100644
--- a/lxd/storage/drivers/driver_cephfs_volumes.go
+++ b/lxd/storage/drivers/driver_cephfs_volumes.go
@@ -318,7 +318,7 @@ func (d *cephfs) SetVolumeQuota(vol Volume, size string, op *operations.Operatio
 
 // GetVolumeDiskPath returns the location of a root disk block device.
 func (d *cephfs) GetVolumeDiskPath(vol Volume) (string, error) {
-	return "", ErrNotImplemented
+	return "", ErrNotSupported
 }
 
 // MountVolume sets up the volume for use.
diff --git a/lxd/storage/drivers/driver_lvm_volumes.go b/lxd/storage/drivers/driver_lvm_volumes.go
index b734a8267d..62540896d3 100644
--- a/lxd/storage/drivers/driver_lvm_volumes.go
+++ b/lxd/storage/drivers/driver_lvm_volumes.go
@@ -409,7 +409,7 @@ func (d *lvm) GetVolumeDiskPath(vol Volume) (string, error) {
 		return volDevPath, nil
 	}
 
-	return "", ErrNotImplemented
+	return "", ErrNotSupported
 }
 
 // MountVolume simulates mounting a volume. As dir driver doesn't have volumes to mount it returns
diff --git a/lxd/storage/drivers/generic_vfs.go b/lxd/storage/drivers/generic_vfs.go
index bd68d9574b..cdc2b76bf0 100644
--- a/lxd/storage/drivers/generic_vfs.go
+++ b/lxd/storage/drivers/generic_vfs.go
@@ -180,7 +180,7 @@ func genericVFSHasVolume(vol Volume) bool {
 // genericVFSGetVolumeDiskPath is a generic GetVolumeDiskPath implementation for VFS-only drivers.
 func genericVFSGetVolumeDiskPath(vol Volume) (string, error) {
 	if vol.contentType != ContentTypeBlock {
-		return "", fmt.Errorf("No disk paths for filesystems")
+		return "", ErrNotSupported
 	}
 
 	return filepath.Join(vol.MountPath(), "root.img"), nil

From a3fae5e6760aab2210ea5952ba9cd0b79fab806e Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 10 Mar 2020 13:43:48 +0000
Subject: [PATCH 06/12] lxd/storage/drivers/generic/vfs: Excludes VM disk image
 file root.img from migration when using rsync

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/drivers/generic_vfs.go | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/lxd/storage/drivers/generic_vfs.go b/lxd/storage/drivers/generic_vfs.go
index cdc2b76bf0..c76d8de9d4 100644
--- a/lxd/storage/drivers/generic_vfs.go
+++ b/lxd/storage/drivers/generic_vfs.go
@@ -135,6 +135,21 @@ func genericVFSRenameVolumeSnapshot(d Driver, snapVol Volume, newSnapshotName st
 func genericVFSMigrateVolume(d Driver, s *state.State, vol Volume, conn io.ReadWriteCloser, volSrcArgs *migration.VolumeSourceArgs, op *operations.Operation) error {
 	bwlimit := d.Config()["rsync.bwlimit"]
 
+	var rsyncArgs []string
+
+	// For VM volumes, if the root volume disk path is a file image then exclude it from being transferred via
+	// rsync, it will be transferred later using a different method.
+	if vol.IsVMBlock() {
+		path, err := d.GetVolumeDiskPath(vol)
+		if err != nil {
+			return errors.Wrapf(err, "Error getting VM block volume disk path")
+		}
+
+		if !shared.IsBlockdevPath(path) {
+			rsyncArgs = []string{"--exclude", filepath.Base(path)}
+		}
+	}
+
 	for _, snapName := range volSrcArgs.Snapshots {
 		snapshot, err := vol.NewSnapshot(snapName)
 		if err != nil {
@@ -149,7 +164,7 @@ func genericVFSMigrateVolume(d Driver, s *state.State, vol Volume, conn io.ReadW
 			}
 
 			path := shared.AddSlash(mountPath)
-			return rsync.Send(snapshot.name, path, conn, wrapper, volSrcArgs.MigrationType.Features, bwlimit, s.OS.ExecPath)
+			return rsync.Send(snapshot.name, path, conn, wrapper, volSrcArgs.MigrationType.Features, bwlimit, s.OS.ExecPath, rsyncArgs...)
 		}, op)
 		if err != nil {
 			return err
@@ -164,7 +179,7 @@ func genericVFSMigrateVolume(d Driver, s *state.State, vol Volume, conn io.ReadW
 		}
 
 		path := shared.AddSlash(mountPath)
-		return rsync.Send(vol.name, path, conn, wrapper, volSrcArgs.MigrationType.Features, bwlimit, s.OS.ExecPath)
+		return rsync.Send(vol.name, path, conn, wrapper, volSrcArgs.MigrationType.Features, bwlimit, s.OS.ExecPath, rsyncArgs...)
 	}, op)
 }
 

From f7e5017d00bc052d3c772785c268da12d86157b2 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 10 Mar 2020 14:54:36 +0000
Subject: [PATCH 07/12] lxd/storage/drivers/generic/vfs: Adds support for
 sending VM block volumes over migration connection

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/drivers/generic_vfs.go | 31 +++++++++++++++++++++++++++++-
 1 file changed, 30 insertions(+), 1 deletion(-)

diff --git a/lxd/storage/drivers/generic_vfs.go b/lxd/storage/drivers/generic_vfs.go
index c76d8de9d4..2c3cf1e33e 100644
--- a/lxd/storage/drivers/generic_vfs.go
+++ b/lxd/storage/drivers/generic_vfs.go
@@ -16,6 +16,7 @@ import (
 	"github.com/lxc/lxd/shared"
 	"github.com/lxc/lxd/shared/api"
 	"github.com/lxc/lxd/shared/ioprogress"
+	log "github.com/lxc/lxd/shared/log15"
 )
 
 // genericVFSGetResources is a generic GetResources implementation for VFS-only drivers.
@@ -179,7 +180,35 @@ func genericVFSMigrateVolume(d Driver, s *state.State, vol Volume, conn io.ReadW
 		}
 
 		path := shared.AddSlash(mountPath)
-		return rsync.Send(vol.name, path, conn, wrapper, volSrcArgs.MigrationType.Features, bwlimit, s.OS.ExecPath, rsyncArgs...)
+
+		d.Logger().Debug("Sending filesystem volume", log.Ctx{"vol": vol.name, "path": path})
+		err := rsync.Send(vol.name, path, conn, wrapper, volSrcArgs.MigrationType.Features, bwlimit, s.OS.ExecPath, rsyncArgs...)
+		if err != nil {
+			return err
+		}
+
+		if vol.IsVMBlock() {
+			defer conn.Close()
+
+			path, err := d.GetVolumeDiskPath(vol)
+			if err != nil {
+				return errors.Wrapf(err, "Error getting VM block volume disk path")
+			}
+
+			from, err := os.Open(path)
+			if err != nil {
+				return errors.Wrapf(err, "Error opening file for reading %q", path)
+			}
+			defer from.Close()
+
+			d.Logger().Debug("Sending block volume", log.Ctx{"vol": vol.name, "path": path})
+			_, err = io.Copy(conn, from)
+			if err != nil {
+				return errors.Wrapf(err, "Error copying file %q to migration connection", path)
+			}
+		}
+
+		return nil
 	}, op)
 }
 

From 78e726f41f25139d2505f454be811e54fbe290e9 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 10 Mar 2020 15:00:11 +0000
Subject: [PATCH 08/12] lxd/storage/drivers/generic: Adds VM block support to
 genericCreateVolumeFromMigration

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/drivers/generic.go | 29 +++++++++++++++++++++++++++--
 1 file changed, 27 insertions(+), 2 deletions(-)

diff --git a/lxd/storage/drivers/generic.go b/lxd/storage/drivers/generic.go
index b3ac53cde6..0258f3c59a 100644
--- a/lxd/storage/drivers/generic.go
+++ b/lxd/storage/drivers/generic.go
@@ -3,6 +3,9 @@ package drivers
 import (
 	"fmt"
 	"io"
+	"os"
+
+	"github.com/pkg/errors"
 
 	"github.com/lxc/lxd/lxd/migration"
 	"github.com/lxc/lxd/lxd/operations"
@@ -207,7 +210,7 @@ func genericCreateVolumeFromMigration(d Driver, initVolume func(vol Volume) (fun
 			wrapper = migration.ProgressTracker(op, "fs_progress", vol.name)
 		}
 
-		d.Logger().Debug("Receiving volume", log.Ctx{"volume": vol.name, "path": path})
+		d.Logger().Debug("Receiving filesystem volume", log.Ctx{"volume": vol.name, "volType": vol.volType, "path": path})
 		err := rsync.Recv(path, conn, wrapper, volTargetArgs.MigrationType.Features)
 		if err != nil {
 			return err
@@ -219,7 +222,7 @@ func genericCreateVolumeFromMigration(d Driver, initVolume func(vol Volume) (fun
 				wrapper = migration.ProgressTracker(op, "fs_progress", vol.name)
 			}
 
-			d.Logger().Debug("Receiving volume (final stage)", log.Ctx{"vol": vol.name, "path": path})
+			d.Logger().Debug("Receiving filesystem volume (final stage)", log.Ctx{"vol": vol.name, "path": path})
 			err = rsync.Recv(path, conn, wrapper, volTargetArgs.MigrationType.Features)
 			if err != nil {
 				return err
@@ -233,6 +236,28 @@ func genericCreateVolumeFromMigration(d Driver, initVolume func(vol Volume) (fun
 			return err
 		}
 
+		if vol.IsVMBlock() {
+			defer conn.Close()
+
+			// Now receive the block volume.
+			path, err := d.GetVolumeDiskPath(vol)
+			if err != nil {
+				return errors.Wrapf(err, "Error getting VM block volume disk path")
+			}
+
+			to, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0)
+			if err != nil {
+				return errors.Wrapf(err, "Error opening file writing %q", path)
+			}
+			defer to.Close()
+
+			d.Logger().Debug("Receiving block volume", log.Ctx{"vol": vol.name, "path": path})
+			_, err = io.Copy(to, conn)
+			if err != nil {
+				return errors.Wrapf(err, "Error copying file from migration connection to %q", path)
+			}
+		}
+
 		return nil
 	}, op)
 	if err != nil {

From df8429929f4daabea7a64db6995010effd8832df Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 10 Mar 2020 15:00:29 +0000
Subject: [PATCH 09/12] lxd/storage/drivers/utils: Error quoting

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/drivers/utils.go | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/lxd/storage/drivers/utils.go b/lxd/storage/drivers/utils.go
index 44200dc733..3de0b7794c 100644
--- a/lxd/storage/drivers/utils.go
+++ b/lxd/storage/drivers/utils.go
@@ -561,19 +561,19 @@ func regenerateFilesystemXFSUUID(devPath string) error {
 func copyDevice(inputPath, outputPath string) error {
 	from, err := os.Open(inputPath)
 	if err != nil {
-		return errors.Wrapf(err, "Error opening file for reading: %s", inputPath)
+		return errors.Wrapf(err, "Error opening file for reading %q", inputPath)
 	}
 	defer from.Close()
 
 	to, err := os.OpenFile(outputPath, os.O_WRONLY, 0)
 	if err != nil {
-		return errors.Wrapf(err, "Error opening file writing: %s", outputPath)
+		return errors.Wrapf(err, "Error opening file writing %q", outputPath)
 	}
 	defer to.Close()
 
 	_, err = io.Copy(to, from)
 	if err != nil {
-		return errors.Wrapf(err, "Error copying file '%s' to '%s'", inputPath, outputPath)
+		return errors.Wrapf(err, "Error copying file %q to %q", inputPath, outputPath)
 	}
 
 	return nil

From 9c5e2891865aa8670339cfd0cbeb3720882ad51b Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 10 Mar 2020 15:27:00 +0000
Subject: [PATCH 10/12] lxd/storage/drivers/driver/dir/utils: Skips initial
 quota for VM block migration

Also improves logging in setupInitialQuota.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/drivers/driver_dir_utils.go | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/lxd/storage/drivers/driver_dir_utils.go b/lxd/storage/drivers/driver_dir_utils.go
index e3f4bdf427..5b3e76f0d2 100644
--- a/lxd/storage/drivers/driver_dir_utils.go
+++ b/lxd/storage/drivers/driver_dir_utils.go
@@ -22,6 +22,10 @@ func (d *dir) withoutGetVolID() Driver {
 // setupInitialQuota enables quota on a new volume and sets with an initial quota from config.
 // Returns a revert function that can be used to remove the quota if there is a subsequent error.
 func (d *dir) setupInitialQuota(vol Volume) (func(), error) {
+	if vol.IsVMBlock() {
+		return nil, nil
+	}
+
 	volPath := vol.MountPath()
 
 	// Get the volume ID for the new volume, which is used to set project quota.
@@ -143,7 +147,7 @@ func (d *dir) setQuota(path string, volID int64, size string) error {
 	if err != nil || !ok {
 		if sizeBytes > 0 {
 			// Skipping quota as underlying filesystem doesn't suppport project quotas.
-			d.logger.Warn("The backing filesystem doesn't support quotas, skipping quota", log.Ctx{"path": path})
+			d.logger.Warn("The backing filesystem doesn't support quotas, skipping set quota", log.Ctx{"path": path, "size": size, "volID": volID})
 		}
 		return nil
 	}

From c9083c9d78be21885102b1f5180f08c939ac3185 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 10 Mar 2020 16:42:43 +0000
Subject: [PATCH 11/12] lxd/instances/post: Adds VM support to
 createFromMigration

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/instances_post.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lxd/instances_post.go b/lxd/instances_post.go
index 16f36e7709..9011448247 100644
--- a/lxd/instances_post.go
+++ b/lxd/instances_post.go
@@ -173,8 +173,8 @@ func createFromMigration(d *Daemon, project string, req *api.InstancesPost) resp
 		return response.BadRequest(err)
 	}
 
-	if dbType != instancetype.Container {
-		return response.BadRequest(fmt.Errorf("Instance type not container"))
+	if dbType != instancetype.Container && dbType != instancetype.VM {
+		return response.BadRequest(fmt.Errorf("Instance type not supported %q", req.Type))
 	}
 
 	// Prepare the instance creation request.

From ee790c61e117b850fda2710615b7b6ee3c87044d Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 10 Mar 2020 16:43:01 +0000
Subject: [PATCH 12/12] lxd/migrate/instance: Adds VM support to
 migrationSourceWs.Do

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/migrate_instance.go | 42 ++++++++++++++++++++---------------------
 1 file changed, 20 insertions(+), 22 deletions(-)

diff --git a/lxd/migrate_instance.go b/lxd/migrate_instance.go
index 3054a8810c..affbc8a135 100644
--- a/lxd/migrate_instance.go
+++ b/lxd/migrate_instance.go
@@ -330,11 +330,6 @@ func (s *migrationSourceWs) preDumpLoop(state *state.State, args *preDumpLoopArg
 
 func (s *migrationSourceWs) Do(state *state.State, migrateOp *operations.Operation) error {
 	<-s.allConnected
-	if s.instance.Type() != instancetype.Container {
-		return fmt.Errorf("Instance is not container type")
-	}
-
-	ct := s.instance.(instance.Container)
 
 	var offerHeader migration.MigrationHeader
 	var poolMigrationTypes []migration.Type
@@ -367,26 +362,29 @@ func (s *migrationSourceWs) Do(state *state.State, migrateOp *operations.Operati
 	}
 	offerHeader.Criu = criuType
 
-	// Add idmap info to source header.
-	idmaps := make([]*migration.IDMapType, 0)
-	idmapset, err := ct.DiskIdmap()
-	if err != nil {
-		return err
-	} else if idmapset != nil {
-		for _, ctnIdmap := range idmapset.Idmap {
-			idmap := migration.IDMapType{
-				Isuid:    proto.Bool(ctnIdmap.Isuid),
-				Isgid:    proto.Bool(ctnIdmap.Isgid),
-				Hostid:   proto.Int32(int32(ctnIdmap.Hostid)),
-				Nsid:     proto.Int32(int32(ctnIdmap.Nsid)),
-				Maprange: proto.Int32(int32(ctnIdmap.Maprange)),
-			}
+	// Add idmap info to source header for containers.
+	if s.instance.Type() == instancetype.Container {
+		ct := s.instance.(instance.Container)
+		idmaps := make([]*migration.IDMapType, 0)
+		idmapset, err := ct.DiskIdmap()
+		if err != nil {
+			return err
+		} else if idmapset != nil {
+			for _, ctnIdmap := range idmapset.Idmap {
+				idmap := migration.IDMapType{
+					Isuid:    proto.Bool(ctnIdmap.Isuid),
+					Isgid:    proto.Bool(ctnIdmap.Isgid),
+					Hostid:   proto.Int32(int32(ctnIdmap.Hostid)),
+					Nsid:     proto.Int32(int32(ctnIdmap.Nsid)),
+					Maprange: proto.Int32(int32(ctnIdmap.Maprange)),
+				}
 
-			idmaps = append(idmaps, &idmap)
+				idmaps = append(idmaps, &idmap)
+			}
 		}
-	}
 
-	offerHeader.Idmap = idmaps
+		offerHeader.Idmap = idmaps
+	}
 
 	// Add snapshot info to source header if needed.
 	snapshots := []*migration.Snapshot{}


More information about the lxc-devel mailing list