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