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