Revision 8b7be6f2
b/lib/hypervisor/hv_kvm.py | ||
---|---|---|
37 | 37 |
import socket |
38 | 38 |
import stat |
39 | 39 |
import StringIO |
40 |
from bitarray import bitarray |
|
40 | 41 |
try: |
41 | 42 |
import affinity # pylint: disable=F0401 |
42 | 43 |
except ImportError: |
... | ... | |
79 | 80 |
constants.HV_KVM_SPICE_USE_TLS, |
80 | 81 |
]) |
81 | 82 |
|
83 |
# Constant bitarray that reflects to a free pci slot |
|
84 |
# Use it with bitarray.search() |
|
85 |
_AVAILABLE_PCI_SLOT = bitarray("0") |
|
86 |
|
|
82 | 87 |
# below constants show the format of runtime file |
83 | 88 |
# the nics are in second possition, while the disks in 4th (last) |
84 | 89 |
# moreover disk entries are stored in tupples of L{objects.Disk}, dev_path |
... | ... | |
105 | 110 |
} |
106 | 111 |
|
107 | 112 |
|
113 |
def _GenerateDeviceKVMId(dev_type, dev): |
|
114 |
"""Helper function to generate a unique device name used by KVM |
|
115 |
|
|
116 |
QEMU monitor commands use names to identify devices. Here we use their pci |
|
117 |
slot and a part of their UUID to name them. dev.pci might be None for old |
|
118 |
devices in the cluster. |
|
119 |
|
|
120 |
@type dev_type: sting |
|
121 |
@param dev_type: device type of param dev |
|
122 |
@type dev: L{objects.Disk} or L{objects.NIC} |
|
123 |
@param dev: the device object for which we generate a kvm name |
|
124 |
@raise errors.HotplugError: in case a device has no pci slot (old devices) |
|
125 |
|
|
126 |
""" |
|
127 |
|
|
128 |
if not dev.pci: |
|
129 |
raise errors.HotplugError("Hotplug is not supported for %s with UUID %s" % |
|
130 |
(dev_type, dev.uuid)) |
|
131 |
|
|
132 |
return "%s-%s-pci-%d" % (dev_type.lower(), dev.uuid.split("-")[0], dev.pci) |
|
133 |
|
|
134 |
|
|
135 |
def _UpdatePCISlots(dev, pci_reservations): |
|
136 |
"""Update pci configuration for a stopped instance |
|
137 |
|
|
138 |
If dev has a pci slot then reserve it, else find first available |
|
139 |
in pci_reservations bitarray. It acts on the same objects passed |
|
140 |
as params so there is no need to return anything. |
|
141 |
|
|
142 |
@type dev: L{objects.Disk} or L{objects.NIC} |
|
143 |
@param dev: the device object for which we update its pci slot |
|
144 |
@type pci_reservations: bitarray |
|
145 |
@param pci_reservations: existing pci reservations for an instance |
|
146 |
@raise errors.HotplugError: in case an instance has all its slot occupied |
|
147 |
|
|
148 |
""" |
|
149 |
if dev.pci: |
|
150 |
free = dev.pci |
|
151 |
else: # pylint: disable=E1103 |
|
152 |
[free] = pci_reservations.search(_AVAILABLE_PCI_SLOT, 1) |
|
153 |
if not free: |
|
154 |
raise errors.HypervisorError("All PCI slots occupied") |
|
155 |
dev.pci = int(free) |
|
156 |
|
|
157 |
pci_reservations[free] = True |
|
158 |
|
|
159 |
|
|
108 | 160 |
def _GetExistingDeviceInfo(dev_type, device, runtime): |
109 | 161 |
"""Helper function to get an existing device inside the runtime file |
110 | 162 |
|
... | ... | |
649 | 701 |
# different than -drive is starting) |
650 | 702 |
_BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S) |
651 | 703 |
|
704 |
_INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*') |
|
705 |
_INFO_PCI_CMD = "info pci" |
|
706 |
_INFO_VERSION_RE = \ |
|
707 |
re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M) |
|
708 |
_INFO_VERSION_CMD = "info version" |
|
709 |
|
|
710 |
_DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000" |
|
711 |
|
|
652 | 712 |
ANCILLARY_FILES = [ |
653 | 713 |
_KVM_NETWORK_SCRIPT, |
654 | 714 |
] |
... | ... | |
1820 | 1880 |
|
1821 | 1881 |
return result |
1822 | 1882 |
|
1883 |
def _GetFreePCISlot(self, instance, dev): |
|
1884 |
"""Get the first available pci slot of a runnung instance. |
|
1885 |
|
|
1886 |
""" |
|
1887 |
slots = bitarray(32) |
|
1888 |
slots.setall(False) # pylint: disable=E1101 |
|
1889 |
output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD) |
|
1890 |
for line in output.stdout.splitlines(): |
|
1891 |
match = self._INFO_PCI_RE.search(line) |
|
1892 |
if match: |
|
1893 |
slot = int(match.group(1)) |
|
1894 |
slots[slot] = True |
|
1895 |
|
|
1896 |
[free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101 |
|
1897 |
if not free: |
|
1898 |
raise errors.HypervisorError("All PCI slots occupied") |
|
1899 |
|
|
1900 |
dev.pci = int(free) |
|
1901 |
|
|
1823 | 1902 |
@classmethod |
1824 | 1903 |
def _ParseKVMVersion(cls, text): |
1825 | 1904 |
"""Parse the KVM version from the --help output. |
Also available in: Unified diff