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