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