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