The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/7002

This e-mail was sent by the LXC bot, direct replies will not reach the author
unless they happen to be subscribed to this list.

=== Description (from pull-request) ===
Adds support for VM migration (and cross-pool local copy/move that uses migration layer):

- [ ] BTRFS
- [ ] Ceph
- [ ] Dir
- [ ] LVM
- [ ] ZFS


From 1b02a8ab5f5000db19195c2b4ae248718a07a796 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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{}
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to