virt.virt_test_utils: run_autotest - 'tar' needs relative paths to strip the leading '/'
[autotest-zwu.git] / client / virt / kvm_vm.py
bloba2f22b4e4b503c2854c580ebe05f5f827ca97fd0
1 """
2 Utility classes and functions to handle Virtual Machine creation using qemu.
4 @copyright: 2008-2009 Red Hat Inc.
5 """
7 import time, os, logging, fcntl, re, commands, glob
8 from autotest_lib.client.common_lib import error
9 from autotest_lib.client.bin import utils
10 import virt_utils, virt_vm, virt_test_setup, kvm_monitor, aexpect
13 class VM(virt_vm.BaseVM):
14 """
15 This class handles all basic VM operations.
16 """
18 MIGRATION_PROTOS = ['tcp', 'unix', 'exec']
20 def __init__(self, name, params, root_dir, address_cache, state=None):
21 """
22 Initialize the object and set a few attributes.
24 @param name: The name of the object
25 @param params: A dict containing VM params
26 (see method make_qemu_command for a full description)
27 @param root_dir: Base directory for relative filenames
28 @param address_cache: A dict that maps MAC addresses to IP addresses
29 @param state: If provided, use this as self.__dict__
30 """
31 virt_vm.BaseVM.__init__(self, name, params)
33 if state:
34 self.__dict__ = state
35 else:
36 self.process = None
37 self.serial_console = None
38 self.redirs = {}
39 self.vnc_port = 5900
40 self.monitors = []
41 self.pci_assignable = None
42 self.netdev_id = []
43 self.device_id = []
44 self.tapfds = []
45 self.uuid = None
48 self.spice_port = 8000
49 self.name = name
50 self.params = params
51 self.root_dir = root_dir
52 self.address_cache = address_cache
55 def verify_alive(self):
56 """
57 Make sure the VM is alive and that the main monitor is responsive.
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())
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())
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()
86 def verify_status(self, status):
87 """
88 Check VM status
90 @param status: Optional VM status, 'running' or 'paused'
91 @raise VMStatusError: If the VM status is not same as parameter
92 """
93 if not self.monitor.verify_status(status):
94 raise virt_vm.VMStatusError("VM status is unexpected")
97 def clone(self, name=None, params=None, root_dir=None, address_cache=None,
98 copy_state=False):
99 """
100 Return a clone of the VM object with optionally modified parameters.
101 The clone is initially not alive and needs to be started using create().
102 Any parameters not passed to this function are copied from the source
105 @param name: Optional new VM name
106 @param params: Optional new VM creation parameters
107 @param root_dir: Optional new base directory for relative filenames
108 @param address_cache: A dict that maps MAC addresses to IP addresses
109 @param copy_state: If True, copy the original VM's state to the clone.
110 Mainly useful for make_qemu_command().
112 if name is None:
113 name = self.name
114 if params is None:
115 params = self.params.copy()
116 if root_dir is None:
117 root_dir = self.root_dir
118 if address_cache is None:
119 address_cache = self.address_cache
120 if copy_state:
121 state = self.__dict__.copy()
122 else:
123 state = None
124 return VM(name, params, root_dir, address_cache, state)
127 def __make_qemu_command(self, name=None, params=None, root_dir=None):
129 Generate a qemu command line. All parameters are optional. If a
130 parameter is not supplied, the corresponding value stored in the
131 class attributes is used.
133 @param name: The name of the object
134 @param params: A dict containing VM params
135 @param root_dir: Base directory for relative filenames
137 @note: The params dict should contain:
138 mem -- memory size in MBs
139 cdrom -- ISO filename to use with the qemu -cdrom parameter
140 extra_params -- a string to append to the qemu command
141 shell_port -- port of the remote shell daemon on the guest
142 (SSH, Telnet or the home-made Remote Shell Server)
143 shell_client -- client program to use for connecting to the
144 remote shell daemon on the guest (ssh, telnet or nc)
145 x11_display -- if specified, the DISPLAY environment variable
146 will be be set to this value for the qemu process (useful for
147 SDL rendering)
148 images -- a list of image object names, separated by spaces
149 nics -- a list of NIC object names, separated by spaces
151 For each image in images:
152 drive_format -- string to pass as 'if' parameter for this
153 image (e.g. ide, scsi)
154 image_snapshot -- if yes, pass 'snapshot=on' to qemu for
155 this image
156 image_boot -- if yes, pass 'boot=on' to qemu for this image
157 In addition, all parameters required by get_image_filename.
159 For each NIC in nics:
160 nic_model -- string to pass as 'model' parameter for this
161 NIC (e.g. e1000)
163 # Helper function for command line option wrappers
164 def has_option(help, option):
165 return bool(re.search(r"^-%s(\s|$)" % option, help, re.MULTILINE))
167 # Wrappers for all supported qemu command line parameters.
168 # This is meant to allow support for multiple qemu versions.
169 # Each of these functions receives the output of 'qemu -help' as a
170 # parameter, and should add the requested command line option
171 # accordingly.
173 def add_name(help, name):
174 return " -name '%s'" % name
176 def add_human_monitor(help, filename):
177 return " -monitor unix:'%s',server,nowait" % filename
179 def add_qmp_monitor(help, filename):
180 return " -qmp unix:'%s',server,nowait" % filename
182 def add_serial(help, filename):
183 return " -serial unix:'%s',server,nowait" % filename
185 def add_mem(help, mem):
186 return " -m %s" % mem
188 def add_smp(help, smp):
189 return " -smp %s" % smp
191 def add_cdrom(help, filename, index=None, format=None):
192 if has_option(help, "drive"):
193 name = None;
194 dev = "";
195 if format == "ahci":
196 name = "ahci%s" % index
197 dev += " -device ide-drive,bus=ahci.%s,drive=%s" % (index, name)
198 format = "none"
199 index = None
200 if format == "usb2":
201 name = "usb2.%s" % index
202 dev += " -device usb-storage,bus=ehci.0,drive=%s" % name
203 dev += ",port=%d" % (int(index) + 1)
204 format = "none"
205 index = None
206 cmd = " -drive file='%s',media=cdrom" % filename
207 if index is not None:
208 cmd += ",index=%s" % index
209 if format:
210 cmd += ",if=%s" % format
211 if name:
212 cmd += ",id=%s" % name
213 return cmd + dev
214 else:
215 return " -cdrom '%s'" % filename
217 def add_drive(help, filename, index=None, format=None, cache=None,
218 werror=None, serial=None, snapshot=False, boot=False):
219 name = None;
220 dev = "";
221 if format == "ahci":
222 name = "ahci%s" % index
223 dev += " -device ide-drive,bus=ahci.%s,drive=%s" % (index, name)
224 format = "none"
225 index = None
226 if format == "usb2":
227 name = "usb2.%s" % index
228 dev += " -device usb-storage,bus=ehci.0,drive=%s" % name
229 dev += ",port=%d" % (int(index) + 1)
230 format = "none"
231 index = None
232 cmd = " -drive file='%s'" % filename
233 if index is not None:
234 cmd += ",index=%s" % index
235 if format:
236 cmd += ",if=%s" % format
237 if cache:
238 cmd += ",cache=%s" % cache
239 if werror:
240 cmd += ",werror=%s" % werror
241 if serial:
242 cmd += ",serial='%s'" % serial
243 if snapshot:
244 cmd += ",snapshot=on"
245 if boot:
246 cmd += ",boot=on"
247 if name:
248 cmd += ",id=%s" % name
249 return cmd + dev
251 def add_nic(help, vlan, model=None, mac=None, device_id=None, netdev_id=None,
252 nic_extra_params=None):
253 if has_option(help, "netdev"):
254 netdev_vlan_str = ",netdev=%s" % netdev_id
255 else:
256 netdev_vlan_str = ",vlan=%d" % vlan
257 if has_option(help, "device"):
258 if not model:
259 model = "rtl8139"
260 elif model == "virtio":
261 model = "virtio-net-pci"
262 cmd = " -device %s" % model + netdev_vlan_str
263 if mac:
264 cmd += ",mac='%s'" % mac
265 if nic_extra_params:
266 cmd += ",%s" % nic_extra_params
267 else:
268 cmd = " -net nic" + netdev_vlan_str
269 if model:
270 cmd += ",model=%s" % model
271 if mac:
272 cmd += ",macaddr='%s'" % mac
273 if device_id:
274 cmd += ",id='%s'" % device_id
275 return cmd
277 def add_net(help, vlan, mode, ifname=None, tftp=None, bootfile=None,
278 hostfwd=[], netdev_id=None, netdev_extra_params=None,
279 tapfd=None):
280 if has_option(help, "netdev"):
281 cmd = " -netdev %s,id=%s" % (mode, netdev_id)
282 if netdev_extra_params:
283 cmd += ",%s" % netdev_extra_params
284 else:
285 cmd = " -net %s,vlan=%d" % (mode, vlan)
286 if mode == "tap" and tapfd:
287 cmd += ",fd=%d" % tapfd
288 elif mode == "user":
289 if tftp and "[,tftp=" in help:
290 cmd += ",tftp='%s'" % tftp
291 if bootfile and "[,bootfile=" in help:
292 cmd += ",bootfile='%s'" % bootfile
293 if "[,hostfwd=" in help:
294 for host_port, guest_port in hostfwd:
295 cmd += ",hostfwd=tcp::%s-:%s" % (host_port, guest_port)
296 return cmd
298 def add_floppy(help, filename):
299 return " -fda '%s'" % filename
301 def add_tftp(help, filename):
302 # If the new syntax is supported, don't add -tftp
303 if "[,tftp=" in help:
304 return ""
305 else:
306 return " -tftp '%s'" % filename
308 def add_bootp(help, filename):
309 # If the new syntax is supported, don't add -bootp
310 if "[,bootfile=" in help:
311 return ""
312 else:
313 return " -bootp '%s'" % filename
315 def add_tcp_redir(help, host_port, guest_port):
316 # If the new syntax is supported, don't add -redir
317 if "[,hostfwd=" in help:
318 return ""
319 else:
320 return " -redir tcp:%s::%s" % (host_port, guest_port)
322 def add_vnc(help, vnc_port):
323 return " -vnc :%d" % (vnc_port - 5900)
325 def add_sdl(help):
326 if has_option(help, "sdl"):
327 return " -sdl"
328 else:
329 return ""
331 def add_nographic(help):
332 return " -nographic"
334 def add_uuid(help, uuid):
335 return " -uuid '%s'" % uuid
337 def add_pcidevice(help, host):
338 return " -pcidevice host='%s'" % host
340 def add_spice(help, port, param):
341 if has_option(help,"spice"):
342 return " -spice port=%s,%s" % (port, param)
343 else:
344 return ""
346 def add_qxl_vga(help, qxl, vga, qxl_dev_nr=None):
347 str = ""
348 if has_option(help, "qxl"):
349 if qxl and qxl_dev_nr is not None:
350 str += " -qxl %s" % qxl_dev_nr
351 if has_option(help, "vga") and vga and vga != "qxl":
352 str += " -vga %s" % vga
353 elif has_option(help, "vga"):
354 if qxl:
355 str += " -vga qxl"
356 elif vga:
357 str += " -vga %s" % vga
358 return str
360 def add_kernel(help, filename):
361 return " -kernel '%s'" % filename
363 def add_initrd(help, filename):
364 return " -initrd '%s'" % filename
366 def add_kernel_cmdline(help, cmdline):
367 return " -append '%s'" % cmdline
369 def add_testdev(help, filename):
370 return (" -chardev file,id=testlog,path=%s"
371 " -device testdev,chardev=testlog" % filename)
373 def add_no_hpet(help):
374 if has_option(help, "no-hpet"):
375 return " -no-hpet"
376 else:
377 return ""
379 # End of command line option wrappers
381 if name is None:
382 name = self.name
383 if params is None:
384 params = self.params
385 if root_dir is None:
386 root_dir = self.root_dir
388 have_ahci = False
389 have_usb2 = False
391 # Clone this VM using the new params
392 vm = self.clone(name, params, root_dir, copy_state=True)
394 qemu_binary = virt_utils.get_path(root_dir, params.get("qemu_binary",
395 "qemu"))
396 help = commands.getoutput("%s -help" % qemu_binary)
398 # Start constructing the qemu command
399 qemu_cmd = ""
400 # Set the X11 display parameter if requested
401 if params.get("x11_display"):
402 qemu_cmd += "DISPLAY=%s " % params.get("x11_display")
403 # Update LD_LIBRARY_PATH for built libraries (libspice-server)
404 library_path = os.path.join(self.root_dir, 'build', 'lib')
405 if os.path.isdir(library_path):
406 library_path = os.path.abspath(library_path)
407 qemu_cmd += "LD_LIBRARY_PATH=%s " % library_path
408 # Add the qemu binary
409 qemu_cmd += qemu_binary
410 # Add the VM's name
411 qemu_cmd += add_name(help, name)
412 # no automagic devices please
413 if has_option(help,"nodefaults"):
414 qemu_cmd += " -nodefaults"
415 qemu_cmd += " -vga std"
416 # Add monitors
417 for monitor_name in params.objects("monitors"):
418 monitor_params = params.object_params(monitor_name)
419 monitor_filename = vm.get_monitor_filename(monitor_name)
420 if monitor_params.get("monitor_type") == "qmp":
421 qemu_cmd += add_qmp_monitor(help, monitor_filename)
422 else:
423 qemu_cmd += add_human_monitor(help, monitor_filename)
425 # Add serial console redirection
426 qemu_cmd += add_serial(help, vm.get_serial_console_filename())
428 for image_name in params.objects("images"):
429 image_params = params.object_params(image_name)
430 if image_params.get("boot_drive") == "no":
431 continue
432 if image_params.get("drive_format") == "ahci" and not have_ahci:
433 qemu_cmd += " -device ahci,id=ahci"
434 have_ahci = True
435 if image_params.get("drive_format") == "usb2" and not have_usb2:
436 qemu_cmd += " -device usb-ehci,id=ehci"
437 have_usb2 = True
438 qemu_cmd += add_drive(help,
439 virt_vm.get_image_filename(image_params, root_dir),
440 image_params.get("drive_index"),
441 image_params.get("drive_format"),
442 image_params.get("drive_cache"),
443 image_params.get("drive_werror"),
444 image_params.get("drive_serial"),
445 image_params.get("image_snapshot") == "yes",
446 image_params.get("image_boot") == "yes")
448 redirs = []
449 for redir_name in params.objects("redirs"):
450 redir_params = params.object_params(redir_name)
451 guest_port = int(redir_params.get("guest_port"))
452 host_port = vm.redirs.get(guest_port)
453 redirs += [(host_port, guest_port)]
455 vlan = 0
456 for nic_name in params.objects("nics"):
457 nic_params = params.object_params(nic_name)
458 try:
459 netdev_id = vm.netdev_id[vlan]
460 device_id = vm.device_id[vlan]
461 except IndexError:
462 netdev_id = None
463 device_id = None
464 # Handle the '-net nic' part
465 try:
466 mac = vm.get_mac_address(vlan)
467 except virt_vm.VMAddressError:
468 mac = None
469 qemu_cmd += add_nic(help, vlan, nic_params.get("nic_model"), mac,
470 device_id, netdev_id, nic_params.get("nic_extra_params"))
471 # Handle the '-net tap' or '-net user' or '-netdev' part
472 tftp = nic_params.get("tftp")
473 if tftp:
474 tftp = virt_utils.get_path(root_dir, tftp)
475 if nic_params.get("nic_mode") == "tap":
476 try:
477 tapfd = vm.tapfds[vlan]
478 except:
479 tapfd = None
480 else:
481 tapfd = None
482 qemu_cmd += add_net(help, vlan,
483 nic_params.get("nic_mode", "user"),
484 vm.get_ifname(vlan), tftp,
485 nic_params.get("bootp"), redirs, netdev_id,
486 nic_params.get("netdev_extra_params"),
487 tapfd)
488 # Proceed to next NIC
489 vlan += 1
491 mem = params.get("mem")
492 if mem:
493 qemu_cmd += add_mem(help, mem)
495 smp = params.get("smp")
496 if smp:
497 qemu_cmd += add_smp(help, smp)
499 for cdrom in params.objects("cdroms"):
500 cdrom_params = params.object_params(cdrom)
501 iso = cdrom_params.get("cdrom")
502 if cdrom_params.get("cd_format") == "ahci" and not have_ahci:
503 qemu_cmd += " -device ahci,id=ahci"
504 have_ahci = True
505 if cdrom_params.get("cd_format") == "usb2" and not have_usb2:
506 qemu_cmd += " -device usb-ehci,id=ehci"
507 have_usb2 = True
508 if iso:
509 qemu_cmd += add_cdrom(help, virt_utils.get_path(root_dir, iso),
510 cdrom_params.get("drive_index"),
511 cdrom_params.get("cd_format"))
513 # We may want to add {floppy_otps} parameter for -fda
514 # {fat:floppy:}/path/. However vvfat is not usually recommended.
515 floppy = params.get("floppy")
516 if floppy:
517 floppy = virt_utils.get_path(root_dir, floppy)
518 qemu_cmd += add_floppy(help, floppy)
520 tftp = params.get("tftp")
521 if tftp:
522 tftp = virt_utils.get_path(root_dir, tftp)
523 qemu_cmd += add_tftp(help, tftp)
525 bootp = params.get("bootp")
526 if bootp:
527 qemu_cmd += add_bootp(help, bootp)
529 kernel = params.get("kernel")
530 if kernel:
531 kernel = virt_utils.get_path(root_dir, kernel)
532 qemu_cmd += add_kernel(help, kernel)
534 kernel_cmdline = params.get("kernel_cmdline")
535 if kernel_cmdline:
536 qemu_cmd += add_kernel_cmdline(help, kernel_cmdline)
538 initrd = params.get("initrd")
539 if initrd:
540 initrd = virt_utils.get_path(root_dir, initrd)
541 qemu_cmd += add_initrd(help, initrd)
543 for host_port, guest_port in redirs:
544 qemu_cmd += add_tcp_redir(help, host_port, guest_port)
546 if params.get("display") == "vnc":
547 qemu_cmd += add_vnc(help, vm.vnc_port)
548 elif params.get("display") == "sdl":
549 qemu_cmd += add_sdl(help)
550 elif params.get("display") == "nographic":
551 qemu_cmd += add_nographic(help)
552 elif params.get("display") == "spice":
553 qemu_cmd += add_spice(help, self.spice_port, params.get("spice"))
555 qxl = ""
556 vga = ""
557 if params.get("qxl"):
558 qxl = params.get("qxl")
559 if params.get("vga"):
560 vga = params.get("vga")
561 if qxl or vga:
562 if params.get("display") == "spice":
563 qxl_dev_nr = params.get("qxl_dev_nr", None)
564 qemu_cmd += add_qxl_vga(help, qxl, vga, qxl_dev_nr)
566 if params.get("uuid") == "random":
567 qemu_cmd += add_uuid(help, vm.uuid)
568 elif params.get("uuid"):
569 qemu_cmd += add_uuid(help, params.get("uuid"))
571 if params.get("testdev") == "yes":
572 qemu_cmd += add_testdev(help, vm.get_testlog_filename())
574 if params.get("disable_hpet") == "yes":
575 qemu_cmd += add_no_hpet(help)
577 # If the PCI assignment step went OK, add each one of the PCI assigned
578 # devices to the qemu command line.
579 if vm.pci_assignable:
580 for pci_id in vm.pa_pci_ids:
581 qemu_cmd += add_pcidevice(help, pci_id)
583 extra_params = params.get("extra_params")
584 if extra_params:
585 qemu_cmd += " %s" % extra_params
587 return qemu_cmd
590 @error.context_aware
591 def create(self, name=None, params=None, root_dir=None, timeout=5.0,
592 migration_mode=None, mac_source=None):
594 Start the VM by running a qemu command.
595 All parameters are optional. If name, params or root_dir are not
596 supplied, the respective values stored as class attributes are used.
598 @param name: The name of the object
599 @param params: A dict containing VM params
600 @param root_dir: Base directory for relative filenames
601 @param migration_mode: If supplied, start VM for incoming migration
602 using this protocol (either 'tcp', 'unix' or 'exec')
603 @param migration_exec_cmd: Command to embed in '-incoming "exec: ..."'
604 (e.g. 'gzip -c -d filename') if migration_mode is 'exec'
605 @param mac_source: A VM object from which to copy MAC addresses. If not
606 specified, new addresses will be generated.
608 @raise VMCreateError: If qemu terminates unexpectedly
609 @raise VMKVMInitError: If KVM initialization fails
610 @raise VMHugePageError: If hugepage initialization fails
611 @raise VMImageMissingError: If a CD image is missing
612 @raise VMHashMismatchError: If a CD image hash has doesn't match the
613 expected hash
614 @raise VMBadPATypeError: If an unsupported PCI assignment type is
615 requested
616 @raise VMPAError: If no PCI assignable devices could be assigned
617 @raise TAPCreationError: If fail to create tap fd
618 @raise BRAddIfError: If fail to add a tap to a bridge
619 @raise TAPBringUpError: If fail to bring up a tap
620 @raise PrivateBridgeError: If fail to bring the private bridge
622 error.context("creating '%s'" % self.name)
623 self.destroy(free_mac_addresses=False)
625 if name is not None:
626 self.name = name
627 if params is not None:
628 self.params = params
629 if root_dir is not None:
630 self.root_dir = root_dir
631 name = self.name
632 params = self.params
633 root_dir = self.root_dir
635 # Verify the md5sum of the ISO images
636 for cdrom in params.objects("cdroms"):
637 cdrom_params = params.object_params(cdrom)
638 iso = cdrom_params.get("cdrom")
639 if iso:
640 iso = virt_utils.get_path(root_dir, iso)
641 if not os.path.exists(iso):
642 raise virt_vm.VMImageMissingError(iso)
643 compare = False
644 if cdrom_params.get("md5sum_1m"):
645 logging.debug("Comparing expected MD5 sum with MD5 sum of "
646 "first MB of ISO file...")
647 actual_hash = utils.hash_file(iso, 1048576, method="md5")
648 expected_hash = cdrom_params.get("md5sum_1m")
649 compare = True
650 elif cdrom_params.get("md5sum"):
651 logging.debug("Comparing expected MD5 sum with MD5 sum of "
652 "ISO file...")
653 actual_hash = utils.hash_file(iso, method="md5")
654 expected_hash = cdrom_params.get("md5sum")
655 compare = True
656 elif cdrom_params.get("sha1sum"):
657 logging.debug("Comparing expected SHA1 sum with SHA1 sum "
658 "of ISO file...")
659 actual_hash = utils.hash_file(iso, method="sha1")
660 expected_hash = cdrom_params.get("sha1sum")
661 compare = True
662 if compare:
663 if actual_hash == expected_hash:
664 logging.debug("Hashes match")
665 else:
666 raise virt_vm.VMHashMismatchError(actual_hash,
667 expected_hash)
669 # Make sure the following code is not executed by more than one thread
670 # at the same time
671 lockfile = open("/tmp/kvm-autotest-vm-create.lock", "w+")
672 fcntl.lockf(lockfile, fcntl.LOCK_EX)
674 try:
675 # Handle port redirections
676 redir_names = params.objects("redirs")
677 host_ports = virt_utils.find_free_ports(5000, 6000, len(redir_names))
678 self.redirs = {}
679 for i in range(len(redir_names)):
680 redir_params = params.object_params(redir_names[i])
681 guest_port = int(redir_params.get("guest_port"))
682 self.redirs[guest_port] = host_ports[i]
684 # Generate netdev IDs for all NICs and create TAP fd
685 self.netdev_id = []
686 self.tapfds = []
687 vlan = 0
688 for nic in params.objects("nics"):
689 self.netdev_id.append(virt_utils.generate_random_id())
690 self.device_id.append(virt_utils.generate_random_id())
691 nic_params = params.object_params(nic)
692 if nic_params.get("nic_mode") == "tap":
693 ifname = self.get_ifname(vlan)
694 brname = nic_params.get("bridge")
695 if brname == "private":
696 brname = virt_test_setup.PrivateBridgeConfig().brname
697 tapfd = virt_utils.open_tap("/dev/net/tun", ifname)
698 virt_utils.add_to_bridge(ifname, brname)
699 virt_utils.bring_up_ifname(ifname)
700 self.tapfds.append(tapfd)
701 vlan += 1
703 # Find available VNC port, if needed
704 if params.get("display") == "vnc":
705 self.vnc_port = virt_utils.find_free_port(5900, 6100)
707 # Find available spice port, if needed
708 if params.get("spice"):
709 self.spice_port = virt_utils.find_free_port(8000, 8100)
711 # Find random UUID if specified 'uuid = random' in config file
712 if params.get("uuid") == "random":
713 f = open("/proc/sys/kernel/random/uuid")
714 self.uuid = f.read().strip()
715 f.close()
717 # Generate or copy MAC addresses for all NICs
718 num_nics = len(params.objects("nics"))
719 for vlan in range(num_nics):
720 nic_name = params.objects("nics")[vlan]
721 nic_params = params.object_params(nic_name)
722 mac = (nic_params.get("nic_mac") or
723 mac_source and mac_source.get_mac_address(vlan))
724 if mac:
725 virt_utils.set_mac_address(self.instance, vlan, mac)
726 else:
727 virt_utils.generate_mac_address(self.instance, vlan)
729 # Assign a PCI assignable device
730 self.pci_assignable = None
731 pa_type = params.get("pci_assignable")
732 if pa_type and pa_type != "no":
733 pa_devices_requested = params.get("devices_requested")
735 # Virtual Functions (VF) assignable devices
736 if pa_type == "vf":
737 self.pci_assignable = virt_utils.PciAssignable(
738 type=pa_type,
739 driver=params.get("driver"),
740 driver_option=params.get("driver_option"),
741 devices_requested=pa_devices_requested)
742 # Physical NIC (PF) assignable devices
743 elif pa_type == "pf":
744 self.pci_assignable = virt_utils.PciAssignable(
745 type=pa_type,
746 names=params.get("device_names"),
747 devices_requested=pa_devices_requested)
748 # Working with both VF and PF
749 elif pa_type == "mixed":
750 self.pci_assignable = virt_utils.PciAssignable(
751 type=pa_type,
752 driver=params.get("driver"),
753 driver_option=params.get("driver_option"),
754 names=params.get("device_names"),
755 devices_requested=pa_devices_requested)
756 else:
757 raise virt_vm.VMBadPATypeError(pa_type)
759 self.pa_pci_ids = self.pci_assignable.request_devs()
761 if self.pa_pci_ids:
762 logging.debug("Successfuly assigned devices: %s",
763 self.pa_pci_ids)
764 else:
765 raise virt_vm.VMPAError(pa_type)
767 # Make qemu command
768 qemu_command = self.__make_qemu_command()
770 # Add migration parameters if required
771 if migration_mode == "tcp":
772 self.migration_port = virt_utils.find_free_port(5200, 6000)
773 qemu_command += " -incoming tcp:0:%d" % self.migration_port
774 elif migration_mode == "unix":
775 self.migration_file = "/tmp/migration-unix-%s" % self.instance
776 qemu_command += " -incoming unix:%s" % self.migration_file
777 elif migration_mode == "exec":
778 self.migration_port = virt_utils.find_free_port(5200, 6000)
779 qemu_command += (' -incoming "exec:nc -l %s"' %
780 self.migration_port)
782 logging.info("Running qemu command:\n%s", qemu_command)
783 self.process = aexpect.run_bg(qemu_command, None,
784 logging.info, "(qemu) ")
785 for tapfd in self.tapfds:
786 try:
787 os.close(tapfd)
788 # File descriptor is already closed
789 except OSError:
790 pass
792 # Make sure the process was started successfully
793 if not self.process.is_alive():
794 e = virt_vm.VMCreateError(qemu_command,
795 self.process.get_status(),
796 self.process.get_output())
797 self.destroy()
798 raise e
800 # Establish monitor connections
801 self.monitors = []
802 for monitor_name in params.objects("monitors"):
803 monitor_params = params.object_params(monitor_name)
804 # Wait for monitor connection to succeed
805 end_time = time.time() + timeout
806 while time.time() < end_time:
807 try:
808 if monitor_params.get("monitor_type") == "qmp":
809 # Add a QMP monitor
810 monitor = kvm_monitor.QMPMonitor(
811 monitor_name,
812 self.get_monitor_filename(monitor_name))
813 else:
814 # Add a "human" monitor
815 monitor = kvm_monitor.HumanMonitor(
816 monitor_name,
817 self.get_monitor_filename(monitor_name))
818 monitor.verify_responsive()
819 break
820 except kvm_monitor.MonitorError, e:
821 logging.warn(e)
822 time.sleep(1)
823 else:
824 self.destroy()
825 raise e
826 # Add this monitor to the list
827 self.monitors += [monitor]
829 # Get the output so far, to see if we have any problems with
830 # KVM modules or with hugepage setup.
831 output = self.process.get_output()
833 if re.search("Could not initialize KVM", output, re.IGNORECASE):
834 e = virt_vm.VMKVMInitError(qemu_command, self.process.get_output())
835 self.destroy()
836 raise e
838 if "alloc_mem_area" in output:
839 e = virt_vm.VMHugePageError(qemu_command, self.process.get_output())
840 self.destroy()
841 raise e
843 logging.debug("VM appears to be alive with PID %s", self.get_pid())
845 # Establish a session with the serial console -- requires a version
846 # of netcat that supports -U
847 self.serial_console = aexpect.ShellSession(
848 "nc -U %s" % self.get_serial_console_filename(),
849 auto_close=False,
850 output_func=virt_utils.log_line,
851 output_params=("serial-%s.log" % name,))
853 finally:
854 fcntl.lockf(lockfile, fcntl.LOCK_UN)
855 lockfile.close()
858 def destroy(self, gracefully=True, free_mac_addresses=True):
860 Destroy the VM.
862 If gracefully is True, first attempt to shutdown the VM with a shell
863 command. Then, attempt to destroy the VM via the monitor with a 'quit'
864 command. If that fails, send SIGKILL to the qemu process.
866 @param gracefully: If True, an attempt will be made to end the VM
867 using a shell command before trying to end the qemu process
868 with a 'quit' or a kill signal.
869 @param free_mac_addresses: If True, the MAC addresses used by the VM
870 will be freed.
872 try:
873 # Is it already dead?
874 if self.is_dead():
875 return
877 logging.debug("Destroying VM with PID %s", self.get_pid())
879 if gracefully and self.params.get("shutdown_command"):
880 # Try to destroy with shell command
881 logging.debug("Trying to shutdown VM with shell command")
882 try:
883 session = self.login()
884 except (virt_utils.LoginError, virt_vm.VMError), e:
885 logging.debug(e)
886 else:
887 try:
888 # Send the shutdown command
889 session.sendline(self.params.get("shutdown_command"))
890 logging.debug("Shutdown command sent; waiting for VM "
891 "to go down")
892 if virt_utils.wait_for(self.is_dead, 60, 1, 1):
893 logging.debug("VM is down")
894 return
895 finally:
896 session.close()
898 if self.monitor:
899 # Try to destroy with a monitor command
900 logging.debug("Trying to kill VM with monitor command")
901 try:
902 self.monitor.quit()
903 except kvm_monitor.MonitorError, e:
904 logging.warn(e)
905 else:
906 # Wait for the VM to be really dead
907 if virt_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
908 logging.debug("VM is down")
909 return
911 # If the VM isn't dead yet...
912 logging.debug("Cannot quit normally, sending a kill to close the "
913 "deal")
914 virt_utils.kill_process_tree(self.process.get_pid(), 9)
915 # Wait for the VM to be really dead
916 if virt_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
917 logging.debug("VM is down")
918 return
920 logging.error("Process %s is a zombie!", self.process.get_pid())
922 finally:
923 self.monitors = []
924 if self.pci_assignable:
925 self.pci_assignable.release_devs()
926 if self.process:
927 self.process.close()
928 if self.serial_console:
929 self.serial_console.close()
930 for f in ([self.get_testlog_filename(),
931 self.get_serial_console_filename()] +
932 self.get_monitor_filenames()):
933 try:
934 os.unlink(f)
935 except OSError:
936 pass
937 if hasattr(self, "migration_file"):
938 try:
939 os.unlink(self.migration_file)
940 except OSError:
941 pass
942 if free_mac_addresses:
943 num_nics = len(self.params.objects("nics"))
944 for vlan in range(num_nics):
945 self.free_mac_address(vlan)
948 @property
949 def monitor(self):
951 Return the main monitor object, selected by the parameter main_monitor.
952 If main_monitor isn't defined, return the first monitor.
953 If no monitors exist, or if main_monitor refers to a nonexistent
954 monitor, return None.
956 for m in self.monitors:
957 if m.name == self.params.get("main_monitor"):
958 return m
959 if self.monitors and not self.params.get("main_monitor"):
960 return self.monitors[0]
963 def get_monitor_filename(self, monitor_name):
965 Return the filename corresponding to a given monitor name.
967 return "/tmp/monitor-%s-%s" % (monitor_name, self.instance)
970 def get_monitor_filenames(self):
972 Return a list of all monitor filenames (as specified in the VM's
973 params).
975 return [self.get_monitor_filename(m) for m in
976 self.params.objects("monitors")]
979 def get_address(self, index=0):
981 Return the address of a NIC of the guest, in host space.
983 If port redirection is used, return 'localhost' (the NIC has no IP
984 address of its own). Otherwise return the NIC's IP address.
986 @param index: Index of the NIC whose address is requested.
987 @raise VMMACAddressMissingError: If no MAC address is defined for the
988 requested NIC
989 @raise VMIPAddressMissingError: If no IP address is found for the the
990 NIC's MAC address
991 @raise VMAddressVerificationError: If the MAC-IP address mapping cannot
992 be verified (using arping)
994 nics = self.params.objects("nics")
995 nic_name = nics[index]
996 nic_params = self.params.object_params(nic_name)
997 if nic_params.get("nic_mode") == "tap":
998 mac = self.get_mac_address(index).lower()
999 # Get the IP address from the cache
1000 ip = self.address_cache.get(mac)
1001 if not ip:
1002 raise virt_vm.VMIPAddressMissingError(mac)
1003 # Make sure the IP address is assigned to this guest
1004 macs = [self.get_mac_address(i) for i in range(len(nics))]
1005 if not virt_utils.verify_ip_address_ownership(ip, macs):
1006 raise virt_vm.VMAddressVerificationError(mac, ip)
1007 return ip
1008 else:
1009 return "localhost"
1012 def get_port(self, port, nic_index=0):
1014 Return the port in host space corresponding to port in guest space.
1016 @param port: Port number in host space.
1017 @param nic_index: Index of the NIC.
1018 @return: If port redirection is used, return the host port redirected
1019 to guest port port. Otherwise return port.
1020 @raise VMPortNotRedirectedError: If an unredirected port is requested
1021 in user mode
1023 nic_name = self.params.objects("nics")[nic_index]
1024 nic_params = self.params.object_params(nic_name)
1025 if nic_params.get("nic_mode") == "tap":
1026 return port
1027 else:
1028 try:
1029 return self.redirs[port]
1030 except KeyError:
1031 raise virt_vm.VMPortNotRedirectedError(port)
1034 def get_peer(self, netid):
1036 Return the peer of netdev or network deivce.
1038 @param netid: id of netdev or device
1039 @return: id of the peer device otherwise None
1041 network_info = self.monitor.info("network")
1042 try:
1043 return re.findall("%s:.*peer=(.*)" % netid, network_info)[0]
1044 except IndexError:
1045 return None
1048 def get_ifname(self, nic_index=0):
1050 Return the ifname of a tap device associated with a NIC.
1052 @param nic_index: Index of the NIC
1054 nics = self.params.objects("nics")
1055 nic_name = nics[nic_index]
1056 nic_params = self.params.object_params(nic_name)
1057 if nic_params.get("nic_ifname"):
1058 return nic_params.get("nic_ifname")
1059 else:
1060 return "t%d-%s" % (nic_index, self.instance[-11:])
1063 def get_mac_address(self, nic_index=0):
1065 Return the MAC address of a NIC.
1067 @param nic_index: Index of the NIC
1068 @raise VMMACAddressMissingError: If no MAC address is defined for the
1069 requested NIC
1071 nic_name = self.params.objects("nics")[nic_index]
1072 nic_params = self.params.object_params(nic_name)
1073 mac = (nic_params.get("nic_mac") or
1074 virt_utils.get_mac_address(self.instance, nic_index))
1075 if not mac:
1076 raise virt_vm.VMMACAddressMissingError(nic_index)
1077 return mac
1080 def free_mac_address(self, nic_index=0):
1082 Free a NIC's MAC address.
1084 @param nic_index: Index of the NIC
1086 virt_utils.free_mac_address(self.instance, nic_index)
1089 def get_pid(self):
1091 Return the VM's PID. If the VM is dead return None.
1093 @note: This works under the assumption that self.process.get_pid()
1094 returns the PID of the parent shell process.
1096 try:
1097 children = commands.getoutput("ps --ppid=%d -o pid=" %
1098 self.process.get_pid()).split()
1099 return int(children[0])
1100 except (TypeError, IndexError, ValueError):
1101 return None
1104 def get_shell_pid(self):
1106 Return the PID of the parent shell process.
1108 @note: This works under the assumption that self.process.get_pid()
1109 returns the PID of the parent shell process.
1111 return self.process.get_pid()
1114 def get_shared_meminfo(self):
1116 Returns the VM's shared memory information.
1118 @return: Shared memory used by VM (MB)
1120 if self.is_dead():
1121 logging.error("Could not get shared memory info from dead VM.")
1122 return None
1124 filename = "/proc/%d/statm" % self.get_pid()
1125 shm = int(open(filename).read().split()[2])
1126 # statm stores informations in pages, translate it to MB
1127 return shm * 4.0 / 1024
1130 @error.context_aware
1131 def migrate(self, timeout=3600, protocol="tcp", cancel_delay=None,
1132 offline=False, stable_check=False, clean=True,
1133 save_path="/tmp", dest_host="localhost", remote_port=None):
1135 Migrate the VM.
1137 If the migration is local, the VM object's state is switched with that
1138 of the destination VM. Otherwise, the state is switched with that of
1139 a dead VM (returned by self.clone()).
1141 @param timeout: Time to wait for migration to complete.
1142 @param protocol: Migration protocol (as defined in MIGRATION_PROTOS)
1143 @param cancel_delay: If provided, specifies a time duration after which
1144 migration will be canceled. Used for testing migrate_cancel.
1145 @param offline: If True, pause the source VM before migration.
1146 @param stable_check: If True, compare the VM's state after migration to
1147 its state before migration and raise an exception if they
1148 differ.
1149 @param clean: If True, delete the saved state files (relevant only if
1150 stable_check is also True).
1151 @save_path: The path for state files.
1152 @param dest_host: Destination host (defaults to 'localhost').
1153 @param remote_port: Port to use for remote migration.
1155 if protocol not in self.MIGRATION_PROTOS:
1156 raise virt_vm.VMMigrateProtoUnsupportedError
1158 error.base_context("migrating '%s'" % self.name)
1160 def mig_finished():
1161 o = self.monitor.info("migrate")
1162 if isinstance(o, str):
1163 return "status: active" not in o
1164 else:
1165 return o.get("status") != "active"
1167 def mig_succeeded():
1168 o = self.monitor.info("migrate")
1169 if isinstance(o, str):
1170 return "status: completed" in o
1171 else:
1172 return o.get("status") == "completed"
1174 def mig_failed():
1175 o = self.monitor.info("migrate")
1176 if isinstance(o, str):
1177 return "status: failed" in o
1178 else:
1179 return o.get("status") == "failed"
1181 def mig_cancelled():
1182 o = self.monitor.info("migrate")
1183 if isinstance(o, str):
1184 return ("Migration status: cancelled" in o or
1185 "Migration status: canceled" in o)
1186 else:
1187 return (o.get("status") == "cancelled" or
1188 o.get("status") == "canceled")
1190 def wait_for_migration():
1191 if not virt_utils.wait_for(mig_finished, timeout, 2, 2,
1192 "Waiting for migration to complete"):
1193 raise virt_vm.VMMigrateTimeoutError("Timeout expired while waiting "
1194 "for migration to finish")
1196 local = dest_host == "localhost"
1198 clone = self.clone()
1199 if local:
1200 error.context("creating destination VM")
1201 if stable_check:
1202 # Pause the dest vm after creation
1203 extra_params = clone.params.get("extra_params", "") + " -S"
1204 clone.params["extra_params"] = extra_params
1205 clone.create(migration_mode=protocol, mac_source=self)
1206 error.context()
1208 try:
1209 if protocol == "tcp":
1210 if local:
1211 uri = "tcp:localhost:%d" % clone.migration_port
1212 else:
1213 uri = "tcp:%s:%d" % (dest_host, remote_port)
1214 elif protocol == "unix":
1215 uri = "unix:%s" % clone.migration_file
1216 elif protocol == "exec":
1217 uri = '"exec:nc localhost %s"' % clone.migration_port
1219 if offline:
1220 self.monitor.cmd("stop")
1222 logging.info("Migrating to %s", uri)
1223 self.monitor.migrate(uri)
1225 if cancel_delay:
1226 time.sleep(cancel_delay)
1227 self.monitor.cmd("migrate_cancel")
1228 if not virt_utils.wait_for(mig_cancelled, 60, 2, 2,
1229 "Waiting for migration "
1230 "cancellation"):
1231 raise virt_vm.VMMigrateCancelError("Cannot cancel migration")
1232 return
1234 wait_for_migration()
1236 # Report migration status
1237 if mig_succeeded():
1238 logging.info("Migration completed successfully")
1239 elif mig_failed():
1240 raise virt_vm.VMMigrateFailedError("Migration failed")
1241 else:
1242 raise virt_vm.VMMigrateFailedError("Migration ended with "
1243 "unknown status")
1245 # Switch self <-> clone
1246 temp = self.clone(copy_state=True)
1247 self.__dict__ = clone.__dict__
1248 clone = temp
1250 # From now on, clone is the source VM that will soon be destroyed
1251 # and self is the destination VM that will remain alive. If this
1252 # is remote migration, self is a dead VM object.
1254 error.context("after migration")
1255 if local:
1256 time.sleep(1)
1257 self.verify_alive()
1259 if local and stable_check:
1260 try:
1261 save1 = os.path.join(save_path, "src-" + clone.instance)
1262 save2 = os.path.join(save_path, "dst-" + self.instance)
1263 clone.save_to_file(save1)
1264 self.save_to_file(save2)
1265 # Fail if we see deltas
1266 md5_save1 = utils.hash_file(save1)
1267 md5_save2 = utils.hash_file(save2)
1268 if md5_save1 != md5_save2:
1269 raise virt_vm.VMMigrateStateMismatchError(md5_save1,
1270 md5_save2)
1271 finally:
1272 if clean:
1273 if os.path.isfile(save1):
1274 os.remove(save1)
1275 if os.path.isfile(save2):
1276 os.remove(save2)
1278 finally:
1279 # If we're doing remote migration and it's completed successfully,
1280 # self points to a dead VM object
1281 if self.is_alive():
1282 self.monitor.cmd("cont")
1283 clone.destroy(gracefully=False)
1286 @error.context_aware
1287 def reboot(self, session=None, method="shell", nic_index=0, timeout=240):
1289 Reboot the VM and wait for it to come back up by trying to log in until
1290 timeout expires.
1292 @param session: A shell session object or None.
1293 @param method: Reboot method. Can be "shell" (send a shell reboot
1294 command) or "system_reset" (send a system_reset monitor command).
1295 @param nic_index: Index of NIC to access in the VM, when logging in
1296 after rebooting.
1297 @param timeout: Time to wait for login to succeed (after rebooting).
1298 @return: A new shell session object.
1300 error.base_context("rebooting '%s'" % self.name, logging.info)
1301 error.context("before reboot")
1302 session = session or self.login()
1303 error.context()
1305 if method == "shell":
1306 session.sendline(self.params.get("reboot_command"))
1307 elif method == "system_reset":
1308 # Clear the event list of all QMP monitors
1309 qmp_monitors = [m for m in self.monitors if m.protocol == "qmp"]
1310 for m in qmp_monitors:
1311 m.clear_events()
1312 # Send a system_reset monitor command
1313 self.monitor.cmd("system_reset")
1314 # Look for RESET QMP events
1315 time.sleep(1)
1316 for m in qmp_monitors:
1317 if m.get_event("RESET"):
1318 logging.info("RESET QMP event received")
1319 else:
1320 raise virt_vm.VMRebootError("RESET QMP event not received "
1321 "after system_reset "
1322 "(monitor '%s')" % m.name)
1323 else:
1324 raise virt_vm.VMRebootError("Unknown reboot method: %s" % method)
1326 error.context("waiting for guest to go down", logging.info)
1327 if not virt_utils.wait_for(lambda:
1328 not session.is_responsive(timeout=30),
1329 120, 0, 1):
1330 raise virt_vm.VMRebootError("Guest refuses to go down")
1331 session.close()
1333 error.context("logging in after reboot", logging.info)
1334 return self.wait_for_login(nic_index, timeout=timeout)
1337 def send_key(self, keystr):
1339 Send a key event to the VM.
1341 @param: keystr: A key event string (e.g. "ctrl-alt-delete")
1343 # For compatibility with versions of QEMU that do not recognize all
1344 # key names: replace keyname with the hex value from the dict, which
1345 # QEMU will definitely accept
1346 dict = {"comma": "0x33",
1347 "dot": "0x34",
1348 "slash": "0x35"}
1349 for key, value in dict.items():
1350 keystr = keystr.replace(key, value)
1351 self.monitor.sendkey(keystr)
1352 time.sleep(0.2)
1355 # should this really be expected from VMs of all hypervisor types?
1356 def screendump(self, filename):
1357 try:
1358 if self.monitor:
1359 self.monitor.screendump(filename=filename)
1360 except kvm_monitor.MonitorError, e:
1361 logging.warn(e)
1364 def save_to_file(self, path):
1366 Save the state of virtual machine to a file through migrate to
1367 exec
1369 # Make sure we only get one iteration
1370 self.monitor.cmd("migrate_set_speed 1000g")
1371 self.monitor.cmd("migrate_set_downtime 100000000")
1372 self.monitor.migrate('"exec:cat>%s"' % path)
1373 # Restore the speed and downtime of migration
1374 self.monitor.cmd("migrate_set_speed %d" % (32<<20))
1375 self.monitor.cmd("migrate_set_downtime 0.03")
1378 def needs_restart(self, name, params, basedir):
1380 Verifies whether the current qemu commandline matches the requested
1381 one, based on the test parameters.
1383 return (self.__make_qemu_command() !=
1384 self.__make_qemu_command(name, params, basedir))