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