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, os, logging, fcntl, re, commands, glob | 8 import time, os, logging, fcntl, re, commands, glob |
9 import kvm_utils, kvm_subprocess, kvm_monitor | 9 import kvm_utils, kvm_subprocess, kvm_monitor |
10 from autotest_lib.client.common_lib import error | 10 from autotest_lib.client.common_lib import error |
(...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
318 if state: | 318 if state: |
319 self.__dict__ = state | 319 self.__dict__ = state |
320 else: | 320 else: |
321 self.process = None | 321 self.process = None |
322 self.serial_console = None | 322 self.serial_console = None |
323 self.redirs = {} | 323 self.redirs = {} |
324 self.vnc_port = 5900 | 324 self.vnc_port = 5900 |
325 self.monitors = [] | 325 self.monitors = [] |
326 self.pci_assignable = None | 326 self.pci_assignable = None |
327 self.netdev_id = [] | 327 self.netdev_id = [] |
| 328 self.device_id = [] |
328 self.uuid = None | 329 self.uuid = None |
329 | 330 |
330 # Find a unique identifier for this VM | 331 # Find a unique identifier for this VM |
331 while True: | 332 while True: |
332 self.instance = (time.strftime("%Y%m%d-%H%M%S-") + | 333 self.instance = (time.strftime("%Y%m%d-%H%M%S-") + |
333 kvm_utils.generate_random_string(4)) | 334 kvm_utils.generate_random_string(4)) |
334 if not glob.glob("/tmp/*%s" % self.instance): | 335 if not glob.glob("/tmp/*%s" % self.instance): |
335 break | 336 break |
336 | 337 |
337 self.name = name | 338 self.name = name |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
454 if werror: | 455 if werror: |
455 cmd += ",werror=%s" % werror | 456 cmd += ",werror=%s" % werror |
456 if serial: | 457 if serial: |
457 cmd += ",serial='%s'" % serial | 458 cmd += ",serial='%s'" % serial |
458 if snapshot: | 459 if snapshot: |
459 cmd += ",snapshot=on" | 460 cmd += ",snapshot=on" |
460 if boot: | 461 if boot: |
461 cmd += ",boot=on" | 462 cmd += ",boot=on" |
462 return cmd | 463 return cmd |
463 | 464 |
464 def add_nic(help, vlan, model=None, mac=None, netdev_id=None, | 465 def add_nic(help, vlan, model=None, mac=None, device_id=None, netdev_id=
None, |
465 nic_extra_params=None): | 466 nic_extra_params=None): |
466 if has_option(help, "netdev"): | 467 if has_option(help, "netdev"): |
467 netdev_vlan_str = ",netdev=%s" % netdev_id | 468 netdev_vlan_str = ",netdev=%s" % netdev_id |
468 else: | 469 else: |
469 netdev_vlan_str = ",vlan=%d" % vlan | 470 netdev_vlan_str = ",vlan=%d" % vlan |
470 if has_option(help, "device"): | 471 if has_option(help, "device"): |
471 if not model: | 472 if not model: |
472 model = "rtl8139" | 473 model = "rtl8139" |
473 elif model == "virtio": | 474 elif model == "virtio": |
474 model = "virtio-net-pci" | 475 model = "virtio-net-pci" |
475 cmd = " -device %s" % model + netdev_vlan_str | 476 cmd = " -device %s" % model + netdev_vlan_str |
476 if mac: | 477 if mac: |
477 cmd += ",mac='%s'" % mac | 478 cmd += ",mac='%s'" % mac |
478 if nic_extra_params: | 479 if nic_extra_params: |
479 cmd += ",%s" % nic_extra_params | 480 cmd += ",%s" % nic_extra_params |
480 else: | 481 else: |
481 cmd = " -net nic" + netdev_vlan_str | 482 cmd = " -net nic" + netdev_vlan_str |
482 if model: | 483 if model: |
483 cmd += ",model=%s" % model | 484 cmd += ",model=%s" % model |
484 if mac: | 485 if mac: |
485 cmd += ",macaddr='%s'" % mac | 486 cmd += ",macaddr='%s'" % mac |
| 487 if device_id: |
| 488 cmd += ",id='%s'" % device_id |
486 return cmd | 489 return cmd |
487 | 490 |
488 def add_net(help, vlan, mode, ifname=None, script=None, | 491 def add_net(help, vlan, mode, ifname=None, script=None, |
489 downscript=None, tftp=None, bootfile=None, hostfwd=[], | 492 downscript=None, tftp=None, bootfile=None, hostfwd=[], |
490 netdev_id=None, netdev_extra_params=None): | 493 netdev_id=None, netdev_extra_params=None): |
491 if has_option(help, "netdev"): | 494 if has_option(help, "netdev"): |
492 cmd = " -netdev %s,id=%s" % (mode, netdev_id) | 495 cmd = " -netdev %s,id=%s" % (mode, netdev_id) |
493 if netdev_extra_params: | 496 if netdev_extra_params: |
494 cmd += ",%s" % netdev_extra_params | 497 cmd += ",%s" % netdev_extra_params |
495 else: | 498 else: |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
628 redir_params = params.object_params(redir_name) | 631 redir_params = params.object_params(redir_name) |
629 guest_port = int(redir_params.get("guest_port")) | 632 guest_port = int(redir_params.get("guest_port")) |
630 host_port = vm.redirs.get(guest_port) | 633 host_port = vm.redirs.get(guest_port) |
631 redirs += [(host_port, guest_port)] | 634 redirs += [(host_port, guest_port)] |
632 | 635 |
633 vlan = 0 | 636 vlan = 0 |
634 for nic_name in params.objects("nics"): | 637 for nic_name in params.objects("nics"): |
635 nic_params = params.object_params(nic_name) | 638 nic_params = params.object_params(nic_name) |
636 try: | 639 try: |
637 netdev_id = vm.netdev_id[vlan] | 640 netdev_id = vm.netdev_id[vlan] |
| 641 device_id = vm.device_id[vlan] |
638 except IndexError: | 642 except IndexError: |
639 netdev_id = None | 643 netdev_id = None |
640 # Handle the '-net nic' part | 644 # Handle the '-net nic' part |
641 mac = vm.get_mac_address(vlan) | 645 try: |
| 646 mac = vm.get_mac_address(vlan) |
| 647 except VMAddressError: |
| 648 mac = None |
642 qemu_cmd += add_nic(help, vlan, nic_params.get("nic_model"), mac, | 649 qemu_cmd += add_nic(help, vlan, nic_params.get("nic_model"), mac, |
643 netdev_id, nic_params.get("nic_extra_params")) | 650 device_id, netdev_id, nic_params.get("nic_extra_
params")) |
644 # Handle the '-net tap' or '-net user' part | 651 # Handle the '-net tap' or '-net user' or '-netdev' part |
645 script = nic_params.get("nic_script") | 652 script = nic_params.get("nic_script") |
646 downscript = nic_params.get("nic_downscript") | 653 downscript = nic_params.get("nic_downscript") |
647 tftp = nic_params.get("tftp") | 654 tftp = nic_params.get("tftp") |
648 if script: | 655 if script: |
649 script = kvm_utils.get_path(root_dir, script) | 656 script = kvm_utils.get_path(root_dir, script) |
650 if downscript: | 657 if downscript: |
651 downscript = kvm_utils.get_path(root_dir, downscript) | 658 downscript = kvm_utils.get_path(root_dir, downscript) |
652 if tftp: | 659 if tftp: |
653 tftp = kvm_utils.get_path(root_dir, tftp) | 660 tftp = kvm_utils.get_path(root_dir, tftp) |
654 qemu_cmd += add_net(help, vlan, nic_params.get("nic_mode", "user"), | 661 qemu_cmd += add_net(help, vlan, nic_params.get("nic_mode", "user"), |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
820 try: | 827 try: |
821 # Handle port redirections | 828 # Handle port redirections |
822 redir_names = params.objects("redirs") | 829 redir_names = params.objects("redirs") |
823 host_ports = kvm_utils.find_free_ports(5000, 6000, len(redir_names)) | 830 host_ports = kvm_utils.find_free_ports(5000, 6000, len(redir_names)) |
824 self.redirs = {} | 831 self.redirs = {} |
825 for i in range(len(redir_names)): | 832 for i in range(len(redir_names)): |
826 redir_params = params.object_params(redir_names[i]) | 833 redir_params = params.object_params(redir_names[i]) |
827 guest_port = int(redir_params.get("guest_port")) | 834 guest_port = int(redir_params.get("guest_port")) |
828 self.redirs[guest_port] = host_ports[i] | 835 self.redirs[guest_port] = host_ports[i] |
829 | 836 |
830 # Generate netdev IDs for all NICs | 837 # Generate netdev/device IDs for all NICs |
831 self.netdev_id = [] | 838 self.netdev_id = [] |
| 839 self.device_id = [] |
832 for nic in params.objects("nics"): | 840 for nic in params.objects("nics"): |
833 self.netdev_id.append(kvm_utils.generate_random_id()) | 841 self.netdev_id.append(kvm_utils.generate_random_id()) |
| 842 self.device_id.append(kvm_utils.generate_random_id()) |
834 | 843 |
835 # Find available VNC port, if needed | 844 # Find available VNC port, if needed |
836 if params.get("display") == "vnc": | 845 if params.get("display") == "vnc": |
837 self.vnc_port = kvm_utils.find_free_port(5900, 6100) | 846 self.vnc_port = kvm_utils.find_free_port(5900, 6100) |
838 | 847 |
839 # Find random UUID if specified 'uuid = random' in config file | 848 # Find random UUID if specified 'uuid = random' in config file |
840 if params.get("uuid") == "random": | 849 if params.get("uuid") == "random": |
841 f = open("/proc/sys/kernel/random/uuid") | 850 f = open("/proc/sys/kernel/random/uuid") |
842 self.uuid = f.read().strip() | 851 self.uuid = f.read().strip() |
843 f.close() | 852 f.close() |
844 | 853 |
845 # Generate or copy MAC addresses for all NICs | 854 # Generate or copy MAC addresses for all NICs |
846 num_nics = len(params.objects("nics")) | 855 num_nics = len(params.objects("nics")) |
847 for vlan in range(num_nics): | 856 for vlan in range(num_nics): |
848 nic_name = params.objects("nics")[vlan] | 857 nic_name = params.objects("nics")[vlan] |
849 nic_params = params.object_params(nic_name) | 858 nic_params = params.object_params(nic_name) |
850 if nic_params.get("nic_mac", None): | 859 mac = (nic_params.get("nic_mac") or |
851 mac = nic_params.get("nic_mac") | 860 mac_source and mac_source.get_mac_address(vlan)) |
| 861 if mac: |
852 kvm_utils.set_mac_address(self.instance, vlan, mac) | 862 kvm_utils.set_mac_address(self.instance, vlan, mac) |
853 else: | 863 else: |
854 mac = mac_source and mac_source.get_mac_address(vlan) | 864 kvm_utils.generate_mac_address(self.instance, vlan) |
855 if mac: | |
856 kvm_utils.set_mac_address(self.instance, vlan, mac) | |
857 else: | |
858 kvm_utils.generate_mac_address(self.instance, vlan) | |
859 | 865 |
860 # Assign a PCI assignable device | 866 # Assign a PCI assignable device |
861 self.pci_assignable = None | 867 self.pci_assignable = None |
862 pa_type = params.get("pci_assignable") | 868 pa_type = params.get("pci_assignable") |
863 if pa_type and pa_type != "no": | 869 if pa_type and pa_type != "no": |
864 pa_devices_requested = params.get("devices_requested") | 870 pa_devices_requested = params.get("devices_requested") |
865 | 871 |
866 # Virtual Functions (VF) assignable devices | 872 # Virtual Functions (VF) assignable devices |
867 if pa_type == "vf": | 873 if pa_type == "vf": |
868 self.pci_assignable = kvm_utils.PciAssignable( | 874 self.pci_assignable = kvm_utils.PciAssignable( |
(...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1200 nic_params = self.params.object_params(nic_name) | 1206 nic_params = self.params.object_params(nic_name) |
1201 if nic_params.get("nic_mode") == "tap": | 1207 if nic_params.get("nic_mode") == "tap": |
1202 return port | 1208 return port |
1203 else: | 1209 else: |
1204 try: | 1210 try: |
1205 return self.redirs[port] | 1211 return self.redirs[port] |
1206 except KeyError: | 1212 except KeyError: |
1207 raise VMPortNotRedirectedError(port) | 1213 raise VMPortNotRedirectedError(port) |
1208 | 1214 |
1209 | 1215 |
| 1216 def get_peer(self, netid): |
| 1217 """ |
| 1218 Return the peer of netdev or network deivce. |
| 1219 |
| 1220 @param netid: id of netdev or device |
| 1221 @return: id of the peer device otherwise None |
| 1222 """ |
| 1223 network_info = self.monitor.info("network") |
| 1224 try: |
| 1225 return re.findall("%s:.*peer=(.*)" % netid, network_info)[0] |
| 1226 except IndexError: |
| 1227 return None |
| 1228 |
| 1229 |
1210 def get_ifname(self, nic_index=0): | 1230 def get_ifname(self, nic_index=0): |
1211 """ | 1231 """ |
1212 Return the ifname of a tap device associated with a NIC. | 1232 Return the ifname of a tap device associated with a NIC. |
1213 | 1233 |
1214 @param nic_index: Index of the NIC | 1234 @param nic_index: Index of the NIC |
1215 """ | 1235 """ |
1216 nics = self.params.objects("nics") | 1236 nics = self.params.objects("nics") |
1217 nic_name = nics[nic_index] | 1237 nic_name = nics[nic_index] |
1218 nic_params = self.params.object_params(nic_name) | 1238 nic_params = self.params.object_params(nic_name) |
1219 if nic_params.get("nic_ifname"): | 1239 if nic_params.get("nic_ifname"): |
1220 return nic_params.get("nic_ifname") | 1240 return nic_params.get("nic_ifname") |
1221 else: | 1241 else: |
1222 return "t%d-%s" % (nic_index, self.instance[-11:]) | 1242 return "t%d-%s" % (nic_index, self.instance[-11:]) |
1223 | 1243 |
1224 | 1244 |
1225 def get_mac_address(self, nic_index=0): | 1245 def get_mac_address(self, nic_index=0): |
1226 """ | 1246 """ |
1227 Return the MAC address of a NIC. | 1247 Return the MAC address of a NIC. |
1228 | 1248 |
1229 @param nic_index: Index of the NIC | 1249 @param nic_index: Index of the NIC |
1230 @raise VMMACAddressMissingError: If no MAC address is defined for the | 1250 @raise VMMACAddressMissingError: If no MAC address is defined for the |
1231 requested NIC | 1251 requested NIC |
1232 """ | 1252 """ |
1233 mac = kvm_utils.get_mac_address(self.instance, nic_index) | 1253 nic_name = self.params.objects("nics")[nic_index] |
| 1254 nic_params = self.params.object_params(nic_name) |
| 1255 mac = (nic_params.get("nic_mac") or |
| 1256 kvm_utils.get_mac_address(self.instance, nic_index)) |
1234 if not mac: | 1257 if not mac: |
1235 raise VMMACAddressMissingError(nic_index) | 1258 raise VMMACAddressMissingError(nic_index) |
1236 return mac | 1259 return mac |
1237 | 1260 |
1238 | 1261 |
1239 def free_mac_address(self, nic_index=0): | 1262 def free_mac_address(self, nic_index=0): |
1240 """ | 1263 """ |
1241 Free a NIC's MAC address. | 1264 Free a NIC's MAC address. |
1242 | 1265 |
1243 @param nic_index: Index of the NIC | 1266 @param nic_index: Index of the NIC |
(...skipping 501 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1745 Save the state of virtual machine to a file through migrate to | 1768 Save the state of virtual machine to a file through migrate to |
1746 exec | 1769 exec |
1747 """ | 1770 """ |
1748 # Make sure we only get one iteration | 1771 # Make sure we only get one iteration |
1749 self.monitor.cmd("migrate_set_speed 1000g") | 1772 self.monitor.cmd("migrate_set_speed 1000g") |
1750 self.monitor.cmd("migrate_set_downtime 100000000") | 1773 self.monitor.cmd("migrate_set_downtime 100000000") |
1751 self.monitor.migrate('"exec:cat>%s"' % path) | 1774 self.monitor.migrate('"exec:cat>%s"' % path) |
1752 # Restore the speed and downtime of migration | 1775 # Restore the speed and downtime of migration |
1753 self.monitor.cmd("migrate_set_speed %d" % (32<<20)) | 1776 self.monitor.cmd("migrate_set_speed %d" % (32<<20)) |
1754 self.monitor.cmd("migrate_set_downtime 0.03") | 1777 self.monitor.cmd("migrate_set_downtime 0.03") |
OLD | NEW |