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