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