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