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