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