qemu: Add functions to process QMP response

Some QMP commands like ```query-hotpluggable-cpus``` returns a
response that needs to be processed and returned to the client as
a struct. This patch adds the function ```executeCommandWithResponse```
that returns the response of a QMP command.

Signed-off-by: Julio Montes <julio.montes@intel.com>
This commit is contained in:
Julio Montes 2017-12-07 10:59:20 -06:00
parent e39da6ca47
commit 24b14059b3

28
qmp.go
View File

@ -107,6 +107,7 @@ type QMPEvent struct {
} }
type qmpResult struct { type qmpResult struct {
response interface{}
err error err error
} }
@ -203,14 +204,14 @@ func (q *QMP) processQMPEvent(cmdQueue *list.List, name interface{}, data interf
} }
} }
func (q *QMP) finaliseCommand(cmdEl *list.Element, cmdQueue *list.List, succeeded bool) { func (q *QMP) finaliseCommandWithResponse(cmdEl *list.Element, cmdQueue *list.List, succeeded bool, response interface{}) {
cmd := cmdEl.Value.(*qmpCommand) cmd := cmdEl.Value.(*qmpCommand)
cmdQueue.Remove(cmdEl) cmdQueue.Remove(cmdEl)
select { select {
case <-cmd.ctx.Done(): case <-cmd.ctx.Done():
default: default:
if succeeded { if succeeded {
cmd.res <- qmpResult{} cmd.res <- qmpResult{response: response}
} else { } else {
cmd.res <- qmpResult{err: fmt.Errorf("QMP command failed")} cmd.res <- qmpResult{err: fmt.Errorf("QMP command failed")}
} }
@ -220,6 +221,10 @@ func (q *QMP) finaliseCommand(cmdEl *list.Element, cmdQueue *list.List, succeede
} }
} }
func (q *QMP) finaliseCommand(cmdEl *list.Element, cmdQueue *list.List, succeeded bool) {
q.finaliseCommandWithResponse(cmdEl, cmdQueue, succeeded, nil)
}
func (q *QMP) processQMPInput(line []byte, cmdQueue *list.List) { func (q *QMP) processQMPInput(line []byte, cmdQueue *list.List) {
var vmData map[string]interface{} var vmData map[string]interface{}
err := json.Unmarshal(line, &vmData) err := json.Unmarshal(line, &vmData)
@ -233,7 +238,7 @@ func (q *QMP) processQMPInput(line []byte, cmdQueue *list.List) {
return return
} }
_, succeeded := vmData["return"] response, succeeded := vmData["return"]
_, failed := vmData["error"] _, failed := vmData["error"]
if !succeeded && !failed { if !succeeded && !failed {
@ -248,7 +253,7 @@ func (q *QMP) processQMPInput(line []byte, cmdQueue *list.List) {
} }
cmd := cmdEl.Value.(*qmpCommand) cmd := cmdEl.Value.(*qmpCommand)
if failed || cmd.filter == nil { if failed || cmd.filter == nil {
q.finaliseCommand(cmdEl, cmdQueue, succeeded) q.finaliseCommandWithResponse(cmdEl, cmdQueue, succeeded, response)
} else { } else {
cmd.resultReceived = true cmd.resultReceived = true
} }
@ -463,9 +468,10 @@ func startQMPLoop(conn io.ReadWriteCloser, cfg QMPConfig,
return q return q
} }
func (q *QMP) executeCommand(ctx context.Context, name string, args map[string]interface{}, func (q *QMP) executeCommandWithResponse(ctx context.Context, name string, args map[string]interface{},
filter *qmpEventFilter) error { filter *qmpEventFilter) (interface{}, error) {
var err error var err error
var response interface{}
resCh := make(chan qmpResult) resCh := make(chan qmpResult)
select { select {
case <-q.disconnectedCh: case <-q.disconnectedCh:
@ -480,16 +486,24 @@ func (q *QMP) executeCommand(ctx context.Context, name string, args map[string]i
} }
if err != nil { if err != nil {
return err return response, err
} }
select { select {
case res := <-resCh: case res := <-resCh:
err = res.err err = res.err
response = res.response
case <-ctx.Done(): case <-ctx.Done():
err = ctx.Err() err = ctx.Err()
} }
return response, err
}
func (q *QMP) executeCommand(ctx context.Context, name string, args map[string]interface{},
filter *qmpEventFilter) error {
_, err := q.executeCommandWithResponse(ctx, name, args, filter)
return err return err
} }