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

Side by Side Diff: client/virt/kvm_vm.py

Issue 6883246: Merge autotest upstream from @5318 ~ @5336 (Closed) Base URL: ssh://gitrw.chromium.org:9222/autotest.git@master
Patch Set: patch Created 9 years, 7 months 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/virt/kvm_monitor.py ('k') | client/virt/ppm_utils.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 #!/usr/bin/python 1 #!/usr/bin/python
2 """ 2 """
3 Utility classes and functions to handle Virtual Machine creation using qemu. 3 Utility classes and functions to handle Virtual Machine creation using qemu.
4 4
5 @copyright: 2008-2009 Red Hat Inc. 5 @copyright: 2008-2009 Red Hat Inc.
6 """ 6 """
7 7
8 import time, os, logging, fcntl, re, commands, glob 8 import time, os, logging, fcntl, re, commands, glob
9 import kvm_utils, kvm_subprocess, kvm_monitor
10 from autotest_lib.client.common_lib import error 9 from autotest_lib.client.common_lib import error
11 from autotest_lib.client.bin import utils 10 from autotest_lib.client.bin import utils
11 import virt_utils, virt_vm, kvm_monitor, aexpect
12 12
13 13
14 class VMError(Exception): 14 class VM(virt_vm.BaseVM):
15 pass
16
17
18 class VMCreateError(VMError):
19 def __init__(self, cmd, status, output):
20 VMError.__init__(self, cmd, status, output)
21 self.cmd = cmd
22 self.status = status
23 self.output = output
24
25 def __str__(self):
26 return ("VM creation command failed: %r (status: %s, "
27 "output: %r)" % (self.cmd, self.status, self.output))
28
29
30 class VMHashMismatchError(VMError):
31 def __init__(self, actual, expected):
32 VMError.__init__(self, actual, expected)
33 self.actual_hash = actual
34 self.expected_hash = expected
35
36 def __str__(self):
37 return ("CD image hash (%s) differs from expected one (%s)" %
38 (self.actual_hash, self.expected_hash))
39
40
41 class VMImageMissingError(VMError):
42 def __init__(self, filename):
43 VMError.__init__(self, filename)
44 self.filename = filename
45
46 def __str__(self):
47 return "CD image file not found: %r" % self.filename
48
49
50 class VMImageCheckError(VMError):
51 def __init__(self, filename):
52 VMError.__init__(self, filename)
53 self.filename = filename
54
55 def __str__(self):
56 return "Errors found on image: %r" % self.filename
57
58
59 class VMBadPATypeError(VMError):
60 def __init__(self, pa_type):
61 VMError.__init__(self, pa_type)
62 self.pa_type = pa_type
63
64 def __str__(self):
65 return "Unsupported PCI assignable type: %r" % self.pa_type
66
67
68 class VMPAError(VMError):
69 def __init__(self, pa_type):
70 VMError.__init__(self, pa_type)
71 self.pa_type = pa_type
72
73 def __str__(self):
74 return ("No PCI assignable devices could be assigned "
75 "(pci_assignable=%r)" % self.pa_type)
76
77
78 class VMPostCreateError(VMError):
79 def __init__(self, cmd, output):
80 VMError.__init__(self, cmd, output)
81 self.cmd = cmd
82 self.output = output
83
84
85 class VMHugePageError(VMPostCreateError):
86 def __str__(self):
87 return ("Cannot allocate hugepage memory (command: %r, "
88 "output: %r)" % (self.cmd, self.output))
89
90
91 class VMKVMInitError(VMPostCreateError):
92 def __str__(self):
93 return ("Cannot initialize KVM (command: %r, output: %r)" %
94 (self.cmd, self.output))
95
96
97 class VMDeadError(VMError):
98 def __init__(self, status, output):
99 VMError.__init__(self, status, output)
100 self.status = status
101 self.output = output
102
103 def __str__(self):
104 return ("VM process is dead (status: %s, output: %r)" %
105 (self.status, self.output))
106
107
108 class VMDeadKernelCrashError(VMError):
109 def __init__(self, kernel_crash):
110 VMError.__init__(self, kernel_crash)
111 self.kernel_crash = kernel_crash
112
113 def __str__(self):
114 return ("VM is dead due to a kernel crash:\n%s" % self.kernel_crash)
115
116
117 class VMAddressError(VMError):
118 pass
119
120
121 class VMPortNotRedirectedError(VMAddressError):
122 def __init__(self, port):
123 VMAddressError.__init__(self, port)
124 self.port = port
125
126 def __str__(self):
127 return "Port not redirected: %s" % self.port
128
129
130 class VMAddressVerificationError(VMAddressError):
131 def __init__(self, mac, ip):
132 VMAddressError.__init__(self, mac, ip)
133 self.mac = mac
134 self.ip = ip
135
136 def __str__(self):
137 return ("Cannot verify MAC-IP address mapping using arping: "
138 "%s ---> %s" % (self.mac, self.ip))
139
140
141 class VMMACAddressMissingError(VMAddressError):
142 def __init__(self, nic_index):
143 VMAddressError.__init__(self, nic_index)
144 self.nic_index = nic_index
145
146 def __str__(self):
147 return "No MAC address defined for NIC #%s" % self.nic_index
148
149
150 class VMIPAddressMissingError(VMAddressError):
151 def __init__(self, mac):
152 VMAddressError.__init__(self, mac)
153 self.mac = mac
154
155 def __str__(self):
156 return "Cannot find IP address for MAC address %s" % self.mac
157
158
159 class VMMigrateError(VMError):
160 pass
161
162
163 class VMMigrateTimeoutError(VMMigrateError):
164 pass
165
166
167 class VMMigrateCancelError(VMMigrateError):
168 pass
169
170
171 class VMMigrateFailedError(VMMigrateError):
172 pass
173
174
175 class VMMigrateStateMismatchError(VMMigrateError):
176 def __init__(self, src_hash, dst_hash):
177 VMMigrateError.__init__(self, src_hash, dst_hash)
178 self.src_hash = src_hash
179 self.dst_hash = dst_hash
180
181 def __str__(self):
182 return ("Mismatch of VM state before and after migration (%s != %s)" %
183 (self.src_hash, self.dst_hash))
184
185
186 class VMRebootError(VMError):
187 pass
188
189
190 def get_image_filename(params, root_dir):
191 """
192 Generate an image path from params and root_dir.
193
194 @param params: Dictionary containing the test parameters.
195 @param root_dir: Base directory for relative filenames.
196
197 @note: params should contain:
198 image_name -- the name of the image file, without extension
199 image_format -- the format of the image (qcow2, raw etc)
200 """
201 image_name = params.get("image_name", "image")
202 image_format = params.get("image_format", "qcow2")
203 if params.get("image_raw_device") == "yes":
204 return image_name
205 image_filename = "%s.%s" % (image_name, image_format)
206 image_filename = kvm_utils.get_path(root_dir, image_filename)
207 return image_filename
208
209
210 def create_image(params, root_dir):
211 """
212 Create an image using qemu_image.
213
214 @param params: Dictionary containing the test parameters.
215 @param root_dir: Base directory for relative filenames.
216
217 @note: params should contain:
218 image_name -- the name of the image file, without extension
219 image_format -- the format of the image (qcow2, raw etc)
220 image_size -- the requested size of the image (a string
221 qemu-img can understand, such as '10G')
222 """
223 qemu_img_cmd = kvm_utils.get_path(root_dir, params.get("qemu_img_binary",
224 "qemu-img"))
225 qemu_img_cmd += " create"
226
227 format = params.get("image_format", "qcow2")
228 qemu_img_cmd += " -f %s" % format
229
230 image_filename = get_image_filename(params, root_dir)
231 qemu_img_cmd += " %s" % image_filename
232
233 size = params.get("image_size", "10G")
234 qemu_img_cmd += " %s" % size
235
236 utils.system(qemu_img_cmd)
237 logging.info("Image created in %r", image_filename)
238 return image_filename
239
240
241 def remove_image(params, root_dir):
242 """
243 Remove an image file.
244
245 @param params: A dict
246 @param root_dir: Base directory for relative filenames.
247
248 @note: params should contain:
249 image_name -- the name of the image file, without extension
250 image_format -- the format of the image (qcow2, raw etc)
251 """
252 image_filename = get_image_filename(params, root_dir)
253 logging.debug("Removing image file %s...", image_filename)
254 if os.path.exists(image_filename):
255 os.unlink(image_filename)
256 else:
257 logging.debug("Image file %s not found")
258
259
260 def check_image(params, root_dir):
261 """
262 Check an image using qemu-img.
263
264 @param params: Dictionary containing the test parameters.
265 @param root_dir: Base directory for relative filenames.
266
267 @note: params should contain:
268 image_name -- the name of the image file, without extension
269 image_format -- the format of the image (qcow2, raw etc)
270
271 @raise VMImageCheckError: In case qemu-img check fails on the image.
272 """
273 image_filename = get_image_filename(params, root_dir)
274 logging.debug("Checking image file %s...", image_filename)
275 qemu_img_cmd = kvm_utils.get_path(root_dir,
276 params.get("qemu_img_binary", "qemu-img"))
277 image_is_qcow2 = params.get("image_format") == 'qcow2'
278 if os.path.exists(image_filename) and image_is_qcow2:
279 # Verifying if qemu-img supports 'check'
280 q_result = utils.run(qemu_img_cmd, ignore_status=True)
281 q_output = q_result.stdout
282 check_img = True
283 if not "check" in q_output:
284 logging.error("qemu-img does not support 'check', "
285 "skipping check...")
286 check_img = False
287 if not "info" in q_output:
288 logging.error("qemu-img does not support 'info', "
289 "skipping check...")
290 check_img = False
291 if check_img:
292 try:
293 utils.system("%s info %s" % (qemu_img_cmd, image_filename))
294 except error.CmdError:
295 logging.error("Error getting info from image %s",
296 image_filename)
297
298 cmd_result = utils.run("%s check %s" %
299 (qemu_img_cmd, image_filename),
300 ignore_status=True)
301 # Error check, large chances of a non-fatal problem.
302 # There are chances that bad data was skipped though
303 if cmd_result.exit_status == 1:
304 for e_line in cmd_result.stdout.splitlines():
305 logging.error("[stdout] %s", e_line)
306 for e_line in cmd_result.stderr.splitlines():
307 logging.error("[stderr] %s", e_line)
308 raise error.TestWarn("qemu-img check error. Some bad data in "
309 "the image may have gone unnoticed")
310 # Exit status 2 is data corruption for sure, so fail the test
311 elif cmd_result.exit_status == 2:
312 for e_line in cmd_result.stdout.splitlines():
313 logging.error("[stdout] %s", e_line)
314 for e_line in cmd_result.stderr.splitlines():
315 logging.error("[stderr] %s", e_line)
316 raise VMImageCheckError(image_filename)
317 # Leaked clusters, they are known to be harmless to data integrity
318 elif cmd_result.exit_status == 3:
319 raise error.TestWarn("Leaked clusters were noticed during "
320 "image check. No data integrity problem "
321 "was found though.")
322
323 else:
324 if not os.path.exists(image_filename):
325 logging.debug("Image file %s not found, skipping check...",
326 image_filename)
327 elif not image_is_qcow2:
328 logging.debug("Image file %s not qcow2, skipping check...",
329 image_filename)
330
331
332 class VM:
333 """ 15 """
334 This class handles all basic VM operations. 16 This class handles all basic VM operations.
335 """ 17 """
336 18
19 MIGRATION_PROTOS = ['tcp', 'unix', 'exec']
20
337 def __init__(self, name, params, root_dir, address_cache, state=None): 21 def __init__(self, name, params, root_dir, address_cache, state=None):
338 """ 22 """
339 Initialize the object and set a few attributes. 23 Initialize the object and set a few attributes.
340 24
341 @param name: The name of the object 25 @param name: The name of the object
342 @param params: A dict containing VM params 26 @param params: A dict containing VM params
343 (see method make_qemu_command for a full description) 27 (see method make_qemu_command for a full description)
344 @param root_dir: Base directory for relative filenames 28 @param root_dir: Base directory for relative filenames
345 @param address_cache: A dict that maps MAC addresses to IP addresses 29 @param address_cache: A dict that maps MAC addresses to IP addresses
346 @param state: If provided, use this as self.__dict__ 30 @param state: If provided, use this as self.__dict__
347 """ 31 """
32 virt_vm.BaseVM.__init__(self, name, params)
33
348 if state: 34 if state:
349 self.__dict__ = state 35 self.__dict__ = state
350 else: 36 else:
351 self.process = None 37 self.process = None
352 self.serial_console = None 38 self.serial_console = None
353 self.redirs = {} 39 self.redirs = {}
354 self.vnc_port = 5900 40 self.vnc_port = 5900
355 self.monitors = [] 41 self.monitors = []
356 self.pci_assignable = None 42 self.pci_assignable = None
357 self.netdev_id = [] 43 self.netdev_id = []
358 self.device_id = [] 44 self.device_id = []
359 self.uuid = None 45 self.uuid = None
360 46
361 # Find a unique identifier for this VM
362 while True:
363 self.instance = (time.strftime("%Y%m%d-%H%M%S-") +
364 kvm_utils.generate_random_string(4))
365 if not glob.glob("/tmp/*%s" % self.instance):
366 break
367 47
368 self.spice_port = 8000 48 self.spice_port = 8000
369 self.name = name 49 self.name = name
370 self.params = params 50 self.params = params
371 self.root_dir = root_dir 51 self.root_dir = root_dir
372 self.address_cache = address_cache 52 self.address_cache = address_cache
373 53
374 54
55 def verify_alive(self):
56 """
57 Make sure the VM is alive and that the main monitor is responsive.
58
59 @raise VMDeadError: If the VM is dead
60 @raise: Various monitor exceptions if the monitor is unresponsive
61 """
62 try:
63 virt_vm.BaseVM.verify_alive(self)
64 if self.monitors:
65 self.monitor.verify_responsive()
66 except virt_vm.VMDeadError:
67 raise virt_vm.VMDeadError(self.process.get_status(),
68 self.process.get_output())
69
70
71 def is_alive(self):
72 """
73 Return True if the VM is alive and its monitor is responsive.
74 """
75 return not self.is_dead() and (not self.monitors or
76 self.monitor.is_responsive())
77
78
79 def is_dead(self):
80 """
81 Return True if the qemu process is dead.
82 """
83 return not self.process or not self.process.is_alive()
84
85
86
87
375 def clone(self, name=None, params=None, root_dir=None, address_cache=None, 88 def clone(self, name=None, params=None, root_dir=None, address_cache=None,
376 copy_state=False): 89 copy_state=False):
377 """ 90 """
378 Return a clone of the VM object with optionally modified parameters. 91 Return a clone of the VM object with optionally modified parameters.
379 The clone is initially not alive and needs to be started using create(). 92 The clone is initially not alive and needs to be started using create().
380 Any parameters not passed to this function are copied from the source 93 Any parameters not passed to this function are copied from the source
381 VM. 94 VM.
382 95
383 @param name: Optional new VM name 96 @param name: Optional new VM name
384 @param params: Optional new VM creation parameters 97 @param params: Optional new VM creation parameters
(...skipping 10 matching lines...) Expand all
395 root_dir = self.root_dir 108 root_dir = self.root_dir
396 if address_cache is None: 109 if address_cache is None:
397 address_cache = self.address_cache 110 address_cache = self.address_cache
398 if copy_state: 111 if copy_state:
399 state = self.__dict__.copy() 112 state = self.__dict__.copy()
400 else: 113 else:
401 state = None 114 state = None
402 return VM(name, params, root_dir, address_cache, state) 115 return VM(name, params, root_dir, address_cache, state)
403 116
404 117
405 def make_qemu_command(self, name=None, params=None, root_dir=None): 118 def __make_qemu_command(self, name=None, params=None, root_dir=None):
406 """ 119 """
407 Generate a qemu command line. All parameters are optional. If a 120 Generate a qemu command line. All parameters are optional. If a
408 parameter is not supplied, the corresponding value stored in the 121 parameter is not supplied, the corresponding value stored in the
409 class attributes is used. 122 class attributes is used.
410 123
411 @param name: The name of the object 124 @param name: The name of the object
412 @param params: A dict containing VM params 125 @param params: A dict containing VM params
413 @param root_dir: Base directory for relative filenames 126 @param root_dir: Base directory for relative filenames
414 127
415 @note: The params dict should contain: 128 @note: The params dict should contain:
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after
628 if name is None: 341 if name is None:
629 name = self.name 342 name = self.name
630 if params is None: 343 if params is None:
631 params = self.params 344 params = self.params
632 if root_dir is None: 345 if root_dir is None:
633 root_dir = self.root_dir 346 root_dir = self.root_dir
634 347
635 # Clone this VM using the new params 348 # Clone this VM using the new params
636 vm = self.clone(name, params, root_dir, copy_state=True) 349 vm = self.clone(name, params, root_dir, copy_state=True)
637 350
638 qemu_binary = kvm_utils.get_path(root_dir, params.get("qemu_binary", 351 qemu_binary = virt_utils.get_path(root_dir, params.get("qemu_binary",
639 "qemu")) 352 "qemu"))
640 # Get the output of 'qemu -help' (log a message in case this call never 353 # Get the output of 'qemu -help' (log a message in case this call never
641 # returns or causes some other kind of trouble) 354 # returns or causes some other kind of trouble)
642 logging.debug("Getting output of 'qemu -help'") 355 logging.debug("Getting output of 'qemu -help'")
643 help = commands.getoutput("%s -help" % qemu_binary) 356 help = commands.getoutput("%s -help" % qemu_binary)
644 357
645 # Start constructing the qemu command 358 # Start constructing the qemu command
646 qemu_cmd = "" 359 qemu_cmd = ""
647 # Set the X11 display parameter if requested 360 # Set the X11 display parameter if requested
648 if params.get("x11_display"): 361 if params.get("x11_display"):
(...skipping 12 matching lines...) Expand all
661 qemu_cmd += add_human_monitor(help, monitor_filename) 374 qemu_cmd += add_human_monitor(help, monitor_filename)
662 375
663 # Add serial console redirection 376 # Add serial console redirection
664 qemu_cmd += add_serial(help, vm.get_serial_console_filename()) 377 qemu_cmd += add_serial(help, vm.get_serial_console_filename())
665 378
666 for image_name in params.objects("images"): 379 for image_name in params.objects("images"):
667 image_params = params.object_params(image_name) 380 image_params = params.object_params(image_name)
668 if image_params.get("boot_drive") == "no": 381 if image_params.get("boot_drive") == "no":
669 continue 382 continue
670 qemu_cmd += add_drive(help, 383 qemu_cmd += add_drive(help,
671 get_image_filename(image_params, root_dir), 384 virt_vm.get_image_filename(image_params, root_dir),
672 image_params.get("drive_index"), 385 image_params.get("drive_index"),
673 image_params.get("drive_format"), 386 image_params.get("drive_format"),
674 image_params.get("drive_cache"), 387 image_params.get("drive_cache"),
675 image_params.get("drive_werror"), 388 image_params.get("drive_werror"),
676 image_params.get("drive_serial"), 389 image_params.get("drive_serial"),
677 image_params.get("image_snapshot") == "yes", 390 image_params.get("image_snapshot") == "yes",
678 image_params.get("image_boot") == "yes") 391 image_params.get("image_boot") == "yes")
679 392
680 redirs = [] 393 redirs = []
681 for redir_name in params.objects("redirs"): 394 for redir_name in params.objects("redirs"):
682 redir_params = params.object_params(redir_name) 395 redir_params = params.object_params(redir_name)
683 guest_port = int(redir_params.get("guest_port")) 396 guest_port = int(redir_params.get("guest_port"))
684 host_port = vm.redirs.get(guest_port) 397 host_port = vm.redirs.get(guest_port)
685 redirs += [(host_port, guest_port)] 398 redirs += [(host_port, guest_port)]
686 399
687 vlan = 0 400 vlan = 0
688 for nic_name in params.objects("nics"): 401 for nic_name in params.objects("nics"):
689 nic_params = params.object_params(nic_name) 402 nic_params = params.object_params(nic_name)
690 try: 403 try:
691 netdev_id = vm.netdev_id[vlan] 404 netdev_id = vm.netdev_id[vlan]
692 device_id = vm.device_id[vlan] 405 device_id = vm.device_id[vlan]
693 except IndexError: 406 except IndexError:
694 netdev_id = None 407 netdev_id = None
695 # Handle the '-net nic' part 408 # Handle the '-net nic' part
696 try: 409 try:
697 mac = vm.get_mac_address(vlan) 410 mac = vm.get_mac_address(vlan)
698 except VMAddressError: 411 except virt_vm.VMAddressError:
699 mac = None 412 mac = None
700 qemu_cmd += add_nic(help, vlan, nic_params.get("nic_model"), mac, 413 qemu_cmd += add_nic(help, vlan, nic_params.get("nic_model"), mac,
701 device_id, netdev_id, nic_params.get("nic_extra_ params")) 414 device_id, netdev_id, nic_params.get("nic_extra_ params"))
702 # Handle the '-net tap' or '-net user' or '-netdev' part 415 # Handle the '-net tap' or '-net user' or '-netdev' part
703 script = nic_params.get("nic_script") 416 script = nic_params.get("nic_script")
704 downscript = nic_params.get("nic_downscript") 417 downscript = nic_params.get("nic_downscript")
705 tftp = nic_params.get("tftp") 418 tftp = nic_params.get("tftp")
706 if script: 419 if script:
707 script = kvm_utils.get_path(root_dir, script) 420 script = virt_utils.get_path(root_dir, script)
708 if downscript: 421 if downscript:
709 downscript = kvm_utils.get_path(root_dir, downscript) 422 downscript = virt_utils.get_path(root_dir, downscript)
710 if tftp: 423 if tftp:
711 tftp = kvm_utils.get_path(root_dir, tftp) 424 tftp = virt_utils.get_path(root_dir, tftp)
712 qemu_cmd += add_net(help, vlan, nic_params.get("nic_mode", "user"), 425 qemu_cmd += add_net(help, vlan, nic_params.get("nic_mode", "user"),
713 vm.get_ifname(vlan), 426 vm.get_ifname(vlan),
714 script, downscript, tftp, 427 script, downscript, tftp,
715 nic_params.get("bootp"), redirs, netdev_id, 428 nic_params.get("bootp"), redirs, netdev_id,
716 nic_params.get("netdev_extra_params")) 429 nic_params.get("netdev_extra_params"))
717 # Proceed to next NIC 430 # Proceed to next NIC
718 vlan += 1 431 vlan += 1
719 432
720 mem = params.get("mem") 433 mem = params.get("mem")
721 if mem: 434 if mem:
722 qemu_cmd += add_mem(help, mem) 435 qemu_cmd += add_mem(help, mem)
723 436
724 smp = params.get("smp") 437 smp = params.get("smp")
725 if smp: 438 if smp:
726 qemu_cmd += add_smp(help, smp) 439 qemu_cmd += add_smp(help, smp)
727 440
728 for cdrom in params.objects("cdroms"): 441 for cdrom in params.objects("cdroms"):
729 cdrom_params = params.object_params(cdrom) 442 cdrom_params = params.object_params(cdrom)
730 iso = cdrom_params.get("cdrom") 443 iso = cdrom_params.get("cdrom")
731 if iso: 444 if iso:
732 qemu_cmd += add_cdrom(help, kvm_utils.get_path(root_dir, iso), 445 qemu_cmd += add_cdrom(help, virt_utils.get_path(root_dir, iso),
733 cdrom_params.get("drive_index")) 446 cdrom_params.get("drive_index"))
734 447
735 # We may want to add {floppy_otps} parameter for -fda 448 # We may want to add {floppy_otps} parameter for -fda
736 # {fat:floppy:}/path/. However vvfat is not usually recommended. 449 # {fat:floppy:}/path/. However vvfat is not usually recommended.
737 floppy = params.get("floppy") 450 floppy = params.get("floppy")
738 if floppy: 451 if floppy:
739 floppy = kvm_utils.get_path(root_dir, floppy) 452 floppy = virt_utils.get_path(root_dir, floppy)
740 qemu_cmd += add_floppy(help, floppy) 453 qemu_cmd += add_floppy(help, floppy)
741 454
742 tftp = params.get("tftp") 455 tftp = params.get("tftp")
743 if tftp: 456 if tftp:
744 tftp = kvm_utils.get_path(root_dir, tftp) 457 tftp = virt_utils.get_path(root_dir, tftp)
745 qemu_cmd += add_tftp(help, tftp) 458 qemu_cmd += add_tftp(help, tftp)
746 459
747 bootp = params.get("bootp") 460 bootp = params.get("bootp")
748 if bootp: 461 if bootp:
749 qemu_cmd += add_bootp(help, bootp) 462 qemu_cmd += add_bootp(help, bootp)
750 463
751 kernel = params.get("kernel") 464 kernel = params.get("kernel")
752 if kernel: 465 if kernel:
753 kernel = kvm_utils.get_path(root_dir, kernel) 466 kernel = virt_utils.get_path(root_dir, kernel)
754 qemu_cmd += add_kernel(help, kernel) 467 qemu_cmd += add_kernel(help, kernel)
755 468
756 kernel_cmdline = params.get("kernel_cmdline") 469 kernel_cmdline = params.get("kernel_cmdline")
757 if kernel_cmdline: 470 if kernel_cmdline:
758 qemu_cmd += add_kernel_cmdline(help, kernel_cmdline) 471 qemu_cmd += add_kernel_cmdline(help, kernel_cmdline)
759 472
760 initrd = params.get("initrd") 473 initrd = params.get("initrd")
761 if initrd: 474 if initrd:
762 initrd = kvm_utils.get_path(root_dir, initrd) 475 initrd = virt_utils.get_path(root_dir, initrd)
763 qemu_cmd += add_initrd(help, initrd) 476 qemu_cmd += add_initrd(help, initrd)
764 477
765 for host_port, guest_port in redirs: 478 for host_port, guest_port in redirs:
766 qemu_cmd += add_tcp_redir(help, host_port, guest_port) 479 qemu_cmd += add_tcp_redir(help, host_port, guest_port)
767 480
768 if params.get("display") == "vnc": 481 if params.get("display") == "vnc":
769 qemu_cmd += add_vnc(help, vm.vnc_port) 482 qemu_cmd += add_vnc(help, vm.vnc_port)
770 elif params.get("display") == "sdl": 483 elif params.get("display") == "sdl":
771 qemu_cmd += add_sdl(help) 484 qemu_cmd += add_sdl(help)
772 elif params.get("display") == "nographic": 485 elif params.get("display") == "nographic":
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
848 self.root_dir = root_dir 561 self.root_dir = root_dir
849 name = self.name 562 name = self.name
850 params = self.params 563 params = self.params
851 root_dir = self.root_dir 564 root_dir = self.root_dir
852 565
853 # Verify the md5sum of the ISO images 566 # Verify the md5sum of the ISO images
854 for cdrom in params.objects("cdroms"): 567 for cdrom in params.objects("cdroms"):
855 cdrom_params = params.object_params(cdrom) 568 cdrom_params = params.object_params(cdrom)
856 iso = cdrom_params.get("cdrom") 569 iso = cdrom_params.get("cdrom")
857 if iso: 570 if iso:
858 iso = kvm_utils.get_path(root_dir, iso) 571 iso = virt_utils.get_path(root_dir, iso)
859 if not os.path.exists(iso): 572 if not os.path.exists(iso):
860 raise VMImageMissingError(iso) 573 raise virt_vm.VMImageMissingError(iso)
861 compare = False 574 compare = False
862 if cdrom_params.get("md5sum_1m"): 575 if cdrom_params.get("md5sum_1m"):
863 logging.debug("Comparing expected MD5 sum with MD5 sum of " 576 logging.debug("Comparing expected MD5 sum with MD5 sum of "
864 "first MB of ISO file...") 577 "first MB of ISO file...")
865 actual_hash = utils.hash_file(iso, 1048576, method="md5") 578 actual_hash = utils.hash_file(iso, 1048576, method="md5")
866 expected_hash = cdrom_params.get("md5sum_1m") 579 expected_hash = cdrom_params.get("md5sum_1m")
867 compare = True 580 compare = True
868 elif cdrom_params.get("md5sum"): 581 elif cdrom_params.get("md5sum"):
869 logging.debug("Comparing expected MD5 sum with MD5 sum of " 582 logging.debug("Comparing expected MD5 sum with MD5 sum of "
870 "ISO file...") 583 "ISO file...")
871 actual_hash = utils.hash_file(iso, method="md5") 584 actual_hash = utils.hash_file(iso, method="md5")
872 expected_hash = cdrom_params.get("md5sum") 585 expected_hash = cdrom_params.get("md5sum")
873 compare = True 586 compare = True
874 elif cdrom_params.get("sha1sum"): 587 elif cdrom_params.get("sha1sum"):
875 logging.debug("Comparing expected SHA1 sum with SHA1 sum " 588 logging.debug("Comparing expected SHA1 sum with SHA1 sum "
876 "of ISO file...") 589 "of ISO file...")
877 actual_hash = utils.hash_file(iso, method="sha1") 590 actual_hash = utils.hash_file(iso, method="sha1")
878 expected_hash = cdrom_params.get("sha1sum") 591 expected_hash = cdrom_params.get("sha1sum")
879 compare = True 592 compare = True
880 if compare: 593 if compare:
881 if actual_hash == expected_hash: 594 if actual_hash == expected_hash:
882 logging.debug("Hashes match") 595 logging.debug("Hashes match")
883 else: 596 else:
884 raise VMHashMismatchError(actual_hash, expected_hash) 597 raise virt_vm.VMHashMismatchError(actual_hash,
598 expected_hash)
885 599
886 # Make sure the following code is not executed by more than one thread 600 # Make sure the following code is not executed by more than one thread
887 # at the same time 601 # at the same time
888 lockfile = open("/tmp/kvm-autotest-vm-create.lock", "w+") 602 lockfile = open("/tmp/kvm-autotest-vm-create.lock", "w+")
889 fcntl.lockf(lockfile, fcntl.LOCK_EX) 603 fcntl.lockf(lockfile, fcntl.LOCK_EX)
890 604
891 try: 605 try:
892 # Handle port redirections 606 # Handle port redirections
893 redir_names = params.objects("redirs") 607 redir_names = params.objects("redirs")
894 host_ports = kvm_utils.find_free_ports(5000, 6000, len(redir_names)) 608 host_ports = virt_utils.find_free_ports(5000, 6000, len(redir_names) )
895 self.redirs = {} 609 self.redirs = {}
896 for i in range(len(redir_names)): 610 for i in range(len(redir_names)):
897 redir_params = params.object_params(redir_names[i]) 611 redir_params = params.object_params(redir_names[i])
898 guest_port = int(redir_params.get("guest_port")) 612 guest_port = int(redir_params.get("guest_port"))
899 self.redirs[guest_port] = host_ports[i] 613 self.redirs[guest_port] = host_ports[i]
900 614
901 # Generate netdev/device IDs for all NICs 615 # Generate netdev/device IDs for all NICs
902 self.netdev_id = [] 616 self.netdev_id = []
903 self.device_id = [] 617 self.device_id = []
904 for nic in params.objects("nics"): 618 for nic in params.objects("nics"):
905 self.netdev_id.append(kvm_utils.generate_random_id()) 619 self.netdev_id.append(virt_utils.generate_random_id())
906 self.device_id.append(kvm_utils.generate_random_id()) 620 self.device_id.append(virt_utils.generate_random_id())
907 621
908 # Find available VNC port, if needed 622 # Find available VNC port, if needed
909 if params.get("display") == "vnc": 623 if params.get("display") == "vnc":
910 self.vnc_port = kvm_utils.find_free_port(5900, 6100) 624 self.vnc_port = virt_utils.find_free_port(5900, 6100)
911 625
912 # Find available spice port 626 # Find available spice port, if needed
913 if params.get("spice"): 627 if params.get("spice"):
914 self.spice_port = kvm_utils.find_free_port(8000, 8100) 628 self.spice_port = virt_utils.find_free_port(8000, 8100)
915 629
916 # Find random UUID if specified 'uuid = random' in config file 630 # Find random UUID if specified 'uuid = random' in config file
917 if params.get("uuid") == "random": 631 if params.get("uuid") == "random":
918 f = open("/proc/sys/kernel/random/uuid") 632 f = open("/proc/sys/kernel/random/uuid")
919 self.uuid = f.read().strip() 633 self.uuid = f.read().strip()
920 f.close() 634 f.close()
921 635
922 # Generate or copy MAC addresses for all NICs 636 # Generate or copy MAC addresses for all NICs
923 num_nics = len(params.objects("nics")) 637 num_nics = len(params.objects("nics"))
924 for vlan in range(num_nics): 638 for vlan in range(num_nics):
925 nic_name = params.objects("nics")[vlan] 639 nic_name = params.objects("nics")[vlan]
926 nic_params = params.object_params(nic_name) 640 nic_params = params.object_params(nic_name)
927 mac = (nic_params.get("nic_mac") or 641 mac = (nic_params.get("nic_mac") or
928 mac_source and mac_source.get_mac_address(vlan)) 642 mac_source and mac_source.get_mac_address(vlan))
929 if mac: 643 if mac:
930 kvm_utils.set_mac_address(self.instance, vlan, mac) 644 virt_utils.set_mac_address(self.instance, vlan, mac)
931 else: 645 else:
932 kvm_utils.generate_mac_address(self.instance, vlan) 646 virt_utils.generate_mac_address(self.instance, vlan)
933 647
934 # Assign a PCI assignable device 648 # Assign a PCI assignable device
935 self.pci_assignable = None 649 self.pci_assignable = None
936 pa_type = params.get("pci_assignable") 650 pa_type = params.get("pci_assignable")
937 if pa_type and pa_type != "no": 651 if pa_type and pa_type != "no":
938 pa_devices_requested = params.get("devices_requested") 652 pa_devices_requested = params.get("devices_requested")
939 653
940 # Virtual Functions (VF) assignable devices 654 # Virtual Functions (VF) assignable devices
941 if pa_type == "vf": 655 if pa_type == "vf":
942 self.pci_assignable = kvm_utils.PciAssignable( 656 self.pci_assignable = virt_utils.PciAssignable(
943 type=pa_type, 657 type=pa_type,
944 driver=params.get("driver"), 658 driver=params.get("driver"),
945 driver_option=params.get("driver_option"), 659 driver_option=params.get("driver_option"),
946 devices_requested=pa_devices_requested) 660 devices_requested=pa_devices_requested)
947 # Physical NIC (PF) assignable devices 661 # Physical NIC (PF) assignable devices
948 elif pa_type == "pf": 662 elif pa_type == "pf":
949 self.pci_assignable = kvm_utils.PciAssignable( 663 self.pci_assignable = virt_utils.PciAssignable(
950 type=pa_type, 664 type=pa_type,
951 names=params.get("device_names"), 665 names=params.get("device_names"),
952 devices_requested=pa_devices_requested) 666 devices_requested=pa_devices_requested)
953 # Working with both VF and PF 667 # Working with both VF and PF
954 elif pa_type == "mixed": 668 elif pa_type == "mixed":
955 self.pci_assignable = kvm_utils.PciAssignable( 669 self.pci_assignable = virt_utils.PciAssignable(
956 type=pa_type, 670 type=pa_type,
957 driver=params.get("driver"), 671 driver=params.get("driver"),
958 driver_option=params.get("driver_option"), 672 driver_option=params.get("driver_option"),
959 names=params.get("device_names"), 673 names=params.get("device_names"),
960 devices_requested=pa_devices_requested) 674 devices_requested=pa_devices_requested)
961 else: 675 else:
962 raise VMBadPATypeError(pa_type) 676 raise virt_vm.VMBadPATypeError(pa_type)
963 677
964 self.pa_pci_ids = self.pci_assignable.request_devs() 678 self.pa_pci_ids = self.pci_assignable.request_devs()
965 679
966 if self.pa_pci_ids: 680 if self.pa_pci_ids:
967 logging.debug("Successfuly assigned devices: %s", 681 logging.debug("Successfuly assigned devices: %s",
968 self.pa_pci_ids) 682 self.pa_pci_ids)
969 else: 683 else:
970 raise VMPAError(pa_type) 684 raise virt_vm.VMPAError(pa_type)
971 685
972 # Make qemu command 686 # Make qemu command
973 qemu_command = self.make_qemu_command() 687 qemu_command = self.__make_qemu_command()
974 688
975 # Add migration parameters if required 689 # Add migration parameters if required
976 if migration_mode == "tcp": 690 if migration_mode == "tcp":
977 self.migration_port = kvm_utils.find_free_port(5200, 6000) 691 self.migration_port = virt_utils.find_free_port(5200, 6000)
978 qemu_command += " -incoming tcp:0:%d" % self.migration_port 692 qemu_command += " -incoming tcp:0:%d" % self.migration_port
979 elif migration_mode == "unix": 693 elif migration_mode == "unix":
980 self.migration_file = "/tmp/migration-unix-%s" % self.instance 694 self.migration_file = "/tmp/migration-unix-%s" % self.instance
981 qemu_command += " -incoming unix:%s" % self.migration_file 695 qemu_command += " -incoming unix:%s" % self.migration_file
982 elif migration_mode == "exec": 696 elif migration_mode == "exec":
983 self.migration_port = kvm_utils.find_free_port(5200, 6000) 697 self.migration_port = virt_utils.find_free_port(5200, 6000)
984 qemu_command += (' -incoming "exec:nc -l %s"' % 698 qemu_command += (' -incoming "exec:nc -l %s"' %
985 self.migration_port) 699 self.migration_port)
986 700
987 logging.info("Running qemu command:\n%s", qemu_command) 701 logging.info("Running qemu command:\n%s", qemu_command)
988 self.process = kvm_subprocess.run_bg(qemu_command, None, 702 self.process = aexpect.run_bg(qemu_command, None,
989 logging.info, "(qemu) ") 703 logging.info, "(qemu) ")
990 704
991 # Make sure the process was started successfully 705 # Make sure the process was started successfully
992 if not self.process.is_alive(): 706 if not self.process.is_alive():
993 e = VMCreateError(qemu_command, 707 e = virt_vm.VMCreateError(qemu_command,
994 self.process.get_status(), 708 self.process.get_status(),
995 self.process.get_output()) 709 self.process.get_output())
996 self.destroy() 710 self.destroy()
997 raise e 711 raise e
998 712
999 # Establish monitor connections 713 # Establish monitor connections
1000 self.monitors = [] 714 self.monitors = []
1001 for monitor_name in params.objects("monitors"): 715 for monitor_name in params.objects("monitors"):
1002 monitor_params = params.object_params(monitor_name) 716 monitor_params = params.object_params(monitor_name)
1003 # Wait for monitor connection to succeed 717 # Wait for monitor connection to succeed
1004 end_time = time.time() + timeout 718 end_time = time.time() + timeout
1005 while time.time() < end_time: 719 while time.time() < end_time:
(...skipping 17 matching lines...) Expand all
1023 self.destroy() 737 self.destroy()
1024 raise e 738 raise e
1025 # Add this monitor to the list 739 # Add this monitor to the list
1026 self.monitors += [monitor] 740 self.monitors += [monitor]
1027 741
1028 # Get the output so far, to see if we have any problems with 742 # Get the output so far, to see if we have any problems with
1029 # KVM modules or with hugepage setup. 743 # KVM modules or with hugepage setup.
1030 output = self.process.get_output() 744 output = self.process.get_output()
1031 745
1032 if re.search("Could not initialize KVM", output, re.IGNORECASE): 746 if re.search("Could not initialize KVM", output, re.IGNORECASE):
1033 e = VMKVMInitError(qemu_command, self.process.get_output()) 747 e = virt_vm.VMKVMInitError(qemu_command, self.process.get_output ())
1034 self.destroy() 748 self.destroy()
1035 raise e 749 raise e
1036 750
1037 if "alloc_mem_area" in output: 751 if "alloc_mem_area" in output:
1038 e = VMHugePageError(qemu_command, self.process.get_output()) 752 e = virt_vm.VMHugePageError(qemu_command, self.process.get_outpu t())
1039 self.destroy() 753 self.destroy()
1040 raise e 754 raise e
1041 755
1042 logging.debug("VM appears to be alive with PID %s", self.get_pid()) 756 logging.debug("VM appears to be alive with PID %s", self.get_pid())
1043 757
1044 # Establish a session with the serial console -- requires a version 758 # Establish a session with the serial console -- requires a version
1045 # of netcat that supports -U 759 # of netcat that supports -U
1046 self.serial_console = kvm_subprocess.ShellSession( 760 self.serial_console = aexpect.ShellSession(
1047 "nc -U %s" % self.get_serial_console_filename(), 761 "nc -U %s" % self.get_serial_console_filename(),
1048 auto_close=False, 762 auto_close=False,
1049 output_func=kvm_utils.log_line, 763 output_func=virt_utils.log_line,
1050 output_params=("serial-%s.log" % name,)) 764 output_params=("serial-%s.log" % name,))
1051 765
1052 finally: 766 finally:
1053 fcntl.lockf(lockfile, fcntl.LOCK_UN) 767 fcntl.lockf(lockfile, fcntl.LOCK_UN)
1054 lockfile.close() 768 lockfile.close()
1055 769
1056 770
1057 def destroy(self, gracefully=True, free_mac_addresses=True): 771 def destroy(self, gracefully=True, free_mac_addresses=True):
1058 """ 772 """
1059 Destroy the VM. 773 Destroy the VM.
(...skipping 13 matching lines...) Expand all
1073 if self.is_dead(): 787 if self.is_dead():
1074 return 788 return
1075 789
1076 logging.debug("Destroying VM with PID %s...", self.get_pid()) 790 logging.debug("Destroying VM with PID %s...", self.get_pid())
1077 791
1078 if gracefully and self.params.get("shutdown_command"): 792 if gracefully and self.params.get("shutdown_command"):
1079 # Try to destroy with shell command 793 # Try to destroy with shell command
1080 logging.debug("Trying to shutdown VM with shell command...") 794 logging.debug("Trying to shutdown VM with shell command...")
1081 try: 795 try:
1082 session = self.login() 796 session = self.login()
1083 except (kvm_utils.LoginError, VMError), e: 797 except (virt_utils.LoginError, virt_vm.VMError), e:
1084 logging.debug(e) 798 logging.debug(e)
1085 else: 799 else:
1086 try: 800 try:
1087 # Send the shutdown command 801 # Send the shutdown command
1088 session.sendline(self.params.get("shutdown_command")) 802 session.sendline(self.params.get("shutdown_command"))
1089 logging.debug("Shutdown command sent; waiting for VM " 803 logging.debug("Shutdown command sent; waiting for VM "
1090 "to go down...") 804 "to go down...")
1091 if kvm_utils.wait_for(self.is_dead, 60, 1, 1): 805 if virt_utils.wait_for(self.is_dead, 60, 1, 1):
1092 logging.debug("VM is down") 806 logging.debug("VM is down")
1093 return 807 return
1094 finally: 808 finally:
1095 session.close() 809 session.close()
1096 810
1097 if self.monitor: 811 if self.monitor:
1098 # Try to destroy with a monitor command 812 # Try to destroy with a monitor command
1099 logging.debug("Trying to kill VM with monitor command...") 813 logging.debug("Trying to kill VM with monitor command...")
1100 try: 814 try:
1101 self.monitor.quit() 815 self.monitor.quit()
1102 except kvm_monitor.MonitorError, e: 816 except kvm_monitor.MonitorError, e:
1103 logging.warn(e) 817 logging.warn(e)
1104 else: 818 else:
1105 # Wait for the VM to be really dead 819 # Wait for the VM to be really dead
1106 if kvm_utils.wait_for(self.is_dead, 5, 0.5, 0.5): 820 if virt_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
1107 logging.debug("VM is down") 821 logging.debug("VM is down")
1108 return 822 return
1109 823
1110 # If the VM isn't dead yet... 824 # If the VM isn't dead yet...
1111 logging.debug("Cannot quit normally; sending a kill to close the " 825 logging.debug("Cannot quit normally; sending a kill to close the "
1112 "deal...") 826 "deal...")
1113 kvm_utils.kill_process_tree(self.process.get_pid(), 9) 827 virt_utils.kill_process_tree(self.process.get_pid(), 9)
1114 # Wait for the VM to be really dead 828 # Wait for the VM to be really dead
1115 if kvm_utils.wait_for(self.is_dead, 5, 0.5, 0.5): 829 if virt_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
1116 logging.debug("VM is down") 830 logging.debug("VM is down")
1117 return 831 return
1118 832
1119 logging.error("Process %s is a zombie!", self.process.get_pid()) 833 logging.error("Process %s is a zombie!", self.process.get_pid())
1120 834
1121 finally: 835 finally:
1122 self.monitors = [] 836 self.monitors = []
1123 if self.pci_assignable: 837 if self.pci_assignable:
1124 self.pci_assignable.release_devs() 838 self.pci_assignable.release_devs()
1125 if self.process: 839 if self.process:
(...skipping 26 matching lines...) Expand all
1152 If no monitors exist, or if main_monitor refers to a nonexistent 866 If no monitors exist, or if main_monitor refers to a nonexistent
1153 monitor, return None. 867 monitor, return None.
1154 """ 868 """
1155 for m in self.monitors: 869 for m in self.monitors:
1156 if m.name == self.params.get("main_monitor"): 870 if m.name == self.params.get("main_monitor"):
1157 return m 871 return m
1158 if self.monitors and not self.params.get("main_monitor"): 872 if self.monitors and not self.params.get("main_monitor"):
1159 return self.monitors[0] 873 return self.monitors[0]
1160 874
1161 875
1162 def verify_alive(self):
1163 """
1164 Make sure the VM is alive and that the main monitor is responsive.
1165
1166 @raise VMDeadError: If the VM is dead
1167 @raise: Various monitor exceptions if the monitor is unresponsive
1168 """
1169 if self.is_dead():
1170 raise VMDeadError(self.process.get_status(),
1171 self.process.get_output())
1172 if self.monitors:
1173 self.monitor.verify_responsive()
1174
1175
1176 def is_alive(self):
1177 """
1178 Return True if the VM is alive and its monitor is responsive.
1179 """
1180 return not self.is_dead() and (not self.monitors or
1181 self.monitor.is_responsive())
1182
1183
1184 def is_dead(self):
1185 """
1186 Return True if the qemu process is dead.
1187 """
1188 return not self.process or not self.process.is_alive()
1189
1190
1191 def verify_kernel_crash(self):
1192 """
1193 Find kernel crash message on the VM serial console.
1194
1195 @raise: VMDeadKernelCrashError, in case a kernel crash message was
1196 found.
1197 """
1198 data = self.serial_console.get_output()
1199 match = re.search(r"BUG:.*---\[ end trace .* \]---", data,
1200 re.DOTALL|re.MULTILINE)
1201 if match is not None:
1202 raise VMDeadKernelCrashError(match.group(0))
1203
1204
1205 def get_params(self):
1206 """
1207 Return the VM's params dict. Most modified params take effect only
1208 upon VM.create().
1209 """
1210 return self.params
1211
1212
1213 def get_monitor_filename(self, monitor_name): 876 def get_monitor_filename(self, monitor_name):
1214 """ 877 """
1215 Return the filename corresponding to a given monitor name. 878 Return the filename corresponding to a given monitor name.
1216 """ 879 """
1217 return "/tmp/monitor-%s-%s" % (monitor_name, self.instance) 880 return "/tmp/monitor-%s-%s" % (monitor_name, self.instance)
1218 881
1219 882
1220 def get_monitor_filenames(self): 883 def get_monitor_filenames(self):
1221 """ 884 """
1222 Return a list of all monitor filenames (as specified in the VM's 885 Return a list of all monitor filenames (as specified in the VM's
1223 params). 886 params).
1224 """ 887 """
1225 return [self.get_monitor_filename(m) for m in 888 return [self.get_monitor_filename(m) for m in
1226 self.params.objects("monitors")] 889 self.params.objects("monitors")]
1227 890
1228 891
1229 def get_serial_console_filename(self):
1230 """
1231 Return the serial console filename.
1232 """
1233 return "/tmp/serial-%s" % self.instance
1234
1235
1236 def get_testlog_filename(self):
1237 """
1238 Return the testlog filename.
1239 """
1240 return "/tmp/testlog-%s" % self.instance
1241
1242
1243 def get_address(self, index=0): 892 def get_address(self, index=0):
1244 """ 893 """
1245 Return the address of a NIC of the guest, in host space. 894 Return the address of a NIC of the guest, in host space.
1246 895
1247 If port redirection is used, return 'localhost' (the NIC has no IP 896 If port redirection is used, return 'localhost' (the NIC has no IP
1248 address of its own). Otherwise return the NIC's IP address. 897 address of its own). Otherwise return the NIC's IP address.
1249 898
1250 @param index: Index of the NIC whose address is requested. 899 @param index: Index of the NIC whose address is requested.
1251 @raise VMMACAddressMissingError: If no MAC address is defined for the 900 @raise VMMACAddressMissingError: If no MAC address is defined for the
1252 requested NIC 901 requested NIC
1253 @raise VMIPAddressMissingError: If no IP address is found for the the 902 @raise VMIPAddressMissingError: If no IP address is found for the the
1254 NIC's MAC address 903 NIC's MAC address
1255 @raise VMAddressVerificationError: If the MAC-IP address mapping cannot 904 @raise VMAddressVerificationError: If the MAC-IP address mapping cannot
1256 be verified (using arping) 905 be verified (using arping)
1257 """ 906 """
1258 nics = self.params.objects("nics") 907 nics = self.params.objects("nics")
1259 nic_name = nics[index] 908 nic_name = nics[index]
1260 nic_params = self.params.object_params(nic_name) 909 nic_params = self.params.object_params(nic_name)
1261 if nic_params.get("nic_mode") == "tap": 910 if nic_params.get("nic_mode") == "tap":
1262 mac = self.get_mac_address(index).lower() 911 mac = self.get_mac_address(index).lower()
1263 # Get the IP address from the cache 912 # Get the IP address from the cache
1264 ip = self.address_cache.get(mac) 913 ip = self.address_cache.get(mac)
1265 if not ip: 914 if not ip:
1266 raise VMIPAddressMissingError(mac) 915 raise virt_vm.VMIPAddressMissingError(mac)
1267 # Make sure the IP address is assigned to this guest 916 # Make sure the IP address is assigned to this guest
1268 macs = [self.get_mac_address(i) for i in range(len(nics))] 917 macs = [self.get_mac_address(i) for i in range(len(nics))]
1269 if not kvm_utils.verify_ip_address_ownership(ip, macs): 918 if not virt_utils.verify_ip_address_ownership(ip, macs):
1270 raise VMAddressVerificationError(mac, ip) 919 raise virt_vm.VMAddressVerificationError(mac, ip)
1271 return ip 920 return ip
1272 else: 921 else:
1273 return "localhost" 922 return "localhost"
1274 923
1275 924
1276 def get_port(self, port, nic_index=0): 925 def get_port(self, port, nic_index=0):
1277 """ 926 """
1278 Return the port in host space corresponding to port in guest space. 927 Return the port in host space corresponding to port in guest space.
1279 928
1280 @param port: Port number in host space. 929 @param port: Port number in host space.
1281 @param nic_index: Index of the NIC. 930 @param nic_index: Index of the NIC.
1282 @return: If port redirection is used, return the host port redirected 931 @return: If port redirection is used, return the host port redirected
1283 to guest port port. Otherwise return port. 932 to guest port port. Otherwise return port.
1284 @raise VMPortNotRedirectedError: If an unredirected port is requested 933 @raise VMPortNotRedirectedError: If an unredirected port is requested
1285 in user mode 934 in user mode
1286 """ 935 """
1287 nic_name = self.params.objects("nics")[nic_index] 936 nic_name = self.params.objects("nics")[nic_index]
1288 nic_params = self.params.object_params(nic_name) 937 nic_params = self.params.object_params(nic_name)
1289 if nic_params.get("nic_mode") == "tap": 938 if nic_params.get("nic_mode") == "tap":
1290 return port 939 return port
1291 else: 940 else:
1292 try: 941 try:
1293 return self.redirs[port] 942 return self.redirs[port]
1294 except KeyError: 943 except KeyError:
1295 raise VMPortNotRedirectedError(port) 944 raise virt_vm.VMPortNotRedirectedError(port)
1296 945
1297 946
1298 def get_peer(self, netid): 947 def get_peer(self, netid):
1299 """ 948 """
1300 Return the peer of netdev or network deivce. 949 Return the peer of netdev or network deivce.
1301 950
1302 @param netid: id of netdev or device 951 @param netid: id of netdev or device
1303 @return: id of the peer device otherwise None 952 @return: id of the peer device otherwise None
1304 """ 953 """
1305 network_info = self.monitor.info("network") 954 network_info = self.monitor.info("network")
(...skipping 22 matching lines...) Expand all
1328 """ 977 """
1329 Return the MAC address of a NIC. 978 Return the MAC address of a NIC.
1330 979
1331 @param nic_index: Index of the NIC 980 @param nic_index: Index of the NIC
1332 @raise VMMACAddressMissingError: If no MAC address is defined for the 981 @raise VMMACAddressMissingError: If no MAC address is defined for the
1333 requested NIC 982 requested NIC
1334 """ 983 """
1335 nic_name = self.params.objects("nics")[nic_index] 984 nic_name = self.params.objects("nics")[nic_index]
1336 nic_params = self.params.object_params(nic_name) 985 nic_params = self.params.object_params(nic_name)
1337 mac = (nic_params.get("nic_mac") or 986 mac = (nic_params.get("nic_mac") or
1338 kvm_utils.get_mac_address(self.instance, nic_index)) 987 virt_utils.get_mac_address(self.instance, nic_index))
1339 if not mac: 988 if not mac:
1340 raise VMMACAddressMissingError(nic_index) 989 raise virt_vm.VMMACAddressMissingError(nic_index)
1341 return mac 990 return mac
1342 991
1343 992
1344 def free_mac_address(self, nic_index=0): 993 def free_mac_address(self, nic_index=0):
1345 """ 994 """
1346 Free a NIC's MAC address. 995 Free a NIC's MAC address.
1347 996
1348 @param nic_index: Index of the NIC 997 @param nic_index: Index of the NIC
1349 """ 998 """
1350 kvm_utils.free_mac_address(self.instance, nic_index) 999 virt_utils.free_mac_address(self.instance, nic_index)
1351 1000
1352 1001
1353 def get_pid(self): 1002 def get_pid(self):
1354 """ 1003 """
1355 Return the VM's PID. If the VM is dead return None. 1004 Return the VM's PID. If the VM is dead return None.
1356 1005
1357 @note: This works under the assumption that self.process.get_pid() 1006 @note: This works under the assumption that self.process.get_pid()
1358 returns the PID of the parent shell process. 1007 returns the PID of the parent shell process.
1359 """ 1008 """
1360 try: 1009 try:
(...skipping 24 matching lines...) Expand all
1385 logging.error("Could not get shared memory info from dead VM.") 1034 logging.error("Could not get shared memory info from dead VM.")
1386 return None 1035 return None
1387 1036
1388 filename = "/proc/%d/statm" % self.get_pid() 1037 filename = "/proc/%d/statm" % self.get_pid()
1389 shm = int(open(filename).read().split()[2]) 1038 shm = int(open(filename).read().split()[2])
1390 # statm stores informations in pages, translate it to MB 1039 # statm stores informations in pages, translate it to MB
1391 return shm * 4.0 / 1024 1040 return shm * 4.0 / 1024
1392 1041
1393 1042
1394 @error.context_aware 1043 @error.context_aware
1395 def login(self, nic_index=0, timeout=10):
1396 """
1397 Log into the guest via SSH/Telnet/Netcat.
1398 If timeout expires while waiting for output from the guest (e.g. a
1399 password prompt or a shell prompt) -- fail.
1400
1401 @param nic_index: The index of the NIC to connect to.
1402 @param timeout: Time (seconds) before giving up logging into the
1403 guest.
1404 @return: A ShellSession object.
1405 """
1406 error.context("logging into '%s'" % self.name)
1407 username = self.params.get("username", "")
1408 password = self.params.get("password", "")
1409 prompt = self.params.get("shell_prompt", "[\#\$]")
1410 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
1411 client = self.params.get("shell_client")
1412 address = self.get_address(nic_index)
1413 port = self.get_port(int(self.params.get("shell_port")))
1414 log_filename = ("session-%s-%s.log" %
1415 (self.name, kvm_utils.generate_random_string(4)))
1416 session = kvm_utils.remote_login(client, address, port, username,
1417 password, prompt, linesep,
1418 log_filename, timeout)
1419 session.set_status_test_command(self.params.get("status_test_command",
1420 ""))
1421 return session
1422
1423
1424 def remote_login(self, nic_index=0, timeout=10):
1425 """
1426 Alias for login() for backward compatibility.
1427 """
1428 return self.login(nic_index, timeout)
1429
1430
1431 def wait_for_login(self, nic_index=0, timeout=240, internal_timeout=10):
1432 """
1433 Make multiple attempts to log into the guest via SSH/Telnet/Netcat.
1434
1435 @param nic_index: The index of the NIC to connect to.
1436 @param timeout: Time (seconds) to keep trying to log in.
1437 @param internal_timeout: Timeout to pass to login().
1438 @return: A ShellSession object.
1439 """
1440 logging.debug("Attempting to log into '%s' (timeout %ds)", self.name,
1441 timeout)
1442 end_time = time.time() + timeout
1443 while time.time() < end_time:
1444 try:
1445 return self.login(nic_index, internal_timeout)
1446 except (kvm_utils.LoginError, VMError), e:
1447 logging.debug(e)
1448 time.sleep(2)
1449 # Timeout expired; try one more time but don't catch exceptions
1450 return self.login(nic_index, internal_timeout)
1451
1452
1453 @error.context_aware
1454 def copy_files_to(self, host_path, guest_path, nic_index=0, verbose=False,
1455 timeout=600):
1456 """
1457 Transfer files to the remote host(guest).
1458
1459 @param host_path: Host path
1460 @param guest_path: Guest path
1461 @param nic_index: The index of the NIC to connect to.
1462 @param verbose: If True, log some stats using logging.debug (RSS only)
1463 @param timeout: Time (seconds) before giving up on doing the remote
1464 copy.
1465 """
1466 error.context("sending file(s) to '%s'" % self.name)
1467 username = self.params.get("username", "")
1468 password = self.params.get("password", "")
1469 client = self.params.get("file_transfer_client")
1470 address = self.get_address(nic_index)
1471 port = self.get_port(int(self.params.get("file_transfer_port")))
1472 log_filename = ("transfer-%s-to-%s-%s.log" %
1473 (self.name, address,
1474 kvm_utils.generate_random_string(4)))
1475 kvm_utils.copy_files_to(address, client, username, password, port,
1476 host_path, guest_path, log_filename, verbose,
1477 timeout)
1478
1479
1480 @error.context_aware
1481 def copy_files_from(self, guest_path, host_path, nic_index=0,
1482 verbose=False, timeout=600):
1483 """
1484 Transfer files from the guest.
1485
1486 @param host_path: Guest path
1487 @param guest_path: Host path
1488 @param nic_index: The index of the NIC to connect to.
1489 @param verbose: If True, log some stats using logging.debug (RSS only)
1490 @param timeout: Time (seconds) before giving up on doing the remote
1491 copy.
1492 """
1493 error.context("receiving file(s) from '%s'" % self.name)
1494 username = self.params.get("username", "")
1495 password = self.params.get("password", "")
1496 client = self.params.get("file_transfer_client")
1497 address = self.get_address(nic_index)
1498 port = self.get_port(int(self.params.get("file_transfer_port")))
1499 log_filename = ("transfer-%s-from-%s-%s.log" %
1500 (self.name, address,
1501 kvm_utils.generate_random_string(4)))
1502 kvm_utils.copy_files_from(address, client, username, password, port,
1503 guest_path, host_path, log_filename,
1504 verbose, timeout)
1505
1506
1507 @error.context_aware
1508 def serial_login(self, timeout=10):
1509 """
1510 Log into the guest via the serial console.
1511 If timeout expires while waiting for output from the guest (e.g. a
1512 password prompt or a shell prompt) -- fail.
1513
1514 @param timeout: Time (seconds) before giving up logging into the guest.
1515 @return: ShellSession object on success and None on failure.
1516 """
1517 error.context("logging into '%s' via serial console" % self.name)
1518 username = self.params.get("username", "")
1519 password = self.params.get("password", "")
1520 prompt = self.params.get("shell_prompt", "[\#\$]")
1521 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
1522 status_test_command = self.params.get("status_test_command", "")
1523
1524 self.serial_console.set_linesep(linesep)
1525 self.serial_console.set_status_test_command(status_test_command)
1526
1527 # Try to get a login prompt
1528 self.serial_console.sendline()
1529
1530 kvm_utils._remote_login(self.serial_console, username, password,
1531 prompt, timeout)
1532 return self.serial_console
1533
1534
1535 def wait_for_serial_login(self, timeout=240, internal_timeout=10):
1536 """
1537 Make multiple attempts to log into the guest via serial console.
1538
1539 @param timeout: Time (seconds) to keep trying to log in.
1540 @param internal_timeout: Timeout to pass to serial_login().
1541 @return: A ShellSession object.
1542 """
1543 logging.debug("Attempting to log into '%s' via serial console "
1544 "(timeout %ds)", self.name, timeout)
1545 end_time = time.time() + timeout
1546 while time.time() < end_time:
1547 try:
1548 return self.serial_login(internal_timeout)
1549 except kvm_utils.LoginError, e:
1550 logging.debug(e)
1551 time.sleep(2)
1552 # Timeout expired; try one more time but don't catch exceptions
1553 return self.serial_login(internal_timeout)
1554
1555
1556 @error.context_aware
1557 def migrate(self, timeout=3600, protocol="tcp", cancel_delay=None, 1044 def migrate(self, timeout=3600, protocol="tcp", cancel_delay=None,
1558 offline=False, stable_check=False, clean=True, 1045 offline=False, stable_check=False, clean=True,
1559 save_path="/tmp", dest_host="localhost", remote_port=None): 1046 save_path="/tmp", dest_host="localhost", remote_port=None):
1560 """ 1047 """
1561 Migrate the VM. 1048 Migrate the VM.
1562 1049
1563 If the migration is local, the VM object's state is switched with that 1050 If the migration is local, the VM object's state is switched with that
1564 of the destination VM. Otherwise, the state is switched with that of 1051 of the destination VM. Otherwise, the state is switched with that of
1565 a dead VM (returned by self.clone()). 1052 a dead VM (returned by self.clone()).
1566 1053
1567 @param timeout: Time to wait for migration to complete. 1054 @param timeout: Time to wait for migration to complete.
1568 @param protocol: Migration protocol ('tcp', 'unix' or 'exec'). 1055 @param protocol: Migration protocol (as defined in MIGRATION_PROTOS)
1569 @param cancel_delay: If provided, specifies a time duration after which 1056 @param cancel_delay: If provided, specifies a time duration after which
1570 migration will be canceled. Used for testing migrate_cancel. 1057 migration will be canceled. Used for testing migrate_cancel.
1571 @param offline: If True, pause the source VM before migration. 1058 @param offline: If True, pause the source VM before migration.
1572 @param stable_check: If True, compare the VM's state after migration to 1059 @param stable_check: If True, compare the VM's state after migration to
1573 its state before migration and raise an exception if they 1060 its state before migration and raise an exception if they
1574 differ. 1061 differ.
1575 @param clean: If True, delete the saved state files (relevant only if 1062 @param clean: If True, delete the saved state files (relevant only if
1576 stable_check is also True). 1063 stable_check is also True).
1577 @save_path: The path for state files. 1064 @save_path: The path for state files.
1578 @param dest_host: Destination host (defaults to 'localhost'). 1065 @param dest_host: Destination host (defaults to 'localhost').
1579 @param remote_port: Port to use for remote migration. 1066 @param remote_port: Port to use for remote migration.
1580 """ 1067 """
1068 if protocol not in self.MIGRATION_PROTOS:
1069 raise virt_vm.VMMigrateProtoUnsupportedError
1070
1581 error.base_context("migrating '%s'" % self.name) 1071 error.base_context("migrating '%s'" % self.name)
1582 1072
1583 def mig_finished(): 1073 def mig_finished():
1584 o = self.monitor.info("migrate") 1074 o = self.monitor.info("migrate")
1585 if isinstance(o, str): 1075 if isinstance(o, str):
1586 return "status: active" not in o 1076 return "status: active" not in o
1587 else: 1077 else:
1588 return o.get("status") != "active" 1078 return o.get("status") != "active"
1589 1079
1590 def mig_succeeded(): 1080 def mig_succeeded():
(...skipping 13 matching lines...) Expand all
1604 def mig_cancelled(): 1094 def mig_cancelled():
1605 o = self.monitor.info("migrate") 1095 o = self.monitor.info("migrate")
1606 if isinstance(o, str): 1096 if isinstance(o, str):
1607 return ("Migration status: cancelled" in o or 1097 return ("Migration status: cancelled" in o or
1608 "Migration status: canceled" in o) 1098 "Migration status: canceled" in o)
1609 else: 1099 else:
1610 return (o.get("status") == "cancelled" or 1100 return (o.get("status") == "cancelled" or
1611 o.get("status") == "canceled") 1101 o.get("status") == "canceled")
1612 1102
1613 def wait_for_migration(): 1103 def wait_for_migration():
1614 if not kvm_utils.wait_for(mig_finished, timeout, 2, 2, 1104 if not virt_utils.wait_for(mig_finished, timeout, 2, 2,
1615 "Waiting for migration to complete"): 1105 "Waiting for migration to complete"):
1616 raise VMMigrateTimeoutError("Timeout expired while waiting " 1106 raise virt_vm.VMMigrateTimeoutError("Timeout expired while waiti ng "
1617 "for migration to finish") 1107 "for migration to finish")
1618 1108
1619 local = dest_host == "localhost" 1109 local = dest_host == "localhost"
1620 1110
1621 clone = self.clone() 1111 clone = self.clone()
1622 if local: 1112 if local:
1623 error.context("creating destination VM") 1113 error.context("creating destination VM")
1624 if stable_check: 1114 if stable_check:
1625 # Pause the dest vm after creation 1115 # Pause the dest vm after creation
1626 extra_params = clone.params.get("extra_params", "") + " -S" 1116 extra_params = clone.params.get("extra_params", "") + " -S"
(...skipping 14 matching lines...) Expand all
1641 1131
1642 if offline: 1132 if offline:
1643 self.monitor.cmd("stop") 1133 self.monitor.cmd("stop")
1644 1134
1645 logging.info("Migrating to %s", uri) 1135 logging.info("Migrating to %s", uri)
1646 self.monitor.migrate(uri) 1136 self.monitor.migrate(uri)
1647 1137
1648 if cancel_delay: 1138 if cancel_delay:
1649 time.sleep(cancel_delay) 1139 time.sleep(cancel_delay)
1650 self.monitor.cmd("migrate_cancel") 1140 self.monitor.cmd("migrate_cancel")
1651 if not kvm_utils.wait_for(mig_cancelled, 60, 2, 2, 1141 if not virt_utils.wait_for(mig_cancelled, 60, 2, 2,
1652 "Waiting for migration " 1142 "Waiting for migration "
1653 "cancellation"): 1143 "cancellation"):
1654 raise VMMigrateCancelError("Cannot cancel migration") 1144 raise virt_vm.VMMigrateCancelError("Cannot cancel migration" )
1655 return 1145 return
1656 1146
1657 wait_for_migration() 1147 wait_for_migration()
1658 1148
1659 # Report migration status 1149 # Report migration status
1660 if mig_succeeded(): 1150 if mig_succeeded():
1661 logging.info("Migration completed successfully") 1151 logging.info("Migration completed successfully")
1662 elif mig_failed(): 1152 elif mig_failed():
1663 raise VMMigrateFailedError("Migration failed") 1153 raise virt_vm.VMMigrateFailedError("Migration failed")
1664 else: 1154 else:
1665 raise VMMigrateFailedError("Migration ended with unknown " 1155 raise virt_vm.VMMigrateFailedError("Migration ended with "
1666 "status") 1156 "unknown status")
1667 1157
1668 # Switch self <-> clone 1158 # Switch self <-> clone
1669 temp = self.clone(copy_state=True) 1159 temp = self.clone(copy_state=True)
1670 self.__dict__ = clone.__dict__ 1160 self.__dict__ = clone.__dict__
1671 clone = temp 1161 clone = temp
1672 1162
1673 # From now on, clone is the source VM that will soon be destroyed 1163 # From now on, clone is the source VM that will soon be destroyed
1674 # and self is the destination VM that will remain alive. If this 1164 # and self is the destination VM that will remain alive. If this
1675 # is remote migration, self is a dead VM object. 1165 # is remote migration, self is a dead VM object.
1676 1166
1677 error.context("after migration") 1167 error.context("after migration")
1678 if local: 1168 if local:
1679 time.sleep(1) 1169 time.sleep(1)
1680 self.verify_alive() 1170 self.verify_alive()
1681 self.verify_kernel_crash()
1682 1171
1683 if local and stable_check: 1172 if local and stable_check:
1684 try: 1173 try:
1685 save1 = os.path.join(save_path, "src-" + clone.instance) 1174 save1 = os.path.join(save_path, "src-" + clone.instance)
1686 save2 = os.path.join(save_path, "dst-" + self.instance) 1175 save2 = os.path.join(save_path, "dst-" + self.instance)
1687 clone.save_to_file(save1) 1176 clone.save_to_file(save1)
1688 self.save_to_file(save2) 1177 self.save_to_file(save2)
1689 # Fail if we see deltas 1178 # Fail if we see deltas
1690 md5_save1 = utils.hash_file(save1) 1179 md5_save1 = utils.hash_file(save1)
1691 md5_save2 = utils.hash_file(save2) 1180 md5_save2 = utils.hash_file(save2)
1692 if md5_save1 != md5_save2: 1181 if md5_save1 != md5_save2:
1693 raise VMMigrateStateMismatchError(md5_save1, md5_save2) 1182 raise virt_vm.VMMigrateStateMismatchError(md5_save1,
1183 md5_save2)
1694 finally: 1184 finally:
1695 if clean: 1185 if clean:
1696 if os.path.isfile(save1): 1186 if os.path.isfile(save1):
1697 os.remove(save1) 1187 os.remove(save1)
1698 if os.path.isfile(save2): 1188 if os.path.isfile(save2):
1699 os.remove(save2) 1189 os.remove(save2)
1700 1190
1701 finally: 1191 finally:
1702 # If we're doing remote migration and it's completed successfully, 1192 # If we're doing remote migration and it's completed successfully,
1703 # self points to a dead VM object 1193 # self points to a dead VM object
(...skipping 29 matching lines...) Expand all
1733 for m in qmp_monitors: 1223 for m in qmp_monitors:
1734 m.clear_events() 1224 m.clear_events()
1735 # Send a system_reset monitor command 1225 # Send a system_reset monitor command
1736 self.monitor.cmd("system_reset") 1226 self.monitor.cmd("system_reset")
1737 # Look for RESET QMP events 1227 # Look for RESET QMP events
1738 time.sleep(1) 1228 time.sleep(1)
1739 for m in qmp_monitors: 1229 for m in qmp_monitors:
1740 if m.get_event("RESET"): 1230 if m.get_event("RESET"):
1741 logging.info("RESET QMP event received") 1231 logging.info("RESET QMP event received")
1742 else: 1232 else:
1743 raise VMRebootError("RESET QMP event not received after " 1233 raise virt_vm.VMRebootError("RESET QMP event not received "
1744 "system_reset (monitor '%s')" % m.name) 1234 "after system_reset "
1235 "(monitor '%s')" % m.name)
1745 else: 1236 else:
1746 raise VMRebootError("Unknown reboot method: %s" % method) 1237 raise virt_vm.VMRebootError("Unknown reboot method: %s" % method)
1747 1238
1748 error.context("waiting for guest to go down", logging.info) 1239 error.context("waiting for guest to go down", logging.info)
1749 if not kvm_utils.wait_for(lambda: 1240 if not virt_utils.wait_for(lambda:
1750 not session.is_responsive(timeout=30), 1241 not session.is_responsive(timeout=30),
1751 120, 0, 1): 1242 120, 0, 1):
1752 raise VMRebootError("Guest refuses to go down") 1243 raise virt_vm.VMRebootError("Guest refuses to go down")
1753 session.close() 1244 session.close()
1754 1245
1755 error.context("logging in after reboot", logging.info) 1246 error.context("logging in after reboot", logging.info)
1756 return self.wait_for_login(nic_index, timeout=timeout) 1247 return self.wait_for_login(nic_index, timeout=timeout)
1757 1248
1758 1249
1759 def send_key(self, keystr): 1250 def send_key(self, keystr):
1760 """ 1251 """
1761 Send a key event to the VM. 1252 Send a key event to the VM.
1762 1253
1763 @param: keystr: A key event string (e.g. "ctrl-alt-delete") 1254 @param: keystr: A key event string (e.g. "ctrl-alt-delete")
1764 """ 1255 """
1765 # For compatibility with versions of QEMU that do not recognize all 1256 # For compatibility with versions of QEMU that do not recognize all
1766 # key names: replace keyname with the hex value from the dict, which 1257 # key names: replace keyname with the hex value from the dict, which
1767 # QEMU will definitely accept 1258 # QEMU will definitely accept
1768 dict = {"comma": "0x33", 1259 dict = {"comma": "0x33",
1769 "dot": "0x34", 1260 "dot": "0x34",
1770 "slash": "0x35"} 1261 "slash": "0x35"}
1771 for key, value in dict.items(): 1262 for key, value in dict.items():
1772 keystr = keystr.replace(key, value) 1263 keystr = keystr.replace(key, value)
1773 self.monitor.sendkey(keystr) 1264 self.monitor.sendkey(keystr)
1774 time.sleep(0.2) 1265 time.sleep(0.2)
1775 1266
1776 1267
1777 def send_string(self, str): 1268 # should this really be expected from VMs of all hypervisor types?
1778 """ 1269 def screendump(self, filename):
1779 Send a string to the VM.
1780
1781 @param str: String, that must consist of alphanumeric characters only.
1782 Capital letters are allowed.
1783 """
1784 for char in str:
1785 if char.isupper():
1786 self.send_key("shift-%s" % char.lower())
1787 else:
1788 self.send_key(char)
1789
1790
1791 def get_uuid(self):
1792 """
1793 Catch UUID of the VM.
1794
1795 @return: None,if not specified in config file
1796 """
1797 if self.params.get("uuid") == "random":
1798 return self.uuid
1799 else:
1800 return self.params.get("uuid", None)
1801
1802
1803 def get_cpu_count(self):
1804 """
1805 Get the cpu count of the VM.
1806 """
1807 session = self.login()
1808 try: 1270 try:
1809 return int(session.cmd(self.params.get("cpu_chk_cmd"))) 1271 if self.monitor:
1810 finally: 1272 self.monitor.screendump(filename=filename)
1811 session.close() 1273 except kvm_monitor.MonitorError, e:
1812 1274 logging.warn(e)
1813
1814 def get_memory_size(self, cmd=None):
1815 """
1816 Get bootup memory size of the VM.
1817
1818 @param check_cmd: Command used to check memory. If not provided,
1819 self.params.get("mem_chk_cmd") will be used.
1820 """
1821 session = self.login()
1822 try:
1823 if not cmd:
1824 cmd = self.params.get("mem_chk_cmd")
1825 mem_str = session.cmd(cmd)
1826 mem = re.findall("([0-9]+)", mem_str)
1827 mem_size = 0
1828 for m in mem:
1829 mem_size += int(m)
1830 if "GB" in mem_str:
1831 mem_size *= 1024
1832 elif "MB" in mem_str:
1833 pass
1834 else:
1835 mem_size /= 1024
1836 return int(mem_size)
1837 finally:
1838 session.close()
1839
1840
1841 def get_current_memory_size(self):
1842 """
1843 Get current memory size of the VM, rather than bootup memory.
1844 """
1845 cmd = self.params.get("mem_chk_cur_cmd")
1846 return self.get_memory_size(cmd)
1847 1275
1848 1276
1849 def save_to_file(self, path): 1277 def save_to_file(self, path):
1850 """ 1278 """
1851 Save the state of virtual machine to a file through migrate to 1279 Save the state of virtual machine to a file through migrate to
1852 exec 1280 exec
1853 """ 1281 """
1854 # Make sure we only get one iteration 1282 # Make sure we only get one iteration
1855 self.monitor.cmd("migrate_set_speed 1000g") 1283 self.monitor.cmd("migrate_set_speed 1000g")
1856 self.monitor.cmd("migrate_set_downtime 100000000") 1284 self.monitor.cmd("migrate_set_downtime 100000000")
1857 self.monitor.migrate('"exec:cat>%s"' % path) 1285 self.monitor.migrate('"exec:cat>%s"' % path)
1858 # Restore the speed and downtime of migration 1286 # Restore the speed and downtime of migration
1859 self.monitor.cmd("migrate_set_speed %d" % (32<<20)) 1287 self.monitor.cmd("migrate_set_speed %d" % (32<<20))
1860 self.monitor.cmd("migrate_set_downtime 0.03") 1288 self.monitor.cmd("migrate_set_downtime 0.03")
1289
1290
1291 def needs_restart(self, name, params, basedir):
1292 """
1293 Verifies whether the current qemu commandline matches the requested
1294 one, based on the test parameters.
1295 """
1296 return (self.__make_qemu_command() !=
1297 self.__make_qemu_command(name, params, basedir))
OLDNEW
« no previous file with comments | « client/virt/kvm_monitor.py ('k') | client/virt/ppm_utils.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698