(fix) Remove uri slot from block_devices
[ganeti-local] / lib / hypervisor / hv_kvm.py
1 #
2 #
3
4 # Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 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 import netutils
53 from ganeti import pathutils
54 from ganeti.hypervisor import hv_base
55 from ganeti.utils import wrapper as utils_wrapper
56
57
58 _KVM_NETWORK_SCRIPT = pathutils.CONF_DIR + "/kvm-vif-bridge"
59 _KVM_START_PAUSED_FLAG = "-S"
60
61 # TUN/TAP driver constants, taken from <linux/if_tun.h>
62 # They are architecture-independent and already hardcoded in qemu-kvm source,
63 # so we can safely include them here.
64 TUNSETIFF = 0x400454ca
65 TUNGETIFF = 0x800454d2
66 TUNGETFEATURES = 0x800454cf
67 IFF_TAP = 0x0002
68 IFF_NO_PI = 0x1000
69 IFF_VNET_HDR = 0x4000
70
71 #: SPICE parameters which depend on L{constants.HV_KVM_SPICE_BIND}
72 _SPICE_ADDITIONAL_PARAMS = frozenset([
73   constants.HV_KVM_SPICE_IP_VERSION,
74   constants.HV_KVM_SPICE_PASSWORD_FILE,
75   constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR,
76   constants.HV_KVM_SPICE_JPEG_IMG_COMPR,
77   constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR,
78   constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION,
79   constants.HV_KVM_SPICE_USE_TLS,
80   ])
81
82 # below constants show the format of runtime file
83 # the nics are in second possition, while the disks in 4th (last)
84 # moreover disk entries are stored in tupples of L{objects.Disk}, dev_path
85 _KVM_NICS_RUNTIME_INDEX = 1
86 _KVM_DISKS_RUNTIME_INDEX = 3
87 _DEVICE_RUNTIME_INDEX = {
88   constants.HOTPLUG_TARGET_DISK: _KVM_DISKS_RUNTIME_INDEX,
89   constants.HOTPLUG_TARGET_NIC: _KVM_NICS_RUNTIME_INDEX
90   }
91 _FIND_RUNTIME_ENTRY = {
92   constants.HOTPLUG_TARGET_NIC:
93     lambda nic, kvm_nics: [n for n in kvm_nics if n.uuid == nic.uuid],
94   constants.HOTPLUG_TARGET_DISK:
95     lambda disk, kvm_disks: [(d, l) for (d, l) in kvm_disks
96                              if d.uuid == disk.uuid]
97   }
98 _RUNTIME_DEVICE = {
99   constants.HOTPLUG_TARGET_NIC: lambda d: d,
100   constants.HOTPLUG_TARGET_DISK: lambda (d, e): d
101   }
102 _RUNTIME_ENTRY = {
103   constants.HOTPLUG_TARGET_NIC: lambda d, e: d,
104   constants.HOTPLUG_TARGET_DISK: lambda d, e: (d, e)
105   }
106
107
108 def _GetExistingDeviceInfo(dev_type, device, runtime):
109   """Helper function to get an existing device inside the runtime file
110
111   Used when an instance is running. Load kvm runtime file and search
112   for a device based on its type and uuid.
113
114   @type dev_type: sting
115   @param dev_type: device type of param dev
116   @type device: L{objects.Disk} or L{objects.NIC}
117   @param device: the device object for which we generate a kvm name
118   @type runtime: tuple (cmd, nics, hvparams, disks)
119   @param runtime: the runtime data to search for the device
120   @raise errors.HotplugError: in case the requested device does not
121     exist (e.g. device has been added without --hotplug option) or
122     device info has not pci slot (e.g. old devices in the cluster)
123
124   """
125   index = _DEVICE_RUNTIME_INDEX[dev_type]
126   found = _FIND_RUNTIME_ENTRY[dev_type](device, runtime[index])
127   if not found:
128     raise errors.HotplugError("Cannot find runtime info for %s with UUID %s" %
129                               (dev_type, device.uuid))
130
131   return found[0]
132
133
134 def _AnalyzeSerializedRuntime(serialized_runtime):
135   """Return runtime entries for a serialized runtime file
136
137   @type serialized_runtime: string
138   @param serialized_runtime: raw text data read from actual runtime file
139   @return: (cmd, nics, hvparams, bdevs)
140   @rtype: list
141
142   """
143   loaded_runtime = serializer.Load(serialized_runtime)
144   if len(loaded_runtime) == 3:
145     serialized_blockdevs = []
146     kvm_cmd, serialized_nics, hvparams = loaded_runtime
147   else:
148     kvm_cmd, serialized_nics, hvparams, serialized_blockdevs = loaded_runtime
149
150   kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
151   block_devices = [(objects.Disk.FromDict(sdisk), link)
152                    for sdisk, link in serialized_blockdevs]
153
154   return (kvm_cmd, kvm_nics, hvparams, block_devices)
155
156
157 def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
158   """Retrieves supported TUN features from file descriptor.
159
160   @see: L{_ProbeTapVnetHdr}
161
162   """
163   req = struct.pack("I", 0)
164   try:
165     buf = _ioctl(fd, TUNGETFEATURES, req)
166   except EnvironmentError, err:
167     logging.warning("ioctl(TUNGETFEATURES) failed: %s", err)
168     return None
169   else:
170     (flags, ) = struct.unpack("I", buf)
171     return flags
172
173
174 def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
175   """Check whether to enable the IFF_VNET_HDR flag.
176
177   To do this, _all_ of the following conditions must be met:
178    1. TUNGETFEATURES ioctl() *must* be implemented
179    2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
180    3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
181       drivers/net/tun.c there is no way to test this until after the tap device
182       has been created using TUNSETIFF, and there is no way to change the
183       IFF_VNET_HDR flag after creating the interface, catch-22! However both
184       TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
185       thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
186
187    @type fd: int
188    @param fd: the file descriptor of /dev/net/tun
189
190   """
191   flags = _features_fn(fd)
192
193   if flags is None:
194     # Not supported
195     return False
196
197   result = bool(flags & IFF_VNET_HDR)
198
199   if not result:
200     logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
201
202   return result
203
204
205 def _OpenTap(vnet_hdr=True):
206   """Open a new tap device and return its file descriptor.
207
208   This is intended to be used by a qemu-type hypervisor together with the -net
209   tap,fd=<fd> command line parameter.
210
211   @type vnet_hdr: boolean
212   @param vnet_hdr: Enable the VNET Header
213   @return: (ifname, tapfd)
214   @rtype: tuple
215
216   """
217   try:
218     tapfd = os.open("/dev/net/tun", os.O_RDWR)
219   except EnvironmentError:
220     raise errors.HypervisorError("Failed to open /dev/net/tun")
221
222   flags = IFF_TAP | IFF_NO_PI
223
224   if vnet_hdr and _ProbeTapVnetHdr(tapfd):
225     flags |= IFF_VNET_HDR
226
227   # The struct ifreq ioctl request (see netdevice(7))
228   ifr = struct.pack("16sh", "", flags)
229
230   try:
231     res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
232   except EnvironmentError, err:
233     raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
234                                  err)
235
236   # Get the interface name from the ioctl
237   ifname = struct.unpack("16sh", res)[0].strip("\x00")
238   return (ifname, tapfd)
239
240
241 class QmpMessage:
242   """QEMU Messaging Protocol (QMP) message.
243
244   """
245   def __init__(self, data):
246     """Creates a new QMP message based on the passed data.
247
248     """
249     if not isinstance(data, dict):
250       raise TypeError("QmpMessage must be initialized with a dict")
251
252     self.data = data
253
254   def __getitem__(self, field_name):
255     """Get the value of the required field if present, or None.
256
257     Overrides the [] operator to provide access to the message data,
258     returning None if the required item is not in the message
259     @return: the value of the field_name field, or None if field_name
260              is not contained in the message
261
262     """
263     return self.data.get(field_name, None)
264
265   def __setitem__(self, field_name, field_value):
266     """Set the value of the required field_name to field_value.
267
268     """
269     self.data[field_name] = field_value
270
271   @staticmethod
272   def BuildFromJsonString(json_string):
273     """Build a QmpMessage from a JSON encoded string.
274
275     @type json_string: str
276     @param json_string: JSON string representing the message
277     @rtype: L{QmpMessage}
278     @return: a L{QmpMessage} built from json_string
279
280     """
281     # Parse the string
282     data = serializer.LoadJson(json_string)
283     return QmpMessage(data)
284
285   def __str__(self):
286     # The protocol expects the JSON object to be sent as a single line.
287     return serializer.DumpJson(self.data)
288
289   def __eq__(self, other):
290     # When comparing two QmpMessages, we are interested in comparing
291     # their internal representation of the message data
292     return self.data == other.data
293
294
295 class QmpConnection:
296   """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
297
298   """
299   _FIRST_MESSAGE_KEY = "QMP"
300   _EVENT_KEY = "event"
301   _ERROR_KEY = "error"
302   _RETURN_KEY = RETURN_KEY = "return"
303   _ACTUAL_KEY = ACTUAL_KEY = "actual"
304   _ERROR_CLASS_KEY = "class"
305   _ERROR_DATA_KEY = "data"
306   _ERROR_DESC_KEY = "desc"
307   _EXECUTE_KEY = "execute"
308   _ARGUMENTS_KEY = "arguments"
309   _CAPABILITIES_COMMAND = "qmp_capabilities"
310   _MESSAGE_END_TOKEN = "\r\n"
311   _SOCKET_TIMEOUT = 5
312
313   def __init__(self, monitor_filename):
314     """Instantiates the QmpConnection object.
315
316     @type monitor_filename: string
317     @param monitor_filename: the filename of the UNIX raw socket on which the
318                              QMP monitor is listening
319
320     """
321     self.monitor_filename = monitor_filename
322     self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
323     # We want to fail if the server doesn't send a complete message
324     # in a reasonable amount of time
325     self.sock.settimeout(self._SOCKET_TIMEOUT)
326     self._connected = False
327     self._buf = ""
328
329   def _check_socket(self):
330     sock_stat = None
331     try:
332       sock_stat = os.stat(self.monitor_filename)
333     except EnvironmentError, err:
334       if err.errno == errno.ENOENT:
335         raise errors.HypervisorError("No qmp socket found")
336       else:
337         raise errors.HypervisorError("Error checking qmp socket: %s",
338                                      utils.ErrnoOrStr(err))
339     if not stat.S_ISSOCK(sock_stat.st_mode):
340       raise errors.HypervisorError("Qmp socket is not a socket")
341
342   def _check_connection(self):
343     """Make sure that the connection is established.
344
345     """
346     if not self._connected:
347       raise errors.ProgrammerError("To use a QmpConnection you need to first"
348                                    " invoke connect() on it")
349
350   def connect(self):
351     """Connects to the QMP monitor.
352
353     Connects to the UNIX socket and makes sure that we can actually send and
354     receive data to the kvm instance via QMP.
355
356     @raise errors.HypervisorError: when there are communication errors
357     @raise errors.ProgrammerError: when there are data serialization errors
358
359     """
360     if self._connected:
361       raise errors.ProgrammerError("Cannot connect twice")
362
363     self._check_socket()
364
365     # Check file existance/stuff
366     try:
367       self.sock.connect(self.monitor_filename)
368     except EnvironmentError:
369       raise errors.HypervisorError("Can't connect to qmp socket")
370     self._connected = True
371
372     # Check if we receive a correct greeting message from the server
373     # (As per the QEMU Protocol Specification 0.1 - section 2.2)
374     greeting = self._Recv()
375     if not greeting[self._FIRST_MESSAGE_KEY]:
376       self._connected = False
377       raise errors.HypervisorError("kvm: QMP communication error (wrong"
378                                    " server greeting")
379
380     # Let's put the monitor in command mode using the qmp_capabilities
381     # command, or else no command will be executable.
382     # (As per the QEMU Protocol Specification 0.1 - section 4)
383     self.Execute(self._CAPABILITIES_COMMAND)
384
385   def _ParseMessage(self, buf):
386     """Extract and parse a QMP message from the given buffer.
387
388     Seeks for a QMP message in the given buf. If found, it parses it and
389     returns it together with the rest of the characters in the buf.
390     If no message is found, returns None and the whole buffer.
391
392     @raise errors.ProgrammerError: when there are data serialization errors
393
394     """
395     message = None
396     # Check if we got the message end token (CRLF, as per the QEMU Protocol
397     # Specification 0.1 - Section 2.1.1)
398     pos = buf.find(self._MESSAGE_END_TOKEN)
399     if pos >= 0:
400       try:
401         message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
402       except Exception, err:
403         raise errors.ProgrammerError("QMP data serialization error: %s" % err)
404       buf = buf[pos + 1:]
405
406     return (message, buf)
407
408   def _Recv(self):
409     """Receives a message from QMP and decodes the received JSON object.
410
411     @rtype: QmpMessage
412     @return: the received message
413     @raise errors.HypervisorError: when there are communication errors
414     @raise errors.ProgrammerError: when there are data serialization errors
415
416     """
417     self._check_connection()
418
419     # Check if there is already a message in the buffer
420     (message, self._buf) = self._ParseMessage(self._buf)
421     if message:
422       return message
423
424     recv_buffer = StringIO.StringIO(self._buf)
425     recv_buffer.seek(len(self._buf))
426     try:
427       while True:
428         data = self.sock.recv(4096)
429         if not data:
430           break
431         recv_buffer.write(data)
432
433         (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
434         if message:
435           return message
436
437     except socket.timeout, err:
438       raise errors.HypervisorError("Timeout while receiving a QMP message: "
439                                    "%s" % (err))
440     except socket.error, err:
441       raise errors.HypervisorError("Unable to receive data from KVM using the"
442                                    " QMP protocol: %s" % err)
443
444   def _Send(self, message):
445     """Encodes and sends a message to KVM using QMP.
446
447     @type message: QmpMessage
448     @param message: message to send to KVM
449     @raise errors.HypervisorError: when there are communication errors
450     @raise errors.ProgrammerError: when there are data serialization errors
451
452     """
453     self._check_connection()
454     try:
455       message_str = str(message)
456     except Exception, err:
457       raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
458
459     try:
460       self.sock.sendall(message_str)
461     except socket.timeout, err:
462       raise errors.HypervisorError("Timeout while sending a QMP message: "
463                                    "%s (%s)" % (err.string, err.errno))
464     except socket.error, err:
465       raise errors.HypervisorError("Unable to send data from KVM using the"
466                                    " QMP protocol: %s" % err)
467
468   def Execute(self, command, arguments=None):
469     """Executes a QMP command and returns the response of the server.
470
471     @type command: str
472     @param command: the command to execute
473     @type arguments: dict
474     @param arguments: dictionary of arguments to be passed to the command
475     @rtype: dict
476     @return: dictionary representing the received JSON object
477     @raise errors.HypervisorError: when there are communication errors
478     @raise errors.ProgrammerError: when there are data serialization errors
479
480     """
481     self._check_connection()
482     message = QmpMessage({self._EXECUTE_KEY: command})
483     if arguments:
484       message[self._ARGUMENTS_KEY] = arguments
485     self._Send(message)
486
487     # Events can occur between the sending of the command and the reception
488     # of the response, so we need to filter out messages with the event key.
489     while True:
490       response = self._Recv()
491       err = response[self._ERROR_KEY]
492       if err:
493         raise errors.HypervisorError("kvm: error executing the %s"
494                                      " command: %s (%s, %s):" %
495                                      (command,
496                                       err[self._ERROR_DESC_KEY],
497                                       err[self._ERROR_CLASS_KEY],
498                                       err[self._ERROR_DATA_KEY]))
499
500       elif not response[self._EVENT_KEY]:
501         return response
502
503
504 class KVMHypervisor(hv_base.BaseHypervisor):
505   """KVM hypervisor interface
506
507   """
508   CAN_MIGRATE = True
509
510   _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
511   _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
512   _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
513   _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
514   _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
515   _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
516   _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
517   # KVM instances with chroot enabled are started in empty chroot directories.
518   _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
519   # After an instance is stopped, its chroot directory is removed.
520   # If the chroot directory is not empty, it can't be removed.
521   # A non-empty chroot directory indicates a possible security incident.
522   # To support forensics, the non-empty chroot directory is quarantined in
523   # a separate directory, called 'chroot-quarantine'.
524   _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
525   _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
526            _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
527
528   PARAMETERS = {
529     constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
530     constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
531     constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
532     constants.HV_ROOT_PATH: hv_base.NO_CHECK,
533     constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
534     constants.HV_ACPI: hv_base.NO_CHECK,
535     constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
536     constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
537     constants.HV_VNC_BIND_ADDRESS:
538       (False, lambda x: (netutils.IP4Address.IsValid(x) or
539                          utils.IsNormAbsPath(x)),
540        "The VNC bind address must be either a valid IP address or an absolute"
541        " pathname", None, None),
542     constants.HV_VNC_TLS: hv_base.NO_CHECK,
543     constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
544     constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
545     constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
546     constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
547     constants.HV_KVM_SPICE_IP_VERSION:
548       (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
549                          x in constants.VALID_IP_VERSIONS),
550        "The SPICE IP version should be 4 or 6",
551        None, None),
552     constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
553     constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
554       hv_base.ParamInSet(
555         False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
556     constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
557       hv_base.ParamInSet(
558         False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
559     constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
560       hv_base.ParamInSet(
561         False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
562     constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
563       hv_base.ParamInSet(
564         False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
565     constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
566     constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
567     constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
568     constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
569     constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
570     constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
571     constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
572     constants.HV_BOOT_ORDER:
573       hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
574     constants.HV_NIC_TYPE:
575       hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
576     constants.HV_DISK_TYPE:
577       hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
578     constants.HV_KVM_CDROM_DISK_TYPE:
579       hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
580     constants.HV_USB_MOUSE:
581       hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
582     constants.HV_KEYMAP: hv_base.NO_CHECK,
583     constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
584     constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
585     constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
586     constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
587     constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
588     constants.HV_DISK_CACHE:
589       hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
590     constants.HV_SECURITY_MODEL:
591       hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
592     constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
593     constants.HV_KVM_FLAG:
594       hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
595     constants.HV_VHOST_NET: hv_base.NO_CHECK,
596     constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
597     constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
598     constants.HV_REBOOT_BEHAVIOR:
599       hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
600     constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
601     constants.HV_CPU_TYPE: hv_base.NO_CHECK,
602     constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
603     constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
604     constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
605     constants.HV_SOUNDHW: hv_base.NO_CHECK,
606     constants.HV_USB_DEVICES: hv_base.NO_CHECK,
607     constants.HV_VGA: hv_base.NO_CHECK,
608     constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
609     constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
610     constants.HV_VNET_HDR: hv_base.NO_CHECK,
611     }
612
613   _VIRTIO = "virtio"
614   _VIRTIO_NET_PCI = "virtio-net-pci"
615   _VIRTIO_BLK_PCI = "virtio-blk-pci"
616
617   _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
618                                     re.M | re.I)
619   _MIGRATION_PROGRESS_RE = \
620     re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
621                r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
622                r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
623
624   _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
625   _MIGRATION_INFO_RETRY_DELAY = 2
626
627   _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
628
629   _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
630   _CPU_INFO_CMD = "info cpus"
631   _CONT_CMD = "cont"
632
633   _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
634   _CHECK_MACHINE_VERSION_RE = \
635     staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
636
637   _QMP_RE = re.compile(r"^-qmp\s", re.M)
638   _SPICE_RE = re.compile(r"^-spice\s", re.M)
639   _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
640   _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
641   _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
642   _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
643   _DISPLAY_RE = re.compile(r"^-display\s", re.M)
644   _MACHINE_RE = re.compile(r"^-machine\s", re.M)
645   _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
646   _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M)
647   # match  -drive.*boot=on|off on different lines, but in between accept only
648   # dashes not preceeded by a new line (which would mean another option
649   # different than -drive is starting)
650   _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
651
652   ANCILLARY_FILES = [
653     _KVM_NETWORK_SCRIPT,
654     ]
655   ANCILLARY_FILES_OPT = [
656     _KVM_NETWORK_SCRIPT,
657     ]
658
659   # Supported kvm options to get output from
660   _KVMOPT_HELP = "help"
661   _KVMOPT_MLIST = "mlist"
662   _KVMOPT_DEVICELIST = "devicelist"
663
664   # Command to execute to get the output from kvm, and whether to
665   # accept the output even on failure.
666   _KVMOPTS_CMDS = {
667     _KVMOPT_HELP: (["--help"], False),
668     _KVMOPT_MLIST: (["-M", "?"], False),
669     _KVMOPT_DEVICELIST: (["-device", "?"], True),
670   }
671
672   def __init__(self):
673     hv_base.BaseHypervisor.__init__(self)
674     # Let's make sure the directories we need exist, even if the RUN_DIR lives
675     # in a tmpfs filesystem or has been otherwise wiped out.
676     dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
677     utils.EnsureDirs(dirs)
678
679   @classmethod
680   def _InstancePidFile(cls, instance_name):
681     """Returns the instance pidfile.
682
683     """
684     return utils.PathJoin(cls._PIDS_DIR, instance_name)
685
686   @classmethod
687   def _InstanceUidFile(cls, instance_name):
688     """Returns the instance uidfile.
689
690     """
691     return utils.PathJoin(cls._UIDS_DIR, instance_name)
692
693   @classmethod
694   def _InstancePidInfo(cls, pid):
695     """Check pid file for instance information.
696
697     Check that a pid file is associated with an instance, and retrieve
698     information from its command line.
699
700     @type pid: string or int
701     @param pid: process id of the instance to check
702     @rtype: tuple
703     @return: (instance_name, memory, vcpus)
704     @raise errors.HypervisorError: when an instance cannot be found
705
706     """
707     alive = utils.IsProcessAlive(pid)
708     if not alive:
709       raise errors.HypervisorError("Cannot get info for pid %s" % pid)
710
711     cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
712     try:
713       cmdline = utils.ReadFile(cmdline_file)
714     except EnvironmentError, err:
715       raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
716                                    (pid, err))
717
718     instance = None
719     memory = 0
720     vcpus = 0
721
722     arg_list = cmdline.split("\x00")
723     while arg_list:
724       arg = arg_list.pop(0)
725       if arg == "-name":
726         instance = arg_list.pop(0)
727       elif arg == "-m":
728         memory = int(arg_list.pop(0))
729       elif arg == "-smp":
730         vcpus = int(arg_list.pop(0).split(",")[0])
731
732     if instance is None:
733       raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
734                                    " instance" % pid)
735
736     return (instance, memory, vcpus)
737
738   def _InstancePidAlive(self, instance_name):
739     """Returns the instance pidfile, pid, and liveness.
740
741     @type instance_name: string
742     @param instance_name: instance name
743     @rtype: tuple
744     @return: (pid file name, pid, liveness)
745
746     """
747     pidfile = self._InstancePidFile(instance_name)
748     pid = utils.ReadPidFile(pidfile)
749
750     alive = False
751     try:
752       cmd_instance = self._InstancePidInfo(pid)[0]
753       alive = (cmd_instance == instance_name)
754     except errors.HypervisorError:
755       pass
756
757     return (pidfile, pid, alive)
758
759   def _CheckDown(self, instance_name):
760     """Raises an error unless the given instance is down.
761
762     """
763     alive = self._InstancePidAlive(instance_name)[2]
764     if alive:
765       raise errors.HypervisorError("Failed to start instance %s: %s" %
766                                    (instance_name, "already running"))
767
768   @classmethod
769   def _InstanceMonitor(cls, instance_name):
770     """Returns the instance monitor socket name
771
772     """
773     return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
774
775   @classmethod
776   def _InstanceSerial(cls, instance_name):
777     """Returns the instance serial socket name
778
779     """
780     return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
781
782   @classmethod
783   def _InstanceQmpMonitor(cls, instance_name):
784     """Returns the instance serial QMP socket name
785
786     """
787     return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
788
789   @staticmethod
790   def _SocatUnixConsoleParams():
791     """Returns the correct parameters for socat
792
793     If we have a new-enough socat we can use raw mode with an escape character.
794
795     """
796     if constants.SOCAT_USE_ESCAPE:
797       return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
798     else:
799       return "echo=0,icanon=0"
800
801   @classmethod
802   def _InstanceKVMRuntime(cls, instance_name):
803     """Returns the instance KVM runtime filename
804
805     """
806     return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
807
808   @classmethod
809   def _InstanceChrootDir(cls, instance_name):
810     """Returns the name of the KVM chroot dir of the instance
811
812     """
813     return utils.PathJoin(cls._CHROOT_DIR, instance_name)
814
815   @classmethod
816   def _InstanceNICDir(cls, instance_name):
817     """Returns the name of the directory holding the tap device files for a
818     given instance.
819
820     """
821     return utils.PathJoin(cls._NICS_DIR, instance_name)
822
823   @classmethod
824   def _InstanceNICFile(cls, instance_name, seq):
825     """Returns the name of the file containing the tap device for a given NIC
826
827     """
828     return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
829
830   @classmethod
831   def _InstanceKeymapFile(cls, instance_name):
832     """Returns the name of the file containing the keymap for a given instance
833
834     """
835     return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
836
837   @classmethod
838   def _TryReadUidFile(cls, uid_file):
839     """Try to read a uid file
840
841     """
842     if os.path.exists(uid_file):
843       try:
844         uid = int(utils.ReadOneLineFile(uid_file))
845         return uid
846       except EnvironmentError:
847         logging.warning("Can't read uid file", exc_info=True)
848       except (TypeError, ValueError):
849         logging.warning("Can't parse uid file contents", exc_info=True)
850     return None
851
852   @classmethod
853   def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
854     """Removes an instance's rutime sockets/files/dirs.
855
856     """
857     utils.RemoveFile(pidfile)
858     utils.RemoveFile(cls._InstanceMonitor(instance_name))
859     utils.RemoveFile(cls._InstanceSerial(instance_name))
860     utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
861     utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
862     utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
863     uid_file = cls._InstanceUidFile(instance_name)
864     uid = cls._TryReadUidFile(uid_file)
865     utils.RemoveFile(uid_file)
866     if uid is not None:
867       uidpool.ReleaseUid(uid)
868     try:
869       shutil.rmtree(cls._InstanceNICDir(instance_name))
870     except OSError, err:
871       if err.errno != errno.ENOENT:
872         raise
873     try:
874       chroot_dir = cls._InstanceChrootDir(instance_name)
875       utils.RemoveDir(chroot_dir)
876     except OSError, err:
877       if err.errno == errno.ENOTEMPTY:
878         # The chroot directory is expected to be empty, but it isn't.
879         new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
880                                           prefix="%s-%s-" %
881                                           (instance_name,
882                                            utils.TimestampForFilename()))
883         logging.warning("The chroot directory of instance %s can not be"
884                         " removed as it is not empty. Moving it to the"
885                         " quarantine instead. Please investigate the"
886                         " contents (%s) and clean up manually",
887                         instance_name, new_chroot_dir)
888         utils.RenameFile(chroot_dir, new_chroot_dir)
889       else:
890         raise
891
892   @staticmethod
893   def _ConfigureNIC(instance, seq, nic, tap):
894     """Run the network configuration script for a specified NIC
895
896     @param instance: instance we're acting on
897     @type instance: instance object
898     @param seq: nic sequence number
899     @type seq: int
900     @param nic: nic we're acting on
901     @type nic: nic object
902     @param tap: the host's tap interface this NIC corresponds to
903     @type tap: str
904
905     """
906     if instance.tags:
907       tags = " ".join(instance.tags)
908     else:
909       tags = ""
910
911     env = {
912       "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
913       "INSTANCE": instance.name,
914       "MAC": nic.mac,
915       "MODE": nic.nicparams[constants.NIC_MODE],
916       "INTERFACE": tap,
917       "INTERFACE_INDEX": str(seq),
918       "TAGS": tags,
919     }
920
921     if nic.ip:
922       env["IP"] = nic.ip
923
924     if nic.nicparams[constants.NIC_LINK]:
925       env["LINK"] = nic.nicparams[constants.NIC_LINK]
926
927     if nic.network:
928       n = objects.Network.FromDict(nic.netinfo)
929       env.update(n.HooksDict())
930
931     if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
932       env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
933
934     result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
935     if result.failed:
936       raise errors.HypervisorError("Failed to configure interface %s: %s;"
937                                    " network configuration script output: %s" %
938                                    (tap, result.fail_reason, result.output))
939
940   @staticmethod
941   def _VerifyAffinityPackage():
942     if affinity is None:
943       raise errors.HypervisorError("affinity Python package not"
944                                    " found; cannot use CPU pinning under KVM")
945
946   @staticmethod
947   def _BuildAffinityCpuMask(cpu_list):
948     """Create a CPU mask suitable for sched_setaffinity from a list of
949     CPUs.
950
951     See man taskset for more info on sched_setaffinity masks.
952     For example: [ 0, 2, 5, 6 ] will return 101 (0x65, 0..01100101).
953
954     @type cpu_list: list of int
955     @param cpu_list: list of physical CPU numbers to map to vCPUs in order
956     @rtype: int
957     @return: a bit mask of CPU affinities
958
959     """
960     if cpu_list == constants.CPU_PINNING_OFF:
961       return constants.CPU_PINNING_ALL_KVM
962     else:
963       return sum(2 ** cpu for cpu in cpu_list)
964
965   @classmethod
966   def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
967     """Change CPU affinity for running VM according to given CPU mask.
968
969     @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
970     @type cpu_mask: string
971     @param process_id: process ID of KVM process. Used to pin entire VM
972                        to physical CPUs.
973     @type process_id: int
974     @param thread_dict: map of virtual CPUs to KVM thread IDs
975     @type thread_dict: dict int:int
976
977     """
978     # Convert the string CPU mask to a list of list of int's
979     cpu_list = utils.ParseMultiCpuMask(cpu_mask)
980
981     if len(cpu_list) == 1:
982       all_cpu_mapping = cpu_list[0]
983       if all_cpu_mapping == constants.CPU_PINNING_OFF:
984         # If CPU pinning has 1 entry that's "all", then do nothing
985         pass
986       else:
987         # If CPU pinning has one non-all entry, map the entire VM to
988         # one set of physical CPUs
989         cls._VerifyAffinityPackage()
990         affinity.set_process_affinity_mask(
991           process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
992     else:
993       # The number of vCPUs mapped should match the number of vCPUs
994       # reported by KVM. This was already verified earlier, so
995       # here only as a sanity check.
996       assert len(thread_dict) == len(cpu_list)
997       cls._VerifyAffinityPackage()
998
999       # For each vCPU, map it to the proper list of physical CPUs
1000       for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1001         affinity.set_process_affinity_mask(thread_dict[i],
1002                                            cls._BuildAffinityCpuMask(vcpu))
1003
1004   def _GetVcpuThreadIds(self, instance_name):
1005     """Get a mapping of vCPU no. to thread IDs for the instance
1006
1007     @type instance_name: string
1008     @param instance_name: instance in question
1009     @rtype: dictionary of int:int
1010     @return: a dictionary mapping vCPU numbers to thread IDs
1011
1012     """
1013     result = {}
1014     output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1015     for line in output.stdout.splitlines():
1016       match = self._CPU_INFO_RE.search(line)
1017       if not match:
1018         continue
1019       grp = map(int, match.groups())
1020       result[grp[0]] = grp[1]
1021
1022     return result
1023
1024   def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1025     """Complete CPU pinning.
1026
1027     @type instance_name: string
1028     @param instance_name: name of instance
1029     @type cpu_mask: string
1030     @param cpu_mask: CPU pinning mask as entered by user
1031
1032     """
1033     # Get KVM process ID, to be used if need to pin entire VM
1034     _, pid, _ = self._InstancePidAlive(instance_name)
1035     # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1036     thread_dict = self._GetVcpuThreadIds(instance_name)
1037     # Run CPU pinning, based on configured mask
1038     self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1039
1040   def ListInstances(self):
1041     """Get the list of running instances.
1042
1043     We can do this by listing our live instances directory and
1044     checking whether the associated kvm process is still alive.
1045
1046     """
1047     result = []
1048     for name in os.listdir(self._PIDS_DIR):
1049       if self._InstancePidAlive(name)[2]:
1050         result.append(name)
1051     return result
1052
1053   def GetInstanceInfo(self, instance_name):
1054     """Get instance properties.
1055
1056     @type instance_name: string
1057     @param instance_name: the instance name
1058     @rtype: tuple of strings
1059     @return: (name, id, memory, vcpus, stat, times)
1060
1061     """
1062     _, pid, alive = self._InstancePidAlive(instance_name)
1063     if not alive:
1064       return None
1065
1066     _, memory, vcpus = self._InstancePidInfo(pid)
1067     istat = "---b-"
1068     times = "0"
1069
1070     try:
1071       qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1072       qmp.connect()
1073       vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1074       # Will fail if ballooning is not enabled, but we can then just resort to
1075       # the value above.
1076       mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1077       memory = mem_bytes / 1048576
1078     except errors.HypervisorError:
1079       pass
1080
1081     return (instance_name, pid, memory, vcpus, istat, times)
1082
1083   def GetAllInstancesInfo(self):
1084     """Get properties of all instances.
1085
1086     @return: list of tuples (name, id, memory, vcpus, stat, times)
1087
1088     """
1089     data = []
1090     for name in os.listdir(self._PIDS_DIR):
1091       try:
1092         info = self.GetInstanceInfo(name)
1093       except errors.HypervisorError:
1094         # Ignore exceptions due to instances being shut down
1095         continue
1096       if info:
1097         data.append(info)
1098     return data
1099
1100   def _GenerateKVMBlockDevicesOptions(self, instance, block_devices, kvmhelp):
1101
1102     hvp = instance.hvparams
1103     boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1104     kvm_path = hvp[constants.HV_KVM_PATH]
1105
1106     # whether this is an older KVM version that uses the boot=on flag
1107     # on devices
1108     needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1109
1110     dev_opts = []
1111     device_driver = None
1112     disk_type = hvp[constants.HV_DISK_TYPE]
1113     if disk_type == constants.HT_DISK_PARAVIRTUAL:
1114       if_val = ",if=%s" % self._VIRTIO
1115       try:
1116         devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1117         if self._VIRTIO_BLK_RE.search(devlist):
1118           # TODO: uncomment when -device is used
1119           # if_val = ",if=none"
1120           # will be passed in -device option as driver
1121           device_driver = self._VIRTIO_BLK_PCI
1122       except errors.HypervisorError, _:
1123         pass
1124     else:
1125       if_val = ",if=%s" % disk_type
1126     # Cache mode
1127     disk_cache = hvp[constants.HV_DISK_CACHE]
1128     if instance.disk_template in constants.DTS_EXT_MIRROR:
1129       if disk_cache != "none":
1130         # TODO: make this a hard error, instead of a silent overwrite
1131         logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1132                         " to prevent shared storage corruption on migration",
1133                         disk_cache)
1134       cache_val = ",cache=none"
1135     elif disk_cache != constants.HT_CACHE_DEFAULT:
1136       cache_val = ",cache=%s" % disk_cache
1137     else:
1138       cache_val = ""
1139     for cfdev, dev_path in block_devices:
1140       if cfdev.mode != constants.DISK_RDWR:
1141         raise errors.HypervisorError("Instance has read-only disks which"
1142                                      " are not supported by KVM")
1143       # TODO: handle FD_LOOP and FD_BLKTAP (?)
1144       boot_val = ""
1145       if boot_disk:
1146         dev_opts.extend(["-boot", "c"])
1147         boot_disk = False
1148         if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1149           boot_val = ",boot=on"
1150       drive_val = "file=%s,format=raw%s%s%s" % \
1151                   (dev_path, if_val, boot_val, cache_val)
1152
1153       if device_driver:
1154         pass
1155       dev_opts.extend(["-drive", drive_val])
1156
1157     return dev_opts
1158
1159   def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1160                           kvmhelp):
1161     """Generate KVM information to start an instance.
1162
1163     @type kvmhelp: string
1164     @param kvmhelp: output of kvm --help
1165     @attention: this function must not have any side-effects; for
1166         example, it must not write to the filesystem, or read values
1167         from the current system the are expected to differ between
1168         nodes, since it is only run once at instance startup;
1169         actions/kvm arguments that can vary between systems should be
1170         done in L{_ExecuteKVMRuntime}
1171
1172     """
1173     # pylint: disable=R0912,R0914,R0915
1174     hvp = instance.hvparams
1175     self.ValidateParameters(hvp)
1176
1177     pidfile = self._InstancePidFile(instance.name)
1178     kvm = hvp[constants.HV_KVM_PATH]
1179     kvm_cmd = [kvm]
1180     # used just by the vnc server, if enabled
1181     kvm_cmd.extend(["-name", instance.name])
1182     kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1183
1184     smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1185     if hvp[constants.HV_CPU_CORES]:
1186       smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1187     if hvp[constants.HV_CPU_THREADS]:
1188       smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1189     if hvp[constants.HV_CPU_SOCKETS]:
1190       smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1191
1192     kvm_cmd.extend(["-smp", ",".join(smp_list)])
1193
1194     kvm_cmd.extend(["-pidfile", pidfile])
1195     kvm_cmd.extend(["-balloon", "virtio"])
1196     kvm_cmd.extend(["-daemonize"])
1197     if not instance.hvparams[constants.HV_ACPI]:
1198       kvm_cmd.extend(["-no-acpi"])
1199     if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1200         constants.INSTANCE_REBOOT_EXIT:
1201       kvm_cmd.extend(["-no-reboot"])
1202
1203     mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1204     if not mversion:
1205       mversion = self._GetDefaultMachineVersion(kvm)
1206     if self._MACHINE_RE.search(kvmhelp):
1207       # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1208       # extra hypervisor parameters. We should also investigate whether and how
1209       # shadow_mem should be considered for the resource model.
1210       if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1211         specprop = ",accel=kvm"
1212       else:
1213         specprop = ""
1214       machinespec = "%s%s" % (mversion, specprop)
1215       kvm_cmd.extend(["-machine", machinespec])
1216     else:
1217       kvm_cmd.extend(["-M", mversion])
1218       if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1219           self._ENABLE_KVM_RE.search(kvmhelp)):
1220         kvm_cmd.extend(["-enable-kvm"])
1221       elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1222             self._DISABLE_KVM_RE.search(kvmhelp)):
1223         kvm_cmd.extend(["-disable-kvm"])
1224
1225     kernel_path = hvp[constants.HV_KERNEL_PATH]
1226     if kernel_path:
1227       boot_cdrom = boot_floppy = boot_network = False
1228     else:
1229       boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1230       boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1231       boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1232
1233     if startup_paused:
1234       kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1235
1236     if boot_network:
1237       kvm_cmd.extend(["-boot", "n"])
1238
1239     # whether this is an older KVM version that uses the boot=on flag
1240     # on devices
1241     needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1242
1243     disk_type = hvp[constants.HV_DISK_TYPE]
1244
1245     #Now we can specify a different device type for CDROM devices.
1246     cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1247     if not cdrom_disk_type:
1248       cdrom_disk_type = disk_type
1249
1250     iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1251     if iso_image:
1252       options = ",format=raw,media=cdrom"
1253       # set cdrom 'if' type
1254       if boot_cdrom:
1255         actual_cdrom_type = constants.HT_DISK_IDE
1256       elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1257         actual_cdrom_type = "virtio"
1258       else:
1259         actual_cdrom_type = cdrom_disk_type
1260       if_val = ",if=%s" % actual_cdrom_type
1261       # set boot flag, if needed
1262       boot_val = ""
1263       if boot_cdrom:
1264         kvm_cmd.extend(["-boot", "d"])
1265         if needs_boot_flag:
1266           boot_val = ",boot=on"
1267       # and finally build the entire '-drive' value
1268       drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1269       kvm_cmd.extend(["-drive", drive_val])
1270
1271     iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1272     if iso_image2:
1273       options = ",format=raw,media=cdrom"
1274       if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1275         if_val = ",if=virtio"
1276       else:
1277         if_val = ",if=%s" % cdrom_disk_type
1278       drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1279       kvm_cmd.extend(["-drive", drive_val])
1280
1281     floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1282     if floppy_image:
1283       options = ",format=raw,media=disk"
1284       if boot_floppy:
1285         kvm_cmd.extend(["-boot", "a"])
1286         options = "%s,boot=on" % options
1287       if_val = ",if=floppy"
1288       options = "%s%s" % (options, if_val)
1289       drive_val = "file=%s%s" % (floppy_image, options)
1290       kvm_cmd.extend(["-drive", drive_val])
1291
1292     if kernel_path:
1293       kvm_cmd.extend(["-kernel", kernel_path])
1294       initrd_path = hvp[constants.HV_INITRD_PATH]
1295       if initrd_path:
1296         kvm_cmd.extend(["-initrd", initrd_path])
1297       root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1298                      hvp[constants.HV_KERNEL_ARGS]]
1299       if hvp[constants.HV_SERIAL_CONSOLE]:
1300         serial_speed = hvp[constants.HV_SERIAL_SPEED]
1301         root_append.append("console=ttyS0,%s" % serial_speed)
1302       kvm_cmd.extend(["-append", " ".join(root_append)])
1303
1304     mem_path = hvp[constants.HV_MEM_PATH]
1305     if mem_path:
1306       kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1307
1308     monitor_dev = ("unix:%s,server,nowait" %
1309                    self._InstanceMonitor(instance.name))
1310     kvm_cmd.extend(["-monitor", monitor_dev])
1311     if hvp[constants.HV_SERIAL_CONSOLE]:
1312       serial_dev = ("unix:%s,server,nowait" %
1313                     self._InstanceSerial(instance.name))
1314       kvm_cmd.extend(["-serial", serial_dev])
1315     else:
1316       kvm_cmd.extend(["-serial", "none"])
1317
1318     mouse_type = hvp[constants.HV_USB_MOUSE]
1319     vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1320     spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1321     spice_ip_version = None
1322
1323     kvm_cmd.extend(["-usb"])
1324
1325     if mouse_type:
1326       kvm_cmd.extend(["-usbdevice", mouse_type])
1327     elif vnc_bind_address:
1328       kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1329
1330     if vnc_bind_address:
1331       if netutils.IP4Address.IsValid(vnc_bind_address):
1332         if instance.network_port > constants.VNC_BASE_PORT:
1333           display = instance.network_port - constants.VNC_BASE_PORT
1334           if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1335             vnc_arg = ":%d" % (display)
1336           else:
1337             vnc_arg = "%s:%d" % (vnc_bind_address, display)
1338         else:
1339           logging.error("Network port is not a valid VNC display (%d < %d),"
1340                         " not starting VNC",
1341                         instance.network_port, constants.VNC_BASE_PORT)
1342           vnc_arg = "none"
1343
1344         # Only allow tls and other option when not binding to a file, for now.
1345         # kvm/qemu gets confused otherwise about the filename to use.
1346         vnc_append = ""
1347         if hvp[constants.HV_VNC_TLS]:
1348           vnc_append = "%s,tls" % vnc_append
1349           if hvp[constants.HV_VNC_X509_VERIFY]:
1350             vnc_append = "%s,x509verify=%s" % (vnc_append,
1351                                                hvp[constants.HV_VNC_X509])
1352           elif hvp[constants.HV_VNC_X509]:
1353             vnc_append = "%s,x509=%s" % (vnc_append,
1354                                          hvp[constants.HV_VNC_X509])
1355         if hvp[constants.HV_VNC_PASSWORD_FILE]:
1356           vnc_append = "%s,password" % vnc_append
1357
1358         vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1359
1360       else:
1361         vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1362
1363       kvm_cmd.extend(["-vnc", vnc_arg])
1364     elif spice_bind:
1365       # FIXME: this is wrong here; the iface ip address differs
1366       # between systems, so it should be done in _ExecuteKVMRuntime
1367       if netutils.IsValidInterface(spice_bind):
1368         # The user specified a network interface, we have to figure out the IP
1369         # address.
1370         addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1371         spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1372
1373         # if the user specified an IP version and the interface does not
1374         # have that kind of IP addresses, throw an exception
1375         if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1376           if not addresses[spice_ip_version]:
1377             raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1378                                          " for %s" % (spice_ip_version,
1379                                                       spice_bind))
1380
1381         # the user did not specify an IP version, we have to figure it out
1382         elif (addresses[constants.IP4_VERSION] and
1383               addresses[constants.IP6_VERSION]):
1384           # we have both ipv4 and ipv6, let's use the cluster default IP
1385           # version
1386           cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1387           spice_ip_version = \
1388             netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1389         elif addresses[constants.IP4_VERSION]:
1390           spice_ip_version = constants.IP4_VERSION
1391         elif addresses[constants.IP6_VERSION]:
1392           spice_ip_version = constants.IP6_VERSION
1393         else:
1394           raise errors.HypervisorError("SPICE: Unable to get an IP address"
1395                                        " for %s" % (spice_bind))
1396
1397         spice_address = addresses[spice_ip_version][0]
1398
1399       else:
1400         # spice_bind is known to be a valid IP address, because
1401         # ValidateParameters checked it.
1402         spice_address = spice_bind
1403
1404       spice_arg = "addr=%s" % spice_address
1405       if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1406         spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1407                      (spice_arg, instance.network_port,
1408                       pathutils.SPICE_CACERT_FILE))
1409         spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1410                      (spice_arg, pathutils.SPICE_CERT_FILE,
1411                       pathutils.SPICE_CERT_FILE))
1412         tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1413         if tls_ciphers:
1414           spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1415       else:
1416         spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1417
1418       if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1419         spice_arg = "%s,disable-ticketing" % spice_arg
1420
1421       if spice_ip_version:
1422         spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1423
1424       # Image compression options
1425       img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1426       img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1427       img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1428       if img_lossless:
1429         spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1430       if img_jpeg:
1431         spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1432       if img_zlib_glz:
1433         spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1434
1435       # Video stream detection
1436       video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1437       if video_streaming:
1438         spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1439
1440       # Audio compression, by default in qemu-kvm it is on
1441       if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1442         spice_arg = "%s,playback-compression=off" % spice_arg
1443       if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1444         spice_arg = "%s,agent-mouse=off" % spice_arg
1445       else:
1446         # Enable the spice agent communication channel between the host and the
1447         # agent.
1448         kvm_cmd.extend(["-device", "virtio-serial-pci"])
1449         kvm_cmd.extend([
1450           "-device",
1451           "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1452           ])
1453         kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1454
1455       logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1456       kvm_cmd.extend(["-spice", spice_arg])
1457
1458     else:
1459       # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1460       # also works in earlier versions though (tested with 1.1 and 1.3)
1461       if self._DISPLAY_RE.search(kvmhelp):
1462         kvm_cmd.extend(["-display", "none"])
1463       else:
1464         kvm_cmd.extend(["-nographic"])
1465
1466     if hvp[constants.HV_USE_LOCALTIME]:
1467       kvm_cmd.extend(["-localtime"])
1468
1469     if hvp[constants.HV_KVM_USE_CHROOT]:
1470       kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1471
1472     # Add qemu-KVM -cpu param
1473     if hvp[constants.HV_CPU_TYPE]:
1474       kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1475
1476     # As requested by music lovers
1477     if hvp[constants.HV_SOUNDHW]:
1478       kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1479
1480     # Pass a -vga option if requested, or if spice is used, for backwards
1481     # compatibility.
1482     if hvp[constants.HV_VGA]:
1483       kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1484     elif spice_bind:
1485       kvm_cmd.extend(["-vga", "qxl"])
1486
1487     # Various types of usb devices, comma separated
1488     if hvp[constants.HV_USB_DEVICES]:
1489       for dev in hvp[constants.HV_USB_DEVICES].split(","):
1490         kvm_cmd.extend(["-usbdevice", dev])
1491
1492     if hvp[constants.HV_KVM_EXTRA]:
1493       kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1494
1495     kvm_disks = []
1496     for disk, dev_path in block_devices:
1497       kvm_disks.append((disk, dev_path))
1498
1499     kvm_nics = []
1500     for nic in instance.nics:
1501       kvm_nics.append(nic)
1502
1503     hvparams = hvp
1504
1505     return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1506
1507   def _WriteKVMRuntime(self, instance_name, data):
1508     """Write an instance's KVM runtime
1509
1510     """
1511     try:
1512       utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1513                       data=data)
1514     except EnvironmentError, err:
1515       raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1516
1517   def _ReadKVMRuntime(self, instance_name):
1518     """Read an instance's KVM runtime
1519
1520     """
1521     try:
1522       file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1523     except EnvironmentError, err:
1524       raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1525     return file_content
1526
1527   def _SaveKVMRuntime(self, instance, kvm_runtime):
1528     """Save an instance's KVM runtime
1529
1530     """
1531     kvm_cmd, kvm_nics, hvparams, block_devices = kvm_runtime
1532
1533     serialized_nics = [nic.ToDict() for nic in kvm_nics]
1534     serialized_blockdevs = [(blk.ToDict(), link)
1535                             for blk, link in block_devices]
1536     serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1537                                       serialized_blockdevs))
1538
1539     self._WriteKVMRuntime(instance.name, serialized_form)
1540
1541   def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1542     """Load an instance's KVM runtime
1543
1544     """
1545     if not serialized_runtime:
1546       serialized_runtime = self._ReadKVMRuntime(instance.name)
1547
1548     return _AnalyzeSerializedRuntime(serialized_runtime)
1549
1550   def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1551     """Run the KVM cmd and check for errors
1552
1553     @type name: string
1554     @param name: instance name
1555     @type kvm_cmd: list of strings
1556     @param kvm_cmd: runcmd input for kvm
1557     @type tap_fds: list of int
1558     @param tap_fds: fds of tap devices opened by Ganeti
1559
1560     """
1561     try:
1562       result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1563     finally:
1564       for fd in tap_fds:
1565         utils_wrapper.CloseFdNoError(fd)
1566
1567     if result.failed:
1568       raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1569                                    (name, result.fail_reason, result.output))
1570     if not self._InstancePidAlive(name)[2]:
1571       raise errors.HypervisorError("Failed to start instance %s" % name)
1572
1573   # 52/50 local variables
1574   # pylint: disable=R0914
1575   def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1576     """Execute a KVM cmd, after completing it with some last minute data.
1577
1578     @type incoming: tuple of strings
1579     @param incoming: (target_host_ip, port)
1580     @type kvmhelp: string
1581     @param kvmhelp: output of kvm --help
1582
1583     """
1584     # Small _ExecuteKVMRuntime hv parameters programming howto:
1585     #  - conf_hvp contains the parameters as configured on ganeti. they might
1586     #    have changed since the instance started; only use them if the change
1587     #    won't affect the inside of the instance (which hasn't been rebooted).
1588     #  - up_hvp contains the parameters as they were when the instance was
1589     #    started, plus any new parameter which has been added between ganeti
1590     #    versions: it is paramount that those default to a value which won't
1591     #    affect the inside of the instance as well.
1592     conf_hvp = instance.hvparams
1593     name = instance.name
1594     self._CheckDown(name)
1595
1596     temp_files = []
1597
1598     kvm_cmd, kvm_nics, up_hvp, block_devices = kvm_runtime
1599     # the first element of kvm_cmd is always the path to the kvm binary
1600     kvm_path = kvm_cmd[0]
1601     up_hvp = objects.FillDict(conf_hvp, up_hvp)
1602
1603     # We know it's safe to run as a different user upon migration, so we'll use
1604     # the latest conf, from conf_hvp.
1605     security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1606     if security_model == constants.HT_SM_USER:
1607       kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1608
1609     keymap = conf_hvp[constants.HV_KEYMAP]
1610     if keymap:
1611       keymap_path = self._InstanceKeymapFile(name)
1612       # If a keymap file is specified, KVM won't use its internal defaults. By
1613       # first including the "en-us" layout, an error on loading the actual
1614       # layout (e.g. because it can't be found) won't lead to a non-functional
1615       # keyboard. A keyboard with incorrect keys is still better than none.
1616       utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1617       kvm_cmd.extend(["-k", keymap_path])
1618
1619     # We have reasons to believe changing something like the nic driver/type
1620     # upon migration won't exactly fly with the instance kernel, so for nic
1621     # related parameters we'll use up_hvp
1622     tapfds = []
1623     taps = []
1624     if not kvm_nics:
1625       kvm_cmd.extend(["-net", "none"])
1626     else:
1627       vnet_hdr = False
1628       tap_extra = ""
1629       nic_type = up_hvp[constants.HV_NIC_TYPE]
1630       if nic_type == constants.HT_NIC_PARAVIRTUAL:
1631         nic_model = self._VIRTIO
1632         try:
1633           devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1634           if self._VIRTIO_NET_RE.search(devlist):
1635             nic_model = self._VIRTIO_NET_PCI
1636             vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1637         except errors.HypervisorError, _:
1638           # Older versions of kvm don't support DEVICE_LIST, but they don't
1639           # have new virtio syntax either.
1640           pass
1641
1642         if up_hvp[constants.HV_VHOST_NET]:
1643           # check for vhost_net support
1644           if self._VHOST_RE.search(kvmhelp):
1645             tap_extra = ",vhost=on"
1646           else:
1647             raise errors.HypervisorError("vhost_net is configured"
1648                                          " but it is not available")
1649       else:
1650         nic_model = nic_type
1651
1652       kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1653
1654       for nic_seq, nic in enumerate(kvm_nics):
1655         tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1656         tapfds.append(tapfd)
1657         taps.append(tapname)
1658         if kvm_supports_netdev:
1659           nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1660           tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1661           kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1662         else:
1663           nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1664                                                          nic.mac, nic_model)
1665           tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1666           kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1667
1668     if incoming:
1669       target, port = incoming
1670       kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1671
1672     # Changing the vnc password doesn't bother the guest that much. At most it
1673     # will surprise people who connect to it. Whether positively or negatively
1674     # it's debatable.
1675     vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1676     vnc_pwd = None
1677     if vnc_pwd_file:
1678       try:
1679         vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1680       except EnvironmentError, err:
1681         raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1682                                      % (vnc_pwd_file, err))
1683
1684     if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1685       utils.EnsureDirs([(self._InstanceChrootDir(name),
1686                          constants.SECURE_DIR_MODE)])
1687
1688     # Automatically enable QMP if version is >= 0.14
1689     if self._QMP_RE.search(kvmhelp):
1690       logging.debug("Enabling QMP")
1691       kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1692                       self._InstanceQmpMonitor(instance.name)])
1693
1694     # Configure the network now for starting instances and bridged interfaces,
1695     # during FinalizeMigration for incoming instances' routed interfaces
1696     for nic_seq, nic in enumerate(kvm_nics):
1697       if (incoming and
1698           nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1699         continue
1700       self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1701
1702     bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1703                                                      block_devices,
1704                                                      kvmhelp)
1705     kvm_cmd.extend(bdev_opts)
1706     # CPU affinity requires kvm to start paused, so we set this flag if the
1707     # instance is not already paused and if we are not going to accept a
1708     # migrating instance. In the latter case, pausing is not needed.
1709     start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1710     if start_kvm_paused:
1711       kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1712
1713     # Note: CPU pinning is using up_hvp since changes take effect
1714     # during instance startup anyway, and to avoid problems when soft
1715     # rebooting the instance.
1716     cpu_pinning = False
1717     if up_hvp.get(constants.HV_CPU_MASK, None):
1718       cpu_pinning = True
1719
1720     if security_model == constants.HT_SM_POOL:
1721       ss = ssconf.SimpleStore()
1722       uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1723       all_uids = set(uidpool.ExpandUidPool(uid_pool))
1724       uid = uidpool.RequestUnusedUid(all_uids)
1725       try:
1726         username = pwd.getpwuid(uid.GetUid()).pw_name
1727         kvm_cmd.extend(["-runas", username])
1728         self._RunKVMCmd(name, kvm_cmd, tapfds)
1729       except:
1730         uidpool.ReleaseUid(uid)
1731         raise
1732       else:
1733         uid.Unlock()
1734         utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1735     else:
1736       self._RunKVMCmd(name, kvm_cmd, tapfds)
1737
1738     utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1739                      constants.RUN_DIRS_MODE)])
1740     for nic_seq, tap in enumerate(taps):
1741       utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1742                       data=tap)
1743
1744     if vnc_pwd:
1745       change_cmd = "change vnc password %s" % vnc_pwd
1746       self._CallMonitorCommand(instance.name, change_cmd)
1747
1748     # Setting SPICE password. We are not vulnerable to malicious passwordless
1749     # connection attempts because SPICE by default does not allow connections
1750     # if neither a password nor the "disable_ticketing" options are specified.
1751     # As soon as we send the password via QMP, that password is a valid ticket
1752     # for connection.
1753     spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1754     if spice_password_file:
1755       spice_pwd = ""
1756       try:
1757         spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1758       except EnvironmentError, err:
1759         raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1760                                      % (spice_password_file, err))
1761
1762       qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1763       qmp.connect()
1764       arguments = {
1765           "protocol": "spice",
1766           "password": spice_pwd,
1767       }
1768       qmp.Execute("set_password", arguments)
1769
1770     for filename in temp_files:
1771       utils.RemoveFile(filename)
1772
1773     # If requested, set CPU affinity and resume instance execution
1774     if cpu_pinning:
1775       self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1776
1777     start_memory = self._InstanceStartupMemory(instance)
1778     if start_memory < instance.beparams[constants.BE_MAXMEM]:
1779       self.BalloonInstanceMemory(instance, start_memory)
1780
1781     if start_kvm_paused:
1782       # To control CPU pinning, ballooning, and vnc/spice passwords
1783       # the VM was started in a frozen state. If freezing was not
1784       # explicitly requested resume the vm status.
1785       self._CallMonitorCommand(instance.name, self._CONT_CMD)
1786
1787   def StartInstance(self, instance, block_devices, startup_paused):
1788     """Start an instance.
1789
1790     """
1791     self._CheckDown(instance.name)
1792     kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1793     kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1794     kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1795                                            startup_paused, kvmhelp)
1796     self._SaveKVMRuntime(instance, kvm_runtime)
1797     self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1798
1799   def _CallMonitorCommand(self, instance_name, command, timeout=None):
1800     """Invoke a command on the instance monitor.
1801
1802     """
1803     if timeout is not None:
1804       timeout_cmd = "timeout %s" % (timeout, )
1805     else:
1806       timeout_cmd = ""
1807
1808     # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1809     # version. The monitor protocol is designed for human consumption, whereas
1810     # QMP is made for programmatic usage. In the worst case QMP can also
1811     # execute monitor commands. As it is, all calls to socat take at least
1812     # 500ms and likely more: socat can't detect the end of the reply and waits
1813     # for 500ms of no data received before exiting (500 ms is the default for
1814     # the "-t" parameter).
1815     socat = ("echo %s | %s %s STDIO UNIX-CONNECT:%s" %
1816              (utils.ShellQuote(command),
1817               timeout_cmd,
1818               constants.SOCAT_PATH,
1819               utils.ShellQuote(self._InstanceMonitor(instance_name))))
1820
1821     result = utils.RunCmd(socat)
1822     if result.failed:
1823       msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1824              " output: %s" %
1825              (command, instance_name, result.fail_reason, result.output))
1826       raise errors.HypervisorError(msg)
1827
1828     return result
1829
1830   @classmethod
1831   def _ParseKVMVersion(cls, text):
1832     """Parse the KVM version from the --help output.
1833
1834     @type text: string
1835     @param text: output of kvm --help
1836     @return: (version, v_maj, v_min, v_rev)
1837     @raise errors.HypervisorError: when the KVM version cannot be retrieved
1838
1839     """
1840     match = cls._VERSION_RE.search(text.splitlines()[0])
1841     if not match:
1842       raise errors.HypervisorError("Unable to get KVM version")
1843
1844     v_all = match.group(0)
1845     v_maj = int(match.group(1))
1846     v_min = int(match.group(2))
1847     if match.group(4):
1848       v_rev = int(match.group(4))
1849     else:
1850       v_rev = 0
1851     return (v_all, v_maj, v_min, v_rev)
1852
1853   @classmethod
1854   def _GetKVMOutput(cls, kvm_path, option):
1855     """Return the output of a kvm invocation
1856
1857     @type kvm_path: string
1858     @param kvm_path: path to the kvm executable
1859     @type option: a key of _KVMOPTS_CMDS
1860     @param option: kvm option to fetch the output from
1861     @return: output a supported kvm invocation
1862     @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1863
1864     """
1865     assert option in cls._KVMOPTS_CMDS, "Invalid output option"
1866
1867     optlist, can_fail = cls._KVMOPTS_CMDS[option]
1868
1869     result = utils.RunCmd([kvm_path] + optlist)
1870     if result.failed and not can_fail:
1871       raise errors.HypervisorError("Unable to get KVM %s output" %
1872                                     " ".join(optlist))
1873     return result.output
1874
1875   @classmethod
1876   def _GetKVMVersion(cls, kvm_path):
1877     """Return the installed KVM version.
1878
1879     @return: (version, v_maj, v_min, v_rev)
1880     @raise errors.HypervisorError: when the KVM version cannot be retrieved
1881
1882     """
1883     return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
1884
1885   @classmethod
1886   def _GetDefaultMachineVersion(cls, kvm_path):
1887     """Return the default hardware revision (e.g. pc-1.1)
1888
1889     """
1890     output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
1891     match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
1892     if match:
1893       return match.group(1)
1894     else:
1895       return "pc"
1896
1897   def StopInstance(self, instance, force=False, retry=False, name=None,
1898                    timeout=None):
1899     """Stop an instance.
1900
1901     """
1902     assert(timeout is None or force is not None)
1903
1904     if name is not None and not force:
1905       raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1906     if name is None:
1907       name = instance.name
1908       acpi = instance.hvparams[constants.HV_ACPI]
1909     else:
1910       acpi = False
1911     _, pid, alive = self._InstancePidAlive(name)
1912     if pid > 0 and alive:
1913       if force or not acpi:
1914         utils.KillProcess(pid)
1915       else:
1916         self._CallMonitorCommand(name, "system_powerdown", timeout)
1917
1918   def CleanupInstance(self, instance_name):
1919     """Cleanup after a stopped instance
1920
1921     """
1922     pidfile, pid, alive = self._InstancePidAlive(instance_name)
1923     if pid > 0 and alive:
1924       raise errors.HypervisorError("Cannot cleanup a live instance")
1925     self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1926
1927   def RebootInstance(self, instance):
1928     """Reboot an instance.
1929
1930     """
1931     # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1932     # socket the instance will stop, but now power up again. So we'll resort
1933     # to shutdown and restart.
1934     _, _, alive = self._InstancePidAlive(instance.name)
1935     if not alive:
1936       raise errors.HypervisorError("Failed to reboot instance %s:"
1937                                    " not running" % instance.name)
1938     # StopInstance will delete the saved KVM runtime so:
1939     # ...first load it...
1940     kvm_runtime = self._LoadKVMRuntime(instance)
1941     # ...now we can safely call StopInstance...
1942     if not self.StopInstance(instance):
1943       self.StopInstance(instance, force=True)
1944     # ...and finally we can save it again, and execute it...
1945     self._SaveKVMRuntime(instance, kvm_runtime)
1946     kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1947     kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1948     self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1949
1950   def MigrationInfo(self, instance):
1951     """Get instance information to perform a migration.
1952
1953     @type instance: L{objects.Instance}
1954     @param instance: instance to be migrated
1955     @rtype: string
1956     @return: content of the KVM runtime file
1957
1958     """
1959     return self._ReadKVMRuntime(instance.name)
1960
1961   def AcceptInstance(self, instance, info, target):
1962     """Prepare to accept an instance.
1963
1964     @type instance: L{objects.Instance}
1965     @param instance: instance to be accepted
1966     @type info: string
1967     @param info: content of the KVM runtime file on the source node
1968     @type target: string
1969     @param target: target host (usually ip), on this node
1970
1971     """
1972     kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1973     incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1974     kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1975     kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1976     self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
1977                             incoming=incoming_address)
1978
1979   def FinalizeMigrationDst(self, instance, info, success):
1980     """Finalize the instance migration on the target node.
1981
1982     Stop the incoming mode KVM.
1983
1984     @type instance: L{objects.Instance}
1985     @param instance: instance whose migration is being finalized
1986
1987     """
1988     if success:
1989       kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1990       kvm_nics = kvm_runtime[1]
1991
1992       for nic_seq, nic in enumerate(kvm_nics):
1993         if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1994           # Bridged interfaces have already been configured
1995           continue
1996         try:
1997           tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1998         except EnvironmentError, err:
1999           logging.warning("Failed to find host interface for %s NIC #%d: %s",
2000                           instance.name, nic_seq, str(err))
2001           continue
2002         try:
2003           self._ConfigureNIC(instance, nic_seq, nic, tap)
2004         except errors.HypervisorError, err:
2005           logging.warning(str(err))
2006
2007       self._WriteKVMRuntime(instance.name, info)
2008     else:
2009       self.StopInstance(instance, force=True)
2010
2011   def MigrateInstance(self, instance, target, live):
2012     """Migrate an instance to a target node.
2013
2014     The migration will not be attempted if the instance is not
2015     currently running.
2016
2017     @type instance: L{objects.Instance}
2018     @param instance: the instance to be migrated
2019     @type target: string
2020     @param target: ip address of the target node
2021     @type live: boolean
2022     @param live: perform a live migration
2023
2024     """
2025     instance_name = instance.name
2026     port = instance.hvparams[constants.HV_MIGRATION_PORT]
2027     _, _, alive = self._InstancePidAlive(instance_name)
2028     if not alive:
2029       raise errors.HypervisorError("Instance not running, cannot migrate")
2030
2031     if not live:
2032       self._CallMonitorCommand(instance_name, "stop")
2033
2034     migrate_command = ("migrate_set_speed %dm" %
2035                        instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2036     self._CallMonitorCommand(instance_name, migrate_command)
2037
2038     migrate_command = ("migrate_set_downtime %dms" %
2039                        instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2040     self._CallMonitorCommand(instance_name, migrate_command)
2041
2042     migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2043     self._CallMonitorCommand(instance_name, migrate_command)
2044
2045   def FinalizeMigrationSource(self, instance, success, live):
2046     """Finalize the instance migration on the source node.
2047
2048     @type instance: L{objects.Instance}
2049     @param instance: the instance that was migrated
2050     @type success: bool
2051     @param success: whether the migration succeeded or not
2052     @type live: bool
2053     @param live: whether the user requested a live migration or not
2054
2055     """
2056     if success:
2057       pidfile, pid, _ = self._InstancePidAlive(instance.name)
2058       utils.KillProcess(pid)
2059       self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2060     elif live:
2061       self._CallMonitorCommand(instance.name, self._CONT_CMD)
2062
2063   def GetMigrationStatus(self, instance):
2064     """Get the migration status
2065
2066     @type instance: L{objects.Instance}
2067     @param instance: the instance that is being migrated
2068     @rtype: L{objects.MigrationStatus}
2069     @return: the status of the current migration (one of
2070              L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2071              progress info that can be retrieved from the hypervisor
2072
2073     """
2074     info_command = "info migrate"
2075     for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2076       result = self._CallMonitorCommand(instance.name, info_command)
2077       match = self._MIGRATION_STATUS_RE.search(result.stdout)
2078       if not match:
2079         if not result.stdout:
2080           logging.info("KVM: empty 'info migrate' result")
2081         else:
2082           logging.warning("KVM: unknown 'info migrate' result: %s",
2083                           result.stdout)
2084       else:
2085         status = match.group(1)
2086         if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2087           migration_status = objects.MigrationStatus(status=status)
2088           match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2089           if match:
2090             migration_status.transferred_ram = match.group("transferred")
2091             migration_status.total_ram = match.group("total")
2092
2093           return migration_status
2094
2095         logging.warning("KVM: unknown migration status '%s'", status)
2096
2097       time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2098
2099     return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2100
2101   def BalloonInstanceMemory(self, instance, mem):
2102     """Balloon an instance memory to a certain value.
2103
2104     @type instance: L{objects.Instance}
2105     @param instance: instance to be accepted
2106     @type mem: int
2107     @param mem: actual memory size to use for instance runtime
2108
2109     """
2110     self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2111
2112   def GetNodeInfo(self):
2113     """Return information about the node.
2114
2115     @return: a dict with the following keys (values in MiB):
2116           - memory_total: the total memory size on the node
2117           - memory_free: the available memory on the node for instances
2118           - memory_dom0: the memory used by the node itself, if available
2119           - hv_version: the hypervisor version in the form (major, minor,
2120                         revision)
2121
2122     """
2123     result = self.GetLinuxNodeInfo()
2124     # FIXME: this is the global kvm version, but the actual version can be
2125     # customized as an hv parameter. we should use the nodegroup's default kvm
2126     # path parameter here.
2127     _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2128     result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2129     return result
2130
2131   @classmethod
2132   def GetInstanceConsole(cls, instance, hvparams, beparams):
2133     """Return a command for connecting to the console of an instance.
2134
2135     """
2136     if hvparams[constants.HV_SERIAL_CONSOLE]:
2137       cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2138              constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2139              utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2140              "STDIO,%s" % cls._SocatUnixConsoleParams(),
2141              "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2142       return objects.InstanceConsole(instance=instance.name,
2143                                      kind=constants.CONS_SSH,
2144                                      host=instance.primary_node,
2145                                      user=constants.SSH_CONSOLE_USER,
2146                                      command=cmd)
2147
2148     vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2149     if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2150       display = instance.network_port - constants.VNC_BASE_PORT
2151       return objects.InstanceConsole(instance=instance.name,
2152                                      kind=constants.CONS_VNC,
2153                                      host=vnc_bind_address,
2154                                      port=instance.network_port,
2155                                      display=display)
2156
2157     spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2158     if spice_bind:
2159       return objects.InstanceConsole(instance=instance.name,
2160                                      kind=constants.CONS_SPICE,
2161                                      host=spice_bind,
2162                                      port=instance.network_port)
2163
2164     return objects.InstanceConsole(instance=instance.name,
2165                                    kind=constants.CONS_MESSAGE,
2166                                    message=("No serial shell for instance %s" %
2167                                             instance.name))
2168
2169   def Verify(self):
2170     """Verify the hypervisor.
2171
2172     Check that the required binaries exist.
2173
2174     @return: Problem description if something is wrong, C{None} otherwise
2175
2176     """
2177     msgs = []
2178     # FIXME: this is the global kvm binary, but the actual path can be
2179     # customized as an hv parameter; we should use the nodegroup's
2180     # default kvm path parameter here.
2181     if not os.path.exists(constants.KVM_PATH):
2182       msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2183     if not os.path.exists(constants.SOCAT_PATH):
2184       msgs.append("The socat binary ('%s') does not exist" %
2185                   constants.SOCAT_PATH)
2186
2187     return self._FormatVerifyResults(msgs)
2188
2189   @classmethod
2190   def CheckParameterSyntax(cls, hvparams):
2191     """Check the given parameters for validity.
2192
2193     @type hvparams:  dict
2194     @param hvparams: dictionary with parameter names/value
2195     @raise errors.HypervisorError: when a parameter is not valid
2196
2197     """
2198     super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2199
2200     kernel_path = hvparams[constants.HV_KERNEL_PATH]
2201     if kernel_path:
2202       if not hvparams[constants.HV_ROOT_PATH]:
2203         raise errors.HypervisorError("Need a root partition for the instance,"
2204                                      " if a kernel is defined")
2205
2206     if (hvparams[constants.HV_VNC_X509_VERIFY] and
2207         not hvparams[constants.HV_VNC_X509]):
2208       raise errors.HypervisorError("%s must be defined, if %s is" %
2209                                    (constants.HV_VNC_X509,
2210                                     constants.HV_VNC_X509_VERIFY))
2211
2212     if hvparams[constants.HV_SERIAL_CONSOLE]:
2213       serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2214       valid_speeds = constants.VALID_SERIAL_SPEEDS
2215       if not serial_speed or serial_speed not in valid_speeds:
2216         raise errors.HypervisorError("Invalid serial console speed, must be"
2217                                      " one of: %s" %
2218                                      utils.CommaJoin(valid_speeds))
2219
2220     boot_order = hvparams[constants.HV_BOOT_ORDER]
2221     if (boot_order == constants.HT_BO_CDROM and
2222         not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2223       raise errors.HypervisorError("Cannot boot from cdrom without an"
2224                                    " ISO path")
2225
2226     security_model = hvparams[constants.HV_SECURITY_MODEL]
2227     if security_model == constants.HT_SM_USER:
2228       if not hvparams[constants.HV_SECURITY_DOMAIN]:
2229         raise errors.HypervisorError("A security domain (user to run kvm as)"
2230                                      " must be specified")
2231     elif (security_model == constants.HT_SM_NONE or
2232           security_model == constants.HT_SM_POOL):
2233       if hvparams[constants.HV_SECURITY_DOMAIN]:
2234         raise errors.HypervisorError("Cannot have a security domain when the"
2235                                      " security model is 'none' or 'pool'")
2236
2237     spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2238     spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2239     if spice_bind:
2240       if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2241         # if an IP version is specified, the spice_bind parameter must be an
2242         # IP of that family
2243         if (netutils.IP4Address.IsValid(spice_bind) and
2244             spice_ip_version != constants.IP4_VERSION):
2245           raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2246                                        " the specified IP version is %s" %
2247                                        (spice_bind, spice_ip_version))
2248
2249         if (netutils.IP6Address.IsValid(spice_bind) and
2250             spice_ip_version != constants.IP6_VERSION):
2251           raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2252                                        " the specified IP version is %s" %
2253                                        (spice_bind, spice_ip_version))
2254     else:
2255       # All the other SPICE parameters depend on spice_bind being set. Raise an
2256       # error if any of them is set without it.
2257       for param in _SPICE_ADDITIONAL_PARAMS:
2258         if hvparams[param]:
2259           raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2260                                        (param, constants.HV_KVM_SPICE_BIND))
2261
2262   @classmethod
2263   def ValidateParameters(cls, hvparams):
2264     """Check the given parameters for validity.
2265
2266     @type hvparams:  dict
2267     @param hvparams: dictionary with parameter names/value
2268     @raise errors.HypervisorError: when a parameter is not valid
2269
2270     """
2271     super(KVMHypervisor, cls).ValidateParameters(hvparams)
2272
2273     kvm_path = hvparams[constants.HV_KVM_PATH]
2274
2275     security_model = hvparams[constants.HV_SECURITY_MODEL]
2276     if security_model == constants.HT_SM_USER:
2277       username = hvparams[constants.HV_SECURITY_DOMAIN]
2278       try:
2279         pwd.getpwnam(username)
2280       except KeyError:
2281         raise errors.HypervisorError("Unknown security domain user %s"
2282                                      % username)
2283
2284     spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2285     if spice_bind:
2286       # only one of VNC and SPICE can be used currently.
2287       if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2288         raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2289                                      " only one of them can be used at a"
2290                                      " given time")
2291
2292       # check that KVM supports SPICE
2293       kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2294       if not cls._SPICE_RE.search(kvmhelp):
2295         raise errors.HypervisorError("SPICE is configured, but it is not"
2296                                      " supported according to 'kvm --help'")
2297
2298       # if spice_bind is not an IP address, it must be a valid interface
2299       bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2300                        netutils.IP6Address.IsValid(spice_bind))
2301       if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2302         raise errors.HypervisorError("SPICE: The %s parameter must be either"
2303                                      " a valid IP address or interface name" %
2304                                      constants.HV_KVM_SPICE_BIND)
2305
2306     machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2307     if machine_version:
2308       output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2309       if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2310         raise errors.HypervisorError("Unsupported machine version: %s" %
2311                                      machine_version)
2312
2313   @classmethod
2314   def PowercycleNode(cls):
2315     """KVM powercycle, just a wrapper over Linux powercycle.
2316
2317     """
2318     cls.LinuxPowercycle()