Skip to content

Commit

Permalink
Merge pull request kubevirt#1845 from vladikr/live_migration_tracking
Browse files Browse the repository at this point in the history
Live migration tracking
  • Loading branch information
davidvossel authored Mar 4, 2019
2 parents 29d2cb6 + ab60e22 commit 629e7a6
Show file tree
Hide file tree
Showing 13 changed files with 471 additions and 5 deletions.
21 changes: 21 additions & 0 deletions api/openapi-spec/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -4941,6 +4941,20 @@
}
}
},
"v1.MigrationConfig": {
"properties": {
"completionTimeoutPerGiB": {
"description": "The time for GiB of data to wait for the migration to be completed before aborting it",
"type": "integer",
"format": "int64"
},
"progressTimeout": {
"description": "The time to wait for live migration to make progress in transferring data.",
"type": "integer",
"format": "int64"
}
}
},
"v1.Network": {
"description": "Network represents a network type and a resource that should be connected to the vm.",
"required": [
Expand Down Expand Up @@ -5870,6 +5884,9 @@
},
"v1.VirtualMachineInstanceMigrationSpec": {
"properties": {
"configuration": {
"$ref": "#/definitions/v1.MigrationConfig"
},
"vmiName": {
"description": "The name of the VMI to perform the migration on. VMI must exist in the migration objects namespace",
"type": "string"
Expand All @@ -5890,6 +5907,10 @@
"description": "Indicates that the migration failed",
"type": "boolean"
},
"migrationConfig": {
"description": "Config contains migration configuration options",
"$ref": "#/definitions/v1.MigrationConfig"
},
"migrationUid": {
"description": "The VirtualMachineInstanceMigration object associated with this migration",
"type": "string"
Expand Down
36 changes: 35 additions & 1 deletion pkg/api/v1/deepcopy_generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion pkg/api/v1/openapi_generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 11 additions & 1 deletion pkg/api/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,15 @@ type VirtualMachineInstanceMigrationState struct {
Failed bool `json:"failed,omitempty"`
// The VirtualMachineInstanceMigration object associated with this migration
MigrationUID types.UID `json:"migrationUid,omitempty"`
// Config contains migration configuration options
Config *MigrationConfig `json:"migrationConfig,omitempty"`
}

type MigrationConfig struct {
// The time for GiB of data to wait for the migration to be completed before aborting it
CompletionTimeoutPerGiB int64 `json:"completionTimeoutPerGiB,omitempty"`
// The time to wait for live migration to make progress in transferring data.
ProgressTimeout int64 `json:"progressTimeout,omitempty"`
}

// ---
Expand Down Expand Up @@ -736,7 +745,8 @@ func (vl *VirtualMachineInstanceMigrationList) GetListMeta() meta.List {
// +k8s:openapi-gen=true
type VirtualMachineInstanceMigrationSpec struct {
// The name of the VMI to perform the migration on. VMI must exist in the migration objects namespace
VMIName string `json:"vmiName,omitempty" valid:"required"`
VMIName string `json:"vmiName,omitempty" valid:"required"`
Config *MigrationConfig `json:"configuration,omitempty"`
}

// VirtualMachineInstanceMigration reprents information pertaining to a VMI's migration.
Expand Down
8 changes: 8 additions & 0 deletions pkg/api/v1/types_swagger_generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions pkg/virt-controller/watch/migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,9 @@ func (c *MigrationController) sync(migration *virtv1.VirtualMachineInstanceMigra
SourceNode: vmi.Status.NodeName,
TargetPod: pod.Name,
}
if migration.Spec.Config != nil {
vmiCopy.Status.MigrationState.Config = migration.Spec.Config.DeepCopy()
}

// By setting this label, virt-handler on the target node will receive
// the vmi and prepare the local environment for the migration
Expand Down
35 changes: 35 additions & 0 deletions pkg/virt-controller/watch/migration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,19 @@ var _ = Describe("Migration watcher", func() {

}).Return(vmi, nil)
}
shouldExpectVirtualMachineHandoffWithConfig := func(vmi *v1.VirtualMachineInstance, migrationUid types.UID, targetNode string, conf *v1.MigrationConfig) {
vmiInterface.EXPECT().Update(gomock.Any()).Do(func(arg interface{}) {
Expect(arg.(*v1.VirtualMachineInstance).Status.MigrationState).ToNot(BeNil())
Expect(arg.(*v1.VirtualMachineInstance).Status.MigrationState.MigrationUID).To(Equal(migrationUid))

Expect(arg.(*v1.VirtualMachineInstance).Status.MigrationState.SourceNode).To(Equal(vmi.Status.NodeName))
Expect(arg.(*v1.VirtualMachineInstance).Status.MigrationState.TargetNode).To(Equal(targetNode))
Expect(arg.(*v1.VirtualMachineInstance).Labels[v1.MigrationTargetNodeNameLabel]).To(Equal(targetNode))
Expect(arg.(*v1.VirtualMachineInstance).Status.MigrationState.Config).ToNot(BeNil())
Expect(arg.(*v1.VirtualMachineInstance).Status.MigrationState.Config.CompletionTimeoutPerGiB).To(Equal(conf.CompletionTimeoutPerGiB))
Expect(arg.(*v1.VirtualMachineInstance).Status.MigrationState.Config.ProgressTimeout).To(Equal(conf.ProgressTimeout))
}).Return(vmi, nil)
}

syncCaches := func(stop chan struct{}) {
go vmiInformer.Run(stop)
Expand Down Expand Up @@ -398,6 +411,28 @@ var _ = Describe("Migration watcher", func() {
controller.Execute()
testutils.ExpectEvent(recorder, SuccessfulHandOverPodReason)
})
It("should hand pod over to target virt-handler with migration config", func() {
vmi := newVirtualMachine("testvmi", v1.Running)
vmi.Status.NodeName = "node02"
migration := newMigration("testmigration", vmi.Name, v1.MigrationScheduled)
migrationConfig := &v1.MigrationConfig{
CompletionTimeoutPerGiB: 300,
ProgressTimeout: 100,
}
migration.Spec.Config = migrationConfig

pod := newTargetPodForVirtualMachine(vmi, migration, k8sv1.PodPending)
pod.Spec.NodeName = "node01"

addMigration(migration)
addVirtualMachine(vmi)
podFeeder.Add(pod)

shouldExpectVirtualMachineHandoffWithConfig(vmi, migration.UID, "node01", migrationConfig)

controller.Execute()
testutils.ExpectEvent(recorder, SuccessfulHandOverPodReason)
})

It("should hand pod over to target virt-handler overriding previous state", func() {
vmi := newVirtualMachine("testvmi", v1.Running)
Expand Down
2 changes: 2 additions & 0 deletions pkg/virt-launcher/virtwrap/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ go_library(
"//pkg/virt-launcher/virtwrap/util:go_default_library",
"//vendor/github.com/golang/mock/gomock:go_default_library",
"//vendor/github.com/libvirt/libvirt-go:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
],
Expand Down
32 changes: 32 additions & 0 deletions pkg/virt-launcher/virtwrap/cli/generated_mock_libvirt.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,38 @@ func (_mr *_MockVirDomainRecorder) MemoryStats(arg0, arg1 interface{}) *gomock.C
return _mr.mock.ctrl.RecordCall(_mr.mock, "MemoryStats", arg0, arg1)
}

func (_m *MockVirDomain) GetJobStats(flags libvirt_go.DomainGetJobStatsFlags) (*libvirt_go.DomainJobInfo, error) {
ret := _m.ctrl.Call(_m, "GetJobStats", flags)
ret0, _ := ret[0].(*libvirt_go.DomainJobInfo)
ret1, _ := ret[1].(error)
return ret0, ret1
}

func (_mr *_MockVirDomainRecorder) GetJobStats(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "GetJobStats", arg0)
}

func (_m *MockVirDomain) GetJobInfo() (*libvirt_go.DomainJobInfo, error) {
ret := _m.ctrl.Call(_m, "GetJobInfo")
ret0, _ := ret[0].(*libvirt_go.DomainJobInfo)
ret1, _ := ret[1].(error)
return ret0, ret1
}

func (_mr *_MockVirDomainRecorder) GetJobInfo() *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "GetJobInfo")
}

func (_m *MockVirDomain) AbortJob() error {
ret := _m.ctrl.Call(_m, "AbortJob")
ret0, _ := ret[0].(error)
return ret0
}

func (_mr *_MockVirDomainRecorder) AbortJob() *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "AbortJob")
}

func (_m *MockVirDomain) Free() error {
ret := _m.ctrl.Call(_m, "Free")
ret0, _ := ret[0].(error)
Expand Down
3 changes: 3 additions & 0 deletions pkg/virt-launcher/virtwrap/cli/libvirt.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,9 @@ type VirDomain interface {
OpenConsole(devname string, stream *libvirt.Stream, flags libvirt.DomainConsoleFlags) error
MigrateToURI3(string, *libvirt.DomainMigrateParameters, libvirt.DomainMigrateFlags) error
MemoryStats(nrStats uint32, flags uint32) ([]libvirt.DomainMemoryStat, error)
GetJobStats(flags libvirt.DomainGetJobStatsFlags) (*libvirt.DomainJobInfo, error)
GetJobInfo() (*libvirt.DomainJobInfo, error)
AbortJob() error
Free() error
}

Expand Down
Loading

0 comments on commit 629e7a6

Please sign in to comment.