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