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