From 79e0d5333d1545898661e5038e08de8a59be3ea1 Mon Sep 17 00:00:00 2001 From: Ning Bo Date: Thu, 1 Aug 2019 09:05:27 +0800 Subject: [PATCH] qmp: support command 'query-qmp-schema' The upper hyervisor manager application maybe need to wait some QMP event to control boot sequence, but the event we wanted maybe not exist in some older version, so we need query all QMP ABI and check the event is supported or not. related: kata-containers/runtime#1918 Signed-off-by: Ning Bo --- qemu/qmp.go | 36 ++++++++++++++++++++++++++++++++++++ qemu/qmp_test.go | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/qemu/qmp.go b/qemu/qmp.go index 2a645ca24f..186f3fadd1 100644 --- a/qemu/qmp.go +++ b/qemu/qmp.go @@ -84,6 +84,9 @@ type QMPConfig struct { // logger is used by the qmpStart function and all the go routines // it spawns to log information. Logger QMPLog + + // specify the capacity of buffer used by receive QMP response. + MaxCapacity int } type qmpEventFilter struct { @@ -242,8 +245,19 @@ type MigrationStatus struct { XbzrleCache MigrationXbzrleCache `json:"xbzrle-cache,omitempty"` } +// SchemaInfo represents all QMP wire ABI +type SchemaInfo struct { + MetaType string `json:"meta-type"` + Name string `json:"name"` +} + func (q *QMP) readLoop(fromVMCh chan<- []byte) { scanner := bufio.NewScanner(q.conn) + if q.cfg.MaxCapacity > 0 { + buffer := make([]byte, q.cfg.MaxCapacity) + scanner.Buffer(buffer, q.cfg.MaxCapacity) + } + for scanner.Scan() { line := scanner.Bytes() if q.cfg.Logger.V(1) { @@ -260,6 +274,7 @@ func (q *QMP) readLoop(fromVMCh chan<- []byte) { fromVMCh <- sendLine } + q.cfg.Logger.Infof("sanner return error: %v", scanner.Err()) close(fromVMCh) } @@ -1509,3 +1524,24 @@ func (q *QMP) ExecuteMigrationIncoming(ctx context.Context, uri string) error { } return q.executeCommand(ctx, "migrate-incoming", args, nil) } + +// ExecQueryQmpSchema query all QMP wire ABI and returns a slice +func (q *QMP) ExecQueryQmpSchema(ctx context.Context) ([]SchemaInfo, error) { + response, err := q.executeCommandWithResponse(ctx, "query-qmp-schema", nil, nil, nil) + if err != nil { + return nil, err + } + + // convert response to json + data, err := json.Marshal(response) + if err != nil { + return nil, fmt.Errorf("unable to extract memory devices information: %v", err) + } + + var schemaInfo []SchemaInfo + if err = json.Unmarshal(data, &schemaInfo); err != nil { + return nil, fmt.Errorf("unable to convert json to schemaInfo: %v", err) + } + + return schemaInfo, nil +} diff --git a/qemu/qmp_test.go b/qemu/qmp_test.go index 11b33a0e05..067665371f 100644 --- a/qemu/qmp_test.go +++ b/qemu/qmp_test.go @@ -1588,3 +1588,38 @@ func TestMainLoopEventBeforeGreeting(t *testing.T) { q.Shutdown() <-disconnectedCh } + +func TestQMPExecQueryQmpSchema(t *testing.T) { + connectedCh := make(chan *QMPVersion) + disconnectedCh := make(chan struct{}) + buf := newQMPTestCommandBuffer(t) + schemaInfo := []SchemaInfo{ + { + MetaType: "command", + Name: "object-add", + }, + { + MetaType: "event", + Name: "VSOCK_RUNNING", + }, + } + buf.AddCommand("query-qmp-schema", nil, "return", schemaInfo) + cfg := QMPConfig{ + Logger: qmpTestLogger{}, + MaxCapacity: 1024, + } + q := startQMPLoop(buf, cfg, connectedCh, disconnectedCh) + checkVersion(t, connectedCh) + info, err := q.ExecQueryQmpSchema(context.Background()) + if err != nil { + t.Fatalf("Unexpected error: %v\n", err) + } + if len(schemaInfo) != 2 { + t.Fatalf("Expected schema infos length equals to 2\n") + } + if reflect.DeepEqual(info, schemaInfo) == false { + t.Fatalf("Expected %v equals to %v\n", info, schemaInfo) + } + q.Shutdown() + <-disconnectedCh +}