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 +}