From 56f645eac6a2db58e5d8bff43b01121405cf738d Mon Sep 17 00:00:00 2001 From: Peng Tao Date: Tue, 18 Sep 2018 16:14:32 +0800 Subject: [PATCH] qmp: add ExecuteQueryMigration It sends query-migrate qmp command to check migration status. Signed-off-by: Peng Tao --- qemu/qmp.go | 60 ++++++++++++++++++++++++++++++++++++++++++++++++ qemu/qmp_test.go | 50 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/qemu/qmp.go b/qemu/qmp.go index ea3e97cb10..58cd76709c 100644 --- a/qemu/qmp.go +++ b/qemu/qmp.go @@ -200,6 +200,46 @@ type CPUInfoFast struct { Props CPUProperties `json:"props"` } +// MigrationRAM represents migration ram status +type MigrationRAM struct { + Total int64 `json:"total"` + Remaining int64 `json:"remaining"` + Transferred int64 `json:"transferred"` + TotalTime int64 `json:"total-time"` + SetupTime int64 `json:"setup-time"` + ExpectedDowntime int64 `json:"expected-downtime"` + Duplicate int64 `json:"duplicate"` + Normal int64 `json:"normal"` + NormalBytes int64 `json:"normal-bytes"` + DirtySyncCount int64 `json:"dirty-sync-count"` +} + +// MigrationDisk represents migration disk status +type MigrationDisk struct { + Total int64 `json:"total"` + Remaining int64 `json:"remaining"` + Transferred int64 `json:"transferred"` +} + +// MigrationXbzrleCache represents migration XbzrleCache status +type MigrationXbzrleCache struct { + CacheSize int64 `json:"cache-size"` + Bytes int64 `json:"bytes"` + Pages int64 `json:"pages"` + CacheMiss int64 `json:"cache-miss"` + CacheMissRate int64 `json:"cache-miss-rate"` + Overflow int64 `json:"overflow"` +} + +// MigrationStatus represents migration status of a vm +type MigrationStatus struct { + Status string `json:"status"` + Capabilities []map[string]interface{} `json:"capabilities,omitempty"` + RAM MigrationRAM `json:"ram,omitempty"` + Disk MigrationDisk `json:"disk,omitempty"` + XbzrleCache MigrationXbzrleCache `json:"xbzrle-cache,omitempty"` +} + func (q *QMP) readLoop(fromVMCh chan<- []byte) { scanner := bufio.NewScanner(q.conn) for scanner.Scan() { @@ -1206,3 +1246,23 @@ func (q *QMP) ExecuteVirtSerialPortAdd(ctx context.Context, id, name, chardev st return q.executeCommand(ctx, "device_add", args, nil) } + +// ExecuteQueryMigration queries migration progress. +func (q *QMP) ExecuteQueryMigration(ctx context.Context) (MigrationStatus, error) { + response, err := q.executeCommandWithResponse(ctx, "query-migrate", nil, nil, nil) + if err != nil { + return MigrationStatus{}, err + } + + data, err := json.Marshal(response) + if err != nil { + return MigrationStatus{}, fmt.Errorf("Unable to extract migrate status information: %v", err) + } + + var status MigrationStatus + if err = json.Unmarshal(data, &status); err != nil { + return MigrationStatus{}, fmt.Errorf("Unable to convert migrate status information: %v", err) + } + + return status, nil +} diff --git a/qemu/qmp_test.go b/qemu/qmp_test.go index 8014cbe0c6..6a70d02c62 100644 --- a/qemu/qmp_test.go +++ b/qemu/qmp_test.go @@ -1295,3 +1295,53 @@ func TestExecuteVirtSerialPortAdd(t *testing.T) { q.Shutdown() <-disconnectedCh } + +// Checks migration status +func TestExecuteQueryMigration(t *testing.T) { + connectedCh := make(chan *QMPVersion) + disconnectedCh := make(chan struct{}) + buf := newQMPTestCommandBuffer(t) + status := MigrationStatus{ + Status: "completed", + RAM: MigrationRAM{ + Total: 100, + Remaining: 101, + Transferred: 101, + TotalTime: 101, + SetupTime: 101, + ExpectedDowntime: 101, + Duplicate: 101, + Normal: 101, + NormalBytes: 101, + DirtySyncCount: 101, + }, + Disk: MigrationDisk{ + Total: 200, + Remaining: 200, + Transferred: 200, + }, + XbzrleCache: MigrationXbzrleCache{ + CacheSize: 300, + Bytes: 300, + Pages: 300, + CacheMiss: 300, + CacheMissRate: 300, + Overflow: 300, + }, + } + caps := map[string]interface{}{"foo": true} + status.Capabilities = append(status.Capabilities, caps) + buf.AddCommand("query-migrate", nil, "return", interface{}(status)) + cfg := QMPConfig{Logger: qmpTestLogger{}} + q := startQMPLoop(buf, cfg, connectedCh, disconnectedCh) + checkVersion(t, connectedCh) + s, err := q.ExecuteQueryMigration(context.Background()) + if err != nil { + t.Fatalf("Unexpected error %v", err) + } + if !reflect.DeepEqual(s, status) { + t.Fatalf("expected %v\n got %v", status, s) + } + q.Shutdown() + <-disconnectedCh +}