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