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