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