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