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