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