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