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