9a83bcdc4f0e4588ec000cbda8fb725b548a4292
[ganeti-github.git] / lib / hypervisor / hv_kvm / __init__.py
1 #
2 #
3
4 # Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Google Inc.
5 # All rights reserved.
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions are
9 # met:
10 #
11 # 1. Redistributions of source code must retain the above copyright notice,
12 # this list of conditions and the following disclaimer.
13 #
14 # 2. Redistributions in binary form must reproduce the above copyright
15 # notice, this list of conditions and the following disclaimer in the
16 # documentation and/or other materials provided with the distribution.
17 #
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
19 # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30
31 """KVM hypervisor
32
33 """
34
35 import errno
36 import os
37 import os.path
38 import re
39 import tempfile
40 import time
41 import logging
42 import pwd
43 import shutil
44 import urllib2
45 from bitarray import bitarray
46 try:
47 import psutil # pylint: disable=F0401
48 if psutil.version_info < (2, 0, 0):
49 # The psutil version seems too old, we ignore it
50 psutil_err = "too old (2.x.x needed, %s found)" % psutil.__version__
51 psutil = None
52 elif psutil.version_info >= (3,):
53 psutil_err = "too new (2.x.x needed, %s found)" % psutil.__version__
54 psutil = None
55 else:
56 psutil_err = "<no error>"
57 except ImportError:
58 psutil_err = "not found"
59 psutil = None
60 try:
61 import fdsend # pylint: disable=F0401
62 except ImportError:
63 fdsend = None
64
65 from ganeti import utils
66 from ganeti import constants
67 from ganeti import errors
68 from ganeti import serializer
69 from ganeti import objects
70 from ganeti import uidpool
71 from ganeti import ssconf
72 from ganeti import netutils
73 from ganeti import pathutils
74 from ganeti.hypervisor import hv_base
75 from ganeti.utils import wrapper as utils_wrapper
76
77 from ganeti.hypervisor.hv_kvm.monitor import QmpConnection, QmpMessage, \
78 MonitorSocket
79 from ganeti.hypervisor.hv_kvm.netdev import OpenTap
80
81
82 _KVM_NETWORK_SCRIPT = pathutils.CONF_DIR + "/kvm-vif-bridge"
83 _KVM_START_PAUSED_FLAG = "-S"
84
85 #: SPICE parameters which depend on L{constants.HV_KVM_SPICE_BIND}
86 _SPICE_ADDITIONAL_PARAMS = frozenset([
87 constants.HV_KVM_SPICE_IP_VERSION,
88 constants.HV_KVM_SPICE_PASSWORD_FILE,
89 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR,
90 constants.HV_KVM_SPICE_JPEG_IMG_COMPR,
91 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR,
92 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION,
93 constants.HV_KVM_SPICE_USE_TLS,
94 ])
95
96 # below constants show the format of runtime file
97 # the nics are in second possition, while the disks in 4th (last)
98 # moreover disk entries are stored as a list of in tuples
99 # (L{objects.Disk}, link_name, uri)
100 _KVM_NICS_RUNTIME_INDEX = 1
101 _KVM_DISKS_RUNTIME_INDEX = 3
102 _DEVICE_RUNTIME_INDEX = {
103 constants.HOTPLUG_TARGET_DISK: _KVM_DISKS_RUNTIME_INDEX,
104 constants.HOTPLUG_TARGET_NIC: _KVM_NICS_RUNTIME_INDEX
105 }
106 _FIND_RUNTIME_ENTRY = {
107 constants.HOTPLUG_TARGET_NIC:
108 lambda nic, kvm_nics: [n for n in kvm_nics if n.uuid == nic.uuid],
109 constants.HOTPLUG_TARGET_DISK:
110 lambda disk, kvm_disks: [(d, l, u) for (d, l, u) in kvm_disks
111 if d.uuid == disk.uuid]
112 }
113 _RUNTIME_DEVICE = {
114 constants.HOTPLUG_TARGET_NIC: lambda d: d,
115 constants.HOTPLUG_TARGET_DISK: lambda (d, e, _): d
116 }
117 _RUNTIME_ENTRY = {
118 constants.HOTPLUG_TARGET_NIC: lambda d, e: d,
119 constants.HOTPLUG_TARGET_DISK: lambda d, e: (d, e[0], e[1])
120 }
121
122 _DEVICE_TYPE = {
123 constants.HOTPLUG_TARGET_NIC: lambda hvp: hvp[constants.HV_NIC_TYPE],
124 constants.HOTPLUG_TARGET_DISK: lambda hvp: hvp[constants.HV_DISK_TYPE],
125 }
126
127 _DEVICE_DRIVER = {
128 constants.HOTPLUG_TARGET_NIC:
129 lambda ht: "virtio-net-pci" if ht == constants.HT_NIC_PARAVIRTUAL else ht,
130 constants.HOTPLUG_TARGET_DISK:
131 lambda ht: "virtio-blk-pci" if ht == constants.HT_DISK_PARAVIRTUAL else ht,
132 }
133
134
135 # NICs and paravirtual disks
136 # show up as devices on the PCI bus (one slot per device).
137 # SCSI disks will be placed on the SCSI bus.
138 _DEVICE_BUS = {
139 constants.HOTPLUG_TARGET_NIC:
140 lambda _: _PCI_BUS,
141 constants.HOTPLUG_TARGET_DISK:
142 lambda ht: _SCSI_BUS if ht in constants.HT_SCSI_DEVICE_TYPES else _PCI_BUS
143 }
144
145 _HOTPLUGGABLE_DEVICE_TYPES = {
146 # All available NIC types except for ne2k_isa
147 constants.HOTPLUG_TARGET_NIC: [
148 constants.HT_NIC_E1000,
149 constants.HT_NIC_I82551,
150 constants.HT_NIC_I8259ER,
151 constants.HT_NIC_I85557B,
152 constants.HT_NIC_NE2K_PCI,
153 constants.HT_NIC_PARAVIRTUAL,
154 constants.HT_NIC_PCNET,
155 constants.HT_NIC_RTL8139,
156 ],
157 constants.HOTPLUG_TARGET_DISK: [
158 constants.HT_DISK_PARAVIRTUAL,
159 constants.HT_DISK_SCSI_BLOCK,
160 constants.HT_DISK_SCSI_GENERIC,
161 constants.HT_DISK_SCSI_HD,
162 constants.HT_DISK_SCSI_CD,
163 ]
164 }
165
166 _PCI_BUS = "pci.0"
167 _SCSI_BUS = "scsi.0"
168
169 _MIGRATION_CAPS_DELIM = ":"
170
171
172 def _with_qmp(fn):
173 """Wrapper used on hotplug related methods"""
174 def wrapper(self, instance, *args, **kwargs):
175 """Create a QmpConnection and run the wrapped method"""
176 if not getattr(self, "qmp", None):
177 filename = self._InstanceQmpMonitor(instance.name)# pylint: disable=W0212
178 self.qmp = QmpConnection(filename)
179 return fn(self, instance, *args, **kwargs)
180 return wrapper
181
182
183 def _GetDriveURI(disk, link, uri):
184 """Helper function to get the drive uri to be used in --drive kvm option
185
186 Invoked during startup and disk hot-add. In latter case and if no userspace
187 access mode is used it will be overriden with /dev/fdset/<fdset-id> (see
188 HotAddDisk() and AddFd() of QmpConnection).
189
190 @type disk: L{objects.Disk}
191 @param disk: A disk configuration object
192 @type link: string
193 @param link: The device link as returned by _SymlinkBlockDev()
194 @type uri: string
195 @param uri: The drive uri as returned by _CalculateDeviceURI()
196
197 @return: The drive uri to use in kvm option
198
199 """
200 access_mode = disk.params.get(constants.LDP_ACCESS,
201 constants.DISK_KERNELSPACE)
202 # If uri is available, use it during startup/hot-add
203 if uri and access_mode == constants.DISK_USERSPACE:
204 drive_uri = uri
205 # Otherwise use the link previously created
206 else:
207 drive_uri = link
208
209 return drive_uri
210
211
212 def _GenerateDeviceKVMId(dev_type, dev):
213 """Helper function to generate a unique device name used by KVM
214
215 QEMU monitor commands use names to identify devices. Since the UUID
216 is too long for a device ID (36 chars vs. 30), we choose to use
217 only the part until the third '-' with a disk/nic prefix.
218 For example if a disk has UUID '932df160-7a22-4067-a566-7e0ca8386133'
219 the resulting device ID would be 'disk-932df160-7a22-4067'.
220
221 @type dev_type: string
222 @param dev_type: device type of param dev (HOTPLUG_TARGET_DISK|NIC)
223 @type dev: L{objects.Disk} or L{objects.NIC}
224 @param dev: the device object for which we generate a kvm name
225
226 """
227 return "%s-%s" % (dev_type.lower(), dev.uuid.rsplit("-", 2)[0])
228
229
230 def _GenerateDeviceHVInfoStr(hvinfo):
231 """Construct the -device option string for hvinfo dict
232
233 PV disk: virtio-blk-pci,id=disk-1234,bus=pci.0,addr=0x9
234 PV NIC: virtio-net-pci,id=nic-1234,bus=pci.0,addr=0x9
235 SG disk: scsi-generic,id=disk-1234,bus=scsi.0,channel=0,scsi-id=1,lun=0
236
237 @type hvinfo: dict
238 @param hvinfo: dictionary created by _GenerateDeviceHVInfo()
239
240 @rtype: string
241 @return: The constructed string to be passed along with a -device option
242
243 """
244
245 # work on a copy
246 d = dict(hvinfo)
247 hvinfo_str = d.pop("driver")
248 for k, v in d.items():
249 hvinfo_str += ",%s=%s" % (k, v)
250
251 return hvinfo_str
252
253
254 def _GenerateDeviceHVInfo(dev_type, kvm_devid, hv_dev_type, bus_slots):
255 """Helper function to generate hvinfo of a device (disk, NIC)
256
257 hvinfo will hold all necessary info for generating the -device QEMU option.
258 We have two main buses: a PCI bus and a SCSI bus (created by a SCSI
259 controller on the PCI bus).
260
261 In case of PCI devices we add them on a free PCI slot (addr) on the first PCI
262 bus (pci.0), and in case of SCSI devices we decide to put each disk on a
263 different SCSI target (scsi-id) on the first SCSI bus (scsi.0).
264
265 @type dev_type: string
266 @param dev_type: either HOTPLUG_TARGET_DISK or HOTPLUG_TARGET_NIC
267 @type kvm_devid: string
268 @param kvm_devid: the id of the device
269 @type hv_dev_type: string
270 @param hv_dev_type: either disk_type or nic_type hvparam
271 @type bus_slots: dict
272 @param bus_slots: the current slots of the first PCI and SCSI buses
273
274 @rtype: dict
275 @return: dict including all necessary info (driver, id, bus and bus location)
276 for generating a -device QEMU option for either a disk or a NIC
277
278 """
279 driver = _DEVICE_DRIVER[dev_type](hv_dev_type)
280 bus = _DEVICE_BUS[dev_type](hv_dev_type)
281 slots = bus_slots[bus]
282 slot = utils.GetFreeSlot(slots, reserve=True)
283
284 hvinfo = {
285 "driver": driver,
286 "id": kvm_devid,
287 "bus": bus,
288 }
289
290 if bus == _PCI_BUS:
291 hvinfo.update({
292 "addr": hex(slot),
293 })
294 elif bus == _SCSI_BUS:
295 hvinfo.update({
296 "channel": 0,
297 "scsi-id": slot,
298 "lun": 0,
299 })
300
301 return hvinfo
302
303
304 def _GetExistingDeviceInfo(dev_type, device, runtime):
305 """Helper function to get an existing device inside the runtime file
306
307 Used when an instance is running. Load kvm runtime file and search
308 for a device based on its type and uuid.
309
310 @type dev_type: sting
311 @param dev_type: device type of param dev
312 @type device: L{objects.Disk} or L{objects.NIC}
313 @param device: the device object for which we generate a kvm name
314 @type runtime: tuple (cmd, nics, hvparams, disks)
315 @param runtime: the runtime data to search for the device
316 @raise errors.HotplugError: in case the requested device does not
317 exist (e.g. device has been added without --hotplug option)
318
319 """
320 index = _DEVICE_RUNTIME_INDEX[dev_type]
321 found = _FIND_RUNTIME_ENTRY[dev_type](device, runtime[index])
322 if not found:
323 raise errors.HotplugError("Cannot find runtime info for %s with UUID %s" %
324 (dev_type, device.uuid))
325
326 return found[0]
327
328
329 def _UpgradeSerializedRuntime(serialized_runtime):
330 """Upgrade runtime data
331
332 Remove any deprecated fields or change the format of the data.
333 The runtime files are not upgraded when Ganeti is upgraded, so the required
334 modification have to be performed here.
335
336 @type serialized_runtime: string
337 @param serialized_runtime: raw text data read from actual runtime file
338 @return: (cmd, nic dicts, hvparams, bdev dicts)
339 @rtype: tuple
340
341 """
342 loaded_runtime = serializer.Load(serialized_runtime)
343 kvm_cmd, serialized_nics, hvparams = loaded_runtime[:3]
344 if len(loaded_runtime) >= 4:
345 serialized_disks = loaded_runtime[3]
346 else:
347 serialized_disks = []
348
349 def update_hvinfo(dev, dev_type):
350 """ Remove deprecated pci slot and substitute it with hvinfo """
351 if "hvinfo" not in dev:
352 dev["hvinfo"] = {}
353 uuid = dev["uuid"]
354 # Ganeti used to save the PCI slot of paravirtual devices
355 # (virtio-blk-pci, virtio-net-pci) in runtime files during
356 # _GenerateKVMRuntime() and HotAddDevice().
357 # In this case we had a -device QEMU option in the command line with id,
358 # drive|netdev, bus, and addr params. All other devices did not have an
359 # id nor placed explicitly on a bus.
360 # hot- prefix is removed in 2.16. Here we add it explicitly to
361 # handle old instances in the cluster properly.
362 if "pci" in dev:
363 # This is practically the old _GenerateDeviceKVMId()
364 dev["hvinfo"]["id"] = "hot%s-%s-%s-%s" % (dev_type.lower(),
365 uuid.split("-")[0],
366 "pci",
367 dev["pci"])
368 dev["hvinfo"]["addr"] = hex(dev["pci"])
369 dev["hvinfo"]["bus"] = _PCI_BUS
370 del dev["pci"]
371
372 for nic in serialized_nics:
373 # Add a dummy uuid slot if an pre-2.8 NIC is found
374 if "uuid" not in nic:
375 nic["uuid"] = utils.NewUUID()
376 update_hvinfo(nic, constants.HOTPLUG_TARGET_NIC)
377
378 for disk_entry in serialized_disks:
379 # We have a (Disk, link, uri) tuple
380 update_hvinfo(disk_entry[0], constants.HOTPLUG_TARGET_DISK)
381
382 return kvm_cmd, serialized_nics, hvparams, serialized_disks
383
384
385 def _AnalyzeSerializedRuntime(serialized_runtime):
386 """Return runtime entries for a serialized runtime file
387
388 @type serialized_runtime: string
389 @param serialized_runtime: raw text data read from actual runtime file
390 @return: (cmd, nics, hvparams, bdevs)
391 @rtype: tuple
392
393 """
394 kvm_cmd, serialized_nics, hvparams, serialized_disks = \
395 _UpgradeSerializedRuntime(serialized_runtime)
396 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
397 kvm_disks = [(objects.Disk.FromDict(sdisk), link, uri)
398 for sdisk, link, uri in serialized_disks]
399
400 return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
401
402
403 class HeadRequest(urllib2.Request):
404 def get_method(self):
405 return "HEAD"
406
407
408 def _CheckUrl(url):
409 """Check if a given URL exists on the server
410
411 """
412 try:
413 urllib2.urlopen(HeadRequest(url))
414 return True
415 except urllib2.URLError:
416 return False
417
418
419 class KVMHypervisor(hv_base.BaseHypervisor):
420 """KVM hypervisor interface
421
422 """
423 CAN_MIGRATE = True
424
425 _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
426 _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
427 _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
428 _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
429 _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
430 _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
431 _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
432 # KVM instances with chroot enabled are started in empty chroot directories.
433 _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
434 # After an instance is stopped, its chroot directory is removed.
435 # If the chroot directory is not empty, it can't be removed.
436 # A non-empty chroot directory indicates a possible security incident.
437 # To support forensics, the non-empty chroot directory is quarantined in
438 # a separate directory, called 'chroot-quarantine'.
439 _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
440 _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
441 _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
442
443 PARAMETERS = {
444 constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
445 constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
446 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
447 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
448 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
449 constants.HV_ACPI: hv_base.NO_CHECK,
450 constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
451 constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
452 constants.HV_VNC_BIND_ADDRESS: hv_base.NO_CHECK, # will be checked later
453 constants.HV_VNC_TLS: hv_base.NO_CHECK,
454 constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
455 constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
456 constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
457 constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
458 constants.HV_KVM_SPICE_IP_VERSION:
459 (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
460 x in constants.VALID_IP_VERSIONS),
461 "The SPICE IP version should be 4 or 6",
462 None, None),
463 constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
464 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
465 hv_base.ParamInSet(
466 False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
467 constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
468 hv_base.ParamInSet(
469 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
470 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
471 hv_base.ParamInSet(
472 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
473 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
474 hv_base.ParamInSet(
475 False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
476 constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
477 constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
478 constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
479 constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
480 constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
481 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_OR_URL_CHECK,
482 constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_OR_URL_CHECK,
483 constants.HV_BOOT_ORDER:
484 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
485 constants.HV_NIC_TYPE:
486 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
487 constants.HV_DISK_TYPE:
488 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
489 constants.HV_KVM_SCSI_CONTROLLER_TYPE:
490 hv_base.ParamInSet(True, constants.HT_KVM_VALID_SCSI_CONTROLLER_TYPES),
491 constants.HV_KVM_CDROM_DISK_TYPE:
492 hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
493 constants.HV_USB_MOUSE:
494 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
495 constants.HV_KEYMAP: hv_base.NO_CHECK,
496 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
497 constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
498 constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
499 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
500 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
501 constants.HV_DISK_CACHE:
502 hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
503 constants.HV_KVM_DISK_AIO:
504 hv_base.ParamInSet(False, constants.HT_KVM_VALID_AIO_TYPES),
505 constants.HV_SECURITY_MODEL:
506 hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
507 constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
508 constants.HV_KVM_FLAG:
509 hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
510 constants.HV_VHOST_NET: hv_base.NO_CHECK,
511 constants.HV_VIRTIO_NET_QUEUES: hv_base.OPT_VIRTIO_NET_QUEUES_CHECK,
512 constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
513 constants.HV_KVM_USER_SHUTDOWN: hv_base.NO_CHECK,
514 constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
515 constants.HV_REBOOT_BEHAVIOR:
516 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
517 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
518 constants.HV_WORKER_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
519 constants.HV_CPU_TYPE: hv_base.NO_CHECK,
520 constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
521 constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
522 constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
523 constants.HV_SOUNDHW: hv_base.NO_CHECK,
524 constants.HV_USB_DEVICES: hv_base.NO_CHECK,
525 constants.HV_VGA: hv_base.NO_CHECK,
526 constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
527 constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
528 constants.HV_KVM_MIGRATION_CAPS: hv_base.NO_CHECK,
529 constants.HV_KVM_PCI_RESERVATIONS:
530 (False, lambda x: (x >= 0 and x <= constants.QEMU_PCI_SLOTS),
531 "The number of PCI slots managed by QEMU (max: %s)" %
532 constants.QEMU_PCI_SLOTS,
533 None, None),
534 constants.HV_VNET_HDR: hv_base.NO_CHECK,
535 }
536
537 _VIRTIO = "virtio"
538 _VIRTIO_NET_PCI = "virtio-net-pci"
539 _VIRTIO_BLK_PCI = "virtio-blk-pci"
540
541 _MIGRATION_STATUS_RE = re.compile(r"Migration\s+status:\s+([-\w]+)",
542 re.M | re.I)
543 _MIGRATION_PROGRESS_RE = \
544 re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n.*"
545 r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
546 r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
547 _MIGRATION_PRECOPY_PASSES_RE = \
548 re.compile(r"\s*dirty sync count:\s+(\d+)", re.I | re.M)
549
550 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
551 _MIGRATION_INFO_RETRY_DELAY = 2
552
553 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
554
555 _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
556 _CPU_INFO_CMD = "info cpus"
557 _CONT_CMD = "cont"
558
559 _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
560 _CHECK_MACHINE_VERSION_RE = \
561 staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
562
563 _QMP_RE = re.compile(r"^-qmp\s", re.M)
564 _SPICE_RE = re.compile(r"^-spice\s", re.M)
565 _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
566 _VIRTIO_NET_QUEUES_RE = re.compile(r"^-net\s.*,fds=x:y:...:z", re.M)
567 _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
568 _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
569 _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
570 _DISPLAY_RE = re.compile(r"^-display\s", re.M)
571 _MACHINE_RE = re.compile(r"^-machine\s", re.M)
572 _DEVICE_DRIVER_SUPPORTED = \
573 staticmethod(lambda drv, devlist:
574 re.compile(r"^name \"%s\"" % drv, re.M).search(devlist))
575 # match -drive.*boot=on|off on different lines, but in between accept only
576 # dashes not preceeded by a new line (which would mean another option
577 # different than -drive is starting)
578 _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
579 _UUID_RE = re.compile(r"^-uuid\s", re.M)
580
581 _INFO_VERSION_RE = \
582 re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
583 _INFO_VERSION_CMD = "info version"
584
585 # Slot 0 for Host bridge, Slot 1 for ISA bridge, Slot 2 for VGA controller
586 # and the rest up to slot 11 will be used by QEMU implicitly.
587 # Ganeti will add disks and NICs from slot 12 onwards.
588 # NOTE: This maps to the default PCI bus created by pc machine type
589 # by default (pci.0). The q35 creates a PCIe bus that is not hotpluggable
590 # and should be handled differently (pcie.0).
591 # NOTE: This bitarray here is defined for more fine-grained control.
592 # Currently the number of slots is QEMU_PCI_SLOTS and the reserved
593 # ones are the first QEMU_DEFAULT_PCI_RESERVATIONS.
594 # If the above constants change without updating _DEFAULT_PCI_RESERVATIONS
595 # properly, TestGenerateDeviceHVInfo() will probably break.
596 _DEFAULT_PCI_RESERVATIONS = "11111111111100000000000000000000"
597 # The SCSI bus is created on demand or automatically and is empty.
598 # For simplicity we decide to use a different target (scsi-id)
599 # for each SCSI disk. Here we support 16 SCSI disks which is
600 # actually the current hard limit (constants.MAX_DISKS).
601 # NOTE: Max device counts depend on the SCSI controller type;
602 # Just for the record, lsi supports up to 7, megasas 64,
603 # and virtio-scsi-pci 255.
604 _DEFAULT_SCSI_RESERVATIONS = "0000000000000000"
605
606 ANCILLARY_FILES = [
607 _KVM_NETWORK_SCRIPT,
608 ]
609 ANCILLARY_FILES_OPT = [
610 _KVM_NETWORK_SCRIPT,
611 ]
612
613 # Supported kvm options to get output from
614 _KVMOPT_HELP = "help"
615 _KVMOPT_MLIST = "mlist"
616 _KVMOPT_DEVICELIST = "devicelist"
617
618 # Command to execute to get the output from kvm, and whether to
619 # accept the output even on failure.
620 _KVMOPTS_CMDS = {
621 _KVMOPT_HELP: (["--help"], False),
622 _KVMOPT_MLIST: (["-M", "?"], False),
623 _KVMOPT_DEVICELIST: (["-device", "?"], True),
624 }
625
626 def __init__(self):
627 hv_base.BaseHypervisor.__init__(self)
628 # Let's make sure the directories we need exist, even if the RUN_DIR lives
629 # in a tmpfs filesystem or has been otherwise wiped out.
630 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
631 utils.EnsureDirs(dirs)
632 self.qmp = None
633
634 @staticmethod
635 def VersionsSafeForMigration(src, target):
636 """Predict if migration is safe between those versions
637
638 """
639 # Actually, it is not that easy. However, with the kvm machine_version
640 # feature, migration suceeds in most cases. So we try not to block
641 # legitimate migrations.
642 return True
643
644 @classmethod
645 def _InstancePidFile(cls, instance_name):
646 """Returns the instance pidfile.
647
648 """
649 return utils.PathJoin(cls._PIDS_DIR, instance_name)
650
651 @classmethod
652 def _InstanceUidFile(cls, instance_name):
653 """Returns the instance uidfile.
654
655 """
656 return utils.PathJoin(cls._UIDS_DIR, instance_name)
657
658 @classmethod
659 def _InstancePidInfo(cls, pid):
660 """Check pid file for instance information.
661
662 Check that a pid file is associated with an instance, and retrieve
663 information from its command line.
664
665 @type pid: string or int
666 @param pid: process id of the instance to check
667 @rtype: tuple
668 @return: (instance_name, memory, vcpus)
669 @raise errors.HypervisorError: when an instance cannot be found
670
671 """
672 alive = utils.IsProcessAlive(pid)
673 if not alive:
674 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
675
676 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
677 try:
678 cmdline = utils.ReadFile(cmdline_file)
679 except EnvironmentError, err:
680 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
681 (pid, err))
682
683 instance = None
684 memory = 0
685 vcpus = 0
686
687 arg_list = cmdline.split("\x00")
688 while arg_list:
689 arg = arg_list.pop(0)
690 if arg == "-name":
691 instance = arg_list.pop(0)
692 elif arg == "-m":
693 memory = int(arg_list.pop(0))
694 elif arg == "-smp":
695 vcpus = int(arg_list.pop(0).split(",")[0])
696
697 if instance is None:
698 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
699 " instance" % pid)
700
701 return (instance, memory, vcpus)
702
703 @classmethod
704 def _InstancePidAlive(cls, instance_name):
705 """Returns the instance pidfile, pid, and liveness.
706
707 @type instance_name: string
708 @param instance_name: instance name
709 @rtype: tuple
710 @return: (pid file name, pid, liveness)
711
712 """
713 pidfile = cls._InstancePidFile(instance_name)
714 pid = utils.ReadPidFile(pidfile)
715
716 alive = False
717 try:
718 cmd_instance = cls._InstancePidInfo(pid)[0]
719 alive = (cmd_instance == instance_name)
720 except errors.HypervisorError:
721 pass
722
723 return (pidfile, pid, alive)
724
725 @classmethod
726 def _CheckDown(cls, instance_name):
727 """Raises an error unless the given instance is down.
728
729 """
730 alive = cls._InstancePidAlive(instance_name)[2]
731 if alive:
732 raise errors.HypervisorError("Failed to start instance %s: %s" %
733 (instance_name, "already running"))
734
735 @classmethod
736 def _InstanceMonitor(cls, instance_name):
737 """Returns the instance monitor socket name
738
739 """
740 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
741
742 @classmethod
743 def _InstanceSerial(cls, instance_name):
744 """Returns the instance serial socket name
745
746 """
747 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
748
749 @classmethod
750 def _InstanceQmpMonitor(cls, instance_name):
751 """Returns the instance serial QMP socket name
752
753 """
754 return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
755
756 @classmethod
757 def _InstanceKvmdMonitor(cls, instance_name):
758 """Returns the instance kvm daemon socket name
759
760 """
761 return utils.PathJoin(cls._CTRL_DIR, "%s.kvmd" % instance_name)
762
763 @classmethod
764 def _InstanceShutdownMonitor(cls, instance_name):
765 """Returns the instance QMP output filename
766
767 """
768 return utils.PathJoin(cls._CTRL_DIR, "%s.shutdown" % instance_name)
769
770 @staticmethod
771 def _SocatUnixConsoleParams():
772 """Returns the correct parameters for socat
773
774 If we have a new-enough socat we can use raw mode with an escape character.
775
776 """
777 if constants.SOCAT_USE_ESCAPE:
778 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
779 else:
780 return "echo=0,icanon=0"
781
782 @classmethod
783 def _InstanceKVMRuntime(cls, instance_name):
784 """Returns the instance KVM runtime filename
785
786 """
787 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
788
789 @classmethod
790 def _InstanceChrootDir(cls, instance_name):
791 """Returns the name of the KVM chroot dir of the instance
792
793 """
794 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
795
796 @classmethod
797 def _InstanceNICDir(cls, instance_name):
798 """Returns the name of the directory holding the tap device files for a
799 given instance.
800
801 """
802 return utils.PathJoin(cls._NICS_DIR, instance_name)
803
804 @classmethod
805 def _InstanceNICFile(cls, instance_name, seq):
806 """Returns the name of the file containing the tap device for a given NIC
807
808 """
809 return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
810
811 @classmethod
812 def _InstanceKeymapFile(cls, instance_name):
813 """Returns the name of the file containing the keymap for a given instance
814
815 """
816 return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
817
818 @classmethod
819 def _TryReadUidFile(cls, uid_file):
820 """Try to read a uid file
821
822 """
823 if os.path.exists(uid_file):
824 try:
825 uid = int(utils.ReadOneLineFile(uid_file))
826 return uid
827 except EnvironmentError:
828 logging.warning("Can't read uid file", exc_info=True)
829 except (TypeError, ValueError):
830 logging.warning("Can't parse uid file contents", exc_info=True)
831 return None
832
833 @classmethod
834 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
835 """Removes an instance's rutime sockets/files/dirs.
836
837 """
838 utils.RemoveFile(pidfile)
839 utils.RemoveFile(cls._InstanceMonitor(instance_name))
840 utils.RemoveFile(cls._InstanceSerial(instance_name))
841 utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
842 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
843 utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
844 uid_file = cls._InstanceUidFile(instance_name)
845 uid = cls._TryReadUidFile(uid_file)
846 utils.RemoveFile(uid_file)
847 if uid is not None:
848 uidpool.ReleaseUid(uid)
849 try:
850 shutil.rmtree(cls._InstanceNICDir(instance_name))
851 except OSError, err:
852 if err.errno != errno.ENOENT:
853 raise
854 try:
855 chroot_dir = cls._InstanceChrootDir(instance_name)
856 utils.RemoveDir(chroot_dir)
857 except OSError, err:
858 if err.errno == errno.ENOTEMPTY:
859 # The chroot directory is expected to be empty, but it isn't.
860 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
861 prefix="%s-%s-" %
862 (instance_name,
863 utils.TimestampForFilename()))
864 logging.warning("The chroot directory of instance %s can not be"
865 " removed as it is not empty. Moving it to the"
866 " quarantine instead. Please investigate the"
867 " contents (%s) and clean up manually",
868 instance_name, new_chroot_dir)
869 utils.RenameFile(chroot_dir, new_chroot_dir)
870 else:
871 raise
872
873 @staticmethod
874 def _ConfigureNIC(instance, seq, nic, tap):
875 """Run the network configuration script for a specified NIC
876
877 See L{hv_base.ConfigureNIC}.
878
879 @param instance: instance we're acting on
880 @type instance: instance object
881 @param seq: nic sequence number
882 @type seq: int
883 @param nic: nic we're acting on
884 @type nic: nic object
885 @param tap: the host's tap interface this NIC corresponds to
886 @type tap: str
887
888 """
889 hv_base.ConfigureNIC([pathutils.KVM_IFUP, tap], instance, seq, nic, tap)
890
891 @classmethod
892 def _SetProcessAffinity(cls, process_id, cpus):
893 """Sets the affinity of a process to the given CPUs.
894
895 @type process_id: int
896 @type cpus: list of int
897 @param cpus: The list of CPUs the process ID may use.
898
899 """
900 if psutil is None:
901 raise errors.HypervisorError("psutil Python package %s"
902 "; cannot use CPU pinning"
903 " under KVM" % psutil_err)
904
905 target_process = psutil.Process(process_id)
906 if cpus == constants.CPU_PINNING_OFF:
907 # we checked this at import time
908 # pylint: disable=E1101
909 target_process.set_cpu_affinity(range(psutil.cpu_count()))
910 else:
911 target_process.set_cpu_affinity(cpus)
912 # psutil 2.x deprecated (but still supports) get_children and the wrapper
913 # method sig doesn't show the keyword args, so quell the pylint warning.
914 # pylint: disable=E1123
915 for p in target_process.get_children(recursive=True):
916 p.set_cpu_affinity(cpus)
917
918 @classmethod
919 def _AssignCpuAffinity(cls, cpu_mask, worker_cpu_mask, process_id,
920 thread_dict):
921 """Change CPU affinity for running VM according to given CPU mask.
922
923 @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
924 @type cpu_mask: string
925 @param worker_cpu_mask: CPU mask as given by the user for the worker
926 threads. e.g. "0-2,4"
927 @type worker_cpu_mask: string
928 @param process_id: process ID of KVM process. Used to pin entire VM
929 to physical CPUs.
930 @type process_id: int
931 @param thread_dict: map of virtual CPUs to KVM thread IDs
932 @type thread_dict: dict int:int
933
934 """
935 worker_cpu_list = utils.ParseCpuMask(worker_cpu_mask)
936 cls._SetProcessAffinity(process_id, worker_cpu_list)
937
938 # Convert the string CPU mask to a list of list of ints
939 cpu_list = utils.ParseMultiCpuMask(cpu_mask)
940 if len(cpu_list) == 1:
941 all_cpu_mapping = cpu_list[0]
942 if all_cpu_mapping != constants.CPU_PINNING_OFF:
943 # The vcpus do not inherit the affinity of the parent process so they
944 # also must be pinned.
945 for vcpu in thread_dict:
946 cls._SetProcessAffinity(thread_dict[vcpu], all_cpu_mapping)
947 else:
948 # The number of vCPUs mapped should match the number of vCPUs
949 # reported by KVM. This was already verified earlier, so
950 # here only as a sanity check.
951 assert len(thread_dict) == len(cpu_list)
952
953 # For each vCPU, map it to the proper list of physical CPUs
954 for i, vcpu in enumerate(cpu_list):
955 cls._SetProcessAffinity(thread_dict[i], vcpu)
956
957 def _GetVcpuThreadIds(self, instance_name):
958 """Get a mapping of vCPU no. to thread IDs for the instance
959
960 @type instance_name: string
961 @param instance_name: instance in question
962 @rtype: dictionary of int:int
963 @return: a dictionary mapping vCPU numbers to thread IDs
964
965 """
966 result = {}
967 output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
968 for line in output.stdout.splitlines():
969 match = self._CPU_INFO_RE.search(line)
970 if not match:
971 continue
972 grp = map(int, match.groups())
973 result[grp[0]] = grp[1]
974
975 return result
976
977 def _ExecuteCpuAffinity(self, instance_name, cpu_mask, worker_cpu_mask):
978 """Complete CPU pinning.
979
980 @type instance_name: string
981 @param instance_name: name of instance
982 @type cpu_mask: string
983 @param cpu_mask: CPU pinning mask as entered by user
984
985 """
986 # Get KVM process ID, to be used if need to pin entire VM
987 _, pid, _ = self._InstancePidAlive(instance_name)
988 # Get vCPU thread IDs, to be used if need to pin vCPUs separately
989 thread_dict = self._GetVcpuThreadIds(instance_name)
990 # Run CPU pinning, based on configured mask
991 self._AssignCpuAffinity(cpu_mask, worker_cpu_mask, pid, thread_dict)
992
993 def ListInstances(self, hvparams=None):
994 """Get the list of running instances.
995
996 We can do this by listing our live instances directory and
997 checking whether the associated kvm process is still alive.
998
999 """
1000 result = []
1001 for name in os.listdir(self._PIDS_DIR):
1002 if self._InstancePidAlive(name)[2]:
1003 result.append(name)
1004 return result
1005
1006 @classmethod
1007 def _IsUserShutdown(cls, instance_name):
1008 return os.path.exists(cls._InstanceShutdownMonitor(instance_name))
1009
1010 @classmethod
1011 def _ClearUserShutdown(cls, instance_name):
1012 utils.RemoveFile(cls._InstanceShutdownMonitor(instance_name))
1013
1014 def GetInstanceInfo(self, instance_name, hvparams=None):
1015 """Get instance properties.
1016
1017 @type instance_name: string
1018 @param instance_name: the instance name
1019 @type hvparams: dict of strings
1020 @param hvparams: hypervisor parameters to be used with this instance
1021 @rtype: tuple of strings
1022 @return: (name, id, memory, vcpus, stat, times)
1023
1024 """
1025 _, pid, alive = self._InstancePidAlive(instance_name)
1026 if not alive:
1027 if self._IsUserShutdown(instance_name):
1028 return (instance_name, -1, 0, 0, hv_base.HvInstanceState.SHUTDOWN, 0)
1029 else:
1030 return None
1031
1032 _, memory, vcpus = self._InstancePidInfo(pid)
1033 istat = hv_base.HvInstanceState.RUNNING
1034 times = 0
1035
1036 try:
1037 qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1038 qmp.connect()
1039 vcpus = len(qmp.Execute("query-cpus"))
1040 # Will fail if ballooning is not enabled, but we can then just resort to
1041 # the value above.
1042 mem_bytes = qmp.Execute("query-balloon")[qmp.ACTUAL_KEY]
1043 memory = mem_bytes / 1048576
1044 except errors.HypervisorError:
1045 pass
1046
1047 return (instance_name, pid, memory, vcpus, istat, times)
1048
1049 def GetAllInstancesInfo(self, hvparams=None):
1050 """Get properties of all instances.
1051
1052 @type hvparams: dict of strings
1053 @param hvparams: hypervisor parameters
1054 @return: list of tuples (name, id, memory, vcpus, stat, times)
1055
1056 """
1057 data = []
1058 for name in os.listdir(self._PIDS_DIR):
1059 try:
1060 info = self.GetInstanceInfo(name)
1061 except errors.HypervisorError:
1062 # Ignore exceptions due to instances being shut down
1063 continue
1064 if info:
1065 data.append(info)
1066 return data
1067
1068 def _GenerateKVMBlockDevicesOptions(self, up_hvp, kvm_disks,
1069 kvmhelp, devlist):
1070 """Generate KVM options regarding instance's block devices.
1071
1072 @type up_hvp: dict
1073 @param up_hvp: the instance's runtime hypervisor parameters
1074 @type kvm_disks: list of tuples
1075 @param kvm_disks: list of tuples [(disk, link_name, uri)..]
1076 @type kvmhelp: string
1077 @param kvmhelp: output of kvm --help
1078 @type devlist: string
1079 @param devlist: output of kvm -device ?
1080 @rtype: list
1081 @return: list of command line options eventually used by kvm executable
1082
1083 """
1084 kernel_path = up_hvp[constants.HV_KERNEL_PATH]
1085 if kernel_path:
1086 boot_disk = False
1087 else:
1088 boot_disk = up_hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1089
1090 # whether this is an older KVM version that uses the boot=on flag
1091 # on devices
1092 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1093
1094 dev_opts = []
1095 disk_type = up_hvp[constants.HV_DISK_TYPE]
1096 # paravirtual implies either '-device virtio-blk-pci... -drive if=none...'
1097 # for new QEMU versions or '-drive if=virtio' for old QEMU versions
1098 if disk_type == constants.HT_DISK_PARAVIRTUAL:
1099 driver = self._VIRTIO_BLK_PCI
1100 iface = self._VIRTIO
1101 else:
1102 driver = iface = disk_type
1103
1104 # Check if a specific driver is supported by QEMU device model.
1105 if self._DEVICE_DRIVER_SUPPORTED(driver, devlist):
1106 if_val = ",if=none" # for the -drive option
1107 device_driver = driver # for the -device option
1108 else:
1109 if_val = ",if=%s" % iface # for the -drive option
1110 device_driver = None # without -device option
1111
1112 # AIO mode
1113 aio_mode = up_hvp[constants.HV_KVM_DISK_AIO]
1114 if aio_mode == constants.HT_KVM_AIO_NATIVE:
1115 aio_val = ",aio=%s" % aio_mode
1116 else:
1117 aio_val = ""
1118 # Cache mode
1119 disk_cache = up_hvp[constants.HV_DISK_CACHE]
1120 for cfdev, link_name, uri in kvm_disks:
1121 if cfdev.dev_type in constants.DTS_EXT_MIRROR:
1122 if disk_cache != "none":
1123 # TODO: make this a hard error, instead of a silent overwrite
1124 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1125 " to prevent shared storage corruption on migration",
1126 disk_cache)
1127 cache_val = ",cache=none"
1128 elif aio_mode == constants.HT_KVM_AIO_NATIVE and disk_cache != "none":
1129 # TODO: make this a hard error, instead of a silent overwrite
1130 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1131 " to prevent QEMU failures in version 2.6+",
1132 disk_cache)
1133 cache_val = ",cache=none"
1134 elif disk_cache != constants.HT_CACHE_DEFAULT:
1135 cache_val = ",cache=%s" % disk_cache
1136 else:
1137 cache_val = ""
1138 if cfdev.mode != constants.DISK_RDWR:
1139 raise errors.HypervisorError("Instance has read-only disks which"
1140 " are not supported by KVM")
1141 # TODO: handle FD_LOOP and FD_BLKTAP (?)
1142 boot_val = ""
1143 if boot_disk:
1144 dev_opts.extend(["-boot", "c"])
1145 boot_disk = False
1146 if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1147 boot_val = ",boot=on"
1148
1149 drive_uri = _GetDriveURI(cfdev, link_name, uri)
1150
1151 drive_val = "file=%s,format=raw%s%s%s%s" % \
1152 (drive_uri, if_val, boot_val, cache_val, aio_val)
1153
1154 # virtio-blk-pci case
1155 if device_driver is not None:
1156 # hvinfo will exist for paravirtual devices either due to
1157 # _UpgradeSerializedRuntime() for old instances or due to
1158 # _GenerateKVMRuntime() for new instances.
1159 kvm_devid = cfdev.hvinfo["id"]
1160 drive_val += ",id=%s" % kvm_devid
1161 # Add driver, id, bus, and addr or channel, scsi-id, lun if any.
1162 dev_val = _GenerateDeviceHVInfoStr(cfdev.hvinfo)
1163 dev_val += ",drive=%s" % kvm_devid
1164 dev_opts.extend(["-device", dev_val])
1165
1166 dev_opts.extend(["-drive", drive_val])
1167
1168 return dev_opts
1169
1170 @staticmethod
1171 def _CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image, cdrom_boot,
1172 needs_boot_flag):
1173 """Extends L{kvm_cmd} with the '-drive' option for a cdrom, and
1174 optionally the '-boot' option.
1175
1176 Example: -drive file=cdrom.iso,media=cdrom,format=raw,if=ide -boot d
1177
1178 Example: -drive file=cdrom.iso,media=cdrom,format=raw,if=ide,boot=on
1179
1180 Example: -drive file=http://hostname.com/cdrom.iso,media=cdrom
1181
1182 @type kvm_cmd: string
1183 @param kvm_cmd: KVM command line
1184
1185 @type cdrom_disk_type:
1186 @param cdrom_disk_type:
1187
1188 @type cdrom_image:
1189 @param cdrom_image:
1190
1191 @type cdrom_boot:
1192 @param cdrom_boot:
1193
1194 @type needs_boot_flag:
1195 @param needs_boot_flag:
1196
1197 """
1198 # Check that the ISO image is accessible
1199 # See https://bugs.launchpad.net/qemu/+bug/597575
1200 if utils.IsUrl(cdrom_image) and not _CheckUrl(cdrom_image):
1201 raise errors.HypervisorError("Cdrom ISO image '%s' is not accessible" %
1202 cdrom_image)
1203
1204 # set cdrom 'media' and 'format', if needed
1205 if utils.IsUrl(cdrom_image):
1206 options = ",media=cdrom"
1207 else:
1208 options = ",media=cdrom,format=raw"
1209
1210 # set cdrom 'if' type
1211 if cdrom_boot:
1212 if_val = ",if=" + constants.HT_DISK_IDE
1213 elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1214 if_val = ",if=virtio"
1215 else:
1216 if_val = ",if=" + cdrom_disk_type
1217
1218 # set boot flag, if needed
1219 boot_val = ""
1220 if cdrom_boot:
1221 kvm_cmd.extend(["-boot", "d"])
1222
1223 # whether this is an older KVM version that requires the 'boot=on' flag
1224 # on devices
1225 if needs_boot_flag:
1226 boot_val = ",boot=on"
1227
1228 # build '-drive' option
1229 drive_val = "file=%s%s%s%s" % (cdrom_image, options, if_val, boot_val)
1230 kvm_cmd.extend(["-drive", drive_val])
1231
1232 def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1233 kvmhelp):
1234 """Generate KVM information to start an instance.
1235
1236 @type kvmhelp: string
1237 @param kvmhelp: output of kvm --help
1238 @attention: this function must not have any side-effects; for
1239 example, it must not write to the filesystem, or read values
1240 from the current system the are expected to differ between
1241 nodes, since it is only run once at instance startup;
1242 actions/kvm arguments that can vary between systems should be
1243 done in L{_ExecuteKVMRuntime}
1244
1245 """
1246 # pylint: disable=R0912,R0914,R0915
1247 hvp = instance.hvparams
1248 self.ValidateParameters(hvp)
1249
1250 pidfile = self._InstancePidFile(instance.name)
1251 kvm = hvp[constants.HV_KVM_PATH]
1252 kvm_cmd = [kvm]
1253 # used just by the vnc server, if enabled
1254 kvm_cmd.extend(["-name", instance.name])
1255 kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1256
1257 smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1258 if hvp[constants.HV_CPU_CORES]:
1259 smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1260 if hvp[constants.HV_CPU_THREADS]:
1261 smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1262 if hvp[constants.HV_CPU_SOCKETS]:
1263 smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1264
1265 kvm_cmd.extend(["-smp", ",".join(smp_list)])
1266
1267 kvm_cmd.extend(["-pidfile", pidfile])
1268
1269 bus_slots = self._GetBusSlots(hvp)
1270
1271 # As requested by music lovers
1272 if hvp[constants.HV_SOUNDHW]:
1273 soundhw = hvp[constants.HV_SOUNDHW]
1274 kvm_cmd.extend(["-soundhw", soundhw])
1275
1276 if hvp[constants.HV_DISK_TYPE] in constants.HT_SCSI_DEVICE_TYPES:
1277 # In case a SCSI disk is given, QEMU adds a SCSI contorller
1278 # (LSI Logic / Symbios Logic 53c895a) implicitly.
1279 # Here, we add the controller explicitly with the default id.
1280 kvm_cmd.extend([
1281 "-device",
1282 "%s,id=scsi" % hvp[constants.HV_KVM_SCSI_CONTROLLER_TYPE]
1283 ])
1284
1285 kvm_cmd.extend(["-balloon", "virtio"])
1286 kvm_cmd.extend(["-daemonize"])
1287 # logfile for qemu
1288 qemu_logfile = utils.PathJoin(pathutils.LOG_KVM_DIR,
1289 "%s.log" % instance.name)
1290 kvm_cmd.extend(["-D", qemu_logfile])
1291 if not instance.hvparams[constants.HV_ACPI]:
1292 kvm_cmd.extend(["-no-acpi"])
1293 if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1294 constants.INSTANCE_REBOOT_EXIT:
1295 kvm_cmd.extend(["-no-reboot"])
1296
1297 mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1298 if not mversion:
1299 mversion = self._GetDefaultMachineVersion(kvm)
1300 if self._MACHINE_RE.search(kvmhelp):
1301 # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1302 # extra hypervisor parameters. We should also investigate whether and how
1303 # shadow_mem should be considered for the resource model.
1304 if hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED:
1305 specprop = ",accel=kvm"
1306 else:
1307 specprop = ""
1308 machinespec = "%s%s" % (mversion, specprop)
1309 kvm_cmd.extend(["-machine", machinespec])
1310 else:
1311 kvm_cmd.extend(["-M", mversion])
1312 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1313 self._ENABLE_KVM_RE.search(kvmhelp)):
1314 kvm_cmd.extend(["-enable-kvm"])
1315 elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1316 self._DISABLE_KVM_RE.search(kvmhelp)):
1317 kvm_cmd.extend(["-disable-kvm"])
1318
1319 kernel_path = hvp[constants.HV_KERNEL_PATH]
1320 if kernel_path:
1321 boot_cdrom = boot_floppy = boot_network = False
1322 else:
1323 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1324 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1325 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1326
1327 if startup_paused:
1328 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1329
1330 if boot_network:
1331 kvm_cmd.extend(["-boot", "n"])
1332
1333 disk_type = hvp[constants.HV_DISK_TYPE]
1334
1335 # Now we can specify a different device type for CDROM devices.
1336 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1337 if not cdrom_disk_type:
1338 cdrom_disk_type = disk_type
1339
1340 cdrom_image1 = hvp[constants.HV_CDROM_IMAGE_PATH]
1341 if cdrom_image1:
1342 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1343 self._CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image1, boot_cdrom,
1344 needs_boot_flag)
1345
1346 cdrom_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1347 if cdrom_image2:
1348 self._CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image2, False, False)
1349
1350 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1351 if floppy_image:
1352 options = ",format=raw,media=disk"
1353 if boot_floppy:
1354 kvm_cmd.extend(["-boot", "a"])
1355 options = "%s,boot=on" % options
1356 if_val = ",if=floppy"
1357 options = "%s%s" % (options, if_val)
1358 drive_val = "file=%s%s" % (floppy_image, options)
1359 kvm_cmd.extend(["-drive", drive_val])
1360
1361 if kernel_path:
1362 kvm_cmd.extend(["-kernel", kernel_path])
1363 initrd_path = hvp[constants.HV_INITRD_PATH]
1364 if initrd_path:
1365 kvm_cmd.extend(["-initrd", initrd_path])
1366 root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1367 hvp[constants.HV_KERNEL_ARGS]]
1368 if hvp[constants.HV_SERIAL_CONSOLE]:
1369 serial_speed = hvp[constants.HV_SERIAL_SPEED]
1370 root_append.append("console=ttyS0,%s" % serial_speed)
1371 kvm_cmd.extend(["-append", " ".join(root_append)])
1372
1373 mem_path = hvp[constants.HV_MEM_PATH]
1374 if mem_path:
1375 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1376
1377 monitor_dev = ("unix:%s,server,nowait" %
1378 self._InstanceMonitor(instance.name))
1379 kvm_cmd.extend(["-monitor", monitor_dev])
1380 if hvp[constants.HV_SERIAL_CONSOLE]:
1381 serial_dev = ("unix:%s,server,nowait" %
1382 self._InstanceSerial(instance.name))
1383 kvm_cmd.extend(["-serial", serial_dev])
1384 else:
1385 kvm_cmd.extend(["-serial", "none"])
1386
1387 mouse_type = hvp[constants.HV_USB_MOUSE]
1388 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1389 spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1390 spice_ip_version = None
1391
1392 kvm_cmd.extend(["-usb"])
1393
1394 if mouse_type:
1395 kvm_cmd.extend(["-usbdevice", mouse_type])
1396 elif vnc_bind_address:
1397 kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1398
1399 if vnc_bind_address:
1400 if netutils.IsValidInterface(vnc_bind_address):
1401 if_addresses = netutils.GetInterfaceIpAddresses(vnc_bind_address)
1402 if_ip4_addresses = if_addresses[constants.IP4_VERSION]
1403 if len(if_ip4_addresses) < 1:
1404 logging.error("Could not determine IPv4 address of interface %s",
1405 vnc_bind_address)
1406 else:
1407 vnc_bind_address = if_ip4_addresses[0]
1408 if (netutils.IP4Address.IsValid(vnc_bind_address) or
1409 netutils.IP6Address.IsValid(vnc_bind_address)):
1410 if instance.network_port > constants.VNC_BASE_PORT:
1411 display = instance.network_port - constants.VNC_BASE_PORT
1412 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1413 vnc_arg = ":%d" % (display)
1414 elif netutils.IP6Address.IsValid(vnc_bind_address):
1415 vnc_arg = "[%s]:%d" % (vnc_bind_address, display)
1416 else:
1417 vnc_arg = "%s:%d" % (vnc_bind_address, display)
1418 else:
1419 logging.error("Network port is not a valid VNC display (%d < %d),"
1420 " not starting VNC",
1421 instance.network_port, constants.VNC_BASE_PORT)
1422 vnc_arg = "none"
1423
1424 # Only allow tls and other option when not binding to a file, for now.
1425 # kvm/qemu gets confused otherwise about the filename to use.
1426 vnc_append = ""
1427 if hvp[constants.HV_VNC_TLS]:
1428 vnc_append = "%s,tls" % vnc_append
1429 if hvp[constants.HV_VNC_X509_VERIFY]:
1430 vnc_append = "%s,x509verify=%s" % (vnc_append,
1431 hvp[constants.HV_VNC_X509])
1432 elif hvp[constants.HV_VNC_X509]:
1433 vnc_append = "%s,x509=%s" % (vnc_append,
1434 hvp[constants.HV_VNC_X509])
1435 if hvp[constants.HV_VNC_PASSWORD_FILE]:
1436 vnc_append = "%s,password" % vnc_append
1437
1438 vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1439
1440 else:
1441 vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1442
1443 kvm_cmd.extend(["-vnc", vnc_arg])
1444 elif spice_bind:
1445 # FIXME: this is wrong here; the iface ip address differs
1446 # between systems, so it should be done in _ExecuteKVMRuntime
1447 if netutils.IsValidInterface(spice_bind):
1448 # The user specified a network interface, we have to figure out the IP
1449 # address.
1450 addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1451 spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1452
1453 # if the user specified an IP version and the interface does not
1454 # have that kind of IP addresses, throw an exception
1455 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1456 if not addresses[spice_ip_version]:
1457 raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1458 " for %s" % (spice_ip_version,
1459 spice_bind))
1460
1461 # the user did not specify an IP version, we have to figure it out
1462 elif (addresses[constants.IP4_VERSION] and
1463 addresses[constants.IP6_VERSION]):
1464 # we have both ipv4 and ipv6, let's use the cluster default IP
1465 # version
1466 cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1467 spice_ip_version = \
1468 netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1469 elif addresses[constants.IP4_VERSION]:
1470 spice_ip_version = constants.IP4_VERSION
1471 elif addresses[constants.IP6_VERSION]:
1472 spice_ip_version = constants.IP6_VERSION
1473 else:
1474 raise errors.HypervisorError("SPICE: Unable to get an IP address"
1475 " for %s" % (spice_bind))
1476
1477 spice_address = addresses[spice_ip_version][0]
1478
1479 else:
1480 # spice_bind is known to be a valid IP address, because
1481 # ValidateParameters checked it.
1482 spice_address = spice_bind
1483
1484 spice_arg = "addr=%s" % spice_address
1485 if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1486 spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1487 (spice_arg, instance.network_port,
1488 pathutils.SPICE_CACERT_FILE))
1489 spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1490 (spice_arg, pathutils.SPICE_CERT_FILE,
1491 pathutils.SPICE_CERT_FILE))
1492 tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1493 if tls_ciphers:
1494 spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1495 else:
1496 spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1497
1498 if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1499 spice_arg = "%s,disable-ticketing" % spice_arg
1500
1501 if spice_ip_version:
1502 spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1503
1504 # Image compression options
1505 img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1506 img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1507 img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1508 if img_lossless:
1509 spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1510 if img_jpeg:
1511 spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1512 if img_zlib_glz:
1513 spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1514
1515 # Video stream detection
1516 video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1517 if video_streaming:
1518 spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1519
1520 # Audio compression, by default in qemu-kvm it is on
1521 if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1522 spice_arg = "%s,playback-compression=off" % spice_arg
1523 if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1524 spice_arg = "%s,agent-mouse=off" % spice_arg
1525 else:
1526 # Enable the spice agent communication channel between the host and the
1527 # agent.
1528 kvm_cmd.extend(["-device", "virtio-serial-pci,id=spice"])
1529 kvm_cmd.extend([
1530 "-device",
1531 "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1532 ])
1533 kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1534
1535 logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1536 kvm_cmd.extend(["-spice", spice_arg])
1537
1538 else:
1539 # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1540 # also works in earlier versions though (tested with 1.1 and 1.3)
1541 if self._DISPLAY_RE.search(kvmhelp):
1542 kvm_cmd.extend(["-display", "none"])
1543 else:
1544 kvm_cmd.extend(["-nographic"])
1545
1546 if hvp[constants.HV_USE_LOCALTIME]:
1547 kvm_cmd.extend(["-localtime"])
1548
1549 if hvp[constants.HV_KVM_USE_CHROOT]:
1550 kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1551
1552 # Add qemu-KVM -cpu param
1553 if hvp[constants.HV_CPU_TYPE]:
1554 kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1555
1556 # Pass a -vga option if requested, or if spice is used, for backwards
1557 # compatibility.
1558 if hvp[constants.HV_VGA]:
1559 kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1560 elif spice_bind:
1561 kvm_cmd.extend(["-vga", "qxl"])
1562
1563 # Various types of usb devices, comma separated
1564 if hvp[constants.HV_USB_DEVICES]:
1565 for dev in hvp[constants.HV_USB_DEVICES].split(","):
1566 kvm_cmd.extend(["-usbdevice", dev])
1567
1568 # Set system UUID to instance UUID
1569 if self._UUID_RE.search(kvmhelp):
1570 kvm_cmd.extend(["-uuid", instance.uuid])
1571
1572 if hvp[constants.HV_KVM_EXTRA]:
1573 kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1574
1575 def _generate_kvm_device(dev_type, dev):
1576 """Helper for generating a kvm device out of a Ganeti device."""
1577 kvm_devid = _GenerateDeviceKVMId(dev_type, dev)
1578 hv_dev_type = _DEVICE_TYPE[dev_type](hvp)
1579 dev.hvinfo = _GenerateDeviceHVInfo(dev_type, kvm_devid,
1580 hv_dev_type, bus_slots)
1581
1582 kvm_disks = []
1583 for disk, link_name, uri in block_devices:
1584 _generate_kvm_device(constants.HOTPLUG_TARGET_DISK, disk)
1585 kvm_disks.append((disk, link_name, uri))
1586
1587 kvm_nics = []
1588 for nic in instance.nics:
1589 _generate_kvm_device(constants.HOTPLUG_TARGET_NIC, nic)
1590 kvm_nics.append(nic)
1591
1592 hvparams = hvp
1593
1594 return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1595
1596 def _WriteKVMRuntime(self, instance_name, data):
1597 """Write an instance's KVM runtime
1598
1599 """
1600 try:
1601 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1602 data=data)
1603 except EnvironmentError, err:
1604 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1605
1606 def _ReadKVMRuntime(self, instance_name):
1607 """Read an instance's KVM runtime
1608
1609 """
1610 try:
1611 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1612 except EnvironmentError, err:
1613 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1614 return file_content
1615
1616 def _SaveKVMRuntime(self, instance, kvm_runtime):
1617 """Save an instance's KVM runtime
1618
1619 """
1620 kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1621
1622 serialized_nics = [nic.ToDict() for nic in kvm_nics]
1623 serialized_disks = [(blk.ToDict(), link, uri)
1624 for blk, link, uri in kvm_disks]
1625 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1626 serialized_disks))
1627
1628 self._WriteKVMRuntime(instance.name, serialized_form)
1629
1630 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1631 """Load an instance's KVM runtime
1632
1633 """
1634 if not serialized_runtime:
1635 serialized_runtime = self._ReadKVMRuntime(instance.name)
1636
1637 return _AnalyzeSerializedRuntime(serialized_runtime)
1638
1639 def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1640 """Run the KVM cmd and check for errors
1641
1642 @type name: string
1643 @param name: instance name
1644 @type kvm_cmd: list of strings
1645 @param kvm_cmd: runcmd input for kvm
1646 @type tap_fds: list of int
1647 @param tap_fds: fds of tap devices opened by Ganeti
1648
1649 """
1650 try:
1651 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1652 finally:
1653 for fd in tap_fds:
1654 utils_wrapper.CloseFdNoError(fd)
1655
1656 if result.failed:
1657 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1658 (name, result.fail_reason, result.output))
1659 if not self._InstancePidAlive(name)[2]:
1660 raise errors.HypervisorError("Failed to start instance %s" % name)
1661
1662 @staticmethod
1663 def _GenerateKvmTapName(nic):
1664 """Generate a TAP network interface name for a NIC.
1665
1666 See L{hv_base.GenerateTapName}.
1667
1668 For the case of the empty string, see L{OpenTap}
1669
1670 @type nic: ganeti.objects.NIC
1671 @param nic: NIC object for the name should be generated
1672
1673 @rtype: string
1674 @return: TAP network interface name, or the empty string if the
1675 NIC is not used in instance communication
1676
1677 """
1678 if nic.name is None or not \
1679 nic.name.startswith(constants.INSTANCE_COMMUNICATION_NIC_PREFIX):
1680 return ""
1681
1682 return hv_base.GenerateTapName()
1683
1684 def _GetNetworkDeviceFeatures(self, up_hvp, devlist, kvmhelp):
1685 """Get network device options to properly enable supported features.
1686
1687 Return a dict of supported and enabled tap features with nic_model along
1688 with the extra strings to be appended to the --netdev and --device options.
1689 This function is called before opening a new tap device.
1690
1691 Currently the features_dict includes the following attributes:
1692 - vhost (boolean)
1693 - vnet_hdr (boolean)
1694 - mq (boolean, int)
1695
1696 @rtype: (dict, str, str) tuple
1697 @return: The supported features,
1698 the string to be appended to the --netdev option,
1699 the string to be appended to the --device option
1700
1701 """
1702 nic_type = up_hvp[constants.HV_NIC_TYPE]
1703 nic_extra_str = ""
1704 tap_extra_str = ""
1705 features = {
1706 "vhost": False,
1707 "vnet_hdr": False,
1708 "mq": (False, 1)
1709 }
1710 update_features = {}
1711 if nic_type == constants.HT_NIC_PARAVIRTUAL:
1712 if self._DEVICE_DRIVER_SUPPORTED(self._VIRTIO_NET_PCI, devlist):
1713 nic_model = self._VIRTIO_NET_PCI
1714 update_features["vnet_hdr"] = up_hvp[constants.HV_VNET_HDR]
1715 else:
1716 # Older versions of kvm don't support DEVICE_LIST, but they don't
1717 # have new virtio syntax either.
1718 nic_model = self._VIRTIO
1719
1720 if up_hvp[constants.HV_VHOST_NET]:
1721 # Check for vhost_net support.
1722 if self._VHOST_RE.search(kvmhelp):
1723 update_features["vhost"] = True
1724 tap_extra_str = ",vhost=on"
1725 else:
1726 raise errors.HypervisorError("vhost_net is configured"
1727 " but it is not available")
1728 virtio_net_queues = up_hvp.get(constants.HV_VIRTIO_NET_QUEUES, 1)
1729 if virtio_net_queues > 1:
1730 # Check for multiqueue virtio-net support.
1731 if self._VIRTIO_NET_QUEUES_RE.search(kvmhelp):
1732 # As advised at http://www.linux-kvm.org/page/Multiqueue formula
1733 # for calculating vector size is: vectors=2*N+1 where N is the
1734 # number of queues (HV_VIRTIO_NET_QUEUES).
1735 nic_extra_str = ",mq=on,vectors=%d" % (2 * virtio_net_queues + 1)
1736 update_features["mq"] = (True, virtio_net_queues)
1737 else:
1738 raise errors.HypervisorError("virtio_net_queues is configured"
1739 " but it is not available")
1740 else:
1741 nic_model = nic_type
1742
1743 update_features["driver"] = nic_model
1744 features.update(update_features)
1745
1746 return features, tap_extra_str, nic_extra_str
1747
1748 # too many local variables
1749 # pylint: disable=R0914
1750 def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1751 """Execute a KVM cmd, after completing it with some last minute data.
1752
1753 @type instance: L{objects.Instance} object
1754 @param instance: the VM this command acts upon
1755 @type kvm_runtime: tuple of (list of str, list of L{objects.NIC} objects,
1756 dict of hypervisor options, list of tuples (L{objects.Disk}, str, str)
1757 @param kvm_runtime: (kvm command, NICs of the instance, options at startup
1758 of the instance, [(disk, link_name, uri)..])
1759 @type incoming: tuple of strings
1760 @param incoming: (target_host_ip, port) for migration.
1761 @type kvmhelp: string
1762 @param kvmhelp: output of kvm --help
1763
1764 """
1765 # Small _ExecuteKVMRuntime hv parameters programming howto:
1766 # - conf_hvp contains the parameters as configured on ganeti. they might
1767 # have changed since the instance started; only use them if the change
1768 # won't affect the inside of the instance (which hasn't been rebooted).
1769 # - up_hvp contains the parameters as they were when the instance was
1770 # started, plus any new parameter which has been added between ganeti
1771 # versions: it is paramount that those default to a value which won't
1772 # affect the inside of the instance as well.
1773 conf_hvp = instance.hvparams
1774 name = instance.name
1775 self._CheckDown(name)
1776
1777 self._ClearUserShutdown(instance.name)
1778 self._StartKvmd(instance.hvparams)
1779
1780 temp_files = []
1781
1782 kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1783 # the first element of kvm_cmd is always the path to the kvm binary
1784 kvm_path = kvm_cmd[0]
1785 up_hvp = objects.FillDict(conf_hvp, up_hvp)
1786
1787 # We know it's safe to run as a different user upon migration, so we'll use
1788 # the latest conf, from conf_hvp.
1789 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1790 if security_model == constants.HT_SM_USER:
1791 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1792
1793 keymap = conf_hvp[constants.HV_KEYMAP]
1794 if keymap:
1795 keymap_path = self._InstanceKeymapFile(name)
1796 # If a keymap file is specified, KVM won't use its internal defaults. By
1797 # first including the "en-us" layout, an error on loading the actual
1798 # layout (e.g. because it can't be found) won't lead to a non-functional
1799 # keyboard. A keyboard with incorrect keys is still better than none.
1800 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1801 kvm_cmd.extend(["-k", keymap_path])
1802
1803 # We have reasons to believe changing something like the nic driver/type
1804 # upon migration won't exactly fly with the instance kernel, so for nic
1805 # related parameters we'll use up_hvp
1806 tapfds = []
1807 taps = []
1808 devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1809 if not kvm_nics:
1810 kvm_cmd.extend(["-net", "none"])
1811 else:
1812 features, tap_extra, nic_extra = \
1813 self._GetNetworkDeviceFeatures(up_hvp, devlist, kvmhelp)
1814 nic_model = features["driver"]
1815 kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1816 for nic_seq, nic in enumerate(kvm_nics):
1817 tapname, nic_tapfds, nic_vhostfds = \
1818 OpenTap(features=features, name=self._GenerateKvmTapName(nic))
1819
1820 tapfds.extend(nic_tapfds)
1821 tapfds.extend(nic_vhostfds)
1822 taps.append(tapname)
1823 tapfd = "%s%s" % ("fds=" if len(nic_tapfds) > 1 else "fd=",
1824 ":".join(str(fd) for fd in nic_tapfds))
1825
1826 if nic_vhostfds:
1827 vhostfd = "%s%s" % (",vhostfds="
1828 if len(nic_vhostfds) > 1 else ",vhostfd=",
1829 ":".join(str(fd) for fd in nic_vhostfds))
1830 else:
1831 vhostfd = ""
1832
1833 if kvm_supports_netdev:
1834 # Non paravirtual NICs hvinfo is empty
1835 if "id" in nic.hvinfo:
1836 nic_val = _GenerateDeviceHVInfoStr(nic.hvinfo)
1837 netdev = nic.hvinfo["id"]
1838 else:
1839 nic_val = "%s" % nic_model
1840 netdev = "netdev%d" % nic_seq
1841 nic_val += (",netdev=%s,mac=%s%s" % (netdev, nic.mac, nic_extra))
1842 tap_val = ("type=tap,id=%s,%s%s%s" %
1843 (netdev, tapfd, vhostfd, tap_extra))
1844 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1845 else:
1846 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1847 nic.mac, nic_model)
1848 tap_val = "tap,vlan=%s,%s" % (nic_seq, tapfd)
1849 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1850
1851 if incoming:
1852 target, port = incoming
1853 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1854
1855 # Changing the vnc password doesn't bother the guest that much. At most it
1856 # will surprise people who connect to it. Whether positively or negatively
1857 # it's debatable.
1858 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1859 vnc_pwd = None
1860 if vnc_pwd_file:
1861 try:
1862 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1863 except EnvironmentError, err:
1864 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1865 % (vnc_pwd_file, err))
1866
1867 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1868 utils.EnsureDirs([(self._InstanceChrootDir(name),
1869 constants.SECURE_DIR_MODE)])
1870
1871 # Automatically enable QMP if version is >= 0.14
1872 if self._QMP_RE.search(kvmhelp):
1873 logging.debug("Enabling QMP")
1874 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1875 self._InstanceQmpMonitor(instance.name)])
1876 # Add a second monitor for kvmd
1877 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1878 self._InstanceKvmdMonitor(instance.name)])
1879
1880 # Configure the network now for starting instances and bridged/OVS
1881 # interfaces, during FinalizeMigration for incoming instances' routed
1882 # interfaces.
1883 for nic_seq, nic in enumerate(kvm_nics):
1884 if (incoming and
1885 nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_ROUTED):
1886 continue
1887 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1888
1889 bdev_opts = self._GenerateKVMBlockDevicesOptions(up_hvp,
1890 kvm_disks,
1891 kvmhelp,
1892 devlist)
1893 kvm_cmd.extend(bdev_opts)
1894 # CPU affinity requires kvm to start paused, so we set this flag if the
1895 # instance is not already paused and if we are not going to accept a
1896 # migrating instance. In the latter case, pausing is not needed.
1897 start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1898 if start_kvm_paused:
1899 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1900
1901 # Note: CPU pinning is using up_hvp since changes take effect
1902 # during instance startup anyway, and to avoid problems when soft
1903 # rebooting the instance.
1904 cpu_pinning = False
1905 if up_hvp.get(constants.HV_CPU_MASK, None) \
1906 and up_hvp[constants.HV_CPU_MASK] != constants.CPU_PINNING_ALL:
1907 cpu_pinning = True
1908
1909 if security_model == constants.HT_SM_POOL:
1910 ss = ssconf.SimpleStore()
1911 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1912 all_uids = set(uidpool.ExpandUidPool(uid_pool))
1913 uid = uidpool.RequestUnusedUid(all_uids)
1914 try:
1915 username = pwd.getpwuid(uid.GetUid()).pw_name
1916 kvm_cmd.extend(["-runas", username])
1917 self._RunKVMCmd(name, kvm_cmd, tapfds)
1918 except:
1919 uidpool.ReleaseUid(uid)
1920 raise
1921 else:
1922 uid.Unlock()
1923 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1924 else:
1925 self._RunKVMCmd(name, kvm_cmd, tapfds)
1926
1927 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1928 constants.RUN_DIRS_MODE)])
1929 for nic_seq, tap in enumerate(taps):
1930 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq), data=tap)
1931
1932 if vnc_pwd:
1933 change_cmd = "change vnc password %s" % vnc_pwd
1934 self._CallMonitorCommand(instance.name, change_cmd)
1935
1936 # Setting SPICE password. We are not vulnerable to malicious passwordless
1937 # connection attempts because SPICE by default does not allow connections
1938 # if neither a password nor the "disable_ticketing" options are specified.
1939 # As soon as we send the password via QMP, that password is a valid ticket
1940 # for connection.
1941 spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1942 if spice_password_file:
1943 spice_pwd = ""
1944 try:
1945 spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1946 except EnvironmentError, err:
1947 raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1948 % (spice_password_file, err))
1949
1950 qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1951 qmp.connect()
1952 arguments = {
1953 "protocol": "spice",
1954 "password": spice_pwd,
1955 }
1956 qmp.Execute("set_password", arguments)
1957
1958 for filename in temp_files:
1959 utils.RemoveFile(filename)
1960
1961 # If requested, set CPU affinity and resume instance execution
1962 if cpu_pinning:
1963 self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK],
1964 up_hvp[constants.HV_WORKER_CPU_MASK])
1965
1966 start_memory = self._InstanceStartupMemory(instance)
1967 if start_memory < instance.beparams[constants.BE_MAXMEM]:
1968 self.BalloonInstanceMemory(instance, start_memory)
1969
1970 if start_kvm_paused:
1971 # To control CPU pinning, ballooning, and vnc/spice passwords
1972 # the VM was started in a frozen state. If freezing was not
1973 # explicitly requested resume the vm status.
1974 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1975
1976 @staticmethod
1977 def _StartKvmd(hvparams):
1978 """Ensure that the Kvm daemon is running.
1979
1980 @type hvparams: dict of strings
1981 @param hvparams: hypervisor parameters
1982
1983 """
1984 if hvparams is None \
1985 or not hvparams[constants.HV_KVM_USER_SHUTDOWN] \
1986 or utils.IsDaemonAlive(constants.KVMD):
1987 return
1988
1989 result = utils.RunCmd([pathutils.DAEMON_UTIL, "start", constants.KVMD])
1990
1991 if result.failed:
1992 raise errors.HypervisorError("Failed to start KVM daemon")
1993
1994 def StartInstance(self, instance, block_devices, startup_paused):
1995 """Start an instance.
1996
1997 """
1998 self._CheckDown(instance.name)
1999 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2000 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2001 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
2002 startup_paused, kvmhelp)
2003 self._SaveKVMRuntime(instance, kvm_runtime)
2004 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2005
2006 @classmethod
2007 def _CallMonitorCommand(cls, instance_name, command, timeout=None):
2008 """Invoke a command on the instance monitor.
2009
2010 """
2011 if timeout is not None:
2012 timeout_cmd = "timeout %s" % (timeout, )
2013 else:
2014 timeout_cmd = ""
2015
2016 # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
2017 # version. The monitor protocol is designed for human consumption, whereas
2018 # QMP is made for programmatic usage. In the worst case QMP can also
2019 # execute monitor commands. As it is, all calls to socat take at least
2020 # 500ms and likely more: socat can't detect the end of the reply and waits
2021 # for 500ms of no data received before exiting (500 ms is the default for
2022 # the "-t" parameter).
2023 socat = ("echo %s | %s %s STDIO UNIX-CONNECT:%s" %
2024 (utils.ShellQuote(command),
2025 timeout_cmd,
2026 constants.SOCAT_PATH,
2027 utils.ShellQuote(cls._InstanceMonitor(instance_name))))
2028 result = utils.RunCmd(socat)
2029 if result.failed:
2030 msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
2031 " output: %s" %
2032 (command, instance_name, result.fail_reason, result.output))
2033 raise errors.HypervisorError(msg)
2034
2035 return result
2036
2037 @_with_qmp
2038 def VerifyHotplugSupport(self, instance, action, dev_type):
2039 """Verifies that hotplug is supported.
2040
2041 Hotplug is not supported if:
2042
2043 - the instance is not running
2044 - the device type is not hotplug-able
2045 - the QMP version does not support the corresponding commands
2046
2047 @raise errors.HypervisorError: if one of the above applies
2048
2049 """
2050 runtime = self._LoadKVMRuntime(instance)
2051 device_type = _DEVICE_TYPE[dev_type](runtime[2])
2052 if device_type not in _HOTPLUGGABLE_DEVICE_TYPES[dev_type]:
2053 msg = "Hotplug is not supported for device type %s" % device_type
2054 raise errors.HypervisorError(msg)
2055
2056 if dev_type == constants.HOTPLUG_TARGET_DISK:
2057 if action == constants.HOTPLUG_ACTION_ADD:
2058 self.qmp.CheckDiskHotAddSupport()
2059 if dev_type == constants.HOTPLUG_TARGET_NIC:
2060 if action == constants.HOTPLUG_ACTION_ADD:
2061 self.qmp.CheckNicHotAddSupport()
2062
2063 def HotplugSupported(self, instance):
2064 """Checks if hotplug is generally supported.
2065
2066 Hotplug is *not* supported in case of:
2067 - qemu versions < 1.7 (where all qmp related commands are supported)
2068 - for stopped instances
2069
2070 @raise errors.HypervisorError: in one of the previous cases
2071
2072 """
2073 try:
2074 output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2075 except errors.HypervisorError:
2076 raise errors.HotplugError("Instance is probably down")
2077
2078 match = self._INFO_VERSION_RE.search(output.stdout)
2079 if not match:
2080 raise errors.HotplugError("Cannot parse qemu version via monitor")
2081
2082 #TODO: delegate more fine-grained checks to VerifyHotplugSupport
2083 v_major, v_min, _, _ = match.groups()
2084 if (int(v_major), int(v_min)) < (1, 7):
2085 raise errors.HotplugError("Hotplug not supported for qemu versions < 1.7")
2086
2087 def _GetBusSlots(self, hvp=None, runtime=None):
2088 """Helper function to get the slots of PCI and SCSI QEMU buses.
2089
2090 This will return the status of the first PCI and SCSI buses. By default
2091 QEMU boots with one PCI bus (pci.0) and occupies the first 3 PCI slots. If
2092 a SCSI disk is found then a SCSI controller is added on the PCI bus and a
2093 SCSI bus (scsi.0) is created.
2094
2095 During hotplug we could query QEMU via info qtree HMP command but parsing
2096 the result is too complicated. Instead we use the info stored in runtime
2097 files. We parse NIC and disk entries and based on their hvinfo we reserve
2098 the corresponding slots.
2099
2100 The runtime argument is a tuple as returned by _LoadKVMRuntime(). Obtain
2101 disks and NICs from it. In case a runtime file is not available (see
2102 _GenerateKVMRuntime()) we return the bus slots that QEMU boots with by
2103 default.
2104
2105 """
2106 # This is by default and returned during _GenerateKVMRuntime()
2107 bus_slots = {
2108 _PCI_BUS: bitarray(self._DEFAULT_PCI_RESERVATIONS),
2109 _SCSI_BUS: bitarray(self._DEFAULT_SCSI_RESERVATIONS),
2110 }
2111
2112 # Adjust the empty slots depending of the corresponding hvparam
2113 if hvp and constants.HV_KVM_PCI_RESERVATIONS in hvp:
2114 res = hvp[constants.HV_KVM_PCI_RESERVATIONS]
2115 pci = bitarray(constants.QEMU_PCI_SLOTS)
2116 pci.setall(False) # pylint: disable=E1101
2117 pci[0:res:1] = True
2118 bus_slots[_PCI_BUS] = pci
2119
2120 # This is during hot-add
2121 if runtime:
2122 _, nics, _, disks = runtime
2123 disks = [d for d, _, _ in disks]
2124 for d in disks + nics:
2125 if not d.hvinfo or "bus" not in d.hvinfo:
2126 continue
2127 bus = d.hvinfo["bus"]
2128 slots = bus_slots[bus]
2129 if bus == _PCI_BUS:
2130 slot = d.hvinfo["addr"]
2131 slots[int(slot, 16)] = True
2132 elif bus == _SCSI_BUS:
2133 slot = d.hvinfo["scsi-id"]
2134 slots[slot] = True
2135
2136 return bus_slots
2137
2138 @_with_qmp
2139 def _VerifyHotplugCommand(self, _instance, kvm_devid, should_exist):
2140 """Checks if a previous hotplug command has succeeded.
2141
2142 Depending on the should_exist value, verifies that an entry identified by
2143 device ID is present or not.
2144
2145 @raise errors.HypervisorError: if result is not the expected one
2146
2147 """
2148 for i in range(5):
2149 found = self.qmp.HasDevice(kvm_devid)
2150 logging.info("Verifying hotplug command (retry %s): %s", i, found)
2151 if found and should_exist:
2152 break
2153 if not found and not should_exist:
2154 break
2155 time.sleep(1)
2156
2157 if found and not should_exist:
2158 msg = "Device %s should have been removed but is still there" % kvm_devid
2159 raise errors.HypervisorError(msg)
2160
2161 if not found and should_exist:
2162 msg = "Device %s should have been added but is missing" % kvm_devid
2163 raise errors.HypervisorError(msg)
2164
2165 logging.info("Device %s has been correctly hot-plugged", kvm_devid)
2166
2167 @_with_qmp
2168 def HotAddDevice(self, instance, dev_type, device, extra, seq):
2169 """ Helper method to hot-add a new device
2170
2171 It generates the device ID and hvinfo, and invokes the
2172 device-specific method.
2173
2174 """
2175 kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2176 runtime = self._LoadKVMRuntime(instance)
2177 up_hvp = runtime[2]
2178 device_type = _DEVICE_TYPE[dev_type](up_hvp)
2179 bus_state = self._GetBusSlots(up_hvp, runtime)
2180 # in case of hot-mod this is given
2181 if not device.hvinfo:
2182 device.hvinfo = _GenerateDeviceHVInfo(dev_type, kvm_devid,
2183 device_type, bus_state)
2184 if dev_type == constants.HOTPLUG_TARGET_DISK:
2185 uri = _GetDriveURI(device, extra[0], extra[1])
2186
2187 def drive_add_fn(filename):
2188 """Helper function that uses HMP to hot-add a drive."""
2189 cmd = "drive_add dummy file=%s,if=none,id=%s,format=raw" % \
2190 (filename, kvm_devid)
2191 self._CallMonitorCommand(instance.name, cmd)
2192
2193 # This must be done indirectly due to the fact that we pass the drive's
2194 # file descriptor via QMP first, then we add the corresponding drive that
2195 # refers to this fd. Note that if the QMP connection terminates before
2196 # a drive which keeps a reference to the fd passed via the add-fd QMP
2197 # command has been created, then the fd gets closed and cannot be used
2198 # later (e.g., via an drive_add HMP command).
2199 self.qmp.HotAddDisk(device, kvm_devid, uri, drive_add_fn)
2200 elif dev_type == constants.HOTPLUG_TARGET_NIC:
2201 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2202 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2203 devlist = self._GetKVMOutput(kvmpath, self._KVMOPT_DEVICELIST)
2204 features, _, _ = self._GetNetworkDeviceFeatures(up_hvp, devlist, kvmhelp)
2205 (tap, tapfds, vhostfds) = OpenTap(features=features)
2206 self._ConfigureNIC(instance, seq, device, tap)
2207 self.qmp.HotAddNic(device, kvm_devid, tapfds, vhostfds, features)
2208 utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
2209
2210 self._VerifyHotplugCommand(instance, kvm_devid, True)
2211 # update relevant entries in runtime file
2212 index = _DEVICE_RUNTIME_INDEX[dev_type]
2213 entry = _RUNTIME_ENTRY[dev_type](device, extra)
2214 runtime[index].append(entry)
2215 self._SaveKVMRuntime(instance, runtime)
2216
2217 @_with_qmp
2218 def HotDelDevice(self, instance, dev_type, device, _, seq):
2219 """ Helper method for hot-del device
2220
2221 It gets device info from runtime file, generates the device name and
2222 invokes the device-specific method.
2223
2224 """
2225 runtime = self._LoadKVMRuntime(instance)
2226 entry = _GetExistingDeviceInfo(dev_type, device, runtime)
2227 kvm_device = _RUNTIME_DEVICE[dev_type](entry)
2228 kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
2229 if dev_type == constants.HOTPLUG_TARGET_DISK:
2230 self.qmp.HotDelDisk(kvm_devid)
2231 # drive_del is not implemented yet in qmp
2232 command = "drive_del %s\n" % kvm_devid
2233 self._CallMonitorCommand(instance.name, command)
2234 elif dev_type == constants.HOTPLUG_TARGET_NIC:
2235 self.qmp.HotDelNic(kvm_devid)
2236 utils.RemoveFile(self._InstanceNICFile(instance.name, seq))
2237 self._VerifyHotplugCommand(instance, kvm_devid, False)
2238 index = _DEVICE_RUNTIME_INDEX[dev_type]
2239 runtime[index].remove(entry)
2240 self._SaveKVMRuntime(instance, runtime)
2241
2242 return kvm_device.hvinfo
2243
2244 def HotModDevice(self, instance, dev_type, device, _, seq):
2245 """ Helper method for hot-mod device
2246
2247 It gets device info from runtime file, generates the device name and
2248 invokes the device-specific method. Currently only NICs support hot-mod
2249
2250 """
2251 if dev_type == constants.HOTPLUG_TARGET_NIC:
2252 # putting it back in the same bus and slot
2253 device.hvinfo = self.HotDelDevice(instance, dev_type, device, _, seq)
2254 self.HotAddDevice(instance, dev_type, device, _, seq)
2255
2256 @classmethod
2257 def _ParseKVMVersion(cls, text):
2258 """Parse the KVM version from the --help output.
2259
2260 @type text: string
2261 @param text: output of kvm --help
2262 @return: (version, v_maj, v_min, v_rev)
2263 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2264
2265 """
2266 match = cls._VERSION_RE.search(text.splitlines()[0])
2267 if not match:
2268 raise errors.HypervisorError("Unable to get KVM version")
2269
2270 v_all = match.group(0)
2271 v_maj = int(match.group(1))
2272 v_min = int(match.group(2))
2273 if match.group(4):
2274 v_rev = int(match.group(4))
2275 else:
2276 v_rev = 0
2277 return (v_all, v_maj, v_min, v_rev)
2278
2279 @classmethod
2280 def _GetKVMOutput(cls, kvm_path, option):
2281 """Return the output of a kvm invocation
2282
2283 @type kvm_path: string
2284 @param kvm_path: path to the kvm executable
2285 @type option: a key of _KVMOPTS_CMDS
2286 @param option: kvm option to fetch the output from
2287 @return: output a supported kvm invocation
2288 @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2289
2290 """
2291 assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2292
2293 optlist, can_fail = cls._KVMOPTS_CMDS[option]
2294
2295 result = utils.RunCmd([kvm_path] + optlist)
2296 if result.failed and not can_fail:
2297 raise errors.HypervisorError("Unable to get KVM %s output" %
2298 " ".join(optlist))
2299 return result.output
2300
2301 @classmethod
2302 def _GetKVMVersion(cls, kvm_path):
2303 """Return the installed KVM version.
2304
2305 @return: (version, v_maj, v_min, v_rev)
2306 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2307
2308 """
2309 return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2310
2311 @classmethod
2312 def _GetDefaultMachineVersion(cls, kvm_path):
2313 """Return the default hardware revision (e.g. pc-1.1)
2314
2315 """
2316 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2317 match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2318 if match:
2319 return match.group(1)
2320 else:
2321 return "pc"
2322
2323 @classmethod
2324 def _StopInstance(cls, instance, force=False, name=None, timeout=None):
2325 """Stop an instance.
2326
2327 """
2328 assert(timeout is None or force is not None)
2329
2330 if name is not None and not force:
2331 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2332 if name is None:
2333 name = instance.name
2334 acpi = instance.hvparams[constants.HV_ACPI]
2335 else:
2336 acpi = False
2337 _, pid, alive = cls._InstancePidAlive(name)
2338 if pid > 0 and alive:
2339 if force or not acpi:
2340 utils.KillProcess(pid)
2341 else:
2342 cls._CallMonitorCommand(name, "system_powerdown", timeout)
2343 cls._ClearUserShutdown(instance.name)
2344
2345 def StopInstance(self, instance, force=False, retry=False, name=None,
2346 timeout=None):
2347 """Stop an instance.
2348
2349 """
2350 self._StopInstance(instance, force, name=name, timeout=timeout)
2351
2352 def CleanupInstance(self, instance_name):
2353 """Cleanup after a stopped instance
2354
2355 """
2356 pidfile, pid, alive = self._InstancePidAlive(instance_name)
2357 if pid > 0 and alive:
2358 raise errors.HypervisorError("Cannot cleanup a live instance")
2359 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2360 self._ClearUserShutdown(instance_name)
2361
2362 def RebootInstance(self, instance):
2363 """Reboot an instance.
2364
2365 """
2366 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2367 # socket the instance will stop, but now power up again. So we'll resort
2368 # to shutdown and restart.
2369 _, _, alive = self._InstancePidAlive(instance.name)
2370 if not alive:
2371 raise errors.HypervisorError("Failed to reboot instance %s:"
2372 " not running" % instance.name)
2373 # StopInstance will delete the saved KVM runtime so:
2374 # ...first load it...
2375 kvm_runtime = self._LoadKVMRuntime(instance)
2376 # ...now we can safely call StopInstance...
2377 if not self.StopInstance(instance):
2378 self.StopInstance(instance, force=True)
2379 # ...and finally we can save it again, and execute it...
2380 self._SaveKVMRuntime(instance, kvm_runtime)
2381 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2382 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2383 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2384
2385 def MigrationInfo(self, instance):
2386 """Get instance information to perform a migration.
2387
2388 @type instance: L{objects.Instance}
2389 @param instance: instance to be migrated
2390 @rtype: string
2391 @return: content of the KVM runtime file
2392
2393 """
2394 return self._ReadKVMRuntime(instance.name)
2395
2396 def AcceptInstance(self, instance, info, target):
2397 """Prepare to accept an instance.
2398
2399 @type instance: L{objects.Instance}
2400 @param instance: instance to be accepted
2401 @type info: string
2402 @param info: content of the KVM runtime file on the source node
2403 @type target: string
2404 @param target: target host (usually ip), on this node
2405
2406 """
2407 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2408 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2409 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2410 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2411 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2412 incoming=incoming_address)
2413
2414 def _ConfigureRoutedNICs(self, instance, info):
2415 """Configures all NICs in routed mode
2416
2417 @type instance: L{objects.Instance}
2418 @param instance: the instance to be configured
2419 @type info: string
2420 @param info: serialized KVM runtime info
2421 """
2422 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2423 kvm_nics = kvm_runtime[1]
2424
2425 for nic_seq, nic in enumerate(kvm_nics):
2426 if nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_ROUTED:
2427 # Bridged/OVS interfaces have already been configured
2428 continue
2429 try:
2430 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2431 except EnvironmentError, err:
2432 logging.warning("Failed to find host interface for %s NIC #%d: %s",
2433 instance.name, nic_seq, str(err))
2434 continue
2435 try:
2436 self._ConfigureNIC(instance, nic_seq, nic, tap)
2437 except errors.HypervisorError, err:
2438 logging.warning(str(err))
2439
2440 def FinalizeMigrationDst(self, instance, info, success):
2441 """Finalize the instance migration on the target node.
2442
2443 Stop the incoming mode KVM.
2444
2445 @type instance: L{objects.Instance}
2446 @param instance: instance whose migration is being finalized
2447
2448 """
2449 if success:
2450 self._ConfigureRoutedNICs(instance, info)
2451 self._WriteKVMRuntime(instance.name, info)
2452 else:
2453 self.StopInstance(instance, force=True)
2454
2455 def MigrateInstance(self, cluster_name, instance, target, live_migration):
2456 """Migrate an instance to a target node.
2457
2458 The migration will not be attempted if the instance is not
2459 currently running.
2460
2461 @type cluster_name: string
2462 @param cluster_name: name of the cluster
2463 @type instance: L{objects.Instance}
2464 @param instance: the instance to be migrated
2465 @type target: string
2466 @param target: ip address of the target node
2467 @type live_migration: boolean
2468 @param live_migration: perform a live migration
2469
2470 """
2471 instance_name = instance.name
2472 port = instance.hvparams[constants.HV_MIGRATION_PORT]
2473 _, _, alive = self._InstancePidAlive(instance_name)
2474 if not alive:
2475 raise errors.HypervisorError("Instance not running, cannot migrate")
2476
2477 if not live_migration:
2478 self._CallMonitorCommand(instance_name, "stop")
2479
2480 migrate_command = ("migrate_set_speed %dm" %
2481 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2482 self._CallMonitorCommand(instance_name, migrate_command)
2483
2484 migrate_command = ("migrate_set_downtime %dms" %
2485 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2486 self._CallMonitorCommand(instance_name, migrate_command)
2487
2488 migration_caps = instance.hvparams[constants.HV_KVM_MIGRATION_CAPS]
2489 if migration_caps:
2490 capabilities = migration_caps.split(_MIGRATION_CAPS_DELIM)
2491 postcopy_enabled = ('x-postcopy-ram' in capabilities
2492 or 'postcopy-ram' in capabilities)
2493 for c in capabilities:
2494 migrate_command = ("migrate_set_capability %s on" % c)
2495 self._CallMonitorCommand(instance_name, migrate_command)
2496 else:
2497 postcopy_enabled = False
2498
2499 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2500 self._CallMonitorCommand(instance_name, migrate_command)
2501
2502 if postcopy_enabled:
2503 self._PostcopyAfterPrecopy(instance)
2504
2505 def _PostcopyAfterPrecopy(self, instance):
2506 """Enable postcopying RAM after one precopy pass.
2507
2508 Requires that an instance is currently migrating, and that the
2509 postcopy-ram (x-postcopy-ram on QEMU version 2.5 and below)
2510 migration capability is enabled in the instance's hypervisor
2511 parameters.
2512
2513 @type instance: L{objects.Instance}
2514 @param instance: The instance being migrated.
2515
2516 """
2517 precopy_passes = 0
2518 while precopy_passes < 2:
2519 migration_status = \
2520 self._CallMonitorCommand(instance.name, 'info migrate')
2521
2522 status_match = self._MIGRATION_STATUS_RE.search(migration_status.stdout)
2523 if status_match and status_match.group(1) != 'active':
2524 logging.debug('Did not attempt postcopy, migration status: %s'
2525 % status_match.group(1))
2526 break
2527 if migration_status.stderr:
2528 logging.debug('Error polling for dirty sync count in '
2529 'hv_kvm._PostcopyAfterPrecopy(): %s' % migration_status.stderr)
2530 break
2531
2532 passes_match = \
2533 self._MIGRATION_PRECOPY_PASSES_RE.search(migration_status.stdout)
2534 if passes_match:
2535 precopy_passes = int(passes_match.group(1))
2536 else:
2537 self._CallMonitorCommand(instance.name, 'migrate_start_postcopy')
2538
2539 def FinalizeMigrationSource(self, instance, success, _):
2540 """Finalize the instance migration on the source node.
2541
2542 @type instance: L{objects.Instance}
2543 @param instance: the instance that was migrated
2544 @type success: bool
2545 @param success: whether the migration succeeded or not
2546
2547 """
2548 if success:
2549 pidfile, pid, _ = self._InstancePidAlive(instance.name)
2550 utils.KillProcess(pid)
2551 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2552 self._ClearUserShutdown(instance.name)
2553 else:
2554 # Detect if PID is alive rather than deciding if we were to perform a live
2555 # migration.
2556 _, _, alive = self._InstancePidAlive(instance.name)
2557 if alive:
2558 self._CallMonitorCommand(instance.name, self._CONT_CMD)
2559 else:
2560 self.CleanupInstance(instance.name)
2561
2562 def GetMigrationStatus(self, instance):
2563 """Get the migration status
2564
2565 @type instance: L{objects.Instance}
2566 @param instance: the instance that is being migrated
2567 @rtype: L{objects.MigrationStatus}
2568 @return: the status of the current migration (one of
2569 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2570 progress info that can be retrieved from the hypervisor
2571
2572 """
2573 info_command = "info migrate"
2574 for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2575 result = self._CallMonitorCommand(instance.name, info_command)
2576 match = self._MIGRATION_STATUS_RE.search(result.stdout)
2577 if not match:
2578 if not result.stdout:
2579 logging.info("KVM: empty 'info migrate' result")
2580 else:
2581 logging.warning("KVM: unknown 'info migrate' result: %s",
2582 result.stdout)
2583 else:
2584 status = match.group(1)
2585 if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2586 migration_status = objects.MigrationStatus(status=status)
2587 match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2588 if match:
2589 migration_status.transferred_ram = match.group("transferred")
2590 migration_status.total_ram = match.group("total")
2591
2592 return migration_status
2593
2594 logging.warning("KVM: unknown migration status '%s'", status)
2595
2596 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2597
2598 return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2599
2600 def BalloonInstanceMemory(self, instance, mem):
2601 """Balloon an instance memory to a certain value.
2602
2603 @type instance: L{objects.Instance}
2604 @param instance: instance to be accepted
2605 @type mem: int
2606 @param mem: actual memory size to use for instance runtime
2607
2608 """
2609 self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2610
2611 def GetNodeInfo(self, hvparams=None):
2612 """Return information about the node.
2613
2614 @type hvparams: dict of strings
2615 @param hvparams: hypervisor parameters, not used in this class
2616
2617 @return: a dict as returned by L{BaseHypervisor.GetLinuxNodeInfo} plus
2618 the following keys:
2619 - hv_version: the hypervisor version in the form (major, minor,
2620 revision)
2621
2622 """
2623 result = self.GetLinuxNodeInfo()
2624 kvmpath = constants.KVM_PATH
2625 if hvparams is not None:
2626 kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2627 _, v_major, v_min, v_rev = self._GetKVMVersion(kvmpath)
2628 result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2629 return result
2630
2631 @classmethod
2632 def GetInstanceConsole(cls, instance, primary_node, node_group,
2633 hvparams, beparams):
2634 """Return a command for connecting to the console of an instance.
2635
2636 """
2637 if hvparams[constants.HV_SERIAL_CONSOLE]:
2638 cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2639 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2640 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2641 "STDIO,%s" % cls._SocatUnixConsoleParams(),
2642 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2643 ndparams = node_group.FillND(primary_node)
2644 return objects.InstanceConsole(instance=instance.name,
2645 kind=constants.CONS_SSH,
2646 host=primary_node.name,
2647 port=ndparams.get(constants.ND_SSH_PORT),
2648 user=constants.SSH_CONSOLE_USER,
2649 command=cmd)
2650
2651 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2652 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2653 display = instance.network_port - constants.VNC_BASE_PORT
2654 return objects.InstanceConsole(instance=instance.name,
2655 kind=constants.CONS_VNC,
2656 host=vnc_bind_address,
2657 port=instance.network_port,
2658 display=display)
2659
2660 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2661 if spice_bind:
2662 return objects.InstanceConsole(instance=instance.name,
2663 kind=constants.CONS_SPICE,
2664 host=spice_bind,
2665 port=instance.network_port)
2666
2667 return objects.InstanceConsole(instance=instance.name,
2668 kind=constants.CONS_MESSAGE,
2669 message=("No serial shell for instance %s" %
2670 instance.name))
2671
2672 def Verify(self, hvparams=None):
2673 """Verify the hypervisor.
2674
2675 Check that the required binaries exist.
2676
2677 @type hvparams: dict of strings
2678 @param hvparams: hypervisor parameters to be verified against, not used here
2679
2680 @return: Problem description if something is wrong, C{None} otherwise
2681
2682 """
2683 msgs = []
2684 kvmpath = constants.KVM_PATH
2685 if hvparams is not None:
2686 kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2687 if not os.path.exists(kvmpath):
2688 msgs.append("The KVM binary ('%s') does not exist" % kvmpath)
2689 if not os.path.exists(constants.SOCAT_PATH):
2690 msgs.append("The socat binary ('%s') does not exist" %
2691 constants.SOCAT_PATH)
2692
2693 return self._FormatVerifyResults(msgs)
2694
2695 @classmethod
2696 def CheckParameterSyntax(cls, hvparams):
2697 """Check the given parameters for validity.
2698
2699 @type hvparams: dict of strings
2700 @param hvparams: hypervisor parameters
2701 @raise errors.HypervisorError: when a parameter is not valid
2702
2703 """
2704 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2705
2706 kernel_path = hvparams[constants.HV_KERNEL_PATH]
2707 if kernel_path:
2708 if not hvparams[constants.HV_ROOT_PATH]:
2709 raise errors.HypervisorError("Need a root partition for the instance,"
2710 " if a kernel is defined")
2711
2712 if (hvparams[constants.HV_VNC_X509_VERIFY] and
2713 not hvparams[constants.HV_VNC_X509]):
2714 raise errors.HypervisorError("%s must be defined, if %s is" %
2715 (constants.HV_VNC_X509,
2716 constants.HV_VNC_X509_VERIFY))
2717
2718 if hvparams[constants.HV_SERIAL_CONSOLE]:
2719 serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2720 valid_speeds = constants.VALID_SERIAL_SPEEDS
2721 if not serial_speed or serial_speed not in valid_speeds:
2722 raise errors.HypervisorError("Invalid serial console speed, must be"
2723 " one of: %s" %
2724 utils.CommaJoin(valid_speeds))
2725
2726 boot_order = hvparams[constants.HV_BOOT_ORDER]
2727 if (boot_order == constants.HT_BO_CDROM and
2728 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2729 raise errors.HypervisorError("Cannot boot from cdrom without an"
2730 " ISO path")
2731
2732 security_model = hvparams[constants.HV_SECURITY_MODEL]
2733 if security_model == constants.HT_SM_USER:
2734 if not hvparams[constants.HV_SECURITY_DOMAIN]:
2735 raise errors.HypervisorError("A security domain (user to run kvm as)"
2736 " must be specified")
2737 elif (security_model == constants.HT_SM_NONE or
2738 security_model == constants.HT_SM_POOL):
2739 if hvparams[constants.HV_SECURITY_DOMAIN]:
2740 raise errors.HypervisorError("Cannot have a security domain when the"
2741 " security model is 'none' or 'pool'")
2742
2743 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2744 spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2745 if spice_bind:
2746 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2747 # if an IP version is specified, the spice_bind parameter must be an
2748 # IP of that family
2749 if (netutils.IP4Address.IsValid(spice_bind) and
2750 spice_ip_version != constants.IP4_VERSION):
2751 raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2752 " the specified IP version is %s" %
2753 (spice_bind, spice_ip_version))
2754
2755 if (netutils.IP6Address.IsValid(spice_bind) and
2756 spice_ip_version != constants.IP6_VERSION):
2757 raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2758 " the specified IP version is %s" %
2759 (spice_bind, spice_ip_version))
2760 else:
2761 # All the other SPICE parameters depend on spice_bind being set. Raise an
2762 # error if any of them is set without it.
2763 for param in _SPICE_ADDITIONAL_PARAMS:
2764 if hvparams[param]:
2765 raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2766 (param, constants.HV_KVM_SPICE_BIND))
2767
2768 @classmethod
2769 def ValidateParameters(cls, hvparams):
2770 """Check the given parameters for validity.
2771
2772 @type hvparams: dict of strings
2773 @param hvparams: hypervisor parameters
2774 @raise errors.HypervisorError: when a parameter is not valid
2775
2776 """
2777 super(KVMHypervisor, cls).ValidateParameters(hvparams)
2778
2779 kvm_path = hvparams[constants.HV_KVM_PATH]
2780
2781 security_model = hvparams[constants.HV_SECURITY_MODEL]
2782 if security_model == constants.HT_SM_USER:
2783 username = hvparams[constants.HV_SECURITY_DOMAIN]
2784 try:
2785 pwd.getpwnam(username)
2786 except KeyError:
2787 raise errors.HypervisorError("Unknown security domain user %s"
2788 % username)
2789 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2790 if vnc_bind_address:
2791 bound_to_addr = (netutils.IP4Address.IsValid(vnc_bind_address) or
2792 netutils.IP6Address.IsValid(vnc_bind_address))
2793 is_interface = netutils.IsValidInterface(vnc_bind_address)
2794 is_path = utils.IsNormAbsPath(vnc_bind_address)
2795 if not bound_to_addr and not is_interface and not is_path:
2796 raise errors.HypervisorError("VNC: The %s parameter must be either"
2797 " a valid IP address, an interface name,"
2798 " or an absolute path" %
2799 constants.HV_VNC_BIND_ADDRESS)
2800
2801 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2802 if spice_bind:
2803 # only one of VNC and SPICE can be used currently.
2804 if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2805 raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2806 " only one of them can be used at a"
2807 " given time")
2808
2809 # check that KVM supports SPICE
2810 kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2811 if not cls._SPICE_RE.search(kvmhelp):
2812 raise errors.HypervisorError("SPICE is configured, but it is not"
2813 " supported according to 'kvm --help'")
2814
2815 # if spice_bind is not an IP address, it must be a valid interface
2816 bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2817 netutils.IP6Address.IsValid(spice_bind))
2818 if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2819 raise errors.HypervisorError("SPICE: The %s parameter must be either"
2820 " a valid IP address or interface name" %
2821 constants.HV_KVM_SPICE_BIND)
2822
2823 machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2824 if machine_version:
2825 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2826 if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2827 raise errors.HypervisorError("Unsupported machine version: %s" %
2828 machine_version)
2829
2830 @classmethod
2831 def PowercycleNode(cls, hvparams=None):
2832 """KVM powercycle, just a wrapper over Linux powercycle.
2833
2834 @type hvparams: dict of strings
2835 @param hvparams: hypervisor parameters to be used on this node
2836
2837 """
2838 cls.LinuxPowercycle()