Statistics
| Branch: | Revision:

root / QMP / qmp.py @ 9bed0d0d

History | View | Annotate | Download (3.7 kB)

1
# QEMU Monitor Protocol Python class
2
# 
3
# Copyright (C) 2009, 2010 Red Hat Inc.
4
#
5
# Authors:
6
#  Luiz Capitulino <lcapitulino@redhat.com>
7
#
8
# This work is licensed under the terms of the GNU GPL, version 2.  See
9
# the COPYING file in the top-level directory.
10

    
11
import json
12
import errno
13
import socket
14

    
15
class QMPError(Exception):
16
    pass
17

    
18
class QMPConnectError(QMPError):
19
    pass
20

    
21
class QMPCapabilitiesError(QMPError):
22
    pass
23

    
24
class QEMUMonitorProtocol:
25
    def __init__(self, address):
26
        """
27
        Create a QEMUMonitorProtocol class.
28

29
        @param address: QEMU address, can be either a unix socket path (string)
30
                        or a tuple in the form ( address, port ) for a TCP
31
                        connection
32
        @note No connection is established, this is done by the connect() method
33
        """
34
        self.__events = []
35
        self.__address = address
36
        self.__sock = self.__get_sock()
37
        self.__sockfile = self.__sock.makefile()
38

    
39
    def __get_sock(self):
40
        if isinstance(self.__address, tuple):
41
            family = socket.AF_INET
42
        else:
43
            family = socket.AF_UNIX
44
        return socket.socket(family, socket.SOCK_STREAM)
45

    
46
    def __json_read(self):
47
        while True:
48
            data = self.__sockfile.readline()
49
            if not data:
50
                return
51
            resp = json.loads(data)
52
            if 'event' in resp:
53
                self.__events.append(resp)
54
                continue
55
            return resp
56

    
57
    error = socket.error
58

    
59
    def connect(self):
60
        """
61
        Connect to the QMP Monitor and perform capabilities negotiation.
62

63
        @return QMP greeting dict
64
        @raise socket.error on socket connection errors
65
        @raise QMPConnectError if the greeting is not received
66
        @raise QMPCapabilitiesError if fails to negotiate capabilities
67
        """
68
        self.__sock.connect(self.__address)
69
        greeting = self.__json_read()
70
        if greeting is None or not greeting.has_key('QMP'):
71
            raise QMPConnectError
72
        # Greeting seems ok, negotiate capabilities
73
        resp = self.cmd('qmp_capabilities')
74
        if "return" in resp:
75
            return greeting
76
        raise QMPCapabilitiesError
77

    
78
    def cmd_obj(self, qmp_cmd):
79
        """
80
        Send a QMP command to the QMP Monitor.
81

82
        @param qmp_cmd: QMP command to be sent as a Python dict
83
        @return QMP response as a Python dict or None if the connection has
84
                been closed
85
        """
86
        try:
87
            self.__sock.sendall(json.dumps(qmp_cmd))
88
        except socket.error, err:
89
            if err[0] == errno.EPIPE:
90
                return
91
            raise socket.error(err)
92
        return self.__json_read()
93

    
94
    def cmd(self, name, args=None, id=None):
95
        """
96
        Build a QMP command and send it to the QMP Monitor.
97

98
        @param name: command name (string)
99
        @param args: command arguments (dict)
100
        @param id: command id (dict, list, string or int)
101
        """
102
        qmp_cmd = { 'execute': name }
103
        if args:
104
            qmp_cmd['arguments'] = args
105
        if id:
106
            qmp_cmd['id'] = id
107
        return self.cmd_obj(qmp_cmd)
108

    
109
    def get_events(self):
110
        """
111
        Get a list of available QMP events.
112
        """
113
        self.__sock.setblocking(0)
114
        try:
115
            self.__json_read()
116
        except socket.error, err:
117
            if err[0] == errno.EAGAIN:
118
                # No data available
119
                pass
120
        self.__sock.setblocking(1)
121
        return self.__events
122

    
123
    def clear_events(self):
124
        """
125
        Clear current list of pending events.
126
        """
127
        self.__events = []
128

    
129
    def close(self):
130
        self.__sock.close()
131
        self.__sockfile.close()