| OLD | NEW |
| 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, socket, os, logging, fcntl, re, commands, shelve, glob | 8 import time, socket, os, logging, fcntl, re, commands, shelve, glob |
| 9 import kvm_utils, kvm_subprocess, kvm_monitor, rss_file_transfer | 9 import kvm_utils, kvm_subprocess, kvm_monitor, rss_file_transfer |
| 10 from autotest_lib.client.common_lib import error | 10 from autotest_lib.client.common_lib import error |
| 11 from autotest_lib.client.bin import utils | 11 from autotest_lib.client.bin import utils |
| 12 | 12 |
| 13 | 13 |
| 14 def get_image_filename(params, root_dir): | 14 def get_image_filename(params, root_dir): |
| 15 """ | 15 """ |
| 16 Generate an image path from params and root_dir. | 16 Generate an image path from params and root_dir. |
| 17 | 17 |
| 18 @param params: Dictionary containing the test parameters. | 18 @param params: Dictionary containing the test parameters. |
| 19 @param root_dir: Base directory for relative filenames. | 19 @param root_dir: Base directory for relative filenames. |
| 20 | 20 |
| 21 @note: params should contain: | 21 @note: params should contain: |
| 22 image_name -- the name of the image file, without extension | 22 image_name -- the name of the image file, without extension |
| 23 image_format -- the format of the image (qcow2, raw etc) | 23 image_format -- the format of the image (qcow2, raw etc) |
| 24 """ | 24 """ |
| 25 image_name = params.get("image_name", "image") | 25 image_name = params.get("image_name", "image") |
| 26 image_format = params.get("image_format", "qcow2") | 26 image_format = params.get("image_format", "qcow2") |
| 27 if params.get("image_raw_device") == "yes": | |
| 28 return image_name | |
| 29 image_filename = "%s.%s" % (image_name, image_format) | 27 image_filename = "%s.%s" % (image_name, image_format) |
| 30 image_filename = kvm_utils.get_path(root_dir, image_filename) | 28 image_filename = kvm_utils.get_path(root_dir, image_filename) |
| 31 return image_filename | 29 return image_filename |
| 32 | 30 |
| 33 | 31 |
| 34 def create_image(params, root_dir): | 32 def create_image(params, root_dir): |
| 35 """ | 33 """ |
| 36 Create an image using qemu_image. | 34 Create an image using qemu_image. |
| 37 | 35 |
| 38 @param params: Dictionary containing the test parameters. | 36 @param params: Dictionary containing the test parameters. |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 90 os.unlink(image_filename) | 88 os.unlink(image_filename) |
| 91 else: | 89 else: |
| 92 logging.debug("Image file %s not found") | 90 logging.debug("Image file %s not found") |
| 93 | 91 |
| 94 | 92 |
| 95 class VM: | 93 class VM: |
| 96 """ | 94 """ |
| 97 This class handles all basic VM operations. | 95 This class handles all basic VM operations. |
| 98 """ | 96 """ |
| 99 | 97 |
| 100 def __init__(self, name, params, root_dir, address_cache, state=None): | 98 def __init__(self, name, params, root_dir, address_cache): |
| 101 """ | 99 """ |
| 102 Initialize the object and set a few attributes. | 100 Initialize the object and set a few attributes. |
| 103 | 101 |
| 104 @param name: The name of the object | 102 @param name: The name of the object |
| 105 @param params: A dict containing VM params | 103 @param params: A dict containing VM params |
| 106 (see method make_qemu_command for a full description) | 104 (see method make_qemu_command for a full description) |
| 107 @param root_dir: Base directory for relative filenames | 105 @param root_dir: Base directory for relative filenames |
| 108 @param address_cache: A dict that maps MAC addresses to IP addresses | 106 @param address_cache: A dict that maps MAC addresses to IP addresses |
| 109 @param state: If provided, use this as self.__dict__ | |
| 110 """ | 107 """ |
| 111 if state: | 108 self.process = None |
| 112 self.__dict__ = state | 109 self.serial_console = None |
| 113 else: | 110 self.redirs = {} |
| 114 self.process = None | 111 self.vnc_port = 5900 |
| 115 self.serial_console = None | 112 self.monitors = [] |
| 116 self.redirs = {} | 113 self.pci_assignable = None |
| 117 self.vnc_port = 5900 | 114 self.netdev_id = [] |
| 118 self.monitors = [] | 115 self.uuid = None |
| 119 self.pci_assignable = None | |
| 120 self.netdev_id = [] | |
| 121 self.uuid = None | |
| 122 | |
| 123 # Find a unique identifier for this VM | |
| 124 while True: | |
| 125 self.instance = (time.strftime("%Y%m%d-%H%M%S-") + | |
| 126 kvm_utils.generate_random_string(4)) | |
| 127 if not glob.glob("/tmp/*%s" % self.instance): | |
| 128 break | |
| 129 | 116 |
| 130 self.name = name | 117 self.name = name |
| 131 self.params = params | 118 self.params = params |
| 132 self.root_dir = root_dir | 119 self.root_dir = root_dir |
| 133 self.address_cache = address_cache | 120 self.address_cache = address_cache |
| 134 | 121 |
| 122 # Find a unique identifier for this VM |
| 123 while True: |
| 124 self.instance = (time.strftime("%Y%m%d-%H%M%S-") + |
| 125 kvm_utils.generate_random_string(4)) |
| 126 if not glob.glob("/tmp/*%s" % self.instance): |
| 127 break |
| 135 | 128 |
| 136 def clone(self, name=None, params=None, root_dir=None, address_cache=None, | 129 |
| 137 copy_state=False): | 130 def clone(self, name=None, params=None, root_dir=None, address_cache=None): |
| 138 """ | 131 """ |
| 139 Return a clone of the VM object with optionally modified parameters. | 132 Return a clone of the VM object with optionally modified parameters. |
| 140 The clone is initially not alive and needs to be started using create(). | 133 The clone is initially not alive and needs to be started using create(). |
| 141 Any parameters not passed to this function are copied from the source | 134 Any parameters not passed to this function are copied from the source |
| 142 VM. | 135 VM. |
| 143 | 136 |
| 144 @param name: Optional new VM name | 137 @param name: Optional new VM name |
| 145 @param params: Optional new VM creation parameters | 138 @param params: Optional new VM creation parameters |
| 146 @param root_dir: Optional new base directory for relative filenames | 139 @param root_dir: Optional new base directory for relative filenames |
| 147 @param address_cache: A dict that maps MAC addresses to IP addresses | 140 @param address_cache: A dict that maps MAC addresses to IP addresses |
| 148 @param copy_state: If True, copy the original VM's state to the clone. | |
| 149 Mainly useful for make_qemu_command(). | |
| 150 """ | 141 """ |
| 151 if name is None: | 142 if name is None: |
| 152 name = self.name | 143 name = self.name |
| 153 if params is None: | 144 if params is None: |
| 154 params = self.params.copy() | 145 params = self.params.copy() |
| 155 if root_dir is None: | 146 if root_dir is None: |
| 156 root_dir = self.root_dir | 147 root_dir = self.root_dir |
| 157 if address_cache is None: | 148 if address_cache is None: |
| 158 address_cache = self.address_cache | 149 address_cache = self.address_cache |
| 159 if copy_state: | 150 return VM(name, params, root_dir, address_cache) |
| 160 state = self.__dict__.copy() | |
| 161 else: | |
| 162 state = None | |
| 163 return VM(name, params, root_dir, address_cache, state) | |
| 164 | 151 |
| 165 | 152 |
| 166 def make_qemu_command(self, name=None, params=None, root_dir=None): | 153 def make_qemu_command(self, name=None, params=None, root_dir=None): |
| 167 """ | 154 """ |
| 168 Generate a qemu command line. All parameters are optional. If a | 155 Generate a qemu command line. All parameters are optional. If a |
| 169 parameter is not supplied, the corresponding value stored in the | 156 parameter is not supplied, the corresponding value stored in the |
| 170 class attributes is used. | 157 class attributes is used. |
| 171 | 158 |
| 172 @param name: The name of the object | 159 @param name: The name of the object |
| 173 @param params: A dict containing VM params | 160 @param params: A dict containing VM params |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 242 if format: cmd += ",if=%s" % format | 229 if format: cmd += ",if=%s" % format |
| 243 if cache: cmd += ",cache=%s" % cache | 230 if cache: cmd += ",cache=%s" % cache |
| 244 if werror: cmd += ",werror=%s" % werror | 231 if werror: cmd += ",werror=%s" % werror |
| 245 if serial: cmd += ",serial='%s'" % serial | 232 if serial: cmd += ",serial='%s'" % serial |
| 246 if snapshot: cmd += ",snapshot=on" | 233 if snapshot: cmd += ",snapshot=on" |
| 247 if boot: cmd += ",boot=on" | 234 if boot: cmd += ",boot=on" |
| 248 return cmd | 235 return cmd |
| 249 | 236 |
| 250 def add_nic(help, vlan, model=None, mac=None, netdev_id=None, | 237 def add_nic(help, vlan, model=None, mac=None, netdev_id=None, |
| 251 nic_extra_params=None): | 238 nic_extra_params=None): |
| 252 if has_option(help, "netdev"): | |
| 253 netdev_vlan_str = ",netdev=%s" % netdev_id | |
| 254 else: | |
| 255 netdev_vlan_str = ",vlan=%d" % vlan | |
| 256 if has_option(help, "device"): | 239 if has_option(help, "device"): |
| 240 if model == "virtio": |
| 241 model="virtio-net-pci" |
| 257 if not model: | 242 if not model: |
| 258 model = "rtl8139" | 243 model= "rtl8139" |
| 259 elif model == "virtio": | 244 cmd = " -device %s" % model |
| 260 model = "virtio-net-pci" | |
| 261 cmd = " -device %s" % model + netdev_vlan_str | |
| 262 if mac: | 245 if mac: |
| 263 cmd += ",mac='%s'" % mac | 246 cmd += ",mac=%s" % mac |
| 247 if has_option(help, "netdev"): |
| 248 cmd += ",netdev=%s" % netdev_id |
| 249 else: |
| 250 cmd += "vlan=%d," % vlan |
| 264 if nic_extra_params: | 251 if nic_extra_params: |
| 265 cmd += ",%s" % nic_extra_params | 252 cmd += ",%s" % nic_extra_params |
| 266 else: | 253 else: |
| 267 cmd = " -net nic" + netdev_vlan_str | 254 if has_option(help, "netdev"): |
| 255 cmd = " -net nic,netdev=%s" % netdev_id |
| 256 else: |
| 257 cmd = " -net nic,vlan=%d" % vlan |
| 268 if model: | 258 if model: |
| 269 cmd += ",model=%s" % model | 259 cmd += ",model=%s" % model |
| 270 if mac: | 260 if mac: |
| 271 cmd += ",macaddr='%s'" % mac | 261 cmd += ",macaddr='%s'" % mac |
| 272 return cmd | 262 return cmd |
| 273 | 263 |
| 274 def add_net(help, vlan, mode, ifname=None, script=None, | 264 def add_net(help, vlan, mode, ifname=None, script=None, |
| 275 downscript=None, tftp=None, bootfile=None, hostfwd=[], | 265 downscript=None, tftp=None, bootfile=None, hostfwd=[], |
| 276 netdev_id=None, netdev_extra_params=None): | 266 netdev_id=None, vhost=False): |
| 277 if has_option(help, "netdev"): | 267 if has_option(help, "netdev"): |
| 278 cmd = " -netdev %s,id=%s" % (mode, netdev_id) | 268 cmd = " -netdev %s,id=%s" % (mode, netdev_id) |
| 279 if netdev_extra_params: | 269 if vhost: |
| 280 cmd += ",%s" % netdev_extra_params | 270 cmd +=",vhost=on" |
| 281 else: | 271 else: |
| 282 cmd = " -net %s,vlan=%d" % (mode, vlan) | 272 cmd = " -net %s,vlan=%d" % (mode, vlan) |
| 283 if mode == "tap": | 273 if mode == "tap": |
| 284 if ifname: cmd += ",ifname='%s'" % ifname | 274 if ifname: cmd += ",ifname='%s'" % ifname |
| 285 if script: cmd += ",script='%s'" % script | 275 if script: cmd += ",script='%s'" % script |
| 286 cmd += ",downscript='%s'" % (downscript or "no") | 276 cmd += ",downscript='%s'" % (downscript or "no") |
| 287 elif mode == "user": | 277 elif mode == "user": |
| 288 if tftp and "[,tftp=" in help: | 278 if tftp and "[,tftp=" in help: |
| 289 cmd += ",tftp='%s'" % tftp | 279 cmd += ",tftp='%s'" % tftp |
| 290 if bootfile and "[,bootfile=" in help: | 280 if bootfile and "[,bootfile=" in help: |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 354 return " -no-hpet" | 344 return " -no-hpet" |
| 355 else: | 345 else: |
| 356 return "" | 346 return "" |
| 357 | 347 |
| 358 # End of command line option wrappers | 348 # End of command line option wrappers |
| 359 | 349 |
| 360 if name is None: name = self.name | 350 if name is None: name = self.name |
| 361 if params is None: params = self.params | 351 if params is None: params = self.params |
| 362 if root_dir is None: root_dir = self.root_dir | 352 if root_dir is None: root_dir = self.root_dir |
| 363 | 353 |
| 364 # Clone this VM using the new params | |
| 365 vm = self.clone(name, params, root_dir, copy_state=True) | |
| 366 | |
| 367 qemu_binary = kvm_utils.get_path(root_dir, params.get("qemu_binary", | 354 qemu_binary = kvm_utils.get_path(root_dir, params.get("qemu_binary", |
| 368 "qemu")) | 355 "qemu")) |
| 369 # Get the output of 'qemu -help' (log a message in case this call never | 356 # Get the output of 'qemu -help' (log a message in case this call never |
| 370 # returns or causes some other kind of trouble) | 357 # returns or causes some other kind of trouble) |
| 371 logging.debug("Getting output of 'qemu -help'") | 358 logging.debug("Getting output of 'qemu -help'") |
| 372 help = commands.getoutput("%s -help" % qemu_binary) | 359 help = commands.getoutput("%s -help" % qemu_binary) |
| 373 | 360 |
| 374 # Start constructing the qemu command | 361 # Start constructing the qemu command |
| 375 qemu_cmd = "" | 362 qemu_cmd = "" |
| 376 # Set the X11 display parameter if requested | 363 # Set the X11 display parameter if requested |
| 377 if params.get("x11_display"): | 364 if params.get("x11_display"): |
| 378 qemu_cmd += "DISPLAY=%s " % params.get("x11_display") | 365 qemu_cmd += "DISPLAY=%s " % params.get("x11_display") |
| 379 # Add the qemu binary | 366 # Add the qemu binary |
| 380 qemu_cmd += qemu_binary | 367 qemu_cmd += qemu_binary |
| 381 # Add the VM's name | 368 # Add the VM's name |
| 382 qemu_cmd += add_name(help, name) | 369 qemu_cmd += add_name(help, name) |
| 383 # Add monitors | 370 # Add monitors |
| 384 for monitor_name in params.objects("monitors"): | 371 for monitor_name in kvm_utils.get_sub_dict_names(params, "monitors"): |
| 385 monitor_params = params.object_params(monitor_name) | 372 monitor_params = kvm_utils.get_sub_dict(params, monitor_name) |
| 386 monitor_filename = vm.get_monitor_filename(monitor_name) | 373 monitor_filename = self.get_monitor_filename(monitor_name) |
| 387 if monitor_params.get("monitor_type") == "qmp": | 374 if monitor_params.get("monitor_type") == "qmp": |
| 388 qemu_cmd += add_qmp_monitor(help, monitor_filename) | 375 qemu_cmd += add_qmp_monitor(help, monitor_filename) |
| 389 else: | 376 else: |
| 390 qemu_cmd += add_human_monitor(help, monitor_filename) | 377 qemu_cmd += add_human_monitor(help, monitor_filename) |
| 391 | 378 |
| 392 # Add serial console redirection | 379 # Add serial console redirection |
| 393 qemu_cmd += add_serial(help, vm.get_serial_console_filename()) | 380 qemu_cmd += add_serial(help, self.get_serial_console_filename()) |
| 394 | 381 |
| 395 for image_name in params.objects("images"): | 382 for image_name in kvm_utils.get_sub_dict_names(params, "images"): |
| 396 image_params = params.object_params(image_name) | 383 image_params = kvm_utils.get_sub_dict(params, image_name) |
| 397 if image_params.get("boot_drive") == "no": | 384 if image_params.get("boot_drive") == "no": |
| 398 continue | 385 continue |
| 399 qemu_cmd += add_drive(help, | 386 qemu_cmd += add_drive(help, |
| 400 get_image_filename(image_params, root_dir), | 387 get_image_filename(image_params, root_dir), |
| 401 image_params.get("drive_index"), | 388 image_params.get("drive_index"), |
| 402 image_params.get("drive_format"), | 389 image_params.get("drive_format"), |
| 403 image_params.get("drive_cache"), | 390 image_params.get("drive_cache"), |
| 404 image_params.get("drive_werror"), | 391 image_params.get("drive_werror"), |
| 405 image_params.get("drive_serial"), | 392 image_params.get("drive_serial"), |
| 406 image_params.get("image_snapshot") == "yes", | 393 image_params.get("image_snapshot") == "yes", |
| 407 image_params.get("image_boot") == "yes") | 394 image_params.get("image_boot") == "yes") |
| 408 | 395 |
| 409 redirs = [] | 396 redirs = [] |
| 410 for redir_name in params.objects("redirs"): | 397 for redir_name in kvm_utils.get_sub_dict_names(params, "redirs"): |
| 411 redir_params = params.object_params(redir_name) | 398 redir_params = kvm_utils.get_sub_dict(params, redir_name) |
| 412 guest_port = int(redir_params.get("guest_port")) | 399 guest_port = int(redir_params.get("guest_port")) |
| 413 host_port = vm.redirs.get(guest_port) | 400 host_port = self.redirs.get(guest_port) |
| 414 redirs += [(host_port, guest_port)] | 401 redirs += [(host_port, guest_port)] |
| 415 | 402 |
| 416 vlan = 0 | 403 vlan = 0 |
| 417 for nic_name in params.objects("nics"): | 404 for nic_name in kvm_utils.get_sub_dict_names(params, "nics"): |
| 418 nic_params = params.object_params(nic_name) | 405 nic_params = kvm_utils.get_sub_dict(params, nic_name) |
| 419 try: | |
| 420 netdev_id = vm.netdev_id[vlan] | |
| 421 except IndexError: | |
| 422 netdev_id = None | |
| 423 # Handle the '-net nic' part | 406 # Handle the '-net nic' part |
| 424 mac = vm.get_mac_address(vlan) | 407 mac = self.get_mac_address(vlan) |
| 425 qemu_cmd += add_nic(help, vlan, nic_params.get("nic_model"), mac, | 408 qemu_cmd += add_nic(help, vlan, nic_params.get("nic_model"), mac, |
| 426 netdev_id, nic_params.get("nic_extra_params")) | 409 self.netdev_id[vlan], |
| 410 nic_params.get("nic_extra_params")) |
| 427 # Handle the '-net tap' or '-net user' part | 411 # Handle the '-net tap' or '-net user' part |
| 428 script = nic_params.get("nic_script") | 412 script = nic_params.get("nic_script") |
| 429 downscript = nic_params.get("nic_downscript") | 413 downscript = nic_params.get("nic_downscript") |
| 430 tftp = nic_params.get("tftp") | 414 tftp = nic_params.get("tftp") |
| 431 if script: | 415 if script: |
| 432 script = kvm_utils.get_path(root_dir, script) | 416 script = kvm_utils.get_path(root_dir, script) |
| 433 if downscript: | 417 if downscript: |
| 434 downscript = kvm_utils.get_path(root_dir, downscript) | 418 downscript = kvm_utils.get_path(root_dir, downscript) |
| 435 if tftp: | 419 if tftp: |
| 436 tftp = kvm_utils.get_path(root_dir, tftp) | 420 tftp = kvm_utils.get_path(root_dir, tftp) |
| 437 qemu_cmd += add_net(help, vlan, nic_params.get("nic_mode", "user"), | 421 qemu_cmd += add_net(help, vlan, nic_params.get("nic_mode", "user"), |
| 438 vm.get_ifname(vlan), | 422 self.get_ifname(vlan), |
| 439 script, downscript, tftp, | 423 script, downscript, tftp, |
| 440 nic_params.get("bootp"), redirs, netdev_id, | 424 nic_params.get("bootp"), redirs, |
| 441 nic_params.get("netdev_extra_params")) | 425 self.netdev_id[vlan], |
| 426 nic_params.get("vhost")=="yes") |
| 442 # Proceed to next NIC | 427 # Proceed to next NIC |
| 443 vlan += 1 | 428 vlan += 1 |
| 444 | 429 |
| 445 mem = params.get("mem") | 430 mem = params.get("mem") |
| 446 if mem: | 431 if mem: |
| 447 qemu_cmd += add_mem(help, mem) | 432 qemu_cmd += add_mem(help, mem) |
| 448 | 433 |
| 449 smp = params.get("smp") | 434 smp = params.get("smp") |
| 450 if smp: | 435 if smp: |
| 451 qemu_cmd += add_smp(help, smp) | 436 qemu_cmd += add_smp(help, smp) |
| 452 | 437 |
| 453 for cdrom in params.objects("cdroms"): | 438 cdroms = kvm_utils.get_sub_dict_names(params, "cdroms") |
| 454 cdrom_params = params.object_params(cdrom) | 439 for cdrom in cdroms: |
| 440 cdrom_params = kvm_utils.get_sub_dict(params, cdrom) |
| 455 iso = cdrom_params.get("cdrom") | 441 iso = cdrom_params.get("cdrom") |
| 456 if iso: | 442 if iso: |
| 457 qemu_cmd += add_cdrom(help, kvm_utils.get_path(root_dir, iso), | 443 qemu_cmd += add_cdrom(help, kvm_utils.get_path(root_dir, iso), |
| 458 cdrom_params.get("drive_index")) | 444 cdrom_params.get("drive_index")) |
| 459 | 445 |
| 460 # We may want to add {floppy_otps} parameter for -fda | 446 # We may want to add {floppy_otps} parameter for -fda |
| 461 # {fat:floppy:}/path/. However vvfat is not usually recommended. | 447 # {fat:floppy:}/path/. However vvfat is not usually recommended. |
| 462 floppy = params.get("floppy") | 448 floppy = params.get("floppy") |
| 463 if floppy: | 449 if floppy: |
| 464 floppy = kvm_utils.get_path(root_dir, floppy) | 450 floppy = kvm_utils.get_path(root_dir, floppy) |
| (...skipping 19 matching lines...) Expand all Loading... |
| 484 | 470 |
| 485 initrd = params.get("initrd") | 471 initrd = params.get("initrd") |
| 486 if initrd: | 472 if initrd: |
| 487 initrd = kvm_utils.get_path(root_dir, initrd) | 473 initrd = kvm_utils.get_path(root_dir, initrd) |
| 488 qemu_cmd += add_initrd(help, initrd) | 474 qemu_cmd += add_initrd(help, initrd) |
| 489 | 475 |
| 490 for host_port, guest_port in redirs: | 476 for host_port, guest_port in redirs: |
| 491 qemu_cmd += add_tcp_redir(help, host_port, guest_port) | 477 qemu_cmd += add_tcp_redir(help, host_port, guest_port) |
| 492 | 478 |
| 493 if params.get("display") == "vnc": | 479 if params.get("display") == "vnc": |
| 494 qemu_cmd += add_vnc(help, vm.vnc_port) | 480 qemu_cmd += add_vnc(help, self.vnc_port) |
| 495 elif params.get("display") == "sdl": | 481 elif params.get("display") == "sdl": |
| 496 qemu_cmd += add_sdl(help) | 482 qemu_cmd += add_sdl(help) |
| 497 elif params.get("display") == "nographic": | 483 elif params.get("display") == "nographic": |
| 498 qemu_cmd += add_nographic(help) | 484 qemu_cmd += add_nographic(help) |
| 499 | 485 |
| 500 if params.get("uuid") == "random": | 486 if params.get("uuid") == "random": |
| 501 qemu_cmd += add_uuid(help, vm.uuid) | 487 qemu_cmd += add_uuid(help, self.uuid) |
| 502 elif params.get("uuid"): | 488 elif params.get("uuid"): |
| 503 qemu_cmd += add_uuid(help, params.get("uuid")) | 489 qemu_cmd += add_uuid(help, params.get("uuid")) |
| 504 | 490 |
| 505 if params.get("testdev") == "yes": | 491 if params.get("testdev") == "yes": |
| 506 qemu_cmd += add_testdev(help, vm.get_testlog_filename()) | 492 qemu_cmd += add_testdev(help, self.get_testlog_filename()) |
| 507 | 493 |
| 508 if params.get("disable_hpet") == "yes": | 494 if params.get("disable_hpet") == "yes": |
| 509 qemu_cmd += add_no_hpet(help) | 495 qemu_cmd += add_no_hpet(help) |
| 510 | 496 |
| 511 # If the PCI assignment step went OK, add each one of the PCI assigned | 497 # If the PCI assignment step went OK, add each one of the PCI assigned |
| 512 # devices to the qemu command line. | 498 # devices to the qemu command line. |
| 513 if vm.pci_assignable: | 499 if self.pci_assignable: |
| 514 for pci_id in vm.pa_pci_ids: | 500 for pci_id in self.pa_pci_ids: |
| 515 qemu_cmd += add_pcidevice(help, pci_id) | 501 qemu_cmd += add_pcidevice(help, pci_id) |
| 516 | 502 |
| 517 extra_params = params.get("extra_params") | 503 extra_params = params.get("extra_params") |
| 518 if extra_params: | 504 if extra_params: |
| 519 qemu_cmd += " %s" % extra_params | 505 qemu_cmd += " %s" % extra_params |
| 520 | 506 |
| 521 return qemu_cmd | 507 return qemu_cmd |
| 522 | 508 |
| 523 | 509 |
| 524 def create(self, name=None, params=None, root_dir=None, timeout=5.0, | 510 def create(self, name=None, params=None, root_dir=None, timeout=5.0, |
| 525 migration_mode=None, mac_source=None): | 511 migration_mode=None, migration_exec_cmd=None, mac_source=None): |
| 526 """ | 512 """ |
| 527 Start the VM by running a qemu command. | 513 Start the VM by running a qemu command. |
| 528 All parameters are optional. If name, params or root_dir are not | 514 All parameters are optional. If name, params or root_dir are not |
| 529 supplied, the respective values stored as class attributes are used. | 515 supplied, the respective values stored as class attributes are used. |
| 530 | 516 |
| 531 @param name: The name of the object | 517 @param name: The name of the object |
| 532 @param params: A dict containing VM params | 518 @param params: A dict containing VM params |
| 533 @param root_dir: Base directory for relative filenames | 519 @param root_dir: Base directory for relative filenames |
| 534 @param migration_mode: If supplied, start VM for incoming migration | 520 @param migration_mode: If supplied, start VM for incoming migration |
| 535 using this protocol (either 'tcp', 'unix' or 'exec') | 521 using this protocol (either 'tcp', 'unix' or 'exec') |
| 536 @param migration_exec_cmd: Command to embed in '-incoming "exec: ..."' | 522 @param migration_exec_cmd: Command to embed in '-incoming "exec: ..."' |
| 537 (e.g. 'gzip -c -d filename') if migration_mode is 'exec' | 523 (e.g. 'gzip -c -d filename') if migration_mode is 'exec' |
| 538 @param mac_source: A VM object from which to copy MAC addresses. If not | 524 @param mac_source: A VM object from which to copy MAC addresses. If not |
| 539 specified, new addresses will be generated. | 525 specified, new addresses will be generated. |
| 540 """ | 526 """ |
| 541 self.destroy() | 527 self.destroy() |
| 542 | 528 |
| 543 if name is not None: | 529 if name is not None: |
| 544 self.name = name | 530 self.name = name |
| 545 if params is not None: | 531 if params is not None: |
| 546 self.params = params | 532 self.params = params |
| 547 if root_dir is not None: | 533 if root_dir is not None: |
| 548 self.root_dir = root_dir | 534 self.root_dir = root_dir |
| 549 name = self.name | 535 name = self.name |
| 550 params = self.params | 536 params = self.params |
| 551 root_dir = self.root_dir | 537 root_dir = self.root_dir |
| 552 | 538 |
| 553 # Verify the md5sum of the ISO images | 539 # Verify the md5sum of the ISO image |
| 554 for cdrom in params.objects("cdroms"): | 540 iso = params.get("cdrom") |
| 555 cdrom_params = params.object_params(cdrom) | 541 if iso: |
| 556 iso = cdrom_params.get("cdrom") | 542 iso = kvm_utils.get_path(root_dir, iso) |
| 557 if iso: | 543 if not os.path.exists(iso): |
| 558 iso = kvm_utils.get_path(root_dir, iso) | 544 logging.error("ISO file not found: %s" % iso) |
| 559 if not os.path.exists(iso): | 545 return False |
| 560 logging.error("ISO file not found: %s" % iso) | 546 compare = False |
| 547 if params.get("md5sum_1m"): |
| 548 logging.debug("Comparing expected MD5 sum with MD5 sum of " |
| 549 "first MB of ISO file...") |
| 550 actual_hash = utils.hash_file(iso, 1048576, method="md5") |
| 551 expected_hash = params.get("md5sum_1m") |
| 552 compare = True |
| 553 elif params.get("md5sum"): |
| 554 logging.debug("Comparing expected MD5 sum with MD5 sum of ISO " |
| 555 "file...") |
| 556 actual_hash = utils.hash_file(iso, method="md5") |
| 557 expected_hash = params.get("md5sum") |
| 558 compare = True |
| 559 elif params.get("sha1sum"): |
| 560 logging.debug("Comparing expected SHA1 sum with SHA1 sum of " |
| 561 "ISO file...") |
| 562 actual_hash = utils.hash_file(iso, method="sha1") |
| 563 expected_hash = params.get("sha1sum") |
| 564 compare = True |
| 565 if compare: |
| 566 if actual_hash == expected_hash: |
| 567 logging.debug("Hashes match") |
| 568 else: |
| 569 logging.error("Actual hash differs from expected one") |
| 561 return False | 570 return False |
| 562 compare = False | |
| 563 if cdrom_params.get("md5sum_1m"): | |
| 564 logging.debug("Comparing expected MD5 sum with MD5 sum of " | |
| 565 "first MB of ISO file...") | |
| 566 actual_hash = utils.hash_file(iso, 1048576, method="md5") | |
| 567 expected_hash = cdrom_params.get("md5sum_1m") | |
| 568 compare = True | |
| 569 elif cdrom_params.get("md5sum"): | |
| 570 logging.debug("Comparing expected MD5 sum with MD5 sum of " | |
| 571 "ISO file...") | |
| 572 actual_hash = utils.hash_file(iso, method="md5") | |
| 573 expected_hash = cdrom_params.get("md5sum") | |
| 574 compare = True | |
| 575 elif cdrom_params.get("sha1sum"): | |
| 576 logging.debug("Comparing expected SHA1 sum with SHA1 sum " | |
| 577 "of ISO file...") | |
| 578 actual_hash = utils.hash_file(iso, method="sha1") | |
| 579 expected_hash = cdrom_params.get("sha1sum") | |
| 580 compare = True | |
| 581 if compare: | |
| 582 if actual_hash == expected_hash: | |
| 583 logging.debug("Hashes match") | |
| 584 else: | |
| 585 logging.error("Actual hash differs from expected one") | |
| 586 return False | |
| 587 | 571 |
| 588 # Make sure the following code is not executed by more than one thread | 572 # Make sure the following code is not executed by more than one thread |
| 589 # at the same time | 573 # at the same time |
| 590 lockfile = open("/tmp/kvm-autotest-vm-create.lock", "w+") | 574 lockfile = open("/tmp/kvm-autotest-vm-create.lock", "w+") |
| 591 fcntl.lockf(lockfile, fcntl.LOCK_EX) | 575 fcntl.lockf(lockfile, fcntl.LOCK_EX) |
| 592 | 576 |
| 593 try: | 577 try: |
| 594 # Handle port redirections | 578 # Handle port redirections |
| 595 redir_names = params.objects("redirs") | 579 redir_names = kvm_utils.get_sub_dict_names(params, "redirs") |
| 596 host_ports = kvm_utils.find_free_ports(5000, 6000, len(redir_names)) | 580 host_ports = kvm_utils.find_free_ports(5000, 6000, len(redir_names)) |
| 597 self.redirs = {} | 581 self.redirs = {} |
| 598 for i in range(len(redir_names)): | 582 for i in range(len(redir_names)): |
| 599 redir_params = params.object_params(redir_names[i]) | 583 redir_params = kvm_utils.get_sub_dict(params, redir_names[i]) |
| 600 guest_port = int(redir_params.get("guest_port")) | 584 guest_port = int(redir_params.get("guest_port")) |
| 601 self.redirs[guest_port] = host_ports[i] | 585 self.redirs[guest_port] = host_ports[i] |
| 602 | 586 |
| 603 # Generate netdev IDs for all NICs | 587 for nic in kvm_utils.get_sub_dict_names(params, "nics"): |
| 604 self.netdev_id = [] | |
| 605 for nic in params.objects("nics"): | |
| 606 self.netdev_id.append(kvm_utils.generate_random_id()) | 588 self.netdev_id.append(kvm_utils.generate_random_id()) |
| 607 | 589 |
| 608 # Find available VNC port, if needed | 590 # Find available VNC port, if needed |
| 609 if params.get("display") == "vnc": | 591 if params.get("display") == "vnc": |
| 610 self.vnc_port = kvm_utils.find_free_port(5900, 6100) | 592 self.vnc_port = kvm_utils.find_free_port(5900, 6100) |
| 611 | 593 |
| 612 # Find random UUID if specified 'uuid = random' in config file | 594 # Find random UUID if specified 'uuid = random' in config file |
| 613 if params.get("uuid") == "random": | 595 if params.get("uuid") == "random": |
| 614 f = open("/proc/sys/kernel/random/uuid") | 596 f = open("/proc/sys/kernel/random/uuid") |
| 615 self.uuid = f.read().strip() | 597 self.uuid = f.read().strip() |
| 616 f.close() | 598 f.close() |
| 617 | 599 |
| 618 # Generate or copy MAC addresses for all NICs | 600 # Generate or copy MAC addresses for all NICs |
| 619 num_nics = len(params.objects("nics")) | 601 num_nics = len(kvm_utils.get_sub_dict_names(params, "nics")) |
| 620 for vlan in range(num_nics): | 602 for vlan in range(num_nics): |
| 621 nic_name = params.objects("nics")[vlan] | 603 mac = mac_source and mac_source.get_mac_address(vlan) |
| 622 nic_params = params.object_params(nic_name) | 604 if mac: |
| 623 if nic_params.get("nic_mac", None): | |
| 624 mac = nic_params.get("nic_mac") | |
| 625 kvm_utils.set_mac_address(self.instance, vlan, mac) | 605 kvm_utils.set_mac_address(self.instance, vlan, mac) |
| 626 else: | 606 else: |
| 627 mac = mac_source and mac_source.get_mac_address(vlan) | 607 kvm_utils.generate_mac_address(self.instance, vlan) |
| 628 if mac: | |
| 629 kvm_utils.set_mac_address(self.instance, vlan, mac) | |
| 630 else: | |
| 631 kvm_utils.generate_mac_address(self.instance, vlan) | |
| 632 | 608 |
| 633 # Assign a PCI assignable device | 609 # Assign a PCI assignable device |
| 634 self.pci_assignable = None | 610 self.pci_assignable = None |
| 635 pa_type = params.get("pci_assignable") | 611 pa_type = params.get("pci_assignable") |
| 636 if pa_type in ["vf", "pf", "mixed"]: | 612 if pa_type in ["vf", "pf", "mixed"]: |
| 637 pa_devices_requested = params.get("devices_requested") | 613 pa_devices_requested = params.get("devices_requested") |
| 638 | 614 |
| 639 # Virtual Functions (VF) assignable devices | 615 # Virtual Functions (VF) assignable devices |
| 640 if pa_type == "vf": | 616 if pa_type == "vf": |
| 641 self.pci_assignable = kvm_utils.PciAssignable( | 617 self.pci_assignable = kvm_utils.PciAssignable( |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 677 qemu_command = self.make_qemu_command() | 653 qemu_command = self.make_qemu_command() |
| 678 | 654 |
| 679 # Add migration parameters if required | 655 # Add migration parameters if required |
| 680 if migration_mode == "tcp": | 656 if migration_mode == "tcp": |
| 681 self.migration_port = kvm_utils.find_free_port(5200, 6000) | 657 self.migration_port = kvm_utils.find_free_port(5200, 6000) |
| 682 qemu_command += " -incoming tcp:0:%d" % self.migration_port | 658 qemu_command += " -incoming tcp:0:%d" % self.migration_port |
| 683 elif migration_mode == "unix": | 659 elif migration_mode == "unix": |
| 684 self.migration_file = "/tmp/migration-unix-%s" % self.instance | 660 self.migration_file = "/tmp/migration-unix-%s" % self.instance |
| 685 qemu_command += " -incoming unix:%s" % self.migration_file | 661 qemu_command += " -incoming unix:%s" % self.migration_file |
| 686 elif migration_mode == "exec": | 662 elif migration_mode == "exec": |
| 687 self.migration_port = kvm_utils.find_free_port(5200, 6000) | 663 qemu_command += ' -incoming "exec:%s"' % migration_exec_cmd |
| 688 qemu_command += (' -incoming "exec:nc -l %s"' % | |
| 689 self.migration_port) | |
| 690 | 664 |
| 691 logging.debug("Running qemu command:\n%s", qemu_command) | 665 logging.debug("Running qemu command:\n%s", qemu_command) |
| 692 self.process = kvm_subprocess.run_bg(qemu_command, None, | 666 self.process = kvm_subprocess.run_bg(qemu_command, None, |
| 693 logging.debug, "(qemu) ") | 667 logging.debug, "(qemu) ") |
| 694 | 668 |
| 695 # Make sure the process was started successfully | 669 # Make sure the process was started successfully |
| 696 if not self.process.is_alive(): | 670 if not self.process.is_alive(): |
| 697 logging.error("VM could not be created; " | 671 logging.error("VM could not be created; " |
| 698 "qemu command failed:\n%s" % qemu_command) | 672 "qemu command failed:\n%s" % qemu_command) |
| 699 logging.error("Status: %s" % self.process.get_status()) | 673 logging.error("Status: %s" % self.process.get_status()) |
| 700 logging.error("Output:" + kvm_utils.format_str_for_message( | 674 logging.error("Output:" + kvm_utils.format_str_for_message( |
| 701 self.process.get_output())) | 675 self.process.get_output())) |
| 702 self.destroy() | 676 self.destroy() |
| 703 return False | 677 return False |
| 704 | 678 |
| 705 # Establish monitor connections | 679 # Establish monitor connections |
| 706 self.monitors = [] | 680 self.monitors = [] |
| 707 for monitor_name in params.objects("monitors"): | 681 for monitor_name in kvm_utils.get_sub_dict_names(params, |
| 708 monitor_params = params.object_params(monitor_name) | 682 "monitors"): |
| 683 monitor_params = kvm_utils.get_sub_dict(params, monitor_name) |
| 709 # Wait for monitor connection to succeed | 684 # Wait for monitor connection to succeed |
| 710 end_time = time.time() + timeout | 685 end_time = time.time() + timeout |
| 711 while time.time() < end_time: | 686 while time.time() < end_time: |
| 712 try: | 687 try: |
| 713 if monitor_params.get("monitor_type") == "qmp": | 688 if monitor_params.get("monitor_type") == "qmp": |
| 714 # Add a QMP monitor | 689 # Add a QMP monitor |
| 715 monitor = kvm_monitor.QMPMonitor( | 690 monitor = kvm_monitor.QMPMonitor( |
| 716 monitor_name, | 691 monitor_name, |
| 717 self.get_monitor_filename(monitor_name)) | 692 self.get_monitor_filename(monitor_name)) |
| 718 else: | 693 else: |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 751 "qemu command:\n%s" % qemu_command) | 726 "qemu command:\n%s" % qemu_command) |
| 752 logging.error("Output:" + kvm_utils.format_str_for_message( | 727 logging.error("Output:" + kvm_utils.format_str_for_message( |
| 753 self.process.get_output())) | 728 self.process.get_output())) |
| 754 self.destroy() | 729 self.destroy() |
| 755 return False | 730 return False |
| 756 | 731 |
| 757 logging.debug("VM appears to be alive with PID %s", self.get_pid()) | 732 logging.debug("VM appears to be alive with PID %s", self.get_pid()) |
| 758 | 733 |
| 759 # Establish a session with the serial console -- requires a version | 734 # Establish a session with the serial console -- requires a version |
| 760 # of netcat that supports -U | 735 # of netcat that supports -U |
| 761 self.serial_console = kvm_subprocess.ShellSession( | 736 self.serial_console = kvm_subprocess.kvm_shell_session( |
| 762 "nc -U %s" % self.get_serial_console_filename(), | 737 "nc -U %s" % self.get_serial_console_filename(), |
| 763 auto_close=False, | 738 auto_close=False, |
| 764 output_func=kvm_utils.log_line, | 739 output_func=kvm_utils.log_line, |
| 765 output_params=("serial-%s.log" % name,)) | 740 output_params=("serial-%s.log" % name,)) |
| 766 | 741 |
| 767 return True | 742 return True |
| 768 | 743 |
| 769 finally: | 744 finally: |
| 770 fcntl.lockf(lockfile, fcntl.LOCK_UN) | 745 fcntl.lockf(lockfile, fcntl.LOCK_UN) |
| 771 lockfile.close() | 746 lockfile.close() |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 844 self.get_monitor_filenames()): | 819 self.get_monitor_filenames()): |
| 845 try: | 820 try: |
| 846 os.unlink(f) | 821 os.unlink(f) |
| 847 except OSError: | 822 except OSError: |
| 848 pass | 823 pass |
| 849 if hasattr(self, "migration_file"): | 824 if hasattr(self, "migration_file"): |
| 850 try: | 825 try: |
| 851 os.unlink(self.migration_file) | 826 os.unlink(self.migration_file) |
| 852 except OSError: | 827 except OSError: |
| 853 pass | 828 pass |
| 854 num_nics = len(self.params.objects("nics")) | 829 num_nics = len(kvm_utils.get_sub_dict_names(self.params, "nics")) |
| 855 for vlan in range(num_nics): | 830 for vlan in range(num_nics): |
| 856 self.free_mac_address(vlan) | 831 self.free_mac_address(vlan) |
| 857 | 832 |
| 858 | 833 |
| 859 @property | 834 @property |
| 860 def monitor(self): | 835 def monitor(self): |
| 861 """ | 836 """ |
| 862 Return the main monitor object, selected by the parameter main_monitor. | 837 Return the main monitor object, selected by the parameter main_monitor. |
| 863 If main_monitor isn't defined, return the first monitor. | 838 If main_monitor isn't defined, return the first monitor. |
| 864 If no monitors exist, or if main_monitor refers to a nonexistent | 839 If no monitors exist, or if main_monitor refers to a nonexistent |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 903 """ | 878 """ |
| 904 return "/tmp/monitor-%s-%s" % (monitor_name, self.instance) | 879 return "/tmp/monitor-%s-%s" % (monitor_name, self.instance) |
| 905 | 880 |
| 906 | 881 |
| 907 def get_monitor_filenames(self): | 882 def get_monitor_filenames(self): |
| 908 """ | 883 """ |
| 909 Return a list of all monitor filenames (as specified in the VM's | 884 Return a list of all monitor filenames (as specified in the VM's |
| 910 params). | 885 params). |
| 911 """ | 886 """ |
| 912 return [self.get_monitor_filename(m) for m in | 887 return [self.get_monitor_filename(m) for m in |
| 913 self.params.objects("monitors")] | 888 kvm_utils.get_sub_dict_names(self.params, "monitors")] |
| 914 | 889 |
| 915 | 890 |
| 916 def get_serial_console_filename(self): | 891 def get_serial_console_filename(self): |
| 917 """ | 892 """ |
| 918 Return the serial console filename. | 893 Return the serial console filename. |
| 919 """ | 894 """ |
| 920 return "/tmp/serial-%s" % self.instance | 895 return "/tmp/serial-%s" % self.instance |
| 921 | 896 |
| 922 | 897 |
| 923 def get_testlog_filename(self): | 898 def get_testlog_filename(self): |
| 924 """ | 899 """ |
| 925 Return the testlog filename. | 900 Return the testlog filename. |
| 926 """ | 901 """ |
| 927 return "/tmp/testlog-%s" % self.instance | 902 return "/tmp/testlog-%s" % self.instance |
| 928 | 903 |
| 929 | 904 |
| 930 def get_address(self, index=0): | 905 def get_address(self, index=0): |
| 931 """ | 906 """ |
| 932 Return the address of a NIC of the guest, in host space. | 907 Return the address of a NIC of the guest, in host space. |
| 933 | 908 |
| 934 If port redirection is used, return 'localhost' (the NIC has no IP | 909 If port redirection is used, return 'localhost' (the NIC has no IP |
| 935 address of its own). Otherwise return the NIC's IP address. | 910 address of its own). Otherwise return the NIC's IP address. |
| 936 | 911 |
| 937 @param index: Index of the NIC whose address is requested. | 912 @param index: Index of the NIC whose address is requested. |
| 938 """ | 913 """ |
| 939 nics = self.params.objects("nics") | 914 nics = kvm_utils.get_sub_dict_names(self.params, "nics") |
| 940 nic_name = nics[index] | 915 nic_name = nics[index] |
| 941 nic_params = self.params.object_params(nic_name) | 916 nic_params = kvm_utils.get_sub_dict(self.params, nic_name) |
| 942 if nic_params.get("nic_mode") == "tap": | 917 if nic_params.get("nic_mode") == "tap": |
| 943 mac = self.get_mac_address(index) | 918 mac = self.get_mac_address(index) |
| 944 if not mac: | 919 if not mac: |
| 945 logging.debug("MAC address unavailable") | 920 logging.debug("MAC address unavailable") |
| 946 return None | 921 return None |
| 947 mac = mac.lower() | 922 mac = mac.lower() |
| 948 # Get the IP address from the cache | 923 # Get the IP address from the cache |
| 949 ip = self.address_cache.get(mac) | 924 ip = self.address_cache.get(mac) |
| 950 if not ip: | 925 if not ip: |
| 951 logging.debug("Could not find IP address for MAC address: %s" % | 926 logging.debug("Could not find IP address for MAC address: %s" % |
| (...skipping 12 matching lines...) Expand all Loading... |
| 964 | 939 |
| 965 def get_port(self, port, nic_index=0): | 940 def get_port(self, port, nic_index=0): |
| 966 """ | 941 """ |
| 967 Return the port in host space corresponding to port in guest space. | 942 Return the port in host space corresponding to port in guest space. |
| 968 | 943 |
| 969 @param port: Port number in host space. | 944 @param port: Port number in host space. |
| 970 @param nic_index: Index of the NIC. | 945 @param nic_index: Index of the NIC. |
| 971 @return: If port redirection is used, return the host port redirected | 946 @return: If port redirection is used, return the host port redirected |
| 972 to guest port port. Otherwise return port. | 947 to guest port port. Otherwise return port. |
| 973 """ | 948 """ |
| 974 nic_name = self.params.objects("nics")[nic_index] | 949 nic_name = kvm_utils.get_sub_dict_names(self.params, "nics")[nic_index] |
| 975 nic_params = self.params.object_params(nic_name) | 950 nic_params = kvm_utils.get_sub_dict(self.params, nic_name) |
| 976 if nic_params.get("nic_mode") == "tap": | 951 if nic_params.get("nic_mode") == "tap": |
| 977 return port | 952 return port |
| 978 else: | 953 else: |
| 979 if not self.redirs.has_key(port): | 954 if not self.redirs.has_key(port): |
| 980 logging.warn("Warning: guest port %s requested but not " | 955 logging.warn("Warning: guest port %s requested but not " |
| 981 "redirected" % port) | 956 "redirected" % port) |
| 982 return self.redirs.get(port) | 957 return self.redirs.get(port) |
| 983 | 958 |
| 984 | 959 |
| 985 def get_ifname(self, nic_index=0): | 960 def get_ifname(self, nic_index=0): |
| 986 """ | 961 """ |
| 987 Return the ifname of a tap device associated with a NIC. | 962 Return the ifname of a tap device associated with a NIC. |
| 988 | 963 |
| 989 @param nic_index: Index of the NIC | 964 @param nic_index: Index of the NIC |
| 990 """ | 965 """ |
| 991 nics = self.params.objects("nics") | 966 nics = kvm_utils.get_sub_dict_names(self.params, "nics") |
| 992 nic_name = nics[nic_index] | 967 nic_name = nics[nic_index] |
| 993 nic_params = self.params.object_params(nic_name) | 968 nic_params = kvm_utils.get_sub_dict(self.params, nic_name) |
| 994 if nic_params.get("nic_ifname"): | 969 if nic_params.get("nic_ifname"): |
| 995 return nic_params.get("nic_ifname") | 970 return nic_params.get("nic_ifname") |
| 996 else: | 971 else: |
| 997 return "t%d-%s" % (nic_index, self.instance[-11:]) | 972 return "t%d-%s" % (nic_index, self.instance[-11:]) |
| 998 | 973 |
| 999 | 974 |
| 1000 def get_mac_address(self, nic_index=0): | 975 def get_mac_address(self, nic_index=0): |
| 1001 """ | 976 """ |
| 1002 Return the MAC address of a NIC. | 977 Return the MAC address of a NIC. |
| 1003 | 978 |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1058 | 1033 |
| 1059 def remote_login(self, nic_index=0, timeout=10): | 1034 def remote_login(self, nic_index=0, timeout=10): |
| 1060 """ | 1035 """ |
| 1061 Log into the guest via SSH/Telnet/Netcat. | 1036 Log into the guest via SSH/Telnet/Netcat. |
| 1062 If timeout expires while waiting for output from the guest (e.g. a | 1037 If timeout expires while waiting for output from the guest (e.g. a |
| 1063 password prompt or a shell prompt) -- fail. | 1038 password prompt or a shell prompt) -- fail. |
| 1064 | 1039 |
| 1065 @param nic_index: The index of the NIC to connect to. | 1040 @param nic_index: The index of the NIC to connect to. |
| 1066 @param timeout: Time (seconds) before giving up logging into the | 1041 @param timeout: Time (seconds) before giving up logging into the |
| 1067 guest. | 1042 guest. |
| 1068 @return: ShellSession object on success and None on failure. | 1043 @return: kvm_spawn object on success and None on failure. |
| 1069 """ | 1044 """ |
| 1070 username = self.params.get("username", "") | 1045 username = self.params.get("username", "") |
| 1071 password = self.params.get("password", "") | 1046 password = self.params.get("password", "") |
| 1072 prompt = self.params.get("shell_prompt", "[\#\$]") | 1047 prompt = self.params.get("shell_prompt", "[\#\$]") |
| 1073 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n")) | 1048 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n")) |
| 1074 client = self.params.get("shell_client") | 1049 client = self.params.get("shell_client") |
| 1075 address = self.get_address(nic_index) | 1050 address = self.get_address(nic_index) |
| 1076 port = self.get_port(int(self.params.get("shell_port"))) | 1051 port = self.get_port(int(self.params.get("shell_port"))) |
| 1077 log_filename = ("session-%s-%s.log" % | 1052 log_filename = ("session-%s-%s.log" % |
| 1078 (self.name, kvm_utils.generate_random_string(4))) | 1053 (self.name, kvm_utils.generate_random_string(4))) |
| 1079 | 1054 |
| 1080 if not address or not port: | 1055 if not address or not port: |
| 1081 logging.debug("IP address or port unavailable") | 1056 logging.debug("IP address or port unavailable") |
| 1082 return None | 1057 return None |
| 1083 | 1058 |
| 1084 session = kvm_utils.remote_login(client, address, port, username, | 1059 session = kvm_utils.remote_login(client, address, port, username, |
| 1085 password, prompt, linesep, | 1060 password, prompt, linesep, |
| 1086 log_filename, timeout) | 1061 log_filename, timeout) |
| 1087 | 1062 |
| 1088 if session: | 1063 if session: |
| 1089 session.set_status_test_command(self.params.get("status_test_" | 1064 session.set_status_test_command(self.params.get("status_test_" |
| 1090 "command", "")) | 1065 "command", "")) |
| 1091 return session | 1066 return session |
| 1092 | 1067 |
| 1093 | 1068 |
| 1094 def copy_files_to(self, local_path, remote_path, nic_index=0, timeout=600): | 1069 def copy_files_to(self, local_path, remote_path, nic_index=0, timeout=600): |
| 1095 """ | 1070 """ |
| 1096 Transfer files to the remote host(guest). | 1071 Transfer files to the guest. |
| 1097 | 1072 |
| 1098 @param local_path: Host path | 1073 @param local_path: Host path |
| 1099 @param remote_path: Guest path | 1074 @param remote_path: Guest path |
| 1100 @param nic_index: The index of the NIC to connect to. | 1075 @param nic_index: The index of the NIC to connect to. |
| 1101 @param timeout: Time (seconds) before giving up on doing the remote | 1076 @param timeout: Time (seconds) before giving up on doing the remote |
| 1102 copy. | 1077 copy. |
| 1103 """ | 1078 """ |
| 1104 username = self.params.get("username", "") | 1079 username = self.params.get("username", "") |
| 1105 password = self.params.get("password", "") | 1080 password = self.params.get("password", "") |
| 1106 client = self.params.get("file_transfer_client") | 1081 client = self.params.get("file_transfer_client") |
| 1107 address = self.get_address(nic_index) | 1082 address = self.get_address(nic_index) |
| 1108 port = self.get_port(int(self.params.get("file_transfer_port"))) | 1083 port = self.get_port(int(self.params.get("file_transfer_port"))) |
| 1109 | 1084 |
| 1110 log_filename = ("transfer-%s-to-%s-%s.log" % | 1085 if not address or not port: |
| 1111 (self.name, address, | 1086 logging.debug("IP address or port unavailable") |
| 1112 kvm_utils.generate_random_string(4))) | 1087 return None |
| 1113 return kvm_utils.copy_files_to(address, client, username, password, | 1088 |
| 1114 port, local_path, remote_path, | 1089 if client == "scp": |
| 1115 log_filename, timeout) | 1090 log_filename = ("scp-%s-%s.log" % |
| 1091 (self.name, kvm_utils.generate_random_string(4))) |
| 1092 return kvm_utils.scp_to_remote(address, port, username, password, |
| 1093 local_path, remote_path, |
| 1094 log_filename, timeout) |
| 1095 elif client == "rss": |
| 1096 c = rss_file_transfer.FileUploadClient(address, port) |
| 1097 c.upload(local_path, remote_path, timeout) |
| 1098 c.close() |
| 1099 return True |
| 1116 | 1100 |
| 1117 | 1101 |
| 1118 def copy_files_from(self, remote_path, local_path, nic_index=0, timeout=600)
: | 1102 def copy_files_from(self, remote_path, local_path, nic_index=0, timeout=600)
: |
| 1119 """ | 1103 """ |
| 1120 Transfer files from the guest. | 1104 Transfer files from the guest. |
| 1121 | 1105 |
| 1122 @param local_path: Guest path | 1106 @param local_path: Guest path |
| 1123 @param remote_path: Host path | 1107 @param remote_path: Host path |
| 1124 @param nic_index: The index of the NIC to connect to. | 1108 @param nic_index: The index of the NIC to connect to. |
| 1125 @param timeout: Time (seconds) before giving up on doing the remote | 1109 @param timeout: Time (seconds) before giving up on doing the remote |
| 1126 copy. | 1110 copy. |
| 1127 """ | 1111 """ |
| 1128 username = self.params.get("username", "") | 1112 username = self.params.get("username", "") |
| 1129 password = self.params.get("password", "") | 1113 password = self.params.get("password", "") |
| 1130 client = self.params.get("file_transfer_client") | 1114 client = self.params.get("file_transfer_client") |
| 1131 address = self.get_address(nic_index) | 1115 address = self.get_address(nic_index) |
| 1132 port = self.get_port(int(self.params.get("file_transfer_port"))) | 1116 port = self.get_port(int(self.params.get("file_transfer_port"))) |
| 1133 | 1117 |
| 1134 log_filename = ("transfer-%s-from-%s-%s.log" % | 1118 if not address or not port: |
| 1135 (self.name, address, | 1119 logging.debug("IP address or port unavailable") |
| 1136 kvm_utils.generate_random_string(4))) | 1120 return None |
| 1137 return kvm_utils.copy_files_from(address, client, username, password, | 1121 |
| 1138 port, local_path, remote_path, log_filename, timeout) | 1122 if client == "scp": |
| 1123 log_filename = ("scp-%s-%s.log" % |
| 1124 (self.name, kvm_utils.generate_random_string(4))) |
| 1125 return kvm_utils.scp_from_remote(address, port, username, password, |
| 1126 remote_path, local_path, |
| 1127 log_filename, timeout) |
| 1128 elif client == "rss": |
| 1129 c = rss_file_transfer.FileDownloadClient(address, port) |
| 1130 c.download(remote_path, local_path, timeout) |
| 1131 c.close() |
| 1132 return True |
| 1139 | 1133 |
| 1140 | 1134 |
| 1141 def serial_login(self, timeout=10): | 1135 def serial_login(self, timeout=10): |
| 1142 """ | 1136 """ |
| 1143 Log into the guest via the serial console. | 1137 Log into the guest via the serial console. |
| 1144 If timeout expires while waiting for output from the guest (e.g. a | 1138 If timeout expires while waiting for output from the guest (e.g. a |
| 1145 password prompt or a shell prompt) -- fail. | 1139 password prompt or a shell prompt) -- fail. |
| 1146 | 1140 |
| 1147 @param timeout: Time (seconds) before giving up logging into the guest. | 1141 @param timeout: Time (seconds) before giving up logging into the guest. |
| 1148 @return: ShellSession object on success and None on failure. | 1142 @return: kvm_spawn object on success and None on failure. |
| 1149 """ | 1143 """ |
| 1150 username = self.params.get("username", "") | 1144 username = self.params.get("username", "") |
| 1151 password = self.params.get("password", "") | 1145 password = self.params.get("password", "") |
| 1152 prompt = self.params.get("shell_prompt", "[\#\$]") | 1146 prompt = self.params.get("shell_prompt", "[\#\$]") |
| 1153 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n")) | 1147 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n")) |
| 1154 status_test_command = self.params.get("status_test_command", "") | 1148 status_test_command = self.params.get("status_test_command", "") |
| 1155 | 1149 |
| 1156 if self.serial_console: | 1150 if self.serial_console: |
| 1157 self.serial_console.set_linesep(linesep) | 1151 self.serial_console.set_linesep(linesep) |
| 1158 self.serial_console.set_status_test_command(status_test_command) | 1152 self.serial_console.set_status_test_command(status_test_command) |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1212 | 1206 |
| 1213 | 1207 |
| 1214 def get_cpu_count(self): | 1208 def get_cpu_count(self): |
| 1215 """ | 1209 """ |
| 1216 Get the cpu count of the VM. | 1210 Get the cpu count of the VM. |
| 1217 """ | 1211 """ |
| 1218 session = self.remote_login() | 1212 session = self.remote_login() |
| 1219 if not session: | 1213 if not session: |
| 1220 return None | 1214 return None |
| 1221 try: | 1215 try: |
| 1222 return int(session.cmd(self.params.get("cpu_chk_cmd"))) | 1216 cmd = self.params.get("cpu_chk_cmd") |
| 1217 s, count = session.get_command_status_output(cmd) |
| 1218 if s == 0: |
| 1219 return int(count) |
| 1220 return None |
| 1223 finally: | 1221 finally: |
| 1224 session.close() | 1222 session.close() |
| 1225 | 1223 |
| 1226 | 1224 |
| 1227 def get_memory_size(self, cmd=None): | 1225 def get_memory_size(self, cmd=None): |
| 1228 """ | 1226 """ |
| 1229 Get bootup memory size of the VM. | 1227 Get bootup memory size of the VM. |
| 1230 | 1228 |
| 1231 @param check_cmd: Command used to check memory. If not provided, | 1229 @param check_cmd: Command used to check memory. If not provided, |
| 1232 self.params.get("mem_chk_cmd") will be used. | 1230 self.params.get("mem_chk_cmd") will be used. |
| 1233 """ | 1231 """ |
| 1234 session = self.remote_login() | 1232 session = self.remote_login() |
| 1235 if not session: | 1233 if not session: |
| 1236 return None | 1234 return None |
| 1237 try: | 1235 try: |
| 1238 if not cmd: | 1236 if not cmd: |
| 1239 cmd = self.params.get("mem_chk_cmd") | 1237 cmd = self.params.get("mem_chk_cmd") |
| 1240 mem_str = session.cmd(cmd) | 1238 s, mem_str = session.get_command_status_output(cmd) |
| 1239 if s != 0: |
| 1240 return None |
| 1241 mem = re.findall("([0-9]+)", mem_str) | 1241 mem = re.findall("([0-9]+)", mem_str) |
| 1242 mem_size = 0 | 1242 mem_size = 0 |
| 1243 for m in mem: | 1243 for m in mem: |
| 1244 mem_size += int(m) | 1244 mem_size += int(m) |
| 1245 if "GB" in mem_str: | 1245 if "GB" in mem_str: |
| 1246 mem_size *= 1024 | 1246 mem_size *= 1024 |
| 1247 elif "MB" in mem_str: | 1247 elif "MB" in mem_str: |
| 1248 pass | 1248 pass |
| 1249 else: | 1249 else: |
| 1250 mem_size /= 1024 | 1250 mem_size /= 1024 |
| 1251 return int(mem_size) | 1251 return int(mem_size) |
| 1252 finally: | 1252 finally: |
| 1253 session.close() | 1253 session.close() |
| 1254 | 1254 |
| 1255 | 1255 |
| 1256 def get_current_memory_size(self): | 1256 def get_current_memory_size(self): |
| 1257 """ | 1257 """ |
| 1258 Get current memory size of the VM, rather than bootup memory. | 1258 Get current memory size of the VM, rather than bootup memory. |
| 1259 """ | 1259 """ |
| 1260 cmd = self.params.get("mem_chk_cur_cmd") | 1260 cmd = self.params.get("mem_chk_cur_cmd") |
| 1261 return self.get_memory_size(cmd) | 1261 return self.get_memory_size(cmd) |
| 1262 | |
| 1263 | |
| 1264 def save_to_file(self, path): | |
| 1265 """ | |
| 1266 Save the state of virtual machine to a file through migrate to | |
| 1267 exec | |
| 1268 """ | |
| 1269 # Make sure we only get one iteration | |
| 1270 self.monitor.cmd("migrate_set_speed 1000g") | |
| 1271 self.monitor.cmd("migrate_set_downtime 100000000") | |
| 1272 self.monitor.migrate('"exec:cat>%s"' % path) | |
| OLD | NEW |