kvm: abstract getting --help output
[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     }
539
540   _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
541                                     re.M | re.I)
542   _MIGRATION_PROGRESS_RE = \
543     re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
544                r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
545                r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
546
547   _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
548   _MIGRATION_INFO_RETRY_DELAY = 2
549
550   _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
551
552   _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
553   _CPU_INFO_CMD = "info cpus"
554   _CONT_CMD = "cont"
555
556   _DEFAULT_MACHINE_VERSION_RE = re.compile(r"(\S+).*\(default\)")
557
558   ANCILLARY_FILES = [
559     _KVM_NETWORK_SCRIPT,
560     ]
561   ANCILLARY_FILES_OPT = [
562     _KVM_NETWORK_SCRIPT,
563     ]
564
565   def __init__(self):
566     hv_base.BaseHypervisor.__init__(self)
567     # Let's make sure the directories we need exist, even if the RUN_DIR lives
568     # in a tmpfs filesystem or has been otherwise wiped out.
569     dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
570     utils.EnsureDirs(dirs)
571
572   @classmethod
573   def _InstancePidFile(cls, instance_name):
574     """Returns the instance pidfile.
575
576     """
577     return utils.PathJoin(cls._PIDS_DIR, instance_name)
578
579   @classmethod
580   def _InstanceUidFile(cls, instance_name):
581     """Returns the instance uidfile.
582
583     """
584     return utils.PathJoin(cls._UIDS_DIR, instance_name)
585
586   @classmethod
587   def _InstancePidInfo(cls, pid):
588     """Check pid file for instance information.
589
590     Check that a pid file is associated with an instance, and retrieve
591     information from its command line.
592
593     @type pid: string or int
594     @param pid: process id of the instance to check
595     @rtype: tuple
596     @return: (instance_name, memory, vcpus)
597     @raise errors.HypervisorError: when an instance cannot be found
598
599     """
600     alive = utils.IsProcessAlive(pid)
601     if not alive:
602       raise errors.HypervisorError("Cannot get info for pid %s" % pid)
603
604     cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
605     try:
606       cmdline = utils.ReadFile(cmdline_file)
607     except EnvironmentError, err:
608       raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
609                                    (pid, err))
610
611     instance = None
612     memory = 0
613     vcpus = 0
614
615     arg_list = cmdline.split("\x00")
616     while arg_list:
617       arg = arg_list.pop(0)
618       if arg == "-name":
619         instance = arg_list.pop(0)
620       elif arg == "-m":
621         memory = int(arg_list.pop(0))
622       elif arg == "-smp":
623         vcpus = int(arg_list.pop(0).split(",")[0])
624
625     if instance is None:
626       raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
627                                    " instance" % pid)
628
629     return (instance, memory, vcpus)
630
631   def _InstancePidAlive(self, instance_name):
632     """Returns the instance pidfile, pid, and liveness.
633
634     @type instance_name: string
635     @param instance_name: instance name
636     @rtype: tuple
637     @return: (pid file name, pid, liveness)
638
639     """
640     pidfile = self._InstancePidFile(instance_name)
641     pid = utils.ReadPidFile(pidfile)
642
643     alive = False
644     try:
645       cmd_instance = self._InstancePidInfo(pid)[0]
646       alive = (cmd_instance == instance_name)
647     except errors.HypervisorError:
648       pass
649
650     return (pidfile, pid, alive)
651
652   def _CheckDown(self, instance_name):
653     """Raises an error unless the given instance is down.
654
655     """
656     alive = self._InstancePidAlive(instance_name)[2]
657     if alive:
658       raise errors.HypervisorError("Failed to start instance %s: %s" %
659                                    (instance_name, "already running"))
660
661   @classmethod
662   def _InstanceMonitor(cls, instance_name):
663     """Returns the instance monitor socket name
664
665     """
666     return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
667
668   @classmethod
669   def _InstanceSerial(cls, instance_name):
670     """Returns the instance serial socket name
671
672     """
673     return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
674
675   @classmethod
676   def _InstanceQmpMonitor(cls, instance_name):
677     """Returns the instance serial QMP socket name
678
679     """
680     return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
681
682   @staticmethod
683   def _SocatUnixConsoleParams():
684     """Returns the correct parameters for socat
685
686     If we have a new-enough socat we can use raw mode with an escape character.
687
688     """
689     if constants.SOCAT_USE_ESCAPE:
690       return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
691     else:
692       return "echo=0,icanon=0"
693
694   @classmethod
695   def _InstanceKVMRuntime(cls, instance_name):
696     """Returns the instance KVM runtime filename
697
698     """
699     return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
700
701   @classmethod
702   def _InstanceChrootDir(cls, instance_name):
703     """Returns the name of the KVM chroot dir of the instance
704
705     """
706     return utils.PathJoin(cls._CHROOT_DIR, instance_name)
707
708   @classmethod
709   def _InstanceNICDir(cls, instance_name):
710     """Returns the name of the directory holding the tap device files for a
711     given instance.
712
713     """
714     return utils.PathJoin(cls._NICS_DIR, instance_name)
715
716   @classmethod
717   def _InstanceNICFile(cls, instance_name, seq):
718     """Returns the name of the file containing the tap device for a given NIC
719
720     """
721     return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
722
723   @classmethod
724   def _InstanceKeymapFile(cls, instance_name):
725     """Returns the name of the file containing the keymap for a given instance
726
727     """
728     return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
729
730   @classmethod
731   def _TryReadUidFile(cls, uid_file):
732     """Try to read a uid file
733
734     """
735     if os.path.exists(uid_file):
736       try:
737         uid = int(utils.ReadOneLineFile(uid_file))
738         return uid
739       except EnvironmentError:
740         logging.warning("Can't read uid file", exc_info=True)
741       except (TypeError, ValueError):
742         logging.warning("Can't parse uid file contents", exc_info=True)
743     return None
744
745   @classmethod
746   def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
747     """Removes an instance's rutime sockets/files/dirs.
748
749     """
750     utils.RemoveFile(pidfile)
751     utils.RemoveFile(cls._InstanceMonitor(instance_name))
752     utils.RemoveFile(cls._InstanceSerial(instance_name))
753     utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
754     utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
755     utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
756     uid_file = cls._InstanceUidFile(instance_name)
757     uid = cls._TryReadUidFile(uid_file)
758     utils.RemoveFile(uid_file)
759     if uid is not None:
760       uidpool.ReleaseUid(uid)
761     try:
762       shutil.rmtree(cls._InstanceNICDir(instance_name))
763     except OSError, err:
764       if err.errno != errno.ENOENT:
765         raise
766     try:
767       chroot_dir = cls._InstanceChrootDir(instance_name)
768       utils.RemoveDir(chroot_dir)
769     except OSError, err:
770       if err.errno == errno.ENOTEMPTY:
771         # The chroot directory is expected to be empty, but it isn't.
772         new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
773                                           prefix="%s-%s-" %
774                                           (instance_name,
775                                            utils.TimestampForFilename()))
776         logging.warning("The chroot directory of instance %s can not be"
777                         " removed as it is not empty. Moving it to the"
778                         " quarantine instead. Please investigate the"
779                         " contents (%s) and clean up manually",
780                         instance_name, new_chroot_dir)
781         utils.RenameFile(chroot_dir, new_chroot_dir)
782       else:
783         raise
784
785   @staticmethod
786   def _ConfigureNIC(instance, seq, nic, tap):
787     """Run the network configuration script for a specified NIC
788
789     @param instance: instance we're acting on
790     @type instance: instance object
791     @param seq: nic sequence number
792     @type seq: int
793     @param nic: nic we're acting on
794     @type nic: nic object
795     @param tap: the host's tap interface this NIC corresponds to
796     @type tap: str
797
798     """
799     if instance.tags:
800       tags = " ".join(instance.tags)
801     else:
802       tags = ""
803
804     env = {
805       "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
806       "INSTANCE": instance.name,
807       "MAC": nic.mac,
808       "MODE": nic.nicparams[constants.NIC_MODE],
809       "INTERFACE": tap,
810       "INTERFACE_INDEX": str(seq),
811       "TAGS": tags,
812     }
813
814     if nic.ip:
815       env["IP"] = nic.ip
816
817     if nic.nicparams[constants.NIC_LINK]:
818       env["LINK"] = nic.nicparams[constants.NIC_LINK]
819
820     if nic.network:
821       n = objects.Network.FromDict(nic.netinfo)
822       _BuildNetworkEnv(nic.network, n.network, n.gateway,
823                        n.network6, n.gateway6, n.network_type,
824                        n.mac_prefix, n.tags, env)
825
826     if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
827       env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
828
829     result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
830     if result.failed:
831       raise errors.HypervisorError("Failed to configure interface %s: %s."
832                                    " Network configuration script output: %s" %
833                                    (tap, result.fail_reason, result.output))
834
835   @staticmethod
836   def _VerifyAffinityPackage():
837     if affinity is None:
838       raise errors.HypervisorError("affinity Python package not"
839                                    " found; cannot use CPU pinning under KVM")
840
841   @staticmethod
842   def _BuildAffinityCpuMask(cpu_list):
843     """Create a CPU mask suitable for sched_setaffinity from a list of
844     CPUs.
845
846     See man taskset for more info on sched_setaffinity masks.
847     For example: [ 0, 2, 5, 6 ] will return 101 (0x65, 0..01100101).
848
849     @type cpu_list: list of int
850     @param cpu_list: list of physical CPU numbers to map to vCPUs in order
851     @rtype: int
852     @return: a bit mask of CPU affinities
853
854     """
855     if cpu_list == constants.CPU_PINNING_OFF:
856       return constants.CPU_PINNING_ALL_KVM
857     else:
858       return sum(2 ** cpu for cpu in cpu_list)
859
860   @classmethod
861   def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
862     """Change CPU affinity for running VM according to given CPU mask.
863
864     @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
865     @type cpu_mask: string
866     @param process_id: process ID of KVM process. Used to pin entire VM
867                        to physical CPUs.
868     @type process_id: int
869     @param thread_dict: map of virtual CPUs to KVM thread IDs
870     @type thread_dict: dict int:int
871
872     """
873     # Convert the string CPU mask to a list of list of int's
874     cpu_list = utils.ParseMultiCpuMask(cpu_mask)
875
876     if len(cpu_list) == 1:
877       all_cpu_mapping = cpu_list[0]
878       if all_cpu_mapping == constants.CPU_PINNING_OFF:
879         # If CPU pinning has 1 entry that's "all", then do nothing
880         pass
881       else:
882         # If CPU pinning has one non-all entry, map the entire VM to
883         # one set of physical CPUs
884         cls._VerifyAffinityPackage()
885         affinity.set_process_affinity_mask(
886           process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
887     else:
888       # The number of vCPUs mapped should match the number of vCPUs
889       # reported by KVM. This was already verified earlier, so
890       # here only as a sanity check.
891       assert len(thread_dict) == len(cpu_list)
892       cls._VerifyAffinityPackage()
893
894       # For each vCPU, map it to the proper list of physical CPUs
895       for vcpu, i in zip(cpu_list, range(len(cpu_list))):
896         affinity.set_process_affinity_mask(thread_dict[i],
897                                            cls._BuildAffinityCpuMask(vcpu))
898
899   def _GetVcpuThreadIds(self, instance_name):
900     """Get a mapping of vCPU no. to thread IDs for the instance
901
902     @type instance_name: string
903     @param instance_name: instance in question
904     @rtype: dictionary of int:int
905     @return: a dictionary mapping vCPU numbers to thread IDs
906
907     """
908     result = {}
909     output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
910     for line in output.stdout.splitlines():
911       match = self._CPU_INFO_RE.search(line)
912       if not match:
913         continue
914       grp = map(int, match.groups())
915       result[grp[0]] = grp[1]
916
917     return result
918
919   def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
920     """Complete CPU pinning.
921
922     @type instance_name: string
923     @param instance_name: name of instance
924     @type cpu_mask: string
925     @param cpu_mask: CPU pinning mask as entered by user
926
927     """
928     # Get KVM process ID, to be used if need to pin entire VM
929     _, pid, _ = self._InstancePidAlive(instance_name)
930     # Get vCPU thread IDs, to be used if need to pin vCPUs separately
931     thread_dict = self._GetVcpuThreadIds(instance_name)
932     # Run CPU pinning, based on configured mask
933     self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
934
935   def ListInstances(self):
936     """Get the list of running instances.
937
938     We can do this by listing our live instances directory and
939     checking whether the associated kvm process is still alive.
940
941     """
942     result = []
943     for name in os.listdir(self._PIDS_DIR):
944       if self._InstancePidAlive(name)[2]:
945         result.append(name)
946     return result
947
948   def GetInstanceInfo(self, instance_name):
949     """Get instance properties.
950
951     @type instance_name: string
952     @param instance_name: the instance name
953     @rtype: tuple of strings
954     @return: (name, id, memory, vcpus, stat, times)
955
956     """
957     _, pid, alive = self._InstancePidAlive(instance_name)
958     if not alive:
959       return None
960
961     _, memory, vcpus = self._InstancePidInfo(pid)
962     istat = "---b-"
963     times = "0"
964
965     try:
966       qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
967       qmp.connect()
968       vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
969       # Will fail if ballooning is not enabled, but we can then just resort to
970       # the value above.
971       mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
972       memory = mem_bytes / 1048576
973     except errors.HypervisorError:
974       pass
975
976     return (instance_name, pid, memory, vcpus, istat, times)
977
978   def GetAllInstancesInfo(self):
979     """Get properties of all instances.
980
981     @return: list of tuples (name, id, memory, vcpus, stat, times)
982
983     """
984     data = []
985     for name in os.listdir(self._PIDS_DIR):
986       try:
987         info = self.GetInstanceInfo(name)
988       except errors.HypervisorError:
989         # Ignore exceptions due to instances being shut down
990         continue
991       if info:
992         data.append(info)
993     return data
994
995   def _GenerateKVMRuntime(self, instance, block_devices, startup_paused):
996     """Generate KVM information to start an instance.
997
998     @attention: this function must not have any side-effects; for
999         example, it must not write to the filesystem, or read values
1000         from the current system the are expected to differ between
1001         nodes, since it is only run once at instance startup;
1002         actions/kvm arguments that can vary between systems should be
1003         done in L{_ExecuteKVMRuntime}
1004
1005     """
1006     # pylint: disable=R0912,R0914,R0915
1007     _, v_major, v_min, _ = self._GetKVMVersion()
1008     hvp = instance.hvparams
1009
1010     pidfile = self._InstancePidFile(instance.name)
1011     kvm = constants.KVM_PATH
1012     kvm_cmd = [kvm]
1013     kvm_cmd.extend(["-M", self._GetDefaultMachineVersion()])
1014     # used just by the vnc server, if enabled
1015     kvm_cmd.extend(["-name", instance.name])
1016     kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1017
1018     smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1019     if hvp[constants.HV_CPU_CORES]:
1020       smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1021     if hvp[constants.HV_CPU_THREADS]:
1022       smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1023     if hvp[constants.HV_CPU_SOCKETS]:
1024       smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1025
1026     kvm_cmd.extend(["-smp", ",".join(smp_list)])
1027
1028     kvm_cmd.extend(["-pidfile", pidfile])
1029     kvm_cmd.extend(["-balloon", "virtio"])
1030     kvm_cmd.extend(["-daemonize"])
1031     if not instance.hvparams[constants.HV_ACPI]:
1032       kvm_cmd.extend(["-no-acpi"])
1033     if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1034         constants.INSTANCE_REBOOT_EXIT:
1035       kvm_cmd.extend(["-no-reboot"])
1036
1037     kernel_path = hvp[constants.HV_KERNEL_PATH]
1038     if kernel_path:
1039       boot_disk = boot_cdrom = boot_floppy = boot_network = False
1040     else:
1041       boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1042       boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1043       boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1044       boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1045
1046     self.ValidateParameters(hvp)
1047
1048     if startup_paused:
1049       kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1050
1051     if hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED:
1052       kvm_cmd.extend(["-enable-kvm"])
1053     elif hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED:
1054       kvm_cmd.extend(["-disable-kvm"])
1055
1056     if boot_network:
1057       kvm_cmd.extend(["-boot", "n"])
1058
1059     # whether this is an older KVM version that uses the boot=on flag
1060     # on devices
1061     needs_boot_flag = (v_major, v_min) < (0, 14)
1062
1063     disk_type = hvp[constants.HV_DISK_TYPE]
1064     if disk_type == constants.HT_DISK_PARAVIRTUAL:
1065       if_val = ",if=virtio"
1066     else:
1067       if_val = ",if=%s" % disk_type
1068     # Cache mode
1069     disk_cache = hvp[constants.HV_DISK_CACHE]
1070     if instance.disk_template in constants.DTS_EXT_MIRROR:
1071       if disk_cache != "none":
1072         # TODO: make this a hard error, instead of a silent overwrite
1073         logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1074                         " to prevent shared storage corruption on migration",
1075                         disk_cache)
1076       cache_val = ",cache=none"
1077     elif disk_cache != constants.HT_CACHE_DEFAULT:
1078       cache_val = ",cache=%s" % disk_cache
1079     else:
1080       cache_val = ""
1081     for cfdev, dev_path in block_devices:
1082       if cfdev.mode != constants.DISK_RDWR:
1083         raise errors.HypervisorError("Instance has read-only disks which"
1084                                      " are not supported by KVM")
1085       # TODO: handle FD_LOOP and FD_BLKTAP (?)
1086       boot_val = ""
1087       if boot_disk:
1088         kvm_cmd.extend(["-boot", "c"])
1089         boot_disk = False
1090         if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1091           boot_val = ",boot=on"
1092
1093       drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
1094                                                 cache_val)
1095       kvm_cmd.extend(["-drive", drive_val])
1096
1097     #Now we can specify a different device type for CDROM devices.
1098     cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1099     if not cdrom_disk_type:
1100       cdrom_disk_type = disk_type
1101
1102     iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1103     if iso_image:
1104       options = ",format=raw,media=cdrom"
1105       # set cdrom 'if' type
1106       if boot_cdrom:
1107         actual_cdrom_type = constants.HT_DISK_IDE
1108       elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1109         actual_cdrom_type = "virtio"
1110       else:
1111         actual_cdrom_type = cdrom_disk_type
1112       if_val = ",if=%s" % actual_cdrom_type
1113       # set boot flag, if needed
1114       boot_val = ""
1115       if boot_cdrom:
1116         kvm_cmd.extend(["-boot", "d"])
1117         if needs_boot_flag:
1118           boot_val = ",boot=on"
1119       # and finally build the entire '-drive' value
1120       drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1121       kvm_cmd.extend(["-drive", drive_val])
1122
1123     iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1124     if iso_image2:
1125       options = ",format=raw,media=cdrom"
1126       if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1127         if_val = ",if=virtio"
1128       else:
1129         if_val = ",if=%s" % cdrom_disk_type
1130       drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1131       kvm_cmd.extend(["-drive", drive_val])
1132
1133     floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1134     if floppy_image:
1135       options = ",format=raw,media=disk"
1136       if boot_floppy:
1137         kvm_cmd.extend(["-boot", "a"])
1138         options = "%s,boot=on" % options
1139       if_val = ",if=floppy"
1140       options = "%s%s" % (options, if_val)
1141       drive_val = "file=%s%s" % (floppy_image, options)
1142       kvm_cmd.extend(["-drive", drive_val])
1143
1144     if kernel_path:
1145       kvm_cmd.extend(["-kernel", kernel_path])
1146       initrd_path = hvp[constants.HV_INITRD_PATH]
1147       if initrd_path:
1148         kvm_cmd.extend(["-initrd", initrd_path])
1149       root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1150                      hvp[constants.HV_KERNEL_ARGS]]
1151       if hvp[constants.HV_SERIAL_CONSOLE]:
1152         serial_speed = hvp[constants.HV_SERIAL_SPEED]
1153         root_append.append("console=ttyS0,%s" % serial_speed)
1154       kvm_cmd.extend(["-append", " ".join(root_append)])
1155
1156     mem_path = hvp[constants.HV_MEM_PATH]
1157     if mem_path:
1158       kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1159
1160     monitor_dev = ("unix:%s,server,nowait" %
1161                    self._InstanceMonitor(instance.name))
1162     kvm_cmd.extend(["-monitor", monitor_dev])
1163     if hvp[constants.HV_SERIAL_CONSOLE]:
1164       serial_dev = ("unix:%s,server,nowait" %
1165                     self._InstanceSerial(instance.name))
1166       kvm_cmd.extend(["-serial", serial_dev])
1167     else:
1168       kvm_cmd.extend(["-serial", "none"])
1169
1170     mouse_type = hvp[constants.HV_USB_MOUSE]
1171     vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1172     spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1173     spice_ip_version = None
1174
1175     kvm_cmd.extend(["-usb"])
1176
1177     if mouse_type:
1178       kvm_cmd.extend(["-usbdevice", mouse_type])
1179     elif vnc_bind_address:
1180       kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1181
1182     if vnc_bind_address:
1183       if netutils.IP4Address.IsValid(vnc_bind_address):
1184         if instance.network_port > constants.VNC_BASE_PORT:
1185           display = instance.network_port - constants.VNC_BASE_PORT
1186           if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1187             vnc_arg = ":%d" % (display)
1188           else:
1189             vnc_arg = "%s:%d" % (vnc_bind_address, display)
1190         else:
1191           logging.error("Network port is not a valid VNC display (%d < %d)."
1192                         " Not starting VNC", instance.network_port,
1193                         constants.VNC_BASE_PORT)
1194           vnc_arg = "none"
1195
1196         # Only allow tls and other option when not binding to a file, for now.
1197         # kvm/qemu gets confused otherwise about the filename to use.
1198         vnc_append = ""
1199         if hvp[constants.HV_VNC_TLS]:
1200           vnc_append = "%s,tls" % vnc_append
1201           if hvp[constants.HV_VNC_X509_VERIFY]:
1202             vnc_append = "%s,x509verify=%s" % (vnc_append,
1203                                                hvp[constants.HV_VNC_X509])
1204           elif hvp[constants.HV_VNC_X509]:
1205             vnc_append = "%s,x509=%s" % (vnc_append,
1206                                          hvp[constants.HV_VNC_X509])
1207         if hvp[constants.HV_VNC_PASSWORD_FILE]:
1208           vnc_append = "%s,password" % vnc_append
1209
1210         vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1211
1212       else:
1213         vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1214
1215       kvm_cmd.extend(["-vnc", vnc_arg])
1216     elif spice_bind:
1217       # FIXME: this is wrong here; the iface ip address differs
1218       # between systems, so it should be done in _ExecuteKVMRuntime
1219       if netutils.IsValidInterface(spice_bind):
1220         # The user specified a network interface, we have to figure out the IP
1221         # address.
1222         addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1223         spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1224
1225         # if the user specified an IP version and the interface does not
1226         # have that kind of IP addresses, throw an exception
1227         if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1228           if not addresses[spice_ip_version]:
1229             raise errors.HypervisorError("spice: unable to get an IPv%s address"
1230                                          " for %s" % (spice_ip_version,
1231                                                       spice_bind))
1232
1233         # the user did not specify an IP version, we have to figure it out
1234         elif (addresses[constants.IP4_VERSION] and
1235               addresses[constants.IP6_VERSION]):
1236           # we have both ipv4 and ipv6, let's use the cluster default IP
1237           # version
1238           cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1239           spice_ip_version = \
1240             netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1241         elif addresses[constants.IP4_VERSION]:
1242           spice_ip_version = constants.IP4_VERSION
1243         elif addresses[constants.IP6_VERSION]:
1244           spice_ip_version = constants.IP6_VERSION
1245         else:
1246           raise errors.HypervisorError("spice: unable to get an IP address"
1247                                        " for %s" % (spice_bind))
1248
1249         spice_address = addresses[spice_ip_version][0]
1250
1251       else:
1252         # spice_bind is known to be a valid IP address, because
1253         # ValidateParameters checked it.
1254         spice_address = spice_bind
1255
1256       spice_arg = "addr=%s" % spice_address
1257       if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1258         spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1259                      (spice_arg, instance.network_port,
1260                       pathutils.SPICE_CACERT_FILE))
1261         spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1262                      (spice_arg, pathutils.SPICE_CERT_FILE,
1263                       pathutils.SPICE_CERT_FILE))
1264         tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1265         if tls_ciphers:
1266           spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1267       else:
1268         spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1269
1270       if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1271         spice_arg = "%s,disable-ticketing" % spice_arg
1272
1273       if spice_ip_version:
1274         spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1275
1276       # Image compression options
1277       img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1278       img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1279       img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1280       if img_lossless:
1281         spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1282       if img_jpeg:
1283         spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1284       if img_zlib_glz:
1285         spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1286
1287       # Video stream detection
1288       video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1289       if video_streaming:
1290         spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1291
1292       # Audio compression, by default in qemu-kvm it is on
1293       if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1294         spice_arg = "%s,playback-compression=off" % spice_arg
1295       if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1296         spice_arg = "%s,agent-mouse=off" % spice_arg
1297       else:
1298         # Enable the spice agent communication channel between the host and the
1299         # agent.
1300         kvm_cmd.extend(["-device", "virtio-serial-pci"])
1301         kvm_cmd.extend(["-device", "virtserialport,chardev=spicechannel0,"
1302                                                    "name=com.redhat.spice.0"])
1303         kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1304
1305       logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1306       kvm_cmd.extend(["-spice", spice_arg])
1307
1308       # Tell kvm to use the paravirtualized graphic card, optimized for SPICE
1309       kvm_cmd.extend(["-vga", "qxl"])
1310
1311     else:
1312       kvm_cmd.extend(["-nographic"])
1313
1314     if hvp[constants.HV_USE_LOCALTIME]:
1315       kvm_cmd.extend(["-localtime"])
1316
1317     if hvp[constants.HV_KVM_USE_CHROOT]:
1318       kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1319
1320     # Add qemu-KVM -cpu param
1321     if hvp[constants.HV_CPU_TYPE]:
1322       kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1323
1324     # Save the current instance nics, but defer their expansion as parameters,
1325     # as we'll need to generate executable temp files for them.
1326     kvm_nics = instance.nics
1327     hvparams = hvp
1328
1329     return (kvm_cmd, kvm_nics, hvparams)
1330
1331   def _WriteKVMRuntime(self, instance_name, data):
1332     """Write an instance's KVM runtime
1333
1334     """
1335     try:
1336       utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1337                       data=data)
1338     except EnvironmentError, err:
1339       raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1340
1341   def _ReadKVMRuntime(self, instance_name):
1342     """Read an instance's KVM runtime
1343
1344     """
1345     try:
1346       file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1347     except EnvironmentError, err:
1348       raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1349     return file_content
1350
1351   def _SaveKVMRuntime(self, instance, kvm_runtime):
1352     """Save an instance's KVM runtime
1353
1354     """
1355     kvm_cmd, kvm_nics, hvparams = kvm_runtime
1356     serialized_nics = [nic.ToDict() for nic in kvm_nics]
1357     serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1358     self._WriteKVMRuntime(instance.name, serialized_form)
1359
1360   def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1361     """Load an instance's KVM runtime
1362
1363     """
1364     if not serialized_runtime:
1365       serialized_runtime = self._ReadKVMRuntime(instance.name)
1366     loaded_runtime = serializer.Load(serialized_runtime)
1367     kvm_cmd, serialized_nics, hvparams = loaded_runtime
1368     kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1369     return (kvm_cmd, kvm_nics, hvparams)
1370
1371   def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1372     """Run the KVM cmd and check for errors
1373
1374     @type name: string
1375     @param name: instance name
1376     @type kvm_cmd: list of strings
1377     @param kvm_cmd: runcmd input for kvm
1378     @type tap_fds: list of int
1379     @param tap_fds: fds of tap devices opened by Ganeti
1380
1381     """
1382     try:
1383       result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1384     finally:
1385       for fd in tap_fds:
1386         utils_wrapper.CloseFdNoError(fd)
1387
1388     if result.failed:
1389       raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1390                                    (name, result.fail_reason, result.output))
1391     if not self._InstancePidAlive(name)[2]:
1392       raise errors.HypervisorError("Failed to start instance %s" % name)
1393
1394   def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
1395     """Execute a KVM cmd, after completing it with some last minute data.
1396
1397     @type incoming: tuple of strings
1398     @param incoming: (target_host_ip, port)
1399
1400     """
1401     # Small _ExecuteKVMRuntime hv parameters programming howto:
1402     #  - conf_hvp contains the parameters as configured on ganeti. they might
1403     #    have changed since the instance started; only use them if the change
1404     #    won't affect the inside of the instance (which hasn't been rebooted).
1405     #  - up_hvp contains the parameters as they were when the instance was
1406     #    started, plus any new parameter which has been added between ganeti
1407     #    versions: it is paramount that those default to a value which won't
1408     #    affect the inside of the instance as well.
1409     conf_hvp = instance.hvparams
1410     name = instance.name
1411     self._CheckDown(name)
1412
1413     temp_files = []
1414
1415     kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1416     up_hvp = objects.FillDict(conf_hvp, up_hvp)
1417
1418     _, v_major, v_min, _ = self._GetKVMVersion()
1419
1420     # We know it's safe to run as a different user upon migration, so we'll use
1421     # the latest conf, from conf_hvp.
1422     security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1423     if security_model == constants.HT_SM_USER:
1424       kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1425
1426     keymap = conf_hvp[constants.HV_KEYMAP]
1427     if keymap:
1428       keymap_path = self._InstanceKeymapFile(name)
1429       # If a keymap file is specified, KVM won't use its internal defaults. By
1430       # first including the "en-us" layout, an error on loading the actual
1431       # layout (e.g. because it can't be found) won't lead to a non-functional
1432       # keyboard. A keyboard with incorrect keys is still better than none.
1433       utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1434       kvm_cmd.extend(["-k", keymap_path])
1435
1436     # We have reasons to believe changing something like the nic driver/type
1437     # upon migration won't exactly fly with the instance kernel, so for nic
1438     # related parameters we'll use up_hvp
1439     tapfds = []
1440     taps = []
1441     if not kvm_nics:
1442       kvm_cmd.extend(["-net", "none"])
1443     else:
1444       vnet_hdr = False
1445       tap_extra = ""
1446       nic_type = up_hvp[constants.HV_NIC_TYPE]
1447       if nic_type == constants.HT_NIC_PARAVIRTUAL:
1448         # From version 0.12.0, kvm uses a new sintax for network configuration.
1449         if (v_major, v_min) >= (0, 12):
1450           nic_model = "virtio-net-pci"
1451           vnet_hdr = True
1452         else:
1453           nic_model = "virtio"
1454
1455         if up_hvp[constants.HV_VHOST_NET]:
1456           # vhost_net is only available from version 0.13.0 or newer
1457           if (v_major, v_min) >= (0, 13):
1458             tap_extra = ",vhost=on"
1459           else:
1460             raise errors.HypervisorError("vhost_net is configured"
1461                                          " but it is not available")
1462       else:
1463         nic_model = nic_type
1464
1465       for nic_seq, nic in enumerate(kvm_nics):
1466         tapname, tapfd = _OpenTap(vnet_hdr)
1467         tapfds.append(tapfd)
1468         taps.append(tapname)
1469         if (v_major, v_min) >= (0, 12):
1470           nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1471           tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1472           kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1473         else:
1474           nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1475                                                          nic.mac, nic_model)
1476           tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1477           kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1478
1479     if incoming:
1480       target, port = incoming
1481       kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1482
1483     # Changing the vnc password doesn't bother the guest that much. At most it
1484     # will surprise people who connect to it. Whether positively or negatively
1485     # it's debatable.
1486     vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1487     vnc_pwd = None
1488     if vnc_pwd_file:
1489       try:
1490         vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1491       except EnvironmentError, err:
1492         raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1493                                      % (vnc_pwd_file, err))
1494
1495     if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1496       utils.EnsureDirs([(self._InstanceChrootDir(name),
1497                          constants.SECURE_DIR_MODE)])
1498
1499     # Automatically enable QMP if version is >= 0.14
1500     if (v_major, v_min) >= (0, 14):
1501       logging.debug("Enabling QMP")
1502       kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1503                       self._InstanceQmpMonitor(instance.name)])
1504
1505     # Configure the network now for starting instances and bridged interfaces,
1506     # during FinalizeMigration for incoming instances' routed interfaces
1507     for nic_seq, nic in enumerate(kvm_nics):
1508       if (incoming and
1509           nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1510         continue
1511       self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1512
1513     # CPU affinity requires kvm to start paused, so we set this flag if the
1514     # instance is not already paused and if we are not going to accept a
1515     # migrating instance. In the latter case, pausing is not needed.
1516     start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1517     if start_kvm_paused:
1518       kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1519
1520     # Note: CPU pinning is using up_hvp since changes take effect
1521     # during instance startup anyway, and to avoid problems when soft
1522     # rebooting the instance.
1523     cpu_pinning = False
1524     if up_hvp.get(constants.HV_CPU_MASK, None):
1525       cpu_pinning = True
1526
1527     if security_model == constants.HT_SM_POOL:
1528       ss = ssconf.SimpleStore()
1529       uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1530       all_uids = set(uidpool.ExpandUidPool(uid_pool))
1531       uid = uidpool.RequestUnusedUid(all_uids)
1532       try:
1533         username = pwd.getpwuid(uid.GetUid()).pw_name
1534         kvm_cmd.extend(["-runas", username])
1535         self._RunKVMCmd(name, kvm_cmd, tapfds)
1536       except:
1537         uidpool.ReleaseUid(uid)
1538         raise
1539       else:
1540         uid.Unlock()
1541         utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1542     else:
1543       self._RunKVMCmd(name, kvm_cmd, tapfds)
1544
1545     utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1546                      constants.RUN_DIRS_MODE)])
1547     for nic_seq, tap in enumerate(taps):
1548       utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1549                       data=tap)
1550
1551     if vnc_pwd:
1552       change_cmd = "change vnc password %s" % vnc_pwd
1553       self._CallMonitorCommand(instance.name, change_cmd)
1554
1555     # Setting SPICE password. We are not vulnerable to malicious passwordless
1556     # connection attempts because SPICE by default does not allow connections
1557     # if neither a password nor the "disable_ticketing" options are specified.
1558     # As soon as we send the password via QMP, that password is a valid ticket
1559     # for connection.
1560     spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1561     if spice_password_file:
1562       spice_pwd = ""
1563       try:
1564         spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1565       except EnvironmentError, err:
1566         raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1567                                      % (spice_password_file, err))
1568
1569       qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1570       qmp.connect()
1571       arguments = {
1572           "protocol": "spice",
1573           "password": spice_pwd,
1574       }
1575       qmp.Execute("set_password", arguments)
1576
1577     for filename in temp_files:
1578       utils.RemoveFile(filename)
1579
1580     # If requested, set CPU affinity and resume instance execution
1581     if cpu_pinning:
1582       self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1583
1584     start_memory = self._InstanceStartupMemory(instance)
1585     if start_memory < instance.beparams[constants.BE_MAXMEM]:
1586       self.BalloonInstanceMemory(instance, start_memory)
1587
1588     if start_kvm_paused:
1589       # To control CPU pinning, ballooning, and vnc/spice passwords
1590       # the VM was started in a frozen state. If freezing was not
1591       # explicitly requested resume the vm status.
1592       self._CallMonitorCommand(instance.name, self._CONT_CMD)
1593
1594   def StartInstance(self, instance, block_devices, startup_paused):
1595     """Start an instance.
1596
1597     """
1598     self._CheckDown(instance.name)
1599     kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1600                                            startup_paused)
1601     self._SaveKVMRuntime(instance, kvm_runtime)
1602     self._ExecuteKVMRuntime(instance, kvm_runtime)
1603
1604   def _CallMonitorCommand(self, instance_name, command):
1605     """Invoke a command on the instance monitor.
1606
1607     """
1608     socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1609              (utils.ShellQuote(command),
1610               constants.SOCAT_PATH,
1611               utils.ShellQuote(self._InstanceMonitor(instance_name))))
1612     result = utils.RunCmd(socat)
1613     if result.failed:
1614       msg = ("Failed to send command '%s' to instance %s."
1615              " output: %s, error: %s, fail_reason: %s" %
1616              (command, instance_name,
1617               result.stdout, result.stderr, result.fail_reason))
1618       raise errors.HypervisorError(msg)
1619
1620     return result
1621
1622   @classmethod
1623   def _ParseKVMVersion(cls, text):
1624     """Parse the KVM version from the --help output.
1625
1626     @type text: string
1627     @param text: output of kvm --help
1628     @return: (version, v_maj, v_min, v_rev)
1629     @raise errors.HypervisorError: when the KVM version cannot be retrieved
1630
1631     """
1632     match = cls._VERSION_RE.search(text.splitlines()[0])
1633     if not match:
1634       raise errors.HypervisorError("Unable to get KVM version")
1635
1636     v_all = match.group(0)
1637     v_maj = int(match.group(1))
1638     v_min = int(match.group(2))
1639     if match.group(4):
1640       v_rev = int(match.group(4))
1641     else:
1642       v_rev = 0
1643     return (v_all, v_maj, v_min, v_rev)
1644
1645   @classmethod
1646   def _GetKVMHelpOutput(cls):
1647     """Return the KVM help output.
1648
1649     @return: output of kvm --help
1650     @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1651
1652     """
1653     result = utils.RunCmd([constants.KVM_PATH, "--help"])
1654     if result.failed:
1655       raise errors.HypervisorError("Unable to get KVM help output")
1656     return result.output
1657
1658   @classmethod
1659   def _GetKVMVersion(cls):
1660     """Return the installed KVM version.
1661
1662     @return: (version, v_maj, v_min, v_rev)
1663     @raise errors.HypervisorError: when the KVM version cannot be retrieved
1664
1665     """
1666     return cls._ParseKVMVersion(cls._GetKVMHelpOutput())
1667
1668   def StopInstance(self, instance, force=False, retry=False, name=None):
1669     """Stop an instance.
1670
1671     """
1672     if name is not None and not force:
1673       raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1674     if name is None:
1675       name = instance.name
1676       acpi = instance.hvparams[constants.HV_ACPI]
1677     else:
1678       acpi = False
1679     _, pid, alive = self._InstancePidAlive(name)
1680     if pid > 0 and alive:
1681       if force or not acpi:
1682         utils.KillProcess(pid)
1683       else:
1684         self._CallMonitorCommand(name, "system_powerdown")
1685
1686   @classmethod
1687   def _GetDefaultMachineVersion(cls):
1688     """Return the default hardware revision (e.g. pc-1.1)
1689
1690     """
1691     result = utils.RunCmd([constants.KVM_PATH, "-M", "?"])
1692     if result.failed:
1693       raise errors.HypervisorError("Unable to get default hardware revision")
1694     for line in result.output.splitlines():
1695       match = cls._DEFAULT_MACHINE_VERSION_RE.match(line)
1696       if match:
1697         return match.group(1)
1698
1699     return "pc"
1700
1701   def CleanupInstance(self, instance_name):
1702     """Cleanup after a stopped instance
1703
1704     """
1705     pidfile, pid, alive = self._InstancePidAlive(instance_name)
1706     if pid > 0 and alive:
1707       raise errors.HypervisorError("Cannot cleanup a live instance")
1708     self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1709
1710   def RebootInstance(self, instance):
1711     """Reboot an instance.
1712
1713     """
1714     # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1715     # socket the instance will stop, but now power up again. So we'll resort
1716     # to shutdown and restart.
1717     _, _, alive = self._InstancePidAlive(instance.name)
1718     if not alive:
1719       raise errors.HypervisorError("Failed to reboot instance %s:"
1720                                    " not running" % instance.name)
1721     # StopInstance will delete the saved KVM runtime so:
1722     # ...first load it...
1723     kvm_runtime = self._LoadKVMRuntime(instance)
1724     # ...now we can safely call StopInstance...
1725     if not self.StopInstance(instance):
1726       self.StopInstance(instance, force=True)
1727     # ...and finally we can save it again, and execute it...
1728     self._SaveKVMRuntime(instance, kvm_runtime)
1729     self._ExecuteKVMRuntime(instance, kvm_runtime)
1730
1731   def MigrationInfo(self, instance):
1732     """Get instance information to perform a migration.
1733
1734     @type instance: L{objects.Instance}
1735     @param instance: instance to be migrated
1736     @rtype: string
1737     @return: content of the KVM runtime file
1738
1739     """
1740     return self._ReadKVMRuntime(instance.name)
1741
1742   def AcceptInstance(self, instance, info, target):
1743     """Prepare to accept an instance.
1744
1745     @type instance: L{objects.Instance}
1746     @param instance: instance to be accepted
1747     @type info: string
1748     @param info: content of the KVM runtime file on the source node
1749     @type target: string
1750     @param target: target host (usually ip), on this node
1751
1752     """
1753     kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1754     incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1755     self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
1756
1757   def FinalizeMigrationDst(self, instance, info, success):
1758     """Finalize the instance migration on the target node.
1759
1760     Stop the incoming mode KVM.
1761
1762     @type instance: L{objects.Instance}
1763     @param instance: instance whose migration is being finalized
1764
1765     """
1766     if success:
1767       kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1768       kvm_nics = kvm_runtime[1]
1769
1770       for nic_seq, nic in enumerate(kvm_nics):
1771         if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1772           # Bridged interfaces have already been configured
1773           continue
1774         try:
1775           tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1776         except EnvironmentError, err:
1777           logging.warning("Failed to find host interface for %s NIC #%d: %s",
1778                           instance.name, nic_seq, str(err))
1779           continue
1780         try:
1781           self._ConfigureNIC(instance, nic_seq, nic, tap)
1782         except errors.HypervisorError, err:
1783           logging.warning(str(err))
1784
1785       self._WriteKVMRuntime(instance.name, info)
1786     else:
1787       self.StopInstance(instance, force=True)
1788
1789   def MigrateInstance(self, instance, target, live):
1790     """Migrate an instance to a target node.
1791
1792     The migration will not be attempted if the instance is not
1793     currently running.
1794
1795     @type instance: L{objects.Instance}
1796     @param instance: the instance to be migrated
1797     @type target: string
1798     @param target: ip address of the target node
1799     @type live: boolean
1800     @param live: perform a live migration
1801
1802     """
1803     instance_name = instance.name
1804     port = instance.hvparams[constants.HV_MIGRATION_PORT]
1805     _, _, alive = self._InstancePidAlive(instance_name)
1806     if not alive:
1807       raise errors.HypervisorError("Instance not running, cannot migrate")
1808
1809     if not live:
1810       self._CallMonitorCommand(instance_name, "stop")
1811
1812     migrate_command = ("migrate_set_speed %dm" %
1813                        instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1814     self._CallMonitorCommand(instance_name, migrate_command)
1815
1816     migrate_command = ("migrate_set_downtime %dms" %
1817                        instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1818     self._CallMonitorCommand(instance_name, migrate_command)
1819
1820     migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1821     self._CallMonitorCommand(instance_name, migrate_command)
1822
1823   def FinalizeMigrationSource(self, instance, success, live):
1824     """Finalize the instance migration on the source node.
1825
1826     @type instance: L{objects.Instance}
1827     @param instance: the instance that was migrated
1828     @type success: bool
1829     @param success: whether the migration succeeded or not
1830     @type live: bool
1831     @param live: whether the user requested a live migration or not
1832
1833     """
1834     if success:
1835       pidfile, pid, _ = self._InstancePidAlive(instance.name)
1836       utils.KillProcess(pid)
1837       self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1838     elif live:
1839       self._CallMonitorCommand(instance.name, self._CONT_CMD)
1840
1841   def GetMigrationStatus(self, instance):
1842     """Get the migration status
1843
1844     @type instance: L{objects.Instance}
1845     @param instance: the instance that is being migrated
1846     @rtype: L{objects.MigrationStatus}
1847     @return: the status of the current migration (one of
1848              L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1849              progress info that can be retrieved from the hypervisor
1850
1851     """
1852     info_command = "info migrate"
1853     for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
1854       result = self._CallMonitorCommand(instance.name, info_command)
1855       match = self._MIGRATION_STATUS_RE.search(result.stdout)
1856       if not match:
1857         if not result.stdout:
1858           logging.info("KVM: empty 'info migrate' result")
1859         else:
1860           logging.warning("KVM: unknown 'info migrate' result: %s",
1861                           result.stdout)
1862       else:
1863         status = match.group(1)
1864         if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
1865           migration_status = objects.MigrationStatus(status=status)
1866           match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
1867           if match:
1868             migration_status.transferred_ram = match.group("transferred")
1869             migration_status.total_ram = match.group("total")
1870
1871           return migration_status
1872
1873         logging.warning("KVM: unknown migration status '%s'", status)
1874
1875       time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1876
1877     return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
1878
1879   def BalloonInstanceMemory(self, instance, mem):
1880     """Balloon an instance memory to a certain value.
1881
1882     @type instance: L{objects.Instance}
1883     @param instance: instance to be accepted
1884     @type mem: int
1885     @param mem: actual memory size to use for instance runtime
1886
1887     """
1888     self._CallMonitorCommand(instance.name, "balloon %d" % mem)
1889
1890   def GetNodeInfo(self):
1891     """Return information about the node.
1892
1893     @return: a dict with the following keys (values in MiB):
1894           - memory_total: the total memory size on the node
1895           - memory_free: the available memory on the node for instances
1896           - memory_dom0: the memory used by the node itself, if available
1897           - hv_version: the hypervisor version in the form (major, minor,
1898                         revision)
1899
1900     """
1901     result = self.GetLinuxNodeInfo()
1902     _, v_major, v_min, v_rev = self._GetKVMVersion()
1903     result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
1904     return result
1905
1906   @classmethod
1907   def GetInstanceConsole(cls, instance, hvparams, beparams):
1908     """Return a command for connecting to the console of an instance.
1909
1910     """
1911     if hvparams[constants.HV_SERIAL_CONSOLE]:
1912       cmd = [pathutils.KVM_CONSOLE_WRAPPER,
1913              constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1914              utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1915              "STDIO,%s" % cls._SocatUnixConsoleParams(),
1916              "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1917       return objects.InstanceConsole(instance=instance.name,
1918                                      kind=constants.CONS_SSH,
1919                                      host=instance.primary_node,
1920                                      user=constants.SSH_CONSOLE_USER,
1921                                      command=cmd)
1922
1923     vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1924     if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1925       display = instance.network_port - constants.VNC_BASE_PORT
1926       return objects.InstanceConsole(instance=instance.name,
1927                                      kind=constants.CONS_VNC,
1928                                      host=vnc_bind_address,
1929                                      port=instance.network_port,
1930                                      display=display)
1931
1932     spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1933     if spice_bind:
1934       return objects.InstanceConsole(instance=instance.name,
1935                                      kind=constants.CONS_SPICE,
1936                                      host=spice_bind,
1937                                      port=instance.network_port)
1938
1939     return objects.InstanceConsole(instance=instance.name,
1940                                    kind=constants.CONS_MESSAGE,
1941                                    message=("No serial shell for instance %s" %
1942                                             instance.name))
1943
1944   def Verify(self):
1945     """Verify the hypervisor.
1946
1947     Check that the binary exists.
1948
1949     """
1950     if not os.path.exists(constants.KVM_PATH):
1951       return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
1952     if not os.path.exists(constants.SOCAT_PATH):
1953       return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
1954
1955   @classmethod
1956   def CheckParameterSyntax(cls, hvparams):
1957     """Check the given parameters for validity.
1958
1959     @type hvparams:  dict
1960     @param hvparams: dictionary with parameter names/value
1961     @raise errors.HypervisorError: when a parameter is not valid
1962
1963     """
1964     super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
1965
1966     kernel_path = hvparams[constants.HV_KERNEL_PATH]
1967     if kernel_path:
1968       if not hvparams[constants.HV_ROOT_PATH]:
1969         raise errors.HypervisorError("Need a root partition for the instance,"
1970                                      " if a kernel is defined")
1971
1972     if (hvparams[constants.HV_VNC_X509_VERIFY] and
1973         not hvparams[constants.HV_VNC_X509]):
1974       raise errors.HypervisorError("%s must be defined, if %s is" %
1975                                    (constants.HV_VNC_X509,
1976                                     constants.HV_VNC_X509_VERIFY))
1977
1978     if hvparams[constants.HV_SERIAL_CONSOLE]:
1979       serial_speed = hvparams[constants.HV_SERIAL_SPEED]
1980       valid_speeds = constants.VALID_SERIAL_SPEEDS
1981       if not serial_speed or serial_speed not in valid_speeds:
1982         raise errors.HypervisorError("Invalid serial console speed, must be"
1983                                      " one of: %s" %
1984                                      utils.CommaJoin(valid_speeds))
1985
1986     boot_order = hvparams[constants.HV_BOOT_ORDER]
1987     if (boot_order == constants.HT_BO_CDROM and
1988         not hvparams[constants.HV_CDROM_IMAGE_PATH]):
1989       raise errors.HypervisorError("Cannot boot from cdrom without an"
1990                                    " ISO path")
1991
1992     security_model = hvparams[constants.HV_SECURITY_MODEL]
1993     if security_model == constants.HT_SM_USER:
1994       if not hvparams[constants.HV_SECURITY_DOMAIN]:
1995         raise errors.HypervisorError("A security domain (user to run kvm as)"
1996                                      " must be specified")
1997     elif (security_model == constants.HT_SM_NONE or
1998           security_model == constants.HT_SM_POOL):
1999       if hvparams[constants.HV_SECURITY_DOMAIN]:
2000         raise errors.HypervisorError("Cannot have a security domain when the"
2001                                      " security model is 'none' or 'pool'")
2002
2003     spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2004     spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2005     if spice_bind:
2006       if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2007         # if an IP version is specified, the spice_bind parameter must be an
2008         # IP of that family
2009         if (netutils.IP4Address.IsValid(spice_bind) and
2010             spice_ip_version != constants.IP4_VERSION):
2011           raise errors.HypervisorError("spice: got an IPv4 address (%s), but"
2012                                        " the specified IP version is %s" %
2013                                        (spice_bind, spice_ip_version))
2014
2015         if (netutils.IP6Address.IsValid(spice_bind) and
2016             spice_ip_version != constants.IP6_VERSION):
2017           raise errors.HypervisorError("spice: got an IPv6 address (%s), but"
2018                                        " the specified IP version is %s" %
2019                                        (spice_bind, spice_ip_version))
2020     else:
2021       # All the other SPICE parameters depend on spice_bind being set. Raise an
2022       # error if any of them is set without it.
2023       for param in _SPICE_ADDITIONAL_PARAMS:
2024         if hvparams[param]:
2025           raise errors.HypervisorError("spice: %s requires %s to be set" %
2026                                        (param, constants.HV_KVM_SPICE_BIND))
2027
2028   @classmethod
2029   def ValidateParameters(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).ValidateParameters(hvparams)
2038
2039     security_model = hvparams[constants.HV_SECURITY_MODEL]
2040     if security_model == constants.HT_SM_USER:
2041       username = hvparams[constants.HV_SECURITY_DOMAIN]
2042       try:
2043         pwd.getpwnam(username)
2044       except KeyError:
2045         raise errors.HypervisorError("Unknown security domain user %s"
2046                                      % username)
2047
2048     spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2049     if spice_bind:
2050       # only one of VNC and SPICE can be used currently.
2051       if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2052         raise errors.HypervisorError("both SPICE and VNC are configured, but"
2053                                      " only one of them can be used at a"
2054                                      " given time.")
2055
2056       # KVM version should be >= 0.14.0
2057       _, v_major, v_min, _ = cls._GetKVMVersion()
2058       if (v_major, v_min) < (0, 14):
2059         raise errors.HypervisorError("spice is configured, but it is not"
2060                                      " available in versions of KVM < 0.14")
2061
2062       # if spice_bind is not an IP address, it must be a valid interface
2063       bound_to_addr = (netutils.IP4Address.IsValid(spice_bind)
2064                        or netutils.IP6Address.IsValid(spice_bind))
2065       if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2066         raise errors.HypervisorError("spice: the %s parameter must be either"
2067                                      " a valid IP address or interface name" %
2068                                      constants.HV_KVM_SPICE_BIND)
2069
2070   @classmethod
2071   def PowercycleNode(cls):
2072     """KVM powercycle, just a wrapper over Linux powercycle.
2073
2074     """
2075     cls.LinuxPowercycle()