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