QMP: always return the command result
[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 _GenerateTapName(nic):
1466 """Generate a TAP network interface name for a NIC.
1467
1468 This helper function generates a special TAP network interface
1469 name for NICs that are meant to be used in instance communication.
1470 This function checks the existing TAP interfaces in order to find
1471 a unique name for the new TAP network interface. The TAP network
1472 interface names are of the form 'gnt.com.%d', where '%d' is a
1473 unique number within the node.
1474
1475 @type nic: ganeti.objects.NIC
1476 @param nic: NIC object for the name should be generated
1477
1478 @rtype: string
1479 @return: TAP network interface name, or the empty string if the
1480 NIC is not used in instance communication
1481
1482 """
1483 if nic.name is None or not \
1484 nic.name.startswith(constants.INSTANCE_COMMUNICATION_NIC_PREFIX):
1485 return ""
1486
1487 result = utils.RunCmd(["ip", "tuntap", "list"])
1488
1489 if result.failed:
1490 raise errors.HypervisorError("Failed to list TUN/TAP interfaces")
1491
1492 idxs = set()
1493
1494 for line in result.output.splitlines():
1495 parts = line.split(": ", 1)
1496
1497 if len(parts) < 2:
1498 raise errors.HypervisorError("Failed to parse TUN/TAP interfaces")
1499
1500 r = re.match(r"gnt\.com\.([0-9]+)", parts[0])
1501
1502 if r is not None:
1503 idxs.add(int(r.group(1)))
1504
1505 if idxs:
1506 idx = max(idxs) + 1
1507 else:
1508 idx = 0
1509
1510 return "gnt.com.%d" % idx
1511
1512 # too many local variables
1513 # pylint: disable=R0914
1514 def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1515 """Execute a KVM cmd, after completing it with some last minute data.
1516
1517 @type incoming: tuple of strings
1518 @param incoming: (target_host_ip, port)
1519 @type kvmhelp: string
1520 @param kvmhelp: output of kvm --help
1521
1522 """
1523 # Small _ExecuteKVMRuntime hv parameters programming howto:
1524 # - conf_hvp contains the parameters as configured on ganeti. they might
1525 # have changed since the instance started; only use them if the change
1526 # won't affect the inside of the instance (which hasn't been rebooted).
1527 # - up_hvp contains the parameters as they were when the instance was
1528 # started, plus any new parameter which has been added between ganeti
1529 # versions: it is paramount that those default to a value which won't
1530 # affect the inside of the instance as well.
1531 conf_hvp = instance.hvparams
1532 name = instance.name
1533 self._CheckDown(name)
1534
1535 self._ClearUserShutdown(instance.name)
1536 self._StartKvmd(instance.hvparams)
1537
1538 temp_files = []
1539
1540 kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1541 # the first element of kvm_cmd is always the path to the kvm binary
1542 kvm_path = kvm_cmd[0]
1543 up_hvp = objects.FillDict(conf_hvp, up_hvp)
1544
1545 # We know it's safe to run as a different user upon migration, so we'll use
1546 # the latest conf, from conf_hvp.
1547 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1548 if security_model == constants.HT_SM_USER:
1549 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1550
1551 keymap = conf_hvp[constants.HV_KEYMAP]
1552 if keymap:
1553 keymap_path = self._InstanceKeymapFile(name)
1554 # If a keymap file is specified, KVM won't use its internal defaults. By
1555 # first including the "en-us" layout, an error on loading the actual
1556 # layout (e.g. because it can't be found) won't lead to a non-functional
1557 # keyboard. A keyboard with incorrect keys is still better than none.
1558 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1559 kvm_cmd.extend(["-k", keymap_path])
1560
1561 # We have reasons to believe changing something like the nic driver/type
1562 # upon migration won't exactly fly with the instance kernel, so for nic
1563 # related parameters we'll use up_hvp
1564 tapfds = []
1565 taps = []
1566 devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1567 if not kvm_nics:
1568 kvm_cmd.extend(["-net", "none"])
1569 else:
1570 vnet_hdr = False
1571 tap_extra = ""
1572 nic_type = up_hvp[constants.HV_NIC_TYPE]
1573 if nic_type == constants.HT_NIC_PARAVIRTUAL:
1574 nic_model = self._VIRTIO
1575 try:
1576 if self._VIRTIO_NET_RE.search(devlist):
1577 nic_model = self._VIRTIO_NET_PCI
1578 vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1579 except errors.HypervisorError, _:
1580 # Older versions of kvm don't support DEVICE_LIST, but they don't
1581 # have new virtio syntax either.
1582 pass
1583
1584 if up_hvp[constants.HV_VHOST_NET]:
1585 # check for vhost_net support
1586 if self._VHOST_RE.search(kvmhelp):
1587 tap_extra = ",vhost=on"
1588 else:
1589 raise errors.HypervisorError("vhost_net is configured"
1590 " but it is not available")
1591 else:
1592 nic_model = nic_type
1593
1594 kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1595
1596 for nic_seq, nic in enumerate(kvm_nics):
1597 tapname, tapfd = OpenTap(vnet_hdr=vnet_hdr,
1598 name=self._GenerateTapName(nic))
1599 tapfds.append(tapfd)
1600 taps.append(tapname)
1601 if kvm_supports_netdev:
1602 nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1603 try:
1604 # kvm_nics already exist in old runtime files and thus there might
1605 # be some entries without pci slot (therefore try: except:)
1606 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1607 netdev = kvm_devid
1608 nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1609 except errors.HotplugError:
1610 netdev = "netdev%d" % nic_seq
1611 nic_val += (",netdev=%s" % netdev)
1612 tap_val = ("type=tap,id=%s,fd=%d%s" %
1613 (netdev, tapfd, tap_extra))
1614 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1615 else:
1616 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1617 nic.mac, nic_model)
1618 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1619 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1620
1621 if incoming:
1622 target, port = incoming
1623 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1624
1625 # Changing the vnc password doesn't bother the guest that much. At most it
1626 # will surprise people who connect to it. Whether positively or negatively
1627 # it's debatable.
1628 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1629 vnc_pwd = None
1630 if vnc_pwd_file:
1631 try:
1632 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1633 except EnvironmentError, err:
1634 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1635 % (vnc_pwd_file, err))
1636
1637 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1638 utils.EnsureDirs([(self._InstanceChrootDir(name),
1639 constants.SECURE_DIR_MODE)])
1640
1641 # Automatically enable QMP if version is >= 0.14
1642 if self._QMP_RE.search(kvmhelp):
1643 logging.debug("Enabling QMP")
1644 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1645 self._InstanceQmpMonitor(instance.name)])
1646
1647 # Configure the network now for starting instances and bridged interfaces,
1648 # during FinalizeMigration for incoming instances' routed interfaces
1649 for nic_seq, nic in enumerate(kvm_nics):
1650 if (incoming and
1651 nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1652 continue
1653 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1654
1655 bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1656 up_hvp,
1657 kvm_disks,
1658 kvmhelp,
1659 devlist)
1660 kvm_cmd.extend(bdev_opts)
1661 # CPU affinity requires kvm to start paused, so we set this flag if the
1662 # instance is not already paused and if we are not going to accept a
1663 # migrating instance. In the latter case, pausing is not needed.
1664 start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1665 if start_kvm_paused:
1666 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1667
1668 # Note: CPU pinning is using up_hvp since changes take effect
1669 # during instance startup anyway, and to avoid problems when soft
1670 # rebooting the instance.
1671 cpu_pinning = False
1672 if up_hvp.get(constants.HV_CPU_MASK, None):
1673 cpu_pinning = True
1674
1675 if security_model == constants.HT_SM_POOL:
1676 ss = ssconf.SimpleStore()
1677 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1678 all_uids = set(uidpool.ExpandUidPool(uid_pool))
1679 uid = uidpool.RequestUnusedUid(all_uids)
1680 try:
1681 username = pwd.getpwuid(uid.GetUid()).pw_name
1682 kvm_cmd.extend(["-runas", username])
1683 self._RunKVMCmd(name, kvm_cmd, tapfds)
1684 except:
1685 uidpool.ReleaseUid(uid)
1686 raise
1687 else:
1688 uid.Unlock()
1689 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1690 else:
1691 self._RunKVMCmd(name, kvm_cmd, tapfds)
1692
1693 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1694 constants.RUN_DIRS_MODE)])
1695 for nic_seq, tap in enumerate(taps):
1696 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1697 data=tap)
1698
1699 if vnc_pwd:
1700 change_cmd = "change vnc password %s" % vnc_pwd
1701 self._CallMonitorCommand(instance.name, change_cmd)
1702
1703 # Setting SPICE password. We are not vulnerable to malicious passwordless
1704 # connection attempts because SPICE by default does not allow connections
1705 # if neither a password nor the "disable_ticketing" options are specified.
1706 # As soon as we send the password via QMP, that password is a valid ticket
1707 # for connection.
1708 spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1709 if spice_password_file:
1710 spice_pwd = ""
1711 try:
1712 spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1713 except EnvironmentError, err:
1714 raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1715 % (spice_password_file, err))
1716
1717 qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1718 qmp.connect()
1719 arguments = {
1720 "protocol": "spice",
1721 "password": spice_pwd,
1722 }
1723 qmp.Execute("set_password", arguments)
1724
1725 for filename in temp_files:
1726 utils.RemoveFile(filename)
1727
1728 # If requested, set CPU affinity and resume instance execution
1729 if cpu_pinning:
1730 self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1731
1732 start_memory = self._InstanceStartupMemory(instance)
1733 if start_memory < instance.beparams[constants.BE_MAXMEM]:
1734 self.BalloonInstanceMemory(instance, start_memory)
1735
1736 if start_kvm_paused:
1737 # To control CPU pinning, ballooning, and vnc/spice passwords
1738 # the VM was started in a frozen state. If freezing was not
1739 # explicitly requested resume the vm status.
1740 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1741
1742 @staticmethod
1743 def _StartKvmd(hvparams):
1744 """Ensure that the Kvm daemon is running.
1745
1746 """
1747 if hvparams is None \
1748 or not hvparams[constants.HV_KVM_USER_SHUTDOWN] \
1749 or utils.IsDaemonAlive(constants.KVMD):
1750 return
1751
1752 result = utils.RunCmd(constants.KVMD)
1753
1754 if result.failed:
1755 raise errors.HypervisorError("Failed to start KVM daemon")
1756
1757 def StartInstance(self, instance, block_devices, startup_paused):
1758 """Start an instance.
1759
1760 """
1761 self._CheckDown(instance.name)
1762 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1763 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1764 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1765 startup_paused, kvmhelp)
1766 self._SaveKVMRuntime(instance, kvm_runtime)
1767 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1768
1769 @classmethod
1770 def _CallMonitorCommand(cls, instance_name, command, timeout=None):
1771 """Invoke a command on the instance monitor.
1772
1773 """
1774 if timeout is not None:
1775 timeout_cmd = "timeout %s" % (timeout, )
1776 else:
1777 timeout_cmd = ""
1778
1779 # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1780 # version. The monitor protocol is designed for human consumption, whereas
1781 # QMP is made for programmatic usage. In the worst case QMP can also
1782 # execute monitor commands. As it is, all calls to socat take at least
1783 # 500ms and likely more: socat can't detect the end of the reply and waits
1784 # for 500ms of no data received before exiting (500 ms is the default for
1785 # the "-t" parameter).
1786 socat = ("echo %s | %s %s STDIO UNIX-CONNECT:%s" %
1787 (utils.ShellQuote(command),
1788 timeout_cmd,
1789 constants.SOCAT_PATH,
1790 utils.ShellQuote(cls._InstanceMonitor(instance_name))))
1791 result = utils.RunCmd(socat)
1792 if result.failed:
1793 msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1794 " output: %s" %
1795 (command, instance_name, result.fail_reason, result.output))
1796 raise errors.HypervisorError(msg)
1797
1798 return result
1799
1800 def _GetFreePCISlot(self, instance, dev):
1801 """Get the first available pci slot of a runnung instance.
1802
1803 """
1804 slots = bitarray(32)
1805 slots.setall(False) # pylint: disable=E1101
1806 output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
1807 for line in output.stdout.splitlines():
1808 match = self._INFO_PCI_RE.search(line)
1809 if match:
1810 slot = int(match.group(1))
1811 slots[slot] = True
1812
1813 dev.pci = _GetFreeSlot(slots)
1814
1815 def VerifyHotplugSupport(self, instance, action, dev_type):
1816 """Verifies that hotplug is supported.
1817
1818 Hotplug is *not* supported in case of:
1819 - security models and chroot (disk hotplug)
1820 - fdsend module is missing (nic hot-add)
1821
1822 @raise errors.HypervisorError: in one of the previous cases
1823
1824 """
1825 if dev_type == constants.HOTPLUG_TARGET_DISK:
1826 hvp = instance.hvparams
1827 security_model = hvp[constants.HV_SECURITY_MODEL]
1828 use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
1829 if use_chroot:
1830 raise errors.HotplugError("Disk hotplug is not supported"
1831 " in case of chroot.")
1832 if security_model != constants.HT_SM_NONE:
1833 raise errors.HotplugError("Disk Hotplug is not supported in case"
1834 " security models are used.")
1835
1836 if (dev_type == constants.HOTPLUG_TARGET_NIC and
1837 action == constants.HOTPLUG_ACTION_ADD and not fdsend):
1838 raise errors.HotplugError("Cannot hot-add NIC."
1839 " fdsend python module is missing.")
1840
1841 def HotplugSupported(self, instance):
1842 """Checks if hotplug is generally supported.
1843
1844 Hotplug is *not* supported in case of:
1845 - qemu versions < 1.0
1846 - for stopped instances
1847
1848 @raise errors.HypervisorError: in one of the previous cases
1849
1850 """
1851 try:
1852 output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
1853 except errors.HypervisorError:
1854 raise errors.HotplugError("Instance is probably down")
1855
1856 # TODO: search for netdev_add, drive_add, device_add.....
1857 match = self._INFO_VERSION_RE.search(output.stdout)
1858 if not match:
1859 raise errors.HotplugError("Cannot parse qemu version via monitor")
1860
1861 v_major, v_min, _, _ = match.groups()
1862 if (int(v_major), int(v_min)) < (1, 0):
1863 raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
1864
1865 def _CallHotplugCommands(self, name, cmds):
1866 for c in cmds:
1867 self._CallMonitorCommand(name, c)
1868 time.sleep(1)
1869
1870 def _VerifyHotplugCommand(self, instance_name, device, dev_type,
1871 should_exist):
1872 """Checks if a previous hotplug command has succeeded.
1873
1874 It issues info pci monitor command and checks depending on should_exist
1875 value if an entry with PCI slot and device ID is found or not.
1876
1877 @raise errors.HypervisorError: if result is not the expected one
1878
1879 """
1880 output = self._CallMonitorCommand(instance_name, self._INFO_PCI_CMD)
1881 kvm_devid = _GenerateDeviceKVMId(dev_type, device)
1882 match = \
1883 self._FIND_PCI_DEVICE_RE(device.pci, kvm_devid).search(output.stdout)
1884 if match and not should_exist:
1885 msg = "Device %s should have been removed but is still there" % kvm_devid
1886 raise errors.HypervisorError(msg)
1887
1888 if not match and should_exist:
1889 msg = "Device %s should have been added but is missing" % kvm_devid
1890 raise errors.HypervisorError(msg)
1891
1892 logging.info("Device %s has been correctly hot-plugged", kvm_devid)
1893
1894 def HotAddDevice(self, instance, dev_type, device, extra, seq):
1895 """ Helper method to hot-add a new device
1896
1897 It gets free pci slot generates the device name and invokes the
1898 device specific method.
1899
1900 """
1901 # in case of hot-mod this is given
1902 if device.pci is None:
1903 self._GetFreePCISlot(instance, device)
1904 kvm_devid = _GenerateDeviceKVMId(dev_type, device)
1905 runtime = self._LoadKVMRuntime(instance)
1906 if dev_type == constants.HOTPLUG_TARGET_DISK:
1907 cmds = ["drive_add dummy file=%s,if=none,id=%s,format=raw" %
1908 (extra, kvm_devid)]
1909 cmds += ["device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
1910 (hex(device.pci), kvm_devid, kvm_devid)]
1911 elif dev_type == constants.HOTPLUG_TARGET_NIC:
1912 (tap, fd) = OpenTap()
1913 self._ConfigureNIC(instance, seq, device, tap)
1914 self._PassTapFd(instance, fd, device)
1915 cmds = ["netdev_add tap,id=%s,fd=%s" % (kvm_devid, kvm_devid)]
1916 args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
1917 (hex(device.pci), device.mac, kvm_devid, kvm_devid)
1918 cmds += ["device_add %s" % args]
1919 utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
1920
1921 self._CallHotplugCommands(instance.name, cmds)
1922 self._VerifyHotplugCommand(instance.name, device, dev_type, True)
1923 # update relevant entries in runtime file
1924 index = _DEVICE_RUNTIME_INDEX[dev_type]
1925 entry = _RUNTIME_ENTRY[dev_type](device, extra)
1926 runtime[index].append(entry)
1927 self._SaveKVMRuntime(instance, runtime)
1928
1929 def HotDelDevice(self, instance, dev_type, device, _, seq):
1930 """ Helper method for hot-del device
1931
1932 It gets device info from runtime file, generates the device name and
1933 invokes the device specific method.
1934
1935 """
1936 runtime = self._LoadKVMRuntime(instance)
1937 entry = _GetExistingDeviceInfo(dev_type, device, runtime)
1938 kvm_device = _RUNTIME_DEVICE[dev_type](entry)
1939 kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
1940 if dev_type == constants.HOTPLUG_TARGET_DISK:
1941 cmds = ["device_del %s" % kvm_devid]
1942 cmds += ["drive_del %s" % kvm_devid]
1943 elif dev_type == constants.HOTPLUG_TARGET_NIC:
1944 cmds = ["device_del %s" % kvm_devid]
1945 cmds += ["netdev_del %s" % kvm_devid]
1946 utils.RemoveFile(self._InstanceNICFile(instance.name, seq))
1947 self._CallHotplugCommands(instance.name, cmds)
1948 self._VerifyHotplugCommand(instance.name, kvm_device, dev_type, False)
1949 index = _DEVICE_RUNTIME_INDEX[dev_type]
1950 runtime[index].remove(entry)
1951 self._SaveKVMRuntime(instance, runtime)
1952
1953 return kvm_device.pci
1954
1955 def HotModDevice(self, instance, dev_type, device, _, seq):
1956 """ Helper method for hot-mod device
1957
1958 It gets device info from runtime file, generates the device name and
1959 invokes the device specific method. Currently only NICs support hot-mod
1960
1961 """
1962 if dev_type == constants.HOTPLUG_TARGET_NIC:
1963 # putting it back in the same pci slot
1964 device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
1965 self.HotAddDevice(instance, dev_type, device, _, seq)
1966
1967 def _PassTapFd(self, instance, fd, nic):
1968 """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
1969
1970 """
1971 # TODO: factor out code related to unix sockets.
1972 # squash common parts between monitor and qmp
1973 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1974 command = "getfd %s\n" % kvm_devid
1975 fds = [fd]
1976 logging.info("%s", fds)
1977 try:
1978 monsock = MonitorSocket(self._InstanceMonitor(instance.name))
1979 monsock.connect()
1980 fdsend.sendfds(monsock.sock, command, fds=fds)
1981 finally:
1982 monsock.close()
1983
1984 @classmethod
1985 def _ParseKVMVersion(cls, text):
1986 """Parse the KVM version from the --help output.
1987
1988 @type text: string
1989 @param text: output of kvm --help
1990 @return: (version, v_maj, v_min, v_rev)
1991 @raise errors.HypervisorError: when the KVM version cannot be retrieved
1992
1993 """
1994 match = cls._VERSION_RE.search(text.splitlines()[0])
1995 if not match:
1996 raise errors.HypervisorError("Unable to get KVM version")
1997
1998 v_all = match.group(0)
1999 v_maj = int(match.group(1))
2000 v_min = int(match.group(2))
2001 if match.group(4):
2002 v_rev = int(match.group(4))
2003 else:
2004 v_rev = 0
2005 return (v_all, v_maj, v_min, v_rev)
2006
2007 @classmethod
2008 def _GetKVMOutput(cls, kvm_path, option):
2009 """Return the output of a kvm invocation
2010
2011 @type kvm_path: string
2012 @param kvm_path: path to the kvm executable
2013 @type option: a key of _KVMOPTS_CMDS
2014 @param option: kvm option to fetch the output from
2015 @return: output a supported kvm invocation
2016 @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2017
2018 """
2019 assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2020
2021 optlist, can_fail = cls._KVMOPTS_CMDS[option]
2022
2023 result = utils.RunCmd([kvm_path] + optlist)
2024 if result.failed and not can_fail:
2025 raise errors.HypervisorError("Unable to get KVM %s output" %
2026 " ".join(optlist))
2027 return result.output
2028
2029 @classmethod
2030 def _GetKVMVersion(cls, kvm_path):
2031 """Return the installed KVM version.
2032
2033 @return: (version, v_maj, v_min, v_rev)
2034 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2035
2036 """
2037 return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2038
2039 @classmethod
2040 def _GetDefaultMachineVersion(cls, kvm_path):
2041 """Return the default hardware revision (e.g. pc-1.1)
2042
2043 """
2044 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2045 match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2046 if match:
2047 return match.group(1)
2048 else:
2049 return "pc"
2050
2051 @classmethod
2052 def _StopInstance(cls, instance, force=False, name=None, timeout=None):
2053 """Stop an instance.
2054
2055 """
2056 assert(timeout is None or force is not None)
2057
2058 if name is not None and not force:
2059 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2060 if name is None:
2061 name = instance.name
2062 acpi = instance.hvparams[constants.HV_ACPI]
2063 else:
2064 acpi = False
2065 _, pid, alive = cls._InstancePidAlive(name)
2066 if pid > 0 and alive:
2067 if force or not acpi:
2068 utils.KillProcess(pid)
2069 else:
2070 cls._CallMonitorCommand(name, "system_powerdown", timeout)
2071 cls._ClearUserShutdown(instance.name)
2072
2073 def StopInstance(self, instance, force=False, retry=False, name=None,
2074 timeout=None):
2075 """Stop an instance.
2076
2077 """
2078 self._StopInstance(instance, force, name=name, timeout=timeout)
2079
2080 def CleanupInstance(self, instance_name):
2081 """Cleanup after a stopped instance
2082
2083 """
2084 pidfile, pid, alive = self._InstancePidAlive(instance_name)
2085 if pid > 0 and alive:
2086 raise errors.HypervisorError("Cannot cleanup a live instance")
2087 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2088 self._ClearUserShutdown(instance_name)
2089
2090 def RebootInstance(self, instance):
2091 """Reboot an instance.
2092
2093 """
2094 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2095 # socket the instance will stop, but now power up again. So we'll resort
2096 # to shutdown and restart.
2097 _, _, alive = self._InstancePidAlive(instance.name)
2098 if not alive:
2099 raise errors.HypervisorError("Failed to reboot instance %s:"
2100 " not running" % instance.name)
2101 # StopInstance will delete the saved KVM runtime so:
2102 # ...first load it...
2103 kvm_runtime = self._LoadKVMRuntime(instance)
2104 # ...now we can safely call StopInstance...
2105 if not self.StopInstance(instance):
2106 self.StopInstance(instance, force=True)
2107 # ...and finally we can save it again, and execute it...
2108 self._SaveKVMRuntime(instance, kvm_runtime)
2109 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2110 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2111 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2112
2113 def MigrationInfo(self, instance):
2114 """Get instance information to perform a migration.
2115
2116 @type instance: L{objects.Instance}
2117 @param instance: instance to be migrated
2118 @rtype: string
2119 @return: content of the KVM runtime file
2120
2121 """
2122 return self._ReadKVMRuntime(instance.name)
2123
2124 def AcceptInstance(self, instance, info, target):
2125 """Prepare to accept an instance.
2126
2127 @type instance: L{objects.Instance}
2128 @param instance: instance to be accepted
2129 @type info: string
2130 @param info: content of the KVM runtime file on the source node
2131 @type target: string
2132 @param target: target host (usually ip), on this node
2133
2134 """
2135 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2136 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2137 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2138 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2139 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2140 incoming=incoming_address)
2141
2142 def FinalizeMigrationDst(self, instance, info, success):
2143 """Finalize the instance migration on the target node.
2144
2145 Stop the incoming mode KVM.
2146
2147 @type instance: L{objects.Instance}
2148 @param instance: instance whose migration is being finalized
2149
2150 """
2151 if success:
2152 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2153 kvm_nics = kvm_runtime[1]
2154
2155 for nic_seq, nic in enumerate(kvm_nics):
2156 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2157 # Bridged interfaces have already been configured
2158 continue
2159 try:
2160 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2161 except EnvironmentError, err:
2162 logging.warning("Failed to find host interface for %s NIC #%d: %s",
2163 instance.name, nic_seq, str(err))
2164 continue
2165 try:
2166 self._ConfigureNIC(instance, nic_seq, nic, tap)
2167 except errors.HypervisorError, err:
2168 logging.warning(str(err))
2169
2170 self._WriteKVMRuntime(instance.name, info)
2171 else:
2172 self.StopInstance(instance, force=True)
2173
2174 def MigrateInstance(self, cluster_name, instance, target, live):
2175 """Migrate an instance to a target node.
2176
2177 The migration will not be attempted if the instance is not
2178 currently running.
2179
2180 @type cluster_name: string
2181 @param cluster_name: name of the cluster
2182 @type instance: L{objects.Instance}
2183 @param instance: the instance to be migrated
2184 @type target: string
2185 @param target: ip address of the target node
2186 @type live: boolean
2187 @param live: perform a live migration
2188
2189 """
2190 instance_name = instance.name
2191 port = instance.hvparams[constants.HV_MIGRATION_PORT]
2192 _, _, alive = self._InstancePidAlive(instance_name)
2193 if not alive:
2194 raise errors.HypervisorError("Instance not running, cannot migrate")
2195
2196 if not live:
2197 self._CallMonitorCommand(instance_name, "stop")
2198
2199 migrate_command = ("migrate_set_speed %dm" %
2200 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2201 self._CallMonitorCommand(instance_name, migrate_command)
2202
2203 migrate_command = ("migrate_set_downtime %dms" %
2204 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2205 self._CallMonitorCommand(instance_name, migrate_command)
2206
2207 migration_caps = instance.hvparams[constants.HV_KVM_MIGRATION_CAPS]
2208 if migration_caps:
2209 for c in migration_caps.split(_MIGRATION_CAPS_DELIM):
2210 migrate_command = ("migrate_set_capability %s on" % c)
2211 self._CallMonitorCommand(instance_name, migrate_command)
2212
2213 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2214 self._CallMonitorCommand(instance_name, migrate_command)
2215
2216 def FinalizeMigrationSource(self, instance, success, live):
2217 """Finalize the instance migration on the source node.
2218
2219 @type instance: L{objects.Instance}
2220 @param instance: the instance that was migrated
2221 @type success: bool
2222 @param success: whether the migration succeeded or not
2223 @type live: bool
2224 @param live: whether the user requested a live migration or not
2225
2226 """
2227 if success:
2228 pidfile, pid, _ = self._InstancePidAlive(instance.name)
2229 utils.KillProcess(pid)
2230 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2231 elif live:
2232 self._CallMonitorCommand(instance.name, self._CONT_CMD)
2233 self._ClearUserShutdown(instance.name)
2234
2235 def GetMigrationStatus(self, instance):
2236 """Get the migration status
2237
2238 @type instance: L{objects.Instance}
2239 @param instance: the instance that is being migrated
2240 @rtype: L{objects.MigrationStatus}
2241 @return: the status of the current migration (one of
2242 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2243 progress info that can be retrieved from the hypervisor
2244
2245 """
2246 info_command = "info migrate"
2247 for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2248 result = self._CallMonitorCommand(instance.name, info_command)
2249 match = self._MIGRATION_STATUS_RE.search(result.stdout)
2250 if not match:
2251 if not result.stdout:
2252 logging.info("KVM: empty 'info migrate' result")
2253 else:
2254 logging.warning("KVM: unknown 'info migrate' result: %s",
2255 result.stdout)
2256 else:
2257 status = match.group(1)
2258 if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2259 migration_status = objects.MigrationStatus(status=status)
2260 match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2261 if match:
2262 migration_status.transferred_ram = match.group("transferred")
2263 migration_status.total_ram = match.group("total")
2264
2265 return migration_status
2266
2267 logging.warning("KVM: unknown migration status '%s'", status)
2268
2269 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2270
2271 return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2272
2273 def BalloonInstanceMemory(self, instance, mem):
2274 """Balloon an instance memory to a certain value.
2275
2276 @type instance: L{objects.Instance}
2277 @param instance: instance to be accepted
2278 @type mem: int
2279 @param mem: actual memory size to use for instance runtime
2280
2281 """
2282 self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2283
2284 def GetNodeInfo(self, hvparams=None):
2285 """Return information about the node.
2286
2287 @type hvparams: dict of strings
2288 @param hvparams: hypervisor parameters, not used in this class
2289
2290 @return: a dict as returned by L{BaseHypervisor.GetLinuxNodeInfo} plus
2291 the following keys:
2292 - hv_version: the hypervisor version in the form (major, minor,
2293 revision)
2294
2295 """
2296 result = self.GetLinuxNodeInfo()
2297 kvmpath = constants.KVM_PATH
2298 if hvparams is not None:
2299 kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2300 _, v_major, v_min, v_rev = self._GetKVMVersion(kvmpath)
2301 result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2302 return result
2303
2304 @classmethod
2305 def GetInstanceConsole(cls, instance, primary_node, node_group,
2306 hvparams, beparams):
2307 """Return a command for connecting to the console of an instance.
2308
2309 """
2310 if hvparams[constants.HV_SERIAL_CONSOLE]:
2311 cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2312 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2313 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2314 "STDIO,%s" % cls._SocatUnixConsoleParams(),
2315 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2316 ndparams = node_group.FillND(primary_node)
2317 return objects.InstanceConsole(instance=instance.name,
2318 kind=constants.CONS_SSH,
2319 host=primary_node.name,
2320 port=ndparams.get(constants.ND_SSH_PORT),
2321 user=constants.SSH_CONSOLE_USER,
2322 command=cmd)
2323
2324 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2325 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2326 display = instance.network_port - constants.VNC_BASE_PORT
2327 return objects.InstanceConsole(instance=instance.name,
2328 kind=constants.CONS_VNC,
2329 host=vnc_bind_address,
2330 port=instance.network_port,
2331 display=display)
2332
2333 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2334 if spice_bind:
2335 return objects.InstanceConsole(instance=instance.name,
2336 kind=constants.CONS_SPICE,
2337 host=spice_bind,
2338 port=instance.network_port)
2339
2340 return objects.InstanceConsole(instance=instance.name,
2341 kind=constants.CONS_MESSAGE,
2342 message=("No serial shell for instance %s" %
2343 instance.name))
2344
2345 def Verify(self, hvparams=None):
2346 """Verify the hypervisor.
2347
2348 Check that the required binaries exist.
2349
2350 @type hvparams: dict of strings
2351 @param hvparams: hypervisor parameters to be verified against, not used here
2352
2353 @return: Problem description if something is wrong, C{None} otherwise
2354
2355 """
2356 msgs = []
2357 kvmpath = constants.KVM_PATH
2358 if hvparams is not None:
2359 kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2360 if not os.path.exists(kvmpath):
2361 msgs.append("The KVM binary ('%s') does not exist" % kvmpath)
2362 if not os.path.exists(constants.SOCAT_PATH):
2363 msgs.append("The socat binary ('%s') does not exist" %
2364 constants.SOCAT_PATH)
2365
2366 return self._FormatVerifyResults(msgs)
2367
2368 @classmethod
2369 def CheckParameterSyntax(cls, hvparams):
2370 """Check the given parameters for validity.
2371
2372 @type hvparams: dict
2373 @param hvparams: dictionary with parameter names/value
2374 @raise errors.HypervisorError: when a parameter is not valid
2375
2376 """
2377 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2378
2379 kernel_path = hvparams[constants.HV_KERNEL_PATH]
2380 if kernel_path:
2381 if not hvparams[constants.HV_ROOT_PATH]:
2382 raise errors.HypervisorError("Need a root partition for the instance,"
2383 " if a kernel is defined")
2384
2385 if (hvparams[constants.HV_VNC_X509_VERIFY] and
2386 not hvparams[constants.HV_VNC_X509]):
2387 raise errors.HypervisorError("%s must be defined, if %s is" %
2388 (constants.HV_VNC_X509,
2389 constants.HV_VNC_X509_VERIFY))
2390
2391 if hvparams[constants.HV_SERIAL_CONSOLE]:
2392 serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2393 valid_speeds = constants.VALID_SERIAL_SPEEDS
2394 if not serial_speed or serial_speed not in valid_speeds:
2395 raise errors.HypervisorError("Invalid serial console speed, must be"
2396 " one of: %s" %
2397 utils.CommaJoin(valid_speeds))
2398
2399 boot_order = hvparams[constants.HV_BOOT_ORDER]
2400 if (boot_order == constants.HT_BO_CDROM and
2401 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2402 raise errors.HypervisorError("Cannot boot from cdrom without an"
2403 " ISO path")
2404
2405 security_model = hvparams[constants.HV_SECURITY_MODEL]
2406 if security_model == constants.HT_SM_USER:
2407 if not hvparams[constants.HV_SECURITY_DOMAIN]:
2408 raise errors.HypervisorError("A security domain (user to run kvm as)"
2409 " must be specified")
2410 elif (security_model == constants.HT_SM_NONE or
2411 security_model == constants.HT_SM_POOL):
2412 if hvparams[constants.HV_SECURITY_DOMAIN]:
2413 raise errors.HypervisorError("Cannot have a security domain when the"
2414 " security model is 'none' or 'pool'")
2415
2416 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2417 spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2418 if spice_bind:
2419 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2420 # if an IP version is specified, the spice_bind parameter must be an
2421 # IP of that family
2422 if (netutils.IP4Address.IsValid(spice_bind) and
2423 spice_ip_version != constants.IP4_VERSION):
2424 raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2425 " the specified IP version is %s" %
2426 (spice_bind, spice_ip_version))
2427
2428 if (netutils.IP6Address.IsValid(spice_bind) and
2429 spice_ip_version != constants.IP6_VERSION):
2430 raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2431 " the specified IP version is %s" %
2432 (spice_bind, spice_ip_version))
2433 else:
2434 # All the other SPICE parameters depend on spice_bind being set. Raise an
2435 # error if any of them is set without it.
2436 for param in _SPICE_ADDITIONAL_PARAMS:
2437 if hvparams[param]:
2438 raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2439 (param, constants.HV_KVM_SPICE_BIND))
2440
2441 @classmethod
2442 def ValidateParameters(cls, hvparams):
2443 """Check the given parameters for validity.
2444
2445 @type hvparams: dict
2446 @param hvparams: dictionary with parameter names/value
2447 @raise errors.HypervisorError: when a parameter is not valid
2448
2449 """
2450 super(KVMHypervisor, cls).ValidateParameters(hvparams)
2451
2452 kvm_path = hvparams[constants.HV_KVM_PATH]
2453
2454 security_model = hvparams[constants.HV_SECURITY_MODEL]
2455 if security_model == constants.HT_SM_USER:
2456 username = hvparams[constants.HV_SECURITY_DOMAIN]
2457 try:
2458 pwd.getpwnam(username)
2459 except KeyError:
2460 raise errors.HypervisorError("Unknown security domain user %s"
2461 % username)
2462 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2463 if vnc_bind_address:
2464 bound_to_addr = netutils.IP4Address.IsValid(vnc_bind_address)
2465 is_interface = netutils.IsValidInterface(vnc_bind_address)
2466 is_path = utils.IsNormAbsPath(vnc_bind_address)
2467 if not bound_to_addr and not is_interface and not is_path:
2468 raise errors.HypervisorError("VNC: The %s parameter must be either"
2469 " a valid IP address, an interface name,"
2470 " or an absolute path" %
2471 constants.HV_KVM_SPICE_BIND)
2472
2473 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2474 if spice_bind:
2475 # only one of VNC and SPICE can be used currently.
2476 if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2477 raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2478 " only one of them can be used at a"
2479 " given time")
2480
2481 # check that KVM supports SPICE
2482 kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2483 if not cls._SPICE_RE.search(kvmhelp):
2484 raise errors.HypervisorError("SPICE is configured, but it is not"
2485 " supported according to 'kvm --help'")
2486
2487 # if spice_bind is not an IP address, it must be a valid interface
2488 bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2489 netutils.IP6Address.IsValid(spice_bind))
2490 if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2491 raise errors.HypervisorError("SPICE: The %s parameter must be either"
2492 " a valid IP address or interface name" %
2493 constants.HV_KVM_SPICE_BIND)
2494
2495 machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2496 if machine_version:
2497 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2498 if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2499 raise errors.HypervisorError("Unsupported machine version: %s" %
2500 machine_version)
2501
2502 @classmethod
2503 def PowercycleNode(cls, hvparams=None):
2504 """KVM powercycle, just a wrapper over Linux powercycle.
2505
2506 @type hvparams: dict of strings
2507 @param hvparams: hypervisor params to be used on this node
2508
2509 """
2510 cls.LinuxPowercycle()