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