Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(166)

Side by Side Diff: client/tests/kvm/kvm_monitor.py

Issue 4823005: Merge remote branch 'cros/upstream' into tempbranch (Closed) Base URL: http://git.chromium.org/git/autotest.git@master
Patch Set: patch Created 10 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « client/tests/kvm/get_started.py ('k') | client/tests/kvm/kvm_preprocessing.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 """ 1 """
2 Interfaces to the QEMU monitor. 2 Interfaces to the QEMU monitor.
3 3
4 @copyright: 2008-2010 Red Hat Inc. 4 @copyright: 2008-2010 Red Hat Inc.
5 """ 5 """
6 6
7 import socket, time, threading, logging 7 import socket, time, threading, logging, select
8 import kvm_utils 8 import kvm_utils
9 try: 9 try:
10 import json 10 import json
11 except ImportError: 11 except ImportError:
12 logging.warning("Could not import json module. " 12 logging.warning("Could not import json module. "
13 "QMP monitor functionality disabled.") 13 "QMP monitor functionality disabled.")
14 14
15 15
16 class MonitorError(Exception): 16 class MonitorError(Exception):
17 pass 17 pass
18 18
19 19
20 class MonitorConnectError(MonitorError): 20 class MonitorConnectError(MonitorError):
21 pass 21 pass
22 22
23 23
24 class MonitorSendError(MonitorError): 24 class MonitorSocketError(MonitorError):
25 pass 25 pass
26 26
27 27
28 class MonitorLockError(MonitorError): 28 class MonitorLockError(MonitorError):
29 pass 29 pass
30 30
31 31
32 class MonitorProtocolError(MonitorError): 32 class MonitorProtocolError(MonitorError):
33 pass 33 pass
34 34
35 35
36 class MonitorNotSupportedError(MonitorError): 36 class MonitorNotSupportedError(MonitorError):
37 pass 37 pass
38 38
39 39
40 class QMPCmdError(MonitorError): 40 class QMPCmdError(MonitorError):
41 pass 41 def __init__(self, cmd, qmp_args, data):
42 MonitorError.__init__(self, cmd, qmp_args, data)
43 self.cmd = cmd
44 self.qmp_args = qmp_args
45 self.data = data
46
47 def __str__(self):
48 return ("QMP command %r failed (arguments: %r, error message: %r)" %
49 (self.cmd, self.qmp_args, self.data))
42 50
43 51
44 class Monitor: 52 class Monitor:
45 """ 53 """
46 Common code for monitor classes. 54 Common code for monitor classes.
47 """ 55 """
48 56
49 def __init__(self, name, filename): 57 def __init__(self, name, filename):
50 """ 58 """
51 Initialize the instance. 59 Initialize the instance.
52 60
53 @param name: Monitor identifier (a string) 61 @param name: Monitor identifier (a string)
54 @param filename: Monitor socket filename 62 @param filename: Monitor socket filename
55 @raise MonitorConnectError: Raised if the connection fails 63 @raise MonitorConnectError: Raised if the connection fails
56 """ 64 """
57 self.name = name 65 self.name = name
58 self.filename = filename 66 self.filename = filename
59 self._lock = threading.RLock() 67 self._lock = threading.RLock()
60 self._socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) 68 self._socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
61 self._socket.setblocking(False)
62 69
63 try: 70 try:
64 self._socket.connect(filename) 71 self._socket.connect(filename)
65 except socket.error: 72 except socket.error:
66 raise MonitorConnectError("Could not connect to monitor socket") 73 raise MonitorConnectError("Could not connect to monitor socket")
67 74
68 75
69 def __del__(self): 76 def __del__(self):
70 # Automatically close the connection when the instance is garbage 77 # Automatically close the connection when the instance is garbage
71 # collected 78 # collected
(...skipping 23 matching lines...) Expand all
95 102
96 def _acquire_lock(self, timeout=20): 103 def _acquire_lock(self, timeout=20):
97 end_time = time.time() + timeout 104 end_time = time.time() + timeout
98 while time.time() < end_time: 105 while time.time() < end_time:
99 if self._lock.acquire(False): 106 if self._lock.acquire(False):
100 return True 107 return True
101 time.sleep(0.05) 108 time.sleep(0.05)
102 return False 109 return False
103 110
104 111
112 def _data_available(self, timeout=0):
113 timeout = max(0, timeout)
114 return bool(select.select([self._socket], [], [], timeout)[0])
115
116
105 def _recvall(self): 117 def _recvall(self):
106 s = "" 118 s = ""
107 while True: 119 while self._data_available():
108 try: 120 try:
109 data = self._socket.recv(1024) 121 data = self._socket.recv(1024)
110 except socket.error: 122 except socket.error, (errno, msg):
111 break 123 raise MonitorSocketError("Could not receive data from monitor "
124 "(%s)" % msg)
112 if not data: 125 if not data:
113 break 126 break
114 s += data 127 s += data
115 return s 128 return s
116 129
117 130
118 class HumanMonitor(Monitor): 131 class HumanMonitor(Monitor):
119 """ 132 """
120 Wraps "human monitor" commands. 133 Wraps "human monitor" commands.
121 """ 134 """
122 135
123 def __init__(self, name, filename, suppress_exceptions=False): 136 def __init__(self, name, filename, suppress_exceptions=False):
124 """ 137 """
125 Connect to the monitor socket and find the (qemu) prompt. 138 Connect to the monitor socket and find the (qemu) prompt.
126 139
127 @param name: Monitor identifier (a string) 140 @param name: Monitor identifier (a string)
128 @param filename: Monitor socket filename 141 @param filename: Monitor socket filename
129 @raise MonitorConnectError: Raised if the connection fails and 142 @raise MonitorConnectError: Raised if the connection fails and
130 suppress_exceptions is False 143 suppress_exceptions is False
131 @raise MonitorProtocolError: Raised if the initial (qemu) prompt isn't 144 @raise MonitorProtocolError: Raised if the initial (qemu) prompt isn't
132 found and suppress_exceptions is False 145 found and suppress_exceptions is False
133 @note: Other exceptions may be raised. See _get_command_output's 146 @note: Other exceptions may be raised. See cmd()'s
134 docstring. 147 docstring.
135 """ 148 """
136 try: 149 try:
137 Monitor.__init__(self, name, filename) 150 Monitor.__init__(self, name, filename)
138 151
139 self.protocol = "human" 152 self.protocol = "human"
140 153
141 # Find the initial (qemu) prompt 154 # Find the initial (qemu) prompt
142 s, o = self._read_up_to_qemu_prompt(20) 155 s, o = self._read_up_to_qemu_prompt(20)
143 if not s: 156 if not s:
144 raise MonitorProtocolError("Could not find (qemu) prompt " 157 raise MonitorProtocolError("Could not find (qemu) prompt "
145 "after connecting to monitor. " 158 "after connecting to monitor. "
146 "Output so far: %r" % o) 159 "Output so far: %r" % o)
147 160
148 # Save the output of 'help' for future use 161 # Save the output of 'help' for future use
149 self._help_str = self._get_command_output("help") 162 self._help_str = self.cmd("help")
150 163
151 except MonitorError, e: 164 except MonitorError, e:
152 if suppress_exceptions: 165 if suppress_exceptions:
153 logging.warn(e) 166 logging.warn(e)
154 else: 167 else:
155 raise 168 raise
156 169
157 170
158 # Private methods 171 # Private methods
159 172
160 def _read_up_to_qemu_prompt(self, timeout=20): 173 def _read_up_to_qemu_prompt(self, timeout=20):
161 o = "" 174 s = ""
162 end_time = time.time() + timeout 175 end_time = time.time() + timeout
163 while time.time() < end_time: 176 while self._data_available(end_time - time.time()):
177 data = self._recvall()
178 if not data:
179 break
180 s += data
164 try: 181 try:
165 data = self._socket.recv(1024) 182 if s.splitlines()[-1].split()[-1] == "(qemu)":
166 if not data: 183 return True, "\n".join(s.splitlines()[:-1])
167 break 184 except IndexError:
168 o += data 185 continue
169 if o.splitlines()[-1].split()[-1] == "(qemu)": 186 return False, "\n".join(s.splitlines())
170 return True, "\n".join(o.splitlines()[:-1])
171 except (socket.error, IndexError):
172 time.sleep(0.01)
173 return False, "\n".join(o.splitlines())
174 187
175 188
176 def _send_command(self, command): 189 def _send(self, cmd):
177 """ 190 """
178 Send a command without waiting for output. 191 Send a command without waiting for output.
179 192
180 @param command: Command to send 193 @param cmd: Command to send
181 @return: True if successful, False otherwise
182 @raise MonitorLockError: Raised if the lock cannot be acquired 194 @raise MonitorLockError: Raised if the lock cannot be acquired
183 @raise MonitorSendError: Raised if the command cannot be sent 195 @raise MonitorSocketError: Raised if a socket error occurs
184 """ 196 """
185 if not self._acquire_lock(20): 197 if not self._acquire_lock(20):
186 raise MonitorLockError("Could not acquire exclusive lock to send " 198 raise MonitorLockError("Could not acquire exclusive lock to send "
187 "monitor command '%s'" % command) 199 "monitor command '%s'" % cmd)
188 200
189 try: 201 try:
190 try: 202 try:
191 self._socket.sendall(command + "\n") 203 self._socket.sendall(cmd + "\n")
192 except socket.error: 204 except socket.error, (errno, msg):
193 raise MonitorSendError("Could not send monitor command '%s'" % 205 raise MonitorSocketError("Could not send monitor command '%s' "
194 command) 206 "(%s)" % (cmd, msg))
195 207
196 finally: 208 finally:
197 self._lock.release() 209 self._lock.release()
198 210
199 211
200 def _get_command_output(self, command, timeout=20): 212 # Public methods
213
214 def cmd(self, command, timeout=20):
201 """ 215 """
202 Send command to the monitor. 216 Send command to the monitor.
203 217
204 @param command: Command to send to the monitor 218 @param command: Command to send to the monitor
205 @param timeout: Time duration to wait for the (qemu) prompt to return 219 @param timeout: Time duration to wait for the (qemu) prompt to return
206 @return: Output received from the monitor 220 @return: Output received from the monitor
207 @raise MonitorLockError: Raised if the lock cannot be acquired 221 @raise MonitorLockError: Raised if the lock cannot be acquired
208 @raise MonitorSendError: Raised if the command cannot be sent 222 @raise MonitorSocketError: Raised if a socket error occurs
209 @raise MonitorProtocolError: Raised if the (qemu) prompt cannot be 223 @raise MonitorProtocolError: Raised if the (qemu) prompt cannot be
210 found after sending the command 224 found after sending the command
211 """ 225 """
212 if not self._acquire_lock(20): 226 if not self._acquire_lock(20):
213 raise MonitorLockError("Could not acquire exclusive lock to send " 227 raise MonitorLockError("Could not acquire exclusive lock to send "
214 "monitor command '%s'" % command) 228 "monitor command '%s'" % command)
215 229
216 try: 230 try:
217 # Read any data that might be available 231 # Read any data that might be available
218 self._recvall() 232 self._recvall()
219 # Send command 233 # Send command
220 self._send_command(command) 234 self._send(command)
221 # Read output 235 # Read output
222 s, o = self._read_up_to_qemu_prompt(timeout) 236 s, o = self._read_up_to_qemu_prompt(timeout)
223 # Remove command echo from output 237 # Remove command echo from output
224 o = "\n".join(o.splitlines()[1:]) 238 o = "\n".join(o.splitlines()[1:])
225 # Report success/failure 239 # Report success/failure
226 if s: 240 if s:
227 return o 241 return o
228 else: 242 else:
229 msg = ("Could not find (qemu) prompt after command '%s'. " 243 msg = ("Could not find (qemu) prompt after command '%s'. "
230 "Output so far: %r" % (command, o)) 244 "Output so far: %r" % (command, o))
231 raise MonitorProtocolError(msg) 245 raise MonitorProtocolError(msg)
232 246
233 finally: 247 finally:
234 self._lock.release() 248 self._lock.release()
235 249
236 250
237 # Public methods
238
239 def is_responsive(self): 251 def is_responsive(self):
240 """ 252 """
241 Make sure the monitor is responsive by sending a command. 253 Make sure the monitor is responsive by sending a command.
242 254
243 @return: True if responsive, False otherwise 255 @return: True if responsive, False otherwise
244 """ 256 """
245 try: 257 try:
246 self._get_command_output("help") 258 self.cmd("info status")
247 return True 259 return True
248 except MonitorError: 260 except MonitorError:
249 return False 261 return False
250 262
251 263
252 # Command wrappers 264 # Command wrappers
253 # Notes: 265 # Notes:
254 # - All of the following commands raise exceptions in a similar manner to 266 # - All of the following commands raise exceptions in a similar manner to
255 # cmd() and _get_command_output(). 267 # cmd().
256 # - A command wrapper should use self._help_str if it requires information 268 # - A command wrapper should use self._help_str if it requires information
257 # about the monitor's capabilities. 269 # about the monitor's capabilities.
258 270
259 def cmd(self, command, timeout=20):
260 """
261 Send a simple command with no parameters and return its output.
262 Should only be used for commands that take no parameters and are
263 implemented under the same name for both the human and QMP monitors.
264
265 @param command: Command to send
266 @param timeout: Time duration to wait for (qemu) prompt after command
267 @return: The output of the command
268 @raise MonitorLockError: Raised if the lock cannot be acquired
269 @raise MonitorSendError: Raised if the command cannot be sent
270 @raise MonitorProtocolError: Raised if the (qemu) prompt cannot be
271 found after sending the command
272 """
273 return self._get_command_output(command, timeout)
274
275
276 def quit(self): 271 def quit(self):
277 """ 272 """
278 Send "quit" without waiting for output. 273 Send "quit" without waiting for output.
279 """ 274 """
280 self._send_command("quit") 275 self._send("quit")
281 276
282 277
283 def info(self, what): 278 def info(self, what):
284 """ 279 """
285 Request info about something and return the output. 280 Request info about something and return the output.
286 """ 281 """
287 return self._get_command_output("info %s" % what) 282 return self.cmd("info %s" % what)
288 283
289 284
290 def query(self, what): 285 def query(self, what):
291 """ 286 """
292 Alias for info. 287 Alias for info.
293 """ 288 """
294 return self.info(what) 289 return self.info(what)
295 290
296 291
297 def screendump(self, filename): 292 def screendump(self, filename):
298 """ 293 """
299 Request a screendump. 294 Request a screendump.
300 295
301 @param filename: Location for the screendump 296 @param filename: Location for the screendump
302 @return: The command's output 297 @return: The command's output
303 """ 298 """
304 return self._get_command_output("screendump %s" % filename) 299 return self.cmd("screendump %s" % filename)
305 300
306 301
307 def migrate(self, uri, full_copy=False, incremental_copy=False, wait=False): 302 def migrate(self, uri, full_copy=False, incremental_copy=False, wait=False):
308 """ 303 """
309 Migrate. 304 Migrate.
310 305
311 @param uri: destination URI 306 @param uri: destination URI
312 @param full_copy: If true, migrate with full disk copy 307 @param full_copy: If true, migrate with full disk copy
313 @param incremental_copy: If true, migrate with incremental disk copy 308 @param incremental_copy: If true, migrate with incremental disk copy
314 @param wait: If true, wait for completion 309 @param wait: If true, wait for completion
315 @return: The command's output 310 @return: The command's output
316 """ 311 """
317 logging.debug("Migrating to: %s" % uri) 312 logging.debug("Migrating to: %s" % uri)
318 cmd = "migrate" 313 cmd = "migrate"
319 if not wait: 314 if not wait:
320 cmd += " -d" 315 cmd += " -d"
321 if full_copy: 316 if full_copy:
322 cmd += " -b" 317 cmd += " -b"
323 if incremental_copy: 318 if incremental_copy:
324 cmd += " -i" 319 cmd += " -i"
325 cmd += " %s" % uri 320 cmd += " %s" % uri
326 return self._get_command_output(cmd) 321 return self.cmd(cmd)
327 322
328 323
329 def migrate_set_speed(self, value): 324 def migrate_set_speed(self, value):
330 """ 325 """
331 Set maximum speed (in bytes/sec) for migrations. 326 Set maximum speed (in bytes/sec) for migrations.
332 327
333 @param value: Speed in bytes/sec 328 @param value: Speed in bytes/sec
334 @return: The command's output 329 @return: The command's output
335 """ 330 """
336 return self._get_command_output("migrate_set_speed %s" % value) 331 return self.cmd("migrate_set_speed %s" % value)
337 332
338 333
339 def sendkey(self, keystr, hold_time=1): 334 def sendkey(self, keystr, hold_time=1):
340 """ 335 """
341 Send key combination to VM. 336 Send key combination to VM.
342 337
343 @param keystr: Key combination string 338 @param keystr: Key combination string
344 @param hold_time: Hold time in ms (should normally stay 1 ms) 339 @param hold_time: Hold time in ms (should normally stay 1 ms)
345 @return: The command's output 340 @return: The command's output
346 """ 341 """
347 return self._get_command_output("sendkey %s %s" % (keystr, hold_time)) 342 return self.cmd("sendkey %s %s" % (keystr, hold_time))
348 343
349 344
350 def mouse_move(self, dx, dy): 345 def mouse_move(self, dx, dy):
351 """ 346 """
352 Move mouse. 347 Move mouse.
353 348
354 @param dx: X amount 349 @param dx: X amount
355 @param dy: Y amount 350 @param dy: Y amount
356 @return: The command's output 351 @return: The command's output
357 """ 352 """
358 return self._get_command_output("mouse_move %d %d" % (dx, dy)) 353 return self.cmd("mouse_move %d %d" % (dx, dy))
359 354
360 355
361 def mouse_button(self, state): 356 def mouse_button(self, state):
362 """ 357 """
363 Set mouse button state. 358 Set mouse button state.
364 359
365 @param state: Button state (1=L, 2=M, 4=R) 360 @param state: Button state (1=L, 2=M, 4=R)
366 @return: The command's output 361 @return: The command's output
367 """ 362 """
368 return self._get_command_output("mouse_button %d" % state) 363 return self.cmd("mouse_button %d" % state)
369 364
370 365
371 class QMPMonitor(Monitor): 366 class QMPMonitor(Monitor):
372 """ 367 """
373 Wraps QMP monitor commands. 368 Wraps QMP monitor commands.
374 """ 369 """
375 370
376 def __init__(self, name, filename, suppress_exceptions=False): 371 def __init__(self, name, filename, suppress_exceptions=False):
377 """ 372 """
378 Connect to the monitor socket, read the greeting message and issue the 373 Connect to the monitor socket, read the greeting message and issue the
379 qmp_capabilities command. Also make sure the json module is available. 374 qmp_capabilities command. Also make sure the json module is available.
380 375
381 @param name: Monitor identifier (a string) 376 @param name: Monitor identifier (a string)
382 @param filename: Monitor socket filename 377 @param filename: Monitor socket filename
383 @raise MonitorConnectError: Raised if the connection fails and 378 @raise MonitorConnectError: Raised if the connection fails and
384 suppress_exceptions is False 379 suppress_exceptions is False
385 @raise MonitorProtocolError: Raised if the no QMP greeting message is 380 @raise MonitorProtocolError: Raised if the no QMP greeting message is
386 received and suppress_exceptions is False 381 received and suppress_exceptions is False
387 @raise MonitorNotSupportedError: Raised if json isn't available and 382 @raise MonitorNotSupportedError: Raised if json isn't available and
388 suppress_exceptions is False 383 suppress_exceptions is False
389 @note: Other exceptions may be raised if the qmp_capabilities command 384 @note: Other exceptions may be raised if the qmp_capabilities command
390 fails. See _get_command_output's docstring. 385 fails. See cmd()'s docstring.
391 """ 386 """
392 try: 387 try:
393 Monitor.__init__(self, name, filename) 388 Monitor.__init__(self, name, filename)
394 389
395 self.protocol = "qmp" 390 self.protocol = "qmp"
396 self._greeting = None 391 self._greeting = None
397 self._events = [] 392 self._events = []
398 393
399 # Make sure json is available 394 # Make sure json is available
400 try: 395 try:
401 json 396 json
402 except NameError: 397 except NameError:
403 raise MonitorNotSupportedError("QMP requires the json module " 398 raise MonitorNotSupportedError("QMP requires the json module "
404 "(Python 2.6 and up)") 399 "(Python 2.6 and up)")
405 400
406 # Read greeting message 401 # Read greeting message
407 end_time = time.time() + 20 402 end_time = time.time() + 20
408 while time.time() < end_time: 403 while time.time() < end_time:
409 for obj in self._read_objects(): 404 for obj in self._read_objects():
410 if "QMP" in obj: 405 if "QMP" in obj:
411 self._greeting = obj["QMP"] 406 self._greeting = obj
412 break 407 break
413 if self._greeting: 408 if self._greeting:
414 break 409 break
415 time.sleep(0.1) 410 time.sleep(0.1)
416 else: 411 else:
417 raise MonitorProtocolError("No QMP greeting message received") 412 raise MonitorProtocolError("No QMP greeting message received")
418 413
419 # Issue qmp_capabilities 414 # Issue qmp_capabilities
420 self._get_command_output("qmp_capabilities") 415 self.cmd("qmp_capabilities")
421 416
422 except MonitorError, e: 417 except MonitorError, e:
423 if suppress_exceptions: 418 if suppress_exceptions:
424 logging.warn(e) 419 logging.warn(e)
425 else: 420 else:
426 raise 421 raise
427 422
428 423
429 # Private methods 424 # Private methods
430 425
431 def _build_cmd(self, cmd, args=None, id=None): 426 def _build_cmd(self, cmd, args=None, id=None):
432 obj = {"execute": cmd} 427 obj = {"execute": cmd}
433 if args is not None: 428 if args is not None:
434 obj["arguments"] = args 429 obj["arguments"] = args
435 if id is not None: 430 if id is not None:
436 obj["id"] = id 431 obj["id"] = id
437 return obj 432 return obj
438 433
439 434
440 def _read_objects(self, timeout=5): 435 def _read_objects(self, timeout=5):
441 """ 436 """
442 Read lines from monitor and try to decode them. 437 Read lines from the monitor and try to decode them.
443 Stop when all available lines have been successfully decoded, or when 438 Stop when all available lines have been successfully decoded, or when
444 timeout expires. If any decoded objects are asynchronous events, store 439 timeout expires. If any decoded objects are asynchronous events, store
445 them in self._events. Return all decoded objects. 440 them in self._events. Return all decoded objects.
446 441
447 @param timeout: Time to wait for all lines to decode successfully 442 @param timeout: Time to wait for all lines to decode successfully
448 @return: A list of objects 443 @return: A list of objects
449 """ 444 """
445 if not self._data_available():
446 return []
450 s = "" 447 s = ""
451 objs = []
452 end_time = time.time() + timeout 448 end_time = time.time() + timeout
453 while time.time() < end_time: 449 while self._data_available(end_time - time.time()):
454 s += self._recvall() 450 s += self._recvall()
451 # Make sure all lines are decodable
455 for line in s.splitlines(): 452 for line in s.splitlines():
456 if not line: 453 if line:
457 continue 454 try:
458 try: 455 json.loads(line)
459 obj = json.loads(line) 456 except:
460 except: 457 # Found an incomplete or broken line -- keep reading
461 # Found an incomplete or broken line -- keep reading 458 break
462 break
463 objs += [obj]
464 else: 459 else:
465 # All lines are OK -- stop reading 460 # All lines are OK -- stop reading
466 break 461 break
467 time.sleep(0.1) 462 # Decode all decodable lines
463 objs = []
464 for line in s.splitlines():
465 try:
466 objs += [json.loads(line)]
467 except:
468 pass
468 # Keep track of asynchronous events 469 # Keep track of asynchronous events
469 self._events += [obj for obj in objs if "event" in obj] 470 self._events += [obj for obj in objs if "event" in obj]
470 return objs 471 return objs
471 472
472 473
473 def _send_command(self, cmd, args=None, id=None): 474 def _send(self, data):
474 """ 475 """
475 Send command without waiting for response. 476 Send raw data without waiting for response.
476 477
477 @param cmd: Command to send 478 @param data: Data to send
478 @param args: A dict containing command arguments, or None 479 @raise MonitorSocketError: Raised if a socket error occurs
479 @raise MonitorLockError: Raised if the lock cannot be acquired
480 @raise MonitorSendError: Raised if the command cannot be sent
481 """ 480 """
482 if not self._acquire_lock(20):
483 raise MonitorLockError("Could not acquire exclusive lock to send "
484 "QMP command '%s'" % cmd)
485
486 try: 481 try:
487 cmdobj = self._build_cmd(cmd, args, id) 482 self._socket.sendall(data)
488 try: 483 except socket.error, (errno, msg):
489 self._socket.sendall(json.dumps(cmdobj) + "\n") 484 raise MonitorSocketError("Could not send data: %r (%s)" %
490 except socket.error: 485 (data, msg))
491 raise MonitorSendError("Could not send QMP command '%s'" % cmd)
492
493 finally:
494 self._lock.release()
495 486
496 487
497 def _get_command_output(self, cmd, args=None, timeout=20): 488 def _get_response(self, id=None, timeout=20):
498 """ 489 """
499 Send monitor command and wait for response. 490 Read a response from the QMP monitor.
491
492 @param id: If not None, look for a response with this id
493 @param timeout: Time duration to wait for response
494 @return: The response dict, or None if none was found
495 """
496 end_time = time.time() + timeout
497 while self._data_available(end_time - time.time()):
498 for obj in self._read_objects():
499 if isinstance(obj, dict):
500 if id is not None and obj.get("id") != id:
501 continue
502 if "return" in obj or "error" in obj:
503 return obj
504
505
506 # Public methods
507
508 def cmd(self, cmd, args=None, timeout=20):
509 """
510 Send a QMP monitor command and return the response.
511
512 Note: an id is automatically assigned to the command and the response
513 is checked for the presence of the same id.
500 514
501 @param cmd: Command to send 515 @param cmd: Command to send
502 @param args: A dict containing command arguments, or None 516 @param args: A dict containing command arguments, or None
503 @param timeout: Time duration to wait for response 517 @param timeout: Time duration to wait for response
504 @return: The response received 518 @return: The response received
505 @raise MonitorLockError: Raised if the lock cannot be acquired 519 @raise MonitorLockError: Raised if the lock cannot be acquired
506 @raise MonitorSendError: Raised if the command cannot be sent 520 @raise MonitorSocketError: Raised if a socket error occurs
507 @raise MonitorProtocolError: Raised if no response is received 521 @raise MonitorProtocolError: Raised if no response is received
508 @raise QMPCmdError: Raised if the response is an error message 522 @raise QMPCmdError: Raised if the response is an error message
509 (the exception's args are (msg, data) where msg is a string and 523 (the exception's args are (cmd, args, data) where data is the
510 data is the error data) 524 error data)
511 """ 525 """
512 if not self._acquire_lock(20): 526 if not self._acquire_lock(20):
513 raise MonitorLockError("Could not acquire exclusive lock to send " 527 raise MonitorLockError("Could not acquire exclusive lock to send "
514 "QMP command '%s'" % cmd) 528 "QMP command '%s'" % cmd)
515 529
516 try: 530 try:
517 # Read any data that might be available 531 # Read any data that might be available
518 self._read_objects() 532 self._read_objects()
519 # Send command 533 # Send command
520 id = kvm_utils.generate_random_string(8) 534 id = kvm_utils.generate_random_string(8)
521 self._send_command(cmd, args, id) 535 self._send(json.dumps(self._build_cmd(cmd, args, id)) + "\n")
522 # Read response 536 # Read response
523 end_time = time.time() + timeout 537 r = self._get_response(id, timeout)
524 while time.time() < end_time: 538 if r is None:
525 for obj in self._read_objects(): 539 raise MonitorProtocolError("Received no response to QMP "
526 if isinstance(obj, dict) and obj.get("id") == id: 540 "command '%s', or received a "
527 if "return" in obj: 541 "response with an incorrect id"
528 return obj["return"] 542 % cmd)
529 elif "error" in obj: 543 if "return" in r:
530 raise QMPCmdError("QMP command '%s' failed" % cmd, 544 return r["return"]
531 obj["error"]) 545 if "error" in r:
532 time.sleep(0.1) 546 raise QMPCmdError(cmd, args, r["error"])
533 # No response found
534 raise MonitorProtocolError("Received no response to QMP command "
535 "'%s', or received a response with an "
536 "incorrect id" % cmd)
537 547
538 finally: 548 finally:
539 self._lock.release() 549 self._lock.release()
540 550
541 551
542 # Public methods 552 def cmd_raw(self, data, timeout=20):
553 """
554 Send a raw string to the QMP monitor and return the response.
555 Unlike cmd(), return the raw response dict without performing any
556 checks on it.
557
558 @param data: The data to send
559 @param timeout: Time duration to wait for response
560 @return: The response received
561 @raise MonitorLockError: Raised if the lock cannot be acquired
562 @raise MonitorSocketError: Raised if a socket error occurs
563 @raise MonitorProtocolError: Raised if no response is received
564 """
565 if not self._acquire_lock(20):
566 raise MonitorLockError("Could not acquire exclusive lock to send "
567 "data: %r" % data)
568
569 try:
570 self._read_objects()
571 self._send(data)
572 r = self._get_response(None, timeout)
573 if r is None:
574 raise MonitorProtocolError("Received no response to data: %r" %
575 data)
576 return r
577
578 finally:
579 self._lock.release()
580
581
582 def cmd_obj(self, obj, timeout=20):
583 """
584 Transform a Python object to JSON, send the resulting string to the QMP
585 monitor, and return the response.
586 Unlike cmd(), return the raw response dict without performing any
587 checks on it.
588
589 @param obj: The object to send
590 @param timeout: Time duration to wait for response
591 @return: The response received
592 @raise MonitorLockError: Raised if the lock cannot be acquired
593 @raise MonitorSocketError: Raised if a socket error occurs
594 @raise MonitorProtocolError: Raised if no response is received
595 """
596 return self.cmd_raw(json.dumps(obj) + "\n")
597
598
599 def cmd_qmp(self, cmd, args=None, id=None, timeout=20):
600 """
601 Build a QMP command from the passed arguments, send it to the monitor
602 and return the response.
603 Unlike cmd(), return the raw response dict without performing any
604 checks on it.
605
606 @param cmd: Command to send
607 @param args: A dict containing command arguments, or None
608 @param id: An id for the command, or None
609 @param timeout: Time duration to wait for response
610 @return: The response received
611 @raise MonitorLockError: Raised if the lock cannot be acquired
612 @raise MonitorSocketError: Raised if a socket error occurs
613 @raise MonitorProtocolError: Raised if no response is received
614 """
615 return self.cmd_obj(self._build_cmd(cmd, args, id), timeout)
616
543 617
544 def is_responsive(self): 618 def is_responsive(self):
545 """ 619 """
546 Make sure the monitor is responsive by sending a command. 620 Make sure the monitor is responsive by sending a command.
547 621
548 @return: True if responsive, False otherwise 622 @return: True if responsive, False otherwise
549 """ 623 """
550 try: 624 try:
551 self._get_command_output("query-version") 625 self.cmd("query-status")
552 return True 626 return True
553 except MonitorError: 627 except MonitorError:
554 return False 628 return False
555 629
556 630
557 def get_events(self): 631 def get_events(self):
558 """ 632 """
559 Return a list of the asynchronous events received since the last 633 Return a list of the asynchronous events received since the last
560 clear_events() call. 634 clear_events() call.
561 635
(...skipping 28 matching lines...) Expand all
590 664
591 @raise MonitorLockError: Raised if the lock cannot be acquired 665 @raise MonitorLockError: Raised if the lock cannot be acquired
592 """ 666 """
593 if not self._acquire_lock(20): 667 if not self._acquire_lock(20):
594 raise MonitorLockError("Could not acquire exclusive lock to clear " 668 raise MonitorLockError("Could not acquire exclusive lock to clear "
595 "QMP event list") 669 "QMP event list")
596 self._events = [] 670 self._events = []
597 self._lock.release() 671 self._lock.release()
598 672
599 673
674 def get_greeting(self):
675 """
676 Return QMP greeting message.
677 """
678 return self._greeting
679
680
600 # Command wrappers 681 # Command wrappers
601 # Note: all of the following functions raise exceptions in a similar manner 682 # Note: all of the following functions raise exceptions in a similar manner
602 # to cmd() and _get_command_output(). 683 # to cmd().
603
604 def cmd(self, command, timeout=20):
605 """
606 Send a simple command with no parameters and return its output.
607 Should only be used for commands that take no parameters and are
608 implemented under the same name for both the human and QMP monitors.
609
610 @param command: Command to send
611 @param timeout: Time duration to wait for response
612 @return: The response to the command
613 @raise MonitorLockError: Raised if the lock cannot be acquired
614 @raise MonitorSendError: Raised if the command cannot be sent
615 @raise MonitorProtocolError: Raised if no response is received
616 """
617 return self._get_command_output(command, timeout=timeout)
618
619 684
620 def quit(self): 685 def quit(self):
621 """ 686 """
622 Send "quit" and return the response. 687 Send "quit" and return the response.
623 """ 688 """
624 return self._get_command_output("quit") 689 return self.cmd("quit")
625 690
626 691
627 def info(self, what): 692 def info(self, what):
628 """ 693 """
629 Request info about something and return the response. 694 Request info about something and return the response.
630 """ 695 """
631 return self._get_command_output("query-%s" % what) 696 return self.cmd("query-%s" % what)
632 697
633 698
634 def query(self, what): 699 def query(self, what):
635 """ 700 """
636 Alias for info. 701 Alias for info.
637 """ 702 """
638 return self.info(what) 703 return self.info(what)
639 704
640 705
641 def screendump(self, filename): 706 def screendump(self, filename):
642 """ 707 """
643 Request a screendump. 708 Request a screendump.
644 709
645 @param filename: Location for the screendump 710 @param filename: Location for the screendump
646 @return: The response to the command 711 @return: The response to the command
647 """ 712 """
648 args = {"filename": filename} 713 args = {"filename": filename}
649 return self._get_command_output("screendump", args) 714 return self.cmd("screendump", args)
650 715
651 716
652 def migrate(self, uri, full_copy=False, incremental_copy=False, wait=False): 717 def migrate(self, uri, full_copy=False, incremental_copy=False, wait=False):
653 """ 718 """
654 Migrate. 719 Migrate.
655 720
656 @param uri: destination URI 721 @param uri: destination URI
657 @param full_copy: If true, migrate with full disk copy 722 @param full_copy: If true, migrate with full disk copy
658 @param incremental_copy: If true, migrate with incremental disk copy 723 @param incremental_copy: If true, migrate with incremental disk copy
659 @param wait: If true, wait for completion 724 @param wait: If true, wait for completion
660 @return: The response to the command 725 @return: The response to the command
661 """ 726 """
662 args = {"uri": uri, 727 args = {"uri": uri,
663 "blk": full_copy, 728 "blk": full_copy,
664 "inc": incremental_copy} 729 "inc": incremental_copy}
665 return self._get_command_output("migrate", args) 730 return self.cmd("migrate", args)
666 731
667 732
668 def migrate_set_speed(self, value): 733 def migrate_set_speed(self, value):
669 """ 734 """
670 Set maximum speed (in bytes/sec) for migrations. 735 Set maximum speed (in bytes/sec) for migrations.
671 736
672 @param value: Speed in bytes/sec 737 @param value: Speed in bytes/sec
673 @return: The response to the command 738 @return: The response to the command
674 """ 739 """
675 args = {"value": value} 740 args = {"value": value}
676 return self._get_command_output("migrate_set_speed", args) 741 return self.cmd("migrate_set_speed", args)
OLDNEW
« no previous file with comments | « client/tests/kvm/get_started.py ('k') | client/tests/kvm/kvm_preprocessing.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698