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