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