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 |