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