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