Do not add a new Inotify watchers on timer
[ganeti-github.git] / lib / hypervisor / hv_kvm / __init__.py
1 #
2 #
3
4 # Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Google Inc.
5 # All rights reserved.
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions are
9 # met:
10 #
11 # 1. Redistributions of source code must retain the above copyright notice,
12 # this list of conditions and the following disclaimer.
13 #
14 # 2. Redistributions in binary form must reproduce the above copyright
15 # notice, this list of conditions and the following disclaimer in the
16 # documentation and/or other materials provided with the distribution.
17 #
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
19 # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30
31 """KVM hypervisor
32
33 """
34
35 import errno
36 import os
37 import os.path
38 import re
39 import tempfile
40 import time
41 import logging
42 import pwd
43 import shutil
44 import urllib2
45 from bitarray import bitarray
46 try:
47 import psutil # pylint: disable=F0401
48 except ImportError:
49 psutil = None
50 try:
51 import fdsend # pylint: disable=F0401
52 except ImportError:
53 fdsend = None
54
55 from ganeti import utils
56 from ganeti import constants
57 from ganeti import errors
58 from ganeti import serializer
59 from ganeti import objects
60 from ganeti import uidpool
61 from ganeti import ssconf
62 from ganeti import netutils
63 from ganeti import pathutils
64 from ganeti.hypervisor import hv_base
65 from ganeti.utils import wrapper as utils_wrapper
66
67 from ganeti.hypervisor.hv_kvm.monitor import QmpConnection, QmpMessage, \
68 MonitorSocket
69 from ganeti.hypervisor.hv_kvm.netdev import OpenTap
70
71
72 _KVM_NETWORK_SCRIPT = pathutils.CONF_DIR + "/kvm-vif-bridge"
73 _KVM_START_PAUSED_FLAG = "-S"
74
75 #: SPICE parameters which depend on L{constants.HV_KVM_SPICE_BIND}
76 _SPICE_ADDITIONAL_PARAMS = frozenset([
77 constants.HV_KVM_SPICE_IP_VERSION,
78 constants.HV_KVM_SPICE_PASSWORD_FILE,
79 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR,
80 constants.HV_KVM_SPICE_JPEG_IMG_COMPR,
81 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR,
82 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION,
83 constants.HV_KVM_SPICE_USE_TLS,
84 ])
85
86 # below constants show the format of runtime file
87 # the nics are in second possition, while the disks in 4th (last)
88 # moreover disk entries are stored as a list of in tuples
89 # (L{objects.Disk}, link_name, uri)
90 _KVM_NICS_RUNTIME_INDEX = 1
91 _KVM_DISKS_RUNTIME_INDEX = 3
92 _DEVICE_RUNTIME_INDEX = {
93 constants.HOTPLUG_TARGET_DISK: _KVM_DISKS_RUNTIME_INDEX,
94 constants.HOTPLUG_TARGET_NIC: _KVM_NICS_RUNTIME_INDEX
95 }
96 _FIND_RUNTIME_ENTRY = {
97 constants.HOTPLUG_TARGET_NIC:
98 lambda nic, kvm_nics: [n for n in kvm_nics if n.uuid == nic.uuid],
99 constants.HOTPLUG_TARGET_DISK:
100 lambda disk, kvm_disks: [(d, l, u) for (d, l, u) in kvm_disks
101 if d.uuid == disk.uuid]
102 }
103 _RUNTIME_DEVICE = {
104 constants.HOTPLUG_TARGET_NIC: lambda d: d,
105 constants.HOTPLUG_TARGET_DISK: lambda (d, e, _): d
106 }
107 _RUNTIME_ENTRY = {
108 constants.HOTPLUG_TARGET_NIC: lambda d, e: d,
109 constants.HOTPLUG_TARGET_DISK: lambda d, e: (d, e[0], e[1])
110 }
111
112 _MIGRATION_CAPS_DELIM = ":"
113
114
115 def _with_qmp(fn):
116 """Wrapper used on hotplug related methods"""
117 def wrapper(self, instance, *args, **kwargs):
118 """Create a QmpConnection and run the wrapped method"""
119 if not getattr(self, "qmp", None):
120 filename = self._InstanceQmpMonitor(instance.name)# pylint: disable=W0212
121 self.qmp = QmpConnection(filename)
122 return fn(self, instance, *args, **kwargs)
123 return wrapper
124
125
126 def _GetDriveURI(disk, link, uri):
127 """Helper function to get the drive uri to be used in --drive kvm option
128
129 Invoked during startup and disk hot-add. In latter case and if no userspace
130 access mode is used it will be overriden with /dev/fdset/<fdset-id> (see
131 HotAddDisk() and AddFd() of QmpConnection).
132
133 @type disk: L{objects.Disk}
134 @param disk: A disk configuration object
135 @type link: string
136 @param link: The device link as returned by _SymlinkBlockDev()
137 @type uri: string
138 @param uri: The drive uri as returned by _CalculateDeviceURI()
139
140 @return: The drive uri to use in kvm option
141
142 """
143 access_mode = disk.params.get(constants.LDP_ACCESS,
144 constants.DISK_KERNELSPACE)
145 # If uri is available, use it during startup/hot-add
146 if (uri and access_mode == constants.DISK_USERSPACE):
147 drive_uri = uri
148 # Otherwise use the link previously created
149 else:
150 drive_uri = link
151
152 return drive_uri
153
154
155 def _GenerateDeviceKVMId(dev_type, dev):
156 """Helper function to generate a unique device name used by KVM
157
158 QEMU monitor commands use names to identify devices. Here we use their pci
159 slot and a part of their UUID to name them. dev.pci might be None for old
160 devices in the cluster.
161
162 @type dev_type: sting
163 @param dev_type: device type of param dev
164 @type dev: L{objects.Disk} or L{objects.NIC}
165 @param dev: the device object for which we generate a kvm name
166 @raise errors.HotplugError: in case a device has no pci slot (old devices)
167
168 """
169
170 if not dev.pci:
171 raise errors.HotplugError("Hotplug is not supported for %s with UUID %s" %
172 (dev_type, dev.uuid))
173
174 return "%s-%s-pci-%d" % (dev_type.lower(), dev.uuid.split("-")[0], dev.pci)
175
176
177 def _GetExistingDeviceInfo(dev_type, device, runtime):
178 """Helper function to get an existing device inside the runtime file
179
180 Used when an instance is running. Load kvm runtime file and search
181 for a device based on its type and uuid.
182
183 @type dev_type: sting
184 @param dev_type: device type of param dev
185 @type device: L{objects.Disk} or L{objects.NIC}
186 @param device: the device object for which we generate a kvm name
187 @type runtime: tuple (cmd, nics, hvparams, disks)
188 @param runtime: the runtime data to search for the device
189 @raise errors.HotplugError: in case the requested device does not
190 exist (e.g. device has been added without --hotplug option) or
191 device info has not pci slot (e.g. old devices in the cluster)
192
193 """
194 index = _DEVICE_RUNTIME_INDEX[dev_type]
195 found = _FIND_RUNTIME_ENTRY[dev_type](device, runtime[index])
196 if not found:
197 raise errors.HotplugError("Cannot find runtime info for %s with UUID %s" %
198 (dev_type, device.uuid))
199
200 return found[0]
201
202
203 def _UpgradeSerializedRuntime(serialized_runtime):
204 """Upgrade runtime data
205
206 Remove any deprecated fields or change the format of the data.
207 The runtime files are not upgraded when Ganeti is upgraded, so the required
208 modification have to be performed here.
209
210 @type serialized_runtime: string
211 @param serialized_runtime: raw text data read from actual runtime file
212 @return: (cmd, nic dicts, hvparams, bdev dicts)
213 @rtype: tuple
214
215 """
216 loaded_runtime = serializer.Load(serialized_runtime)
217 kvm_cmd, serialized_nics, hvparams = loaded_runtime[:3]
218 if len(loaded_runtime) >= 4:
219 serialized_disks = loaded_runtime[3]
220 else:
221 serialized_disks = []
222
223 for nic in serialized_nics:
224 # Add a dummy uuid slot if an pre-2.8 NIC is found
225 if "uuid" not in nic:
226 nic["uuid"] = utils.NewUUID()
227
228 return kvm_cmd, serialized_nics, hvparams, serialized_disks
229
230
231 def _AnalyzeSerializedRuntime(serialized_runtime):
232 """Return runtime entries for a serialized runtime file
233
234 @type serialized_runtime: string
235 @param serialized_runtime: raw text data read from actual runtime file
236 @return: (cmd, nics, hvparams, bdevs)
237 @rtype: tuple
238
239 """
240 kvm_cmd, serialized_nics, hvparams, serialized_disks = \
241 _UpgradeSerializedRuntime(serialized_runtime)
242 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
243 kvm_disks = [(objects.Disk.FromDict(sdisk), link, uri)
244 for sdisk, link, uri in serialized_disks]
245
246 return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
247
248
249 class HeadRequest(urllib2.Request):
250 def get_method(self):
251 return "HEAD"
252
253
254 def _CheckUrl(url):
255 """Check if a given URL exists on the server
256
257 """
258 try:
259 urllib2.urlopen(HeadRequest(url))
260 return True
261 except urllib2.URLError:
262 return False
263
264
265 class KVMHypervisor(hv_base.BaseHypervisor):
266 """KVM hypervisor interface
267
268 """
269 CAN_MIGRATE = True
270
271 _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
272 _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
273 _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
274 _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
275 _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
276 _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
277 _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
278 # KVM instances with chroot enabled are started in empty chroot directories.
279 _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
280 # After an instance is stopped, its chroot directory is removed.
281 # If the chroot directory is not empty, it can't be removed.
282 # A non-empty chroot directory indicates a possible security incident.
283 # To support forensics, the non-empty chroot directory is quarantined in
284 # a separate directory, called 'chroot-quarantine'.
285 _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
286 _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
287 _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
288
289 PARAMETERS = {
290 constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
291 constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
292 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
293 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
294 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
295 constants.HV_ACPI: hv_base.NO_CHECK,
296 constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
297 constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
298 constants.HV_VNC_BIND_ADDRESS: hv_base.NO_CHECK, # will be checked later
299 constants.HV_VNC_TLS: hv_base.NO_CHECK,
300 constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
301 constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
302 constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
303 constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
304 constants.HV_KVM_SPICE_IP_VERSION:
305 (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
306 x in constants.VALID_IP_VERSIONS),
307 "The SPICE IP version should be 4 or 6",
308 None, None),
309 constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
310 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
311 hv_base.ParamInSet(
312 False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
313 constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
314 hv_base.ParamInSet(
315 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
316 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
317 hv_base.ParamInSet(
318 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
319 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
320 hv_base.ParamInSet(
321 False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
322 constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
323 constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
324 constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
325 constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
326 constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
327 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_OR_URL_CHECK,
328 constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_OR_URL_CHECK,
329 constants.HV_BOOT_ORDER:
330 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
331 constants.HV_NIC_TYPE:
332 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
333 constants.HV_DISK_TYPE:
334 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
335 constants.HV_KVM_CDROM_DISK_TYPE:
336 hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
337 constants.HV_USB_MOUSE:
338 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
339 constants.HV_KEYMAP: hv_base.NO_CHECK,
340 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
341 constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
342 constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
343 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
344 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
345 constants.HV_DISK_CACHE:
346 hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
347 constants.HV_KVM_DISK_AIO:
348 hv_base.ParamInSet(False, constants.HT_KVM_VALID_AIO_TYPES),
349 constants.HV_SECURITY_MODEL:
350 hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
351 constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
352 constants.HV_KVM_FLAG:
353 hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
354 constants.HV_VHOST_NET: hv_base.NO_CHECK,
355 constants.HV_VIRTIO_NET_QUEUES: hv_base.OPT_VIRTIO_NET_QUEUES_CHECK,
356 constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
357 constants.HV_KVM_USER_SHUTDOWN: hv_base.NO_CHECK,
358 constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
359 constants.HV_REBOOT_BEHAVIOR:
360 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
361 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
362 constants.HV_CPU_TYPE: hv_base.NO_CHECK,
363 constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
364 constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
365 constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
366 constants.HV_SOUNDHW: hv_base.NO_CHECK,
367 constants.HV_USB_DEVICES: hv_base.NO_CHECK,
368 constants.HV_VGA: hv_base.NO_CHECK,
369 constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
370 constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
371 constants.HV_KVM_MIGRATION_CAPS: hv_base.NO_CHECK,
372 constants.HV_VNET_HDR: hv_base.NO_CHECK,
373 }
374
375 _VIRTIO = "virtio"
376 _VIRTIO_NET_PCI = "virtio-net-pci"
377 _VIRTIO_BLK_PCI = "virtio-blk-pci"
378
379 _MIGRATION_STATUS_RE = re.compile(r"Migration\s+status:\s+(\w+)",
380 re.M | re.I)
381 _MIGRATION_PROGRESS_RE = \
382 re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
383 r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
384 r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
385
386 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
387 _MIGRATION_INFO_RETRY_DELAY = 2
388
389 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
390
391 _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
392 _CPU_INFO_CMD = "info cpus"
393 _CONT_CMD = "cont"
394
395 _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
396 _CHECK_MACHINE_VERSION_RE = \
397 staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
398
399 _QMP_RE = re.compile(r"^-qmp\s", re.M)
400 _SPICE_RE = re.compile(r"^-spice\s", re.M)
401 _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
402 _VIRTIO_NET_QUEUES_RE = re.compile(r"^-net\s.*,fds=x:y:...:z", re.M)
403 _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
404 _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
405 _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
406 _DISPLAY_RE = re.compile(r"^-display\s", re.M)
407 _MACHINE_RE = re.compile(r"^-machine\s", re.M)
408 _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
409 _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M)
410 # match -drive.*boot=on|off on different lines, but in between accept only
411 # dashes not preceeded by a new line (which would mean another option
412 # different than -drive is starting)
413 _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
414 _UUID_RE = re.compile(r"^-uuid\s", re.M)
415
416 _INFO_VERSION_RE = \
417 re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
418 _INFO_VERSION_CMD = "info version"
419
420 # Slot 0 for Host bridge, Slot 1 for ISA bridge, Slot 2 for VGA controller
421 _DEFAULT_PCI_RESERVATIONS = "11100000000000000000000000000000"
422 _SOUNDHW_WITH_PCI_SLOT = ["ac97", "es1370", "hda"]
423
424 ANCILLARY_FILES = [
425 _KVM_NETWORK_SCRIPT,
426 ]
427 ANCILLARY_FILES_OPT = [
428 _KVM_NETWORK_SCRIPT,
429 ]
430
431 # Supported kvm options to get output from
432 _KVMOPT_HELP = "help"
433 _KVMOPT_MLIST = "mlist"
434 _KVMOPT_DEVICELIST = "devicelist"
435
436 # Command to execute to get the output from kvm, and whether to
437 # accept the output even on failure.
438 _KVMOPTS_CMDS = {
439 _KVMOPT_HELP: (["--help"], False),
440 _KVMOPT_MLIST: (["-M", "?"], False),
441 _KVMOPT_DEVICELIST: (["-device", "?"], True),
442 }
443
444 def __init__(self):
445 hv_base.BaseHypervisor.__init__(self)
446 # Let's make sure the directories we need exist, even if the RUN_DIR lives
447 # in a tmpfs filesystem or has been otherwise wiped out.
448 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
449 utils.EnsureDirs(dirs)
450 self.qmp = None
451
452 @staticmethod
453 def VersionsSafeForMigration(src, target):
454 """Predict if migration is safe between those versions
455
456 """
457 # Actually, it is not that easy. However, with the kvm machine_version
458 # feature, migration suceeds in most cases. So we try not to block
459 # legitimate migrations.
460 return True
461
462 @classmethod
463 def _InstancePidFile(cls, instance_name):
464 """Returns the instance pidfile.
465
466 """
467 return utils.PathJoin(cls._PIDS_DIR, instance_name)
468
469 @classmethod
470 def _InstanceUidFile(cls, instance_name):
471 """Returns the instance uidfile.
472
473 """
474 return utils.PathJoin(cls._UIDS_DIR, instance_name)
475
476 @classmethod
477 def _InstancePidInfo(cls, pid):
478 """Check pid file for instance information.
479
480 Check that a pid file is associated with an instance, and retrieve
481 information from its command line.
482
483 @type pid: string or int
484 @param pid: process id of the instance to check
485 @rtype: tuple
486 @return: (instance_name, memory, vcpus)
487 @raise errors.HypervisorError: when an instance cannot be found
488
489 """
490 alive = utils.IsProcessAlive(pid)
491 if not alive:
492 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
493
494 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
495 try:
496 cmdline = utils.ReadFile(cmdline_file)
497 except EnvironmentError, err:
498 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
499 (pid, err))
500
501 instance = None
502 memory = 0
503 vcpus = 0
504
505 arg_list = cmdline.split("\x00")
506 while arg_list:
507 arg = arg_list.pop(0)
508 if arg == "-name":
509 instance = arg_list.pop(0)
510 elif arg == "-m":
511 memory = int(arg_list.pop(0))
512 elif arg == "-smp":
513 vcpus = int(arg_list.pop(0).split(",")[0])
514
515 if instance is None:
516 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
517 " instance" % pid)
518
519 return (instance, memory, vcpus)
520
521 @classmethod
522 def _InstancePidAlive(cls, instance_name):
523 """Returns the instance pidfile, pid, and liveness.
524
525 @type instance_name: string
526 @param instance_name: instance name
527 @rtype: tuple
528 @return: (pid file name, pid, liveness)
529
530 """
531 pidfile = cls._InstancePidFile(instance_name)
532 pid = utils.ReadPidFile(pidfile)
533
534 alive = False
535 try:
536 cmd_instance = cls._InstancePidInfo(pid)[0]
537 alive = (cmd_instance == instance_name)
538 except errors.HypervisorError:
539 pass
540
541 return (pidfile, pid, alive)
542
543 @classmethod
544 def _CheckDown(cls, instance_name):
545 """Raises an error unless the given instance is down.
546
547 """
548 alive = cls._InstancePidAlive(instance_name)[2]
549 if alive:
550 raise errors.HypervisorError("Failed to start instance %s: %s" %
551 (instance_name, "already running"))
552
553 @classmethod
554 def _InstanceMonitor(cls, instance_name):
555 """Returns the instance monitor socket name
556
557 """
558 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
559
560 @classmethod
561 def _InstanceSerial(cls, instance_name):
562 """Returns the instance serial socket name
563
564 """
565 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
566
567 @classmethod
568 def _InstanceQmpMonitor(cls, instance_name):
569 """Returns the instance serial QMP socket name
570
571 """
572 return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
573
574 @classmethod
575 def _InstanceKvmdMonitor(cls, instance_name):
576 """Returns the instance kvm daemon socket name
577
578 """
579 return utils.PathJoin(cls._CTRL_DIR, "%s.kvmd" % instance_name)
580
581 @classmethod
582 def _InstanceShutdownMonitor(cls, instance_name):
583 """Returns the instance QMP output filename
584
585 """
586 return utils.PathJoin(cls._CTRL_DIR, "%s.shutdown" % instance_name)
587
588 @staticmethod
589 def _SocatUnixConsoleParams():
590 """Returns the correct parameters for socat
591
592 If we have a new-enough socat we can use raw mode with an escape character.
593
594 """
595 if constants.SOCAT_USE_ESCAPE:
596 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
597 else:
598 return "echo=0,icanon=0"
599
600 @classmethod
601 def _InstanceKVMRuntime(cls, instance_name):
602 """Returns the instance KVM runtime filename
603
604 """
605 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
606
607 @classmethod
608 def _InstanceChrootDir(cls, instance_name):
609 """Returns the name of the KVM chroot dir of the instance
610
611 """
612 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
613
614 @classmethod
615 def _InstanceNICDir(cls, instance_name):
616 """Returns the name of the directory holding the tap device files for a
617 given instance.
618
619 """
620 return utils.PathJoin(cls._NICS_DIR, instance_name)
621
622 @classmethod
623 def _InstanceNICFile(cls, instance_name, seq):
624 """Returns the name of the file containing the tap device for a given NIC
625
626 """
627 return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
628
629 @classmethod
630 def _InstanceKeymapFile(cls, instance_name):
631 """Returns the name of the file containing the keymap for a given instance
632
633 """
634 return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
635
636 @classmethod
637 def _TryReadUidFile(cls, uid_file):
638 """Try to read a uid file
639
640 """
641 if os.path.exists(uid_file):
642 try:
643 uid = int(utils.ReadOneLineFile(uid_file))
644 return uid
645 except EnvironmentError:
646 logging.warning("Can't read uid file", exc_info=True)
647 except (TypeError, ValueError):
648 logging.warning("Can't parse uid file contents", exc_info=True)
649 return None
650
651 @classmethod
652 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
653 """Removes an instance's rutime sockets/files/dirs.
654
655 """
656 utils.RemoveFile(pidfile)
657 utils.RemoveFile(cls._InstanceMonitor(instance_name))
658 utils.RemoveFile(cls._InstanceSerial(instance_name))
659 utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
660 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
661 utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
662 uid_file = cls._InstanceUidFile(instance_name)
663 uid = cls._TryReadUidFile(uid_file)
664 utils.RemoveFile(uid_file)
665 if uid is not None:
666 uidpool.ReleaseUid(uid)
667 try:
668 shutil.rmtree(cls._InstanceNICDir(instance_name))
669 except OSError, err:
670 if err.errno != errno.ENOENT:
671 raise
672 try:
673 chroot_dir = cls._InstanceChrootDir(instance_name)
674 utils.RemoveDir(chroot_dir)
675 except OSError, err:
676 if err.errno == errno.ENOTEMPTY:
677 # The chroot directory is expected to be empty, but it isn't.
678 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
679 prefix="%s-%s-" %
680 (instance_name,
681 utils.TimestampForFilename()))
682 logging.warning("The chroot directory of instance %s can not be"
683 " removed as it is not empty. Moving it to the"
684 " quarantine instead. Please investigate the"
685 " contents (%s) and clean up manually",
686 instance_name, new_chroot_dir)
687 utils.RenameFile(chroot_dir, new_chroot_dir)
688 else:
689 raise
690
691 @staticmethod
692 def _ConfigureNIC(instance, seq, nic, tap):
693 """Run the network configuration script for a specified NIC
694
695 See L{hv_base.ConfigureNIC}.
696
697 @param instance: instance we're acting on
698 @type instance: instance object
699 @param seq: nic sequence number
700 @type seq: int
701 @param nic: nic we're acting on
702 @type nic: nic object
703 @param tap: the host's tap interface this NIC corresponds to
704 @type tap: str
705
706 """
707 hv_base.ConfigureNIC([pathutils.KVM_IFUP, tap], instance, seq, nic, tap)
708
709 @classmethod
710 def _SetProcessAffinity(cls, process_id, cpus):
711 """Sets the affinity of a process to the given CPUs.
712
713 @type process_id: int
714 @type cpus: list of int
715 @param cpus: The list of CPUs the process ID may use.
716
717 """
718 if psutil is None:
719 raise errors.HypervisorError("psutil Python package not"
720 " found; cannot use CPU pinning under KVM")
721
722 target_process = psutil.Process(process_id)
723 if cpus == constants.CPU_PINNING_OFF:
724 target_process.set_cpu_affinity(range(psutil.cpu_count()))
725 else:
726 target_process.set_cpu_affinity(cpus)
727
728 @classmethod
729 def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
730 """Change CPU affinity for running VM according to given CPU mask.
731
732 @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
733 @type cpu_mask: string
734 @param process_id: process ID of KVM process. Used to pin entire VM
735 to physical CPUs.
736 @type process_id: int
737 @param thread_dict: map of virtual CPUs to KVM thread IDs
738 @type thread_dict: dict int:int
739
740 """
741 # Convert the string CPU mask to a list of list of int's
742 cpu_list = utils.ParseMultiCpuMask(cpu_mask)
743
744 if len(cpu_list) == 1:
745 all_cpu_mapping = cpu_list[0]
746 if all_cpu_mapping == constants.CPU_PINNING_OFF:
747 # If CPU pinning has 1 entry that's "all", then do nothing
748 pass
749 else:
750 # If CPU pinning has one non-all entry, map the entire VM to
751 # one set of physical CPUs
752 cls._SetProcessAffinity(process_id, all_cpu_mapping)
753 else:
754 # The number of vCPUs mapped should match the number of vCPUs
755 # reported by KVM. This was already verified earlier, so
756 # here only as a sanity check.
757 assert len(thread_dict) == len(cpu_list)
758
759 # For each vCPU, map it to the proper list of physical CPUs
760 for i, vcpu in enumerate(cpu_list):
761 cls._SetProcessAffinity(thread_dict[i], vcpu)
762
763 def _GetVcpuThreadIds(self, instance_name):
764 """Get a mapping of vCPU no. to thread IDs for the instance
765
766 @type instance_name: string
767 @param instance_name: instance in question
768 @rtype: dictionary of int:int
769 @return: a dictionary mapping vCPU numbers to thread IDs
770
771 """
772 result = {}
773 output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
774 for line in output.stdout.splitlines():
775 match = self._CPU_INFO_RE.search(line)
776 if not match:
777 continue
778 grp = map(int, match.groups())
779 result[grp[0]] = grp[1]
780
781 return result
782
783 def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
784 """Complete CPU pinning.
785
786 @type instance_name: string
787 @param instance_name: name of instance
788 @type cpu_mask: string
789 @param cpu_mask: CPU pinning mask as entered by user
790
791 """
792 # Get KVM process ID, to be used if need to pin entire VM
793 _, pid, _ = self._InstancePidAlive(instance_name)
794 # Get vCPU thread IDs, to be used if need to pin vCPUs separately
795 thread_dict = self._GetVcpuThreadIds(instance_name)
796 # Run CPU pinning, based on configured mask
797 self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
798
799 def ListInstances(self, hvparams=None):
800 """Get the list of running instances.
801
802 We can do this by listing our live instances directory and
803 checking whether the associated kvm process is still alive.
804
805 """
806 result = []
807 for name in os.listdir(self._PIDS_DIR):
808 if self._InstancePidAlive(name)[2]:
809 result.append(name)
810 return result
811
812 @classmethod
813 def _IsUserShutdown(cls, instance_name):
814 return os.path.exists(cls._InstanceShutdownMonitor(instance_name))
815
816 @classmethod
817 def _ClearUserShutdown(cls, instance_name):
818 utils.RemoveFile(cls._InstanceShutdownMonitor(instance_name))
819
820 def GetInstanceInfo(self, instance_name, hvparams=None):
821 """Get instance properties.
822
823 @type instance_name: string
824 @param instance_name: the instance name
825 @type hvparams: dict of strings
826 @param hvparams: hypervisor parameters to be used with this instance
827 @rtype: tuple of strings
828 @return: (name, id, memory, vcpus, stat, times)
829
830 """
831 _, pid, alive = self._InstancePidAlive(instance_name)
832 if not alive:
833 if self._IsUserShutdown(instance_name):
834 return (instance_name, -1, 0, 0, hv_base.HvInstanceState.SHUTDOWN, 0)
835 else:
836 return None
837
838 _, memory, vcpus = self._InstancePidInfo(pid)
839 istat = hv_base.HvInstanceState.RUNNING
840 times = 0
841
842 try:
843 qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
844 qmp.connect()
845 vcpus = len(qmp.Execute("query-cpus"))
846 # Will fail if ballooning is not enabled, but we can then just resort to
847 # the value above.
848 mem_bytes = qmp.Execute("query-balloon")[qmp.ACTUAL_KEY]
849 memory = mem_bytes / 1048576
850 except errors.HypervisorError:
851 pass
852
853 return (instance_name, pid, memory, vcpus, istat, times)
854
855 def GetAllInstancesInfo(self, hvparams=None):
856 """Get properties of all instances.
857
858 @type hvparams: dict of strings
859 @param hvparams: hypervisor parameters
860 @return: list of tuples (name, id, memory, vcpus, stat, times)
861
862 """
863 data = []
864 for name in os.listdir(self._PIDS_DIR):
865 try:
866 info = self.GetInstanceInfo(name)
867 except errors.HypervisorError:
868 # Ignore exceptions due to instances being shut down
869 continue
870 if info:
871 data.append(info)
872 return data
873
874 def _GenerateKVMBlockDevicesOptions(self, up_hvp, kvm_disks,
875 kvmhelp, devlist):
876 """Generate KVM options regarding instance's block devices.
877
878 @type up_hvp: dict
879 @param up_hvp: the instance's runtime hypervisor parameters
880 @type kvm_disks: list of tuples
881 @param kvm_disks: list of tuples [(disk, link_name, uri)..]
882 @type kvmhelp: string
883 @param kvmhelp: output of kvm --help
884 @type devlist: string
885 @param devlist: output of kvm -device ?
886 @rtype: list
887 @return: list of command line options eventually used by kvm executable
888
889 """
890 kernel_path = up_hvp[constants.HV_KERNEL_PATH]
891 if kernel_path:
892 boot_disk = False
893 else:
894 boot_disk = up_hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
895
896 # whether this is an older KVM version that uses the boot=on flag
897 # on devices
898 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
899
900 dev_opts = []
901 device_driver = None
902 disk_type = up_hvp[constants.HV_DISK_TYPE]
903 if disk_type == constants.HT_DISK_PARAVIRTUAL:
904 if_val = ",if=%s" % self._VIRTIO
905 try:
906 if self._VIRTIO_BLK_RE.search(devlist):
907 if_val = ",if=none"
908 # will be passed in -device option as driver
909 device_driver = self._VIRTIO_BLK_PCI
910 except errors.HypervisorError, _:
911 pass
912 else:
913 if_val = ",if=%s" % disk_type
914 # AIO mode
915 aio_mode = up_hvp[constants.HV_KVM_DISK_AIO]
916 if aio_mode == constants.HT_KVM_AIO_NATIVE:
917 aio_val = ",aio=%s" % aio_mode
918 else:
919 aio_val = ""
920 # Cache mode
921 disk_cache = up_hvp[constants.HV_DISK_CACHE]
922 for cfdev, link_name, uri in kvm_disks:
923 if cfdev.dev_type in constants.DTS_EXT_MIRROR:
924 if disk_cache != "none":
925 # TODO: make this a hard error, instead of a silent overwrite
926 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
927 " to prevent shared storage corruption on migration",
928 disk_cache)
929 cache_val = ",cache=none"
930 elif disk_cache != constants.HT_CACHE_DEFAULT:
931 cache_val = ",cache=%s" % disk_cache
932 else:
933 cache_val = ""
934 if cfdev.mode != constants.DISK_RDWR:
935 raise errors.HypervisorError("Instance has read-only disks which"
936 " are not supported by KVM")
937 # TODO: handle FD_LOOP and FD_BLKTAP (?)
938 boot_val = ""
939 if boot_disk:
940 dev_opts.extend(["-boot", "c"])
941 boot_disk = False
942 if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
943 boot_val = ",boot=on"
944
945 drive_uri = _GetDriveURI(cfdev, link_name, uri)
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 _ = utils.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 _ = utils.GetFreeSlot(pci_reservations, reserve=True)
1080
1081 # Add id to ballon and place to the first available slot (3 or 4)
1082 addr = utils.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 = utils.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 = utils.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 = utils.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 a dict of supported and enabled tap features with nic_model along
1475 with the extra strings to be appended to the --netdev and --device options.
1476 This function is called before opening a new tap device.
1477
1478 Currently the features_dict includes the following attributes:
1479 - vhost (boolean)
1480 - vnet_hdr (boolean)
1481 - mq (boolean, int)
1482
1483 @rtype: (dict, str, str) tuple
1484 @return: The supported features,
1485 the string to be appended to the --netdev option,
1486 the string to be appended to the --device option
1487
1488 """
1489 nic_type = up_hvp[constants.HV_NIC_TYPE]
1490 nic_extra_str = ""
1491 tap_extra_str = ""
1492 features = {
1493 "vhost": False,
1494 "vnet_hdr": False,
1495 "mq": (False, 1)
1496 }
1497 update_features = {}
1498 if nic_type == constants.HT_NIC_PARAVIRTUAL:
1499 nic_model = self._VIRTIO
1500 try:
1501 if self._VIRTIO_NET_RE.search(devlist):
1502 nic_model = self._VIRTIO_NET_PCI
1503 update_features["vnet_hdr"] = up_hvp[constants.HV_VNET_HDR]
1504 except errors.HypervisorError, _:
1505 # Older versions of kvm don't support DEVICE_LIST, but they don't
1506 # have new virtio syntax either.
1507 pass
1508
1509 if up_hvp[constants.HV_VHOST_NET]:
1510 # Check for vhost_net support.
1511 if self._VHOST_RE.search(kvmhelp):
1512 update_features["vhost"] = True
1513 tap_extra_str = ",vhost=on"
1514 else:
1515 raise errors.HypervisorError("vhost_net is configured"
1516 " but it is not available")
1517 virtio_net_queues = up_hvp.get(constants.HV_VIRTIO_NET_QUEUES, 1)
1518 if virtio_net_queues > 1:
1519 # Check for multiqueue virtio-net support.
1520 if self._VIRTIO_NET_QUEUES_RE.search(kvmhelp):
1521 # As advised at http://www.linux-kvm.org/page/Multiqueue formula
1522 # for calculating vector size is: vectors=2*N+1 where N is the
1523 # number of queues (HV_VIRTIO_NET_QUEUES).
1524 nic_extra_str = ",mq=on,vectors=%d" % (2 * virtio_net_queues + 1)
1525 update_features["mq"] = (True, virtio_net_queues)
1526 else:
1527 raise errors.HypervisorError("virtio_net_queues is configured"
1528 " but it is not available")
1529 else:
1530 nic_model = nic_type
1531
1532 update_features["driver"] = nic_model
1533 features.update(update_features)
1534
1535 return features, tap_extra_str, nic_extra_str
1536
1537 # too many local variables
1538 # pylint: disable=R0914
1539 def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1540 """Execute a KVM cmd, after completing it with some last minute data.
1541
1542 @type instance: L{objects.Instance} object
1543 @param instance: the VM this command acts upon
1544 @type kvm_runtime: tuple of (list of str, list of L{objects.NIC} objects,
1545 dict of hypervisor options, list of tuples (L{objects.Disk}, str, str)
1546 @param kvm_runtime: (kvm command, NICs of the instance, options at startup
1547 of the instance, [(disk, link_name, uri)..])
1548 @type incoming: tuple of strings
1549 @param incoming: (target_host_ip, port) for migration.
1550 @type kvmhelp: string
1551 @param kvmhelp: output of kvm --help
1552
1553 """
1554 # Small _ExecuteKVMRuntime hv parameters programming howto:
1555 # - conf_hvp contains the parameters as configured on ganeti. they might
1556 # have changed since the instance started; only use them if the change
1557 # won't affect the inside of the instance (which hasn't been rebooted).
1558 # - up_hvp contains the parameters as they were when the instance was
1559 # started, plus any new parameter which has been added between ganeti
1560 # versions: it is paramount that those default to a value which won't
1561 # affect the inside of the instance as well.
1562 conf_hvp = instance.hvparams
1563 name = instance.name
1564 self._CheckDown(name)
1565
1566 self._ClearUserShutdown(instance.name)
1567 self._StartKvmd(instance.hvparams)
1568
1569 temp_files = []
1570
1571 kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1572 # the first element of kvm_cmd is always the path to the kvm binary
1573 kvm_path = kvm_cmd[0]
1574 up_hvp = objects.FillDict(conf_hvp, up_hvp)
1575
1576 # We know it's safe to run as a different user upon migration, so we'll use
1577 # the latest conf, from conf_hvp.
1578 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1579 if security_model == constants.HT_SM_USER:
1580 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1581
1582 keymap = conf_hvp[constants.HV_KEYMAP]
1583 if keymap:
1584 keymap_path = self._InstanceKeymapFile(name)
1585 # If a keymap file is specified, KVM won't use its internal defaults. By
1586 # first including the "en-us" layout, an error on loading the actual
1587 # layout (e.g. because it can't be found) won't lead to a non-functional
1588 # keyboard. A keyboard with incorrect keys is still better than none.
1589 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1590 kvm_cmd.extend(["-k", keymap_path])
1591
1592 # We have reasons to believe changing something like the nic driver/type
1593 # upon migration won't exactly fly with the instance kernel, so for nic
1594 # related parameters we'll use up_hvp
1595 tapfds = []
1596 taps = []
1597 devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1598 if not kvm_nics:
1599 kvm_cmd.extend(["-net", "none"])
1600 else:
1601 features, tap_extra, nic_extra = \
1602 self._GetNetworkDeviceFeatures(up_hvp, devlist, kvmhelp)
1603 nic_model = features["driver"]
1604 kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1605 for nic_seq, nic in enumerate(kvm_nics):
1606 tapname, nic_tapfds, nic_vhostfds = \
1607 OpenTap(features=features, name=self._GenerateKvmTapName(nic))
1608
1609 tapfds.extend(nic_tapfds)
1610 tapfds.extend(nic_vhostfds)
1611 taps.append(tapname)
1612 tapfd = "%s%s" % ("fds=" if len(nic_tapfds) > 1 else "fd=",
1613 ":".join(str(fd) for fd in nic_tapfds))
1614
1615 if nic_vhostfds:
1616 vhostfd = "%s%s" % (",vhostfds="
1617 if len(nic_vhostfds) > 1 else ",vhostfd=",
1618 ":".join(str(fd) for fd in nic_vhostfds))
1619 else:
1620 vhostfd = ""
1621
1622 if kvm_supports_netdev:
1623 nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1624 try:
1625 # kvm_nics already exist in old runtime files and thus there might
1626 # be some entries without pci slot (therefore try: except:)
1627 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1628 netdev = kvm_devid
1629 nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1630 except errors.HotplugError:
1631 netdev = "netdev%d" % nic_seq
1632 nic_val += (",netdev=%s%s" % (netdev, nic_extra))
1633 tap_val = ("type=tap,id=%s,%s%s%s" %
1634 (netdev, tapfd, vhostfd, tap_extra))
1635 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1636 else:
1637 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1638 nic.mac, nic_model)
1639 tap_val = "tap,vlan=%s,%s" % (nic_seq, tapfd)
1640 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1641
1642 if incoming:
1643 target, port = incoming
1644 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1645
1646 # Changing the vnc password doesn't bother the guest that much. At most it
1647 # will surprise people who connect to it. Whether positively or negatively
1648 # it's debatable.
1649 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1650 vnc_pwd = None
1651 if vnc_pwd_file:
1652 try:
1653 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1654 except EnvironmentError, err:
1655 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1656 % (vnc_pwd_file, err))
1657
1658 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1659 utils.EnsureDirs([(self._InstanceChrootDir(name),
1660 constants.SECURE_DIR_MODE)])
1661
1662 # Automatically enable QMP if version is >= 0.14
1663 if self._QMP_RE.search(kvmhelp):
1664 logging.debug("Enabling QMP")
1665 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1666 self._InstanceQmpMonitor(instance.name)])
1667 # Add a second monitor for kvmd
1668 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1669 self._InstanceKvmdMonitor(instance.name)])
1670
1671 # Configure the network now for starting instances and bridged/OVS
1672 # interfaces, during FinalizeMigration for incoming instances' routed
1673 # interfaces.
1674 for nic_seq, nic in enumerate(kvm_nics):
1675 if (incoming and
1676 nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_ROUTED):
1677 continue
1678 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1679
1680 bdev_opts = self._GenerateKVMBlockDevicesOptions(up_hvp,
1681 kvm_disks,
1682 kvmhelp,
1683 devlist)
1684 kvm_cmd.extend(bdev_opts)
1685 # CPU affinity requires kvm to start paused, so we set this flag if the
1686 # instance is not already paused and if we are not going to accept a
1687 # migrating instance. In the latter case, pausing is not needed.
1688 start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1689 if start_kvm_paused:
1690 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1691
1692 # Note: CPU pinning is using up_hvp since changes take effect
1693 # during instance startup anyway, and to avoid problems when soft
1694 # rebooting the instance.
1695 cpu_pinning = False
1696 if up_hvp.get(constants.HV_CPU_MASK, None):
1697 cpu_pinning = True
1698
1699 if security_model == constants.HT_SM_POOL:
1700 ss = ssconf.SimpleStore()
1701 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1702 all_uids = set(uidpool.ExpandUidPool(uid_pool))
1703 uid = uidpool.RequestUnusedUid(all_uids)
1704 try:
1705 username = pwd.getpwuid(uid.GetUid()).pw_name
1706 kvm_cmd.extend(["-runas", username])
1707 self._RunKVMCmd(name, kvm_cmd, tapfds)
1708 except:
1709 uidpool.ReleaseUid(uid)
1710 raise
1711 else:
1712 uid.Unlock()
1713 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1714 else:
1715 self._RunKVMCmd(name, kvm_cmd, tapfds)
1716
1717 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1718 constants.RUN_DIRS_MODE)])
1719 for nic_seq, tap in enumerate(taps):
1720 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1721 data=tap)
1722
1723 if vnc_pwd:
1724 change_cmd = "change vnc password %s" % vnc_pwd
1725 self._CallMonitorCommand(instance.name, change_cmd)
1726
1727 # Setting SPICE password. We are not vulnerable to malicious passwordless
1728 # connection attempts because SPICE by default does not allow connections
1729 # if neither a password nor the "disable_ticketing" options are specified.
1730 # As soon as we send the password via QMP, that password is a valid ticket
1731 # for connection.
1732 spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1733 if spice_password_file:
1734 spice_pwd = ""
1735 try:
1736 spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1737 except EnvironmentError, err:
1738 raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1739 % (spice_password_file, err))
1740
1741 qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1742 qmp.connect()
1743 arguments = {
1744 "protocol": "spice",
1745 "password": spice_pwd,
1746 }
1747 qmp.Execute("set_password", arguments)
1748
1749 for filename in temp_files:
1750 utils.RemoveFile(filename)
1751
1752 # If requested, set CPU affinity and resume instance execution
1753 if cpu_pinning:
1754 self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1755
1756 start_memory = self._InstanceStartupMemory(instance)
1757 if start_memory < instance.beparams[constants.BE_MAXMEM]:
1758 self.BalloonInstanceMemory(instance, start_memory)
1759
1760 if start_kvm_paused:
1761 # To control CPU pinning, ballooning, and vnc/spice passwords
1762 # the VM was started in a frozen state. If freezing was not
1763 # explicitly requested resume the vm status.
1764 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1765
1766 @staticmethod
1767 def _StartKvmd(hvparams):
1768 """Ensure that the Kvm daemon is running.
1769
1770 @type hvparams: dict of strings
1771 @param hvparams: hypervisor parameters
1772
1773 """
1774 if hvparams is None \
1775 or not hvparams[constants.HV_KVM_USER_SHUTDOWN] \
1776 or utils.IsDaemonAlive(constants.KVMD):
1777 return
1778
1779 result = utils.RunCmd([pathutils.DAEMON_UTIL, "start", constants.KVMD])
1780
1781 if result.failed:
1782 raise errors.HypervisorError("Failed to start KVM daemon")
1783
1784 def StartInstance(self, instance, block_devices, startup_paused):
1785 """Start an instance.
1786
1787 """
1788 self._CheckDown(instance.name)
1789 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1790 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1791 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1792 startup_paused, kvmhelp)
1793 self._SaveKVMRuntime(instance, kvm_runtime)
1794 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1795
1796 @classmethod
1797 def _CallMonitorCommand(cls, instance_name, command, timeout=None):
1798 """Invoke a command on the instance monitor.
1799
1800 """
1801 if timeout is not None:
1802 timeout_cmd = "timeout %s" % (timeout, )
1803 else:
1804 timeout_cmd = ""
1805
1806 # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1807 # version. The monitor protocol is designed for human consumption, whereas
1808 # QMP is made for programmatic usage. In the worst case QMP can also
1809 # execute monitor commands. As it is, all calls to socat take at least
1810 # 500ms and likely more: socat can't detect the end of the reply and waits
1811 # for 500ms of no data received before exiting (500 ms is the default for
1812 # the "-t" parameter).
1813 socat = ("echo %s | %s %s STDIO UNIX-CONNECT:%s" %
1814 (utils.ShellQuote(command),
1815 timeout_cmd,
1816 constants.SOCAT_PATH,
1817 utils.ShellQuote(cls._InstanceMonitor(instance_name))))
1818 result = utils.RunCmd(socat)
1819 if result.failed:
1820 msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1821 " output: %s" %
1822 (command, instance_name, result.fail_reason, result.output))
1823 raise errors.HypervisorError(msg)
1824
1825 return result
1826
1827 @_with_qmp
1828 def VerifyHotplugSupport(self, instance, action, dev_type):
1829 """Verifies that hotplug is supported.
1830
1831 @raise errors.HypervisorError: in one of the previous cases
1832
1833 """
1834 if dev_type == constants.HOTPLUG_TARGET_DISK:
1835 if action == constants.HOTPLUG_ACTION_ADD:
1836 self.qmp.CheckDiskHotAddSupport()
1837 if dev_type == constants.HOTPLUG_TARGET_NIC:
1838 if action == constants.HOTPLUG_ACTION_ADD:
1839 self.qmp.CheckNicHotAddSupport()
1840
1841 def HotplugSupported(self, instance):
1842 """Checks if hotplug is generally supported.
1843
1844 Hotplug is *not* supported in case of:
1845 - qemu versions < 1.7 (where all qmp related commands are supported)
1846 - for stopped instances
1847
1848 @raise errors.HypervisorError: in one of the previous cases
1849
1850 """
1851 try:
1852 output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
1853 except errors.HypervisorError:
1854 raise errors.HotplugError("Instance is probably down")
1855
1856 match = self._INFO_VERSION_RE.search(output.stdout)
1857 if not match:
1858 raise errors.HotplugError("Cannot parse qemu version via monitor")
1859
1860 #TODO: delegate more fine-grained checks to VerifyHotplugSupport
1861 v_major, v_min, _, _ = match.groups()
1862 if (int(v_major), int(v_min)) < (1, 7):
1863 raise errors.HotplugError("Hotplug not supported for qemu versions < 1.7")
1864
1865 @_with_qmp
1866 def _VerifyHotplugCommand(self, _instance,
1867 device, kvm_devid, should_exist):
1868 """Checks if a previous hotplug command has succeeded.
1869
1870 Depending on the should_exist value, verifies that an entry identified by
1871 the PCI slot and device ID is present or not.
1872
1873 @raise errors.HypervisorError: if result is not the expected one
1874
1875 """
1876 for i in range(5):
1877 found = self.qmp.HasPCIDevice(device, kvm_devid)
1878 logging.info("Verifying hotplug command (retry %s): %s", i, found)
1879 if found and should_exist:
1880 break
1881 if not found and not should_exist:
1882 break
1883 time.sleep(1)
1884
1885 if found and not should_exist:
1886 msg = "Device %s should have been removed but is still there" % kvm_devid
1887 raise errors.HypervisorError(msg)
1888
1889 if not found and should_exist:
1890 msg = "Device %s should have been added but is missing" % kvm_devid
1891 raise errors.HypervisorError(msg)
1892
1893 logging.info("Device %s has been correctly hot-plugged", kvm_devid)
1894
1895 @_with_qmp
1896 def HotAddDevice(self, instance, dev_type, device, extra, seq):
1897 """ Helper method to hot-add a new device
1898
1899 It gets free pci slot generates the device name and invokes the
1900 device specific method.
1901
1902 """
1903 # in case of hot-mod this is given
1904 if device.pci is None:
1905 device.pci = self.qmp.GetFreePCISlot()
1906 kvm_devid = _GenerateDeviceKVMId(dev_type, device)
1907 runtime = self._LoadKVMRuntime(instance)
1908 if dev_type == constants.HOTPLUG_TARGET_DISK:
1909 uri = _GetDriveURI(device, extra[0], extra[1])
1910 self.qmp.HotAddDisk(device, kvm_devid, uri)
1911 elif dev_type == constants.HOTPLUG_TARGET_NIC:
1912 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1913 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1914 devlist = self._GetKVMOutput(kvmpath, self._KVMOPT_DEVICELIST)
1915 up_hvp = runtime[2]
1916 features, _, _ = self._GetNetworkDeviceFeatures(up_hvp, devlist, kvmhelp)
1917 (tap, tapfds, vhostfds) = OpenTap(features=features)
1918 self._ConfigureNIC(instance, seq, device, tap)
1919 self.qmp.HotAddNic(device, kvm_devid, tapfds, vhostfds, features)
1920 utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
1921
1922 self._VerifyHotplugCommand(instance, device, kvm_devid, True)
1923 # update relevant entries in runtime file
1924 index = _DEVICE_RUNTIME_INDEX[dev_type]
1925 entry = _RUNTIME_ENTRY[dev_type](device, extra)
1926 runtime[index].append(entry)
1927 self._SaveKVMRuntime(instance, runtime)
1928
1929 @_with_qmp
1930 def HotDelDevice(self, instance, dev_type, device, _, seq):
1931 """ Helper method for hot-del device
1932
1933 It gets device info from runtime file, generates the device name and
1934 invokes the device specific method.
1935
1936 """
1937 runtime = self._LoadKVMRuntime(instance)
1938 entry = _GetExistingDeviceInfo(dev_type, device, runtime)
1939 kvm_device = _RUNTIME_DEVICE[dev_type](entry)
1940 kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
1941 if dev_type == constants.HOTPLUG_TARGET_DISK:
1942 self.qmp.HotDelDisk(kvm_devid)
1943 # drive_del is not implemented yet in qmp
1944 command = "drive_del %s\n" % kvm_devid
1945 self._CallMonitorCommand(instance.name, command)
1946 elif dev_type == constants.HOTPLUG_TARGET_NIC:
1947 self.qmp.HotDelNic(kvm_devid)
1948 utils.RemoveFile(self._InstanceNICFile(instance.name, seq))
1949 self._VerifyHotplugCommand(instance, kvm_device, kvm_devid, False)
1950 index = _DEVICE_RUNTIME_INDEX[dev_type]
1951 runtime[index].remove(entry)
1952 self._SaveKVMRuntime(instance, runtime)
1953
1954 return kvm_device.pci
1955
1956 def HotModDevice(self, instance, dev_type, device, _, seq):
1957 """ Helper method for hot-mod device
1958
1959 It gets device info from runtime file, generates the device name and
1960 invokes the device specific method. Currently only NICs support hot-mod
1961
1962 """
1963 if dev_type == constants.HOTPLUG_TARGET_NIC:
1964 # putting it back in the same pci slot
1965 device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
1966 self.HotAddDevice(instance, dev_type, device, _, seq)
1967
1968 @classmethod
1969 def _ParseKVMVersion(cls, text):
1970 """Parse the KVM version from the --help output.
1971
1972 @type text: string
1973 @param text: output of kvm --help
1974 @return: (version, v_maj, v_min, v_rev)
1975 @raise errors.HypervisorError: when the KVM version cannot be retrieved
1976
1977 """
1978 match = cls._VERSION_RE.search(text.splitlines()[0])
1979 if not match:
1980 raise errors.HypervisorError("Unable to get KVM version")
1981
1982 v_all = match.group(0)
1983 v_maj = int(match.group(1))
1984 v_min = int(match.group(2))
1985 if match.group(4):
1986 v_rev = int(match.group(4))
1987 else:
1988 v_rev = 0
1989 return (v_all, v_maj, v_min, v_rev)
1990
1991 @classmethod
1992 def _GetKVMOutput(cls, kvm_path, option):
1993 """Return the output of a kvm invocation
1994
1995 @type kvm_path: string
1996 @param kvm_path: path to the kvm executable
1997 @type option: a key of _KVMOPTS_CMDS
1998 @param option: kvm option to fetch the output from
1999 @return: output a supported kvm invocation
2000 @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2001
2002 """
2003 assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2004
2005 optlist, can_fail = cls._KVMOPTS_CMDS[option]
2006
2007 result = utils.RunCmd([kvm_path] + optlist)
2008 if result.failed and not can_fail:
2009 raise errors.HypervisorError("Unable to get KVM %s output" %
2010 " ".join(optlist))
2011 return result.output
2012
2013 @classmethod
2014 def _GetKVMVersion(cls, kvm_path):
2015 """Return the installed KVM version.
2016
2017 @return: (version, v_maj, v_min, v_rev)
2018 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2019
2020 """
2021 return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2022
2023 @classmethod
2024 def _GetDefaultMachineVersion(cls, kvm_path):
2025 """Return the default hardware revision (e.g. pc-1.1)
2026
2027 """
2028 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2029 match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2030 if match:
2031 return match.group(1)
2032 else:
2033 return "pc"
2034
2035 @classmethod
2036 def _StopInstance(cls, instance, force=False, name=None, timeout=None):
2037 """Stop an instance.
2038
2039 """
2040 assert(timeout is None or force is not None)
2041
2042 if name is not None and not force:
2043 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2044 if name is None:
2045 name = instance.name
2046 acpi = instance.hvparams[constants.HV_ACPI]
2047 else:
2048 acpi = False
2049 _, pid, alive = cls._InstancePidAlive(name)
2050 if pid > 0 and alive:
2051 if force or not acpi:
2052 utils.KillProcess(pid)
2053 else:
2054 cls._CallMonitorCommand(name, "system_powerdown", timeout)
2055 cls._ClearUserShutdown(instance.name)
2056
2057 def StopInstance(self, instance, force=False, retry=False, name=None,
2058 timeout=None):
2059 """Stop an instance.
2060
2061 """
2062 self._StopInstance(instance, force, name=name, timeout=timeout)
2063
2064 def CleanupInstance(self, instance_name):
2065 """Cleanup after a stopped instance
2066
2067 """
2068 pidfile, pid, alive = self._InstancePidAlive(instance_name)
2069 if pid > 0 and alive:
2070 raise errors.HypervisorError("Cannot cleanup a live instance")
2071 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2072 self._ClearUserShutdown(instance_name)
2073
2074 def RebootInstance(self, instance):
2075 """Reboot an instance.
2076
2077 """
2078 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2079 # socket the instance will stop, but now power up again. So we'll resort
2080 # to shutdown and restart.
2081 _, _, alive = self._InstancePidAlive(instance.name)
2082 if not alive:
2083 raise errors.HypervisorError("Failed to reboot instance %s:"
2084 " not running" % instance.name)
2085 # StopInstance will delete the saved KVM runtime so:
2086 # ...first load it...
2087 kvm_runtime = self._LoadKVMRuntime(instance)
2088 # ...now we can safely call StopInstance...
2089 if not self.StopInstance(instance):
2090 self.StopInstance(instance, force=True)
2091 # ...and finally we can save it again, and execute it...
2092 self._SaveKVMRuntime(instance, kvm_runtime)
2093 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2094 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2095 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2096
2097 def MigrationInfo(self, instance):
2098 """Get instance information to perform a migration.
2099
2100 @type instance: L{objects.Instance}
2101 @param instance: instance to be migrated
2102 @rtype: string
2103 @return: content of the KVM runtime file
2104
2105 """
2106 return self._ReadKVMRuntime(instance.name)
2107
2108 def AcceptInstance(self, instance, info, target):
2109 """Prepare to accept an instance.
2110
2111 @type instance: L{objects.Instance}
2112 @param instance: instance to be accepted
2113 @type info: string
2114 @param info: content of the KVM runtime file on the source node
2115 @type target: string
2116 @param target: target host (usually ip), on this node
2117
2118 """
2119 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2120 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2121 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2122 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2123 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2124 incoming=incoming_address)
2125
2126 def FinalizeMigrationDst(self, instance, info, success):
2127 """Finalize the instance migration on the target node.
2128
2129 Stop the incoming mode KVM.
2130
2131 @type instance: L{objects.Instance}
2132 @param instance: instance whose migration is being finalized
2133
2134 """
2135 if success:
2136 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2137 kvm_nics = kvm_runtime[1]
2138
2139 for nic_seq, nic in enumerate(kvm_nics):
2140 if nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_ROUTED:
2141 # Bridged/OVS interfaces have already been configured
2142 continue
2143 try:
2144 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2145 except EnvironmentError, err:
2146 logging.warning("Failed to find host interface for %s NIC #%d: %s",
2147 instance.name, nic_seq, str(err))
2148 continue
2149 try:
2150 self._ConfigureNIC(instance, nic_seq, nic, tap)
2151 except errors.HypervisorError, err:
2152 logging.warning(str(err))
2153
2154 self._WriteKVMRuntime(instance.name, info)
2155 else:
2156 self.StopInstance(instance, force=True)
2157
2158 def MigrateInstance(self, cluster_name, instance, target, live):
2159 """Migrate an instance to a target node.
2160
2161 The migration will not be attempted if the instance is not
2162 currently running.
2163
2164 @type cluster_name: string
2165 @param cluster_name: name of the cluster
2166 @type instance: L{objects.Instance}
2167 @param instance: the instance to be migrated
2168 @type target: string
2169 @param target: ip address of the target node
2170 @type live: boolean
2171 @param live: perform a live migration
2172
2173 """
2174 instance_name = instance.name
2175 port = instance.hvparams[constants.HV_MIGRATION_PORT]
2176 _, _, alive = self._InstancePidAlive(instance_name)
2177 if not alive:
2178 raise errors.HypervisorError("Instance not running, cannot migrate")
2179
2180 if not live:
2181 self._CallMonitorCommand(instance_name, "stop")
2182
2183 migrate_command = ("migrate_set_speed %dm" %
2184 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2185 self._CallMonitorCommand(instance_name, migrate_command)
2186
2187 migrate_command = ("migrate_set_downtime %dms" %
2188 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2189 self._CallMonitorCommand(instance_name, migrate_command)
2190
2191 migration_caps = instance.hvparams[constants.HV_KVM_MIGRATION_CAPS]
2192 if migration_caps:
2193 for c in migration_caps.split(_MIGRATION_CAPS_DELIM):
2194 migrate_command = ("migrate_set_capability %s on" % c)
2195 self._CallMonitorCommand(instance_name, migrate_command)
2196
2197 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2198 self._CallMonitorCommand(instance_name, migrate_command)
2199
2200 def FinalizeMigrationSource(self, instance, success, live):
2201 """Finalize the instance migration on the source node.
2202
2203 @type instance: L{objects.Instance}
2204 @param instance: the instance that was migrated
2205 @type success: bool
2206 @param success: whether the migration succeeded or not
2207 @type live: bool
2208 @param live: whether the user requested a live migration or not
2209
2210 """
2211 if success:
2212 pidfile, pid, _ = self._InstancePidAlive(instance.name)
2213 utils.KillProcess(pid)
2214 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2215 elif live:
2216 self._CallMonitorCommand(instance.name, self._CONT_CMD)
2217 self._ClearUserShutdown(instance.name)
2218
2219 def GetMigrationStatus(self, instance):
2220 """Get the migration status
2221
2222 @type instance: L{objects.Instance}
2223 @param instance: the instance that is being migrated
2224 @rtype: L{objects.MigrationStatus}
2225 @return: the status of the current migration (one of
2226 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2227 progress info that can be retrieved from the hypervisor
2228
2229 """
2230 info_command = "info migrate"
2231 for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2232 result = self._CallMonitorCommand(instance.name, info_command)
2233 match = self._MIGRATION_STATUS_RE.search(result.stdout)
2234 if not match:
2235 if not result.stdout:
2236 logging.info("KVM: empty 'info migrate' result")
2237 else:
2238 logging.warning("KVM: unknown 'info migrate' result: %s",
2239 result.stdout)
2240 else:
2241 status = match.group(1)
2242 if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2243 migration_status = objects.MigrationStatus(status=status)
2244 match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2245 if match:
2246 migration_status.transferred_ram = match.group("transferred")
2247 migration_status.total_ram = match.group("total")
2248
2249 return migration_status
2250
2251 logging.warning("KVM: unknown migration status '%s'", status)
2252
2253 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2254
2255 return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2256
2257 def BalloonInstanceMemory(self, instance, mem):
2258 """Balloon an instance memory to a certain value.
2259
2260 @type instance: L{objects.Instance}
2261 @param instance: instance to be accepted
2262 @type mem: int
2263 @param mem: actual memory size to use for instance runtime
2264
2265 """
2266 self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2267
2268 def GetNodeInfo(self, hvparams=None):
2269 """Return information about the node.
2270
2271 @type hvparams: dict of strings
2272 @param hvparams: hypervisor parameters, not used in this class
2273
2274 @return: a dict as returned by L{BaseHypervisor.GetLinuxNodeInfo} plus
2275 the following keys:
2276 - hv_version: the hypervisor version in the form (major, minor,
2277 revision)
2278
2279 """
2280 result = self.GetLinuxNodeInfo()
2281 kvmpath = constants.KVM_PATH
2282 if hvparams is not None:
2283 kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2284 _, v_major, v_min, v_rev = self._GetKVMVersion(kvmpath)
2285 result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2286 return result
2287
2288 @classmethod
2289 def GetInstanceConsole(cls, instance, primary_node, node_group,
2290 hvparams, beparams):
2291 """Return a command for connecting to the console of an instance.
2292
2293 """
2294 if hvparams[constants.HV_SERIAL_CONSOLE]:
2295 cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2296 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2297 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2298 "STDIO,%s" % cls._SocatUnixConsoleParams(),
2299 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2300 ndparams = node_group.FillND(primary_node)
2301 return objects.InstanceConsole(instance=instance.name,
2302 kind=constants.CONS_SSH,
2303 host=primary_node.name,
2304 port=ndparams.get(constants.ND_SSH_PORT),
2305 user=constants.SSH_CONSOLE_USER,
2306 command=cmd)
2307
2308 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2309 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2310 display = instance.network_port - constants.VNC_BASE_PORT
2311 return objects.InstanceConsole(instance=instance.name,
2312 kind=constants.CONS_VNC,
2313 host=vnc_bind_address,
2314 port=instance.network_port,
2315 display=display)
2316
2317 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2318 if spice_bind:
2319 return objects.InstanceConsole(instance=instance.name,
2320 kind=constants.CONS_SPICE,
2321 host=spice_bind,
2322 port=instance.network_port)
2323
2324 return objects.InstanceConsole(instance=instance.name,
2325 kind=constants.CONS_MESSAGE,
2326 message=("No serial shell for instance %s" %
2327 instance.name))
2328
2329 def Verify(self, hvparams=None):
2330 """Verify the hypervisor.
2331
2332 Check that the required binaries exist.
2333
2334 @type hvparams: dict of strings
2335 @param hvparams: hypervisor parameters to be verified against, not used here
2336
2337 @return: Problem description if something is wrong, C{None} otherwise
2338
2339 """
2340 msgs = []
2341 kvmpath = constants.KVM_PATH
2342 if hvparams is not None:
2343 kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2344 if not os.path.exists(kvmpath):
2345 msgs.append("The KVM binary ('%s') does not exist" % kvmpath)
2346 if not os.path.exists(constants.SOCAT_PATH):
2347 msgs.append("The socat binary ('%s') does not exist" %
2348 constants.SOCAT_PATH)
2349
2350 return self._FormatVerifyResults(msgs)
2351
2352 @classmethod
2353 def CheckParameterSyntax(cls, hvparams):
2354 """Check the given parameters for validity.
2355
2356 @type hvparams: dict of strings
2357 @param hvparams: hypervisor parameters
2358 @raise errors.HypervisorError: when a parameter is not valid
2359
2360 """
2361 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2362
2363 kernel_path = hvparams[constants.HV_KERNEL_PATH]
2364 if kernel_path:
2365 if not hvparams[constants.HV_ROOT_PATH]:
2366 raise errors.HypervisorError("Need a root partition for the instance,"
2367 " if a kernel is defined")
2368
2369 if (hvparams[constants.HV_VNC_X509_VERIFY] and
2370 not hvparams[constants.HV_VNC_X509]):
2371 raise errors.HypervisorError("%s must be defined, if %s is" %
2372 (constants.HV_VNC_X509,
2373 constants.HV_VNC_X509_VERIFY))
2374
2375 if hvparams[constants.HV_SERIAL_CONSOLE]:
2376 serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2377 valid_speeds = constants.VALID_SERIAL_SPEEDS
2378 if not serial_speed or serial_speed not in valid_speeds:
2379 raise errors.HypervisorError("Invalid serial console speed, must be"
2380 " one of: %s" %
2381 utils.CommaJoin(valid_speeds))
2382
2383 boot_order = hvparams[constants.HV_BOOT_ORDER]
2384 if (boot_order == constants.HT_BO_CDROM and
2385 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2386 raise errors.HypervisorError("Cannot boot from cdrom without an"
2387 " ISO path")
2388
2389 security_model = hvparams[constants.HV_SECURITY_MODEL]
2390 if security_model == constants.HT_SM_USER:
2391 if not hvparams[constants.HV_SECURITY_DOMAIN]:
2392 raise errors.HypervisorError("A security domain (user to run kvm as)"
2393 " must be specified")
2394 elif (security_model == constants.HT_SM_NONE or
2395 security_model == constants.HT_SM_POOL):
2396 if hvparams[constants.HV_SECURITY_DOMAIN]:
2397 raise errors.HypervisorError("Cannot have a security domain when the"
2398 " security model is 'none' or 'pool'")
2399
2400 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2401 spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2402 if spice_bind:
2403 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2404 # if an IP version is specified, the spice_bind parameter must be an
2405 # IP of that family
2406 if (netutils.IP4Address.IsValid(spice_bind) and
2407 spice_ip_version != constants.IP4_VERSION):
2408 raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2409 " the specified IP version is %s" %
2410 (spice_bind, spice_ip_version))
2411
2412 if (netutils.IP6Address.IsValid(spice_bind) and
2413 spice_ip_version != constants.IP6_VERSION):
2414 raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2415 " the specified IP version is %s" %
2416 (spice_bind, spice_ip_version))
2417 else:
2418 # All the other SPICE parameters depend on spice_bind being set. Raise an
2419 # error if any of them is set without it.
2420 for param in _SPICE_ADDITIONAL_PARAMS:
2421 if hvparams[param]:
2422 raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2423 (param, constants.HV_KVM_SPICE_BIND))
2424
2425 @classmethod
2426 def ValidateParameters(cls, hvparams):
2427 """Check the given parameters for validity.
2428
2429 @type hvparams: dict of strings
2430 @param hvparams: hypervisor parameters
2431 @raise errors.HypervisorError: when a parameter is not valid
2432
2433 """
2434 super(KVMHypervisor, cls).ValidateParameters(hvparams)
2435
2436 kvm_path = hvparams[constants.HV_KVM_PATH]
2437
2438 security_model = hvparams[constants.HV_SECURITY_MODEL]
2439 if security_model == constants.HT_SM_USER:
2440 username = hvparams[constants.HV_SECURITY_DOMAIN]
2441 try:
2442 pwd.getpwnam(username)
2443 except KeyError:
2444 raise errors.HypervisorError("Unknown security domain user %s"
2445 % username)
2446 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2447 if vnc_bind_address:
2448 bound_to_addr = netutils.IP4Address.IsValid(vnc_bind_address)
2449 is_interface = netutils.IsValidInterface(vnc_bind_address)
2450 is_path = utils.IsNormAbsPath(vnc_bind_address)
2451 if not bound_to_addr and not is_interface and not is_path:
2452 raise errors.HypervisorError("VNC: The %s parameter must be either"
2453 " a valid IP address, an interface name,"
2454 " or an absolute path" %
2455 constants.HV_KVM_SPICE_BIND)
2456
2457 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2458 if spice_bind:
2459 # only one of VNC and SPICE can be used currently.
2460 if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2461 raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2462 " only one of them can be used at a"
2463 " given time")
2464
2465 # check that KVM supports SPICE
2466 kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2467 if not cls._SPICE_RE.search(kvmhelp):
2468 raise errors.HypervisorError("SPICE is configured, but it is not"
2469 " supported according to 'kvm --help'")
2470
2471 # if spice_bind is not an IP address, it must be a valid interface
2472 bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2473 netutils.IP6Address.IsValid(spice_bind))
2474 if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2475 raise errors.HypervisorError("SPICE: The %s parameter must be either"
2476 " a valid IP address or interface name" %
2477 constants.HV_KVM_SPICE_BIND)
2478
2479 machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2480 if machine_version:
2481 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2482 if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2483 raise errors.HypervisorError("Unsupported machine version: %s" %
2484 machine_version)
2485
2486 @classmethod
2487 def PowercycleNode(cls, hvparams=None):
2488 """KVM powercycle, just a wrapper over Linux powercycle.
2489
2490 @type hvparams: dict of strings
2491 @param hvparams: hypervisor parameters to be used on this node
2492
2493 """
2494 cls.LinuxPowercycle()