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