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