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