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