Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 1d4a4b26

History | View | Annotate | Download (79.8 kB)

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

    
83
def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
84
  """Retrieves supported TUN features from file descriptor.
85

86
  @see: L{_ProbeTapVnetHdr}
87

88
  """
89
  req = struct.pack("I", 0)
90
  try:
91
    buf = _ioctl(fd, TUNGETFEATURES, req)
92
  except EnvironmentError, err:
93
    logging.warning("ioctl(TUNGETFEATURES) failed: %s", err)
94
    return None
95
  else:
96
    (flags, ) = struct.unpack("I", buf)
97
    return flags
98

    
99

    
100
def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
101
  """Check whether to enable the IFF_VNET_HDR flag.
102

103
  To do this, _all_ of the following conditions must be met:
104
   1. TUNGETFEATURES ioctl() *must* be implemented
105
   2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
106
   3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
107
      drivers/net/tun.c there is no way to test this until after the tap device
108
      has been created using TUNSETIFF, and there is no way to change the
109
      IFF_VNET_HDR flag after creating the interface, catch-22! However both
110
      TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
111
      thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
112

113
   @type fd: int
114
   @param fd: the file descriptor of /dev/net/tun
115

116
  """
117
  flags = _features_fn(fd)
118

    
119
  if flags is None:
120
    # Not supported
121
    return False
122

    
123
  result = bool(flags & IFF_VNET_HDR)
124

    
125
  if not result:
126
    logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
127

    
128
  return result
129

    
130

    
131
def _OpenTap(vnet_hdr=True):
132
  """Open a new tap device and return its file descriptor.
133

134
  This is intended to be used by a qemu-type hypervisor together with the -net
135
  tap,fd=<fd> command line parameter.
136

137
  @type vnet_hdr: boolean
138
  @param vnet_hdr: Enable the VNET Header
139
  @return: (ifname, tapfd)
140
  @rtype: tuple
141

142
  """
143
  try:
144
    tapfd = os.open("/dev/net/tun", os.O_RDWR)
145
  except EnvironmentError:
146
    raise errors.HypervisorError("Failed to open /dev/net/tun")
147

    
148
  flags = IFF_TAP | IFF_NO_PI
149

    
150
  if vnet_hdr and _ProbeTapVnetHdr(tapfd):
151
    flags |= IFF_VNET_HDR
152

    
153
  # The struct ifreq ioctl request (see netdevice(7))
154
  ifr = struct.pack("16sh", "", flags)
155

    
156
  try:
157
    res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
158
  except EnvironmentError, err:
159
    raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
160
                                 err)
161

    
162
  # Get the interface name from the ioctl
163
  ifname = struct.unpack("16sh", res)[0].strip("\x00")
164
  return (ifname, tapfd)
165

    
166

    
167
class QmpMessage:
168
  """QEMU Messaging Protocol (QMP) message.
169

170
  """
171
  def __init__(self, data):
172
    """Creates a new QMP message based on the passed data.
173

174
    """
175
    if not isinstance(data, dict):
176
      raise TypeError("QmpMessage must be initialized with a dict")
177

    
178
    self.data = data
179

    
180
  def __getitem__(self, field_name):
181
    """Get the value of the required field if present, or None.
182

183
    Overrides the [] operator to provide access to the message data,
184
    returning None if the required item is not in the message
185
    @return: the value of the field_name field, or None if field_name
186
             is not contained in the message
187

188
    """
189
    return self.data.get(field_name, None)
190

    
191
  def __setitem__(self, field_name, field_value):
192
    """Set the value of the required field_name to field_value.
193

194
    """
195
    self.data[field_name] = field_value
196

    
197
  @staticmethod
198
  def BuildFromJsonString(json_string):
199
    """Build a QmpMessage from a JSON encoded string.
200

201
    @type json_string: str
202
    @param json_string: JSON string representing the message
203
    @rtype: L{QmpMessage}
204
    @return: a L{QmpMessage} built from json_string
205

206
    """
207
    # Parse the string
208
    data = serializer.LoadJson(json_string)
209
    return QmpMessage(data)
210

    
211
  def __str__(self):
212
    # The protocol expects the JSON object to be sent as a single line.
213
    return serializer.DumpJson(self.data)
214

    
215
  def __eq__(self, other):
216
    # When comparing two QmpMessages, we are interested in comparing
217
    # their internal representation of the message data
218
    return self.data == other.data
219

    
220

    
221
class QmpConnection:
222
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
223

224
  """
225
  _FIRST_MESSAGE_KEY = "QMP"
226
  _EVENT_KEY = "event"
227
  _ERROR_KEY = "error"
228
  _RETURN_KEY = RETURN_KEY = "return"
229
  _ACTUAL_KEY = ACTUAL_KEY = "actual"
230
  _ERROR_CLASS_KEY = "class"
231
  _ERROR_DATA_KEY = "data"
232
  _ERROR_DESC_KEY = "desc"
233
  _EXECUTE_KEY = "execute"
234
  _ARGUMENTS_KEY = "arguments"
235
  _CAPABILITIES_COMMAND = "qmp_capabilities"
236
  _MESSAGE_END_TOKEN = "\r\n"
237
  _SOCKET_TIMEOUT = 5
238

    
239
  def __init__(self, monitor_filename):
240
    """Instantiates the QmpConnection object.
241

242
    @type monitor_filename: string
243
    @param monitor_filename: the filename of the UNIX raw socket on which the
244
                             QMP monitor is listening
245

246
    """
247
    self.monitor_filename = monitor_filename
248
    self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
249
    # We want to fail if the server doesn't send a complete message
250
    # in a reasonable amount of time
251
    self.sock.settimeout(self._SOCKET_TIMEOUT)
252
    self._connected = False
253
    self._buf = ""
254

    
255
  def _check_socket(self):
256
    sock_stat = None
257
    try:
258
      sock_stat = os.stat(self.monitor_filename)
259
    except EnvironmentError, err:
260
      if err.errno == errno.ENOENT:
261
        raise errors.HypervisorError("No qmp socket found")
262
      else:
263
        raise errors.HypervisorError("Error checking qmp socket: %s",
264
                                     utils.ErrnoOrStr(err))
265
    if not stat.S_ISSOCK(sock_stat.st_mode):
266
      raise errors.HypervisorError("Qmp socket is not a socket")
267

    
268
  def _check_connection(self):
269
    """Make sure that the connection is established.
270

271
    """
272
    if not self._connected:
273
      raise errors.ProgrammerError("To use a QmpConnection you need to first"
274
                                   " invoke connect() on it")
275

    
276
  def connect(self):
277
    """Connects to the QMP monitor.
278

279
    Connects to the UNIX socket and makes sure that we can actually send and
280
    receive data to the kvm instance via QMP.
281

282
    @raise errors.HypervisorError: when there are communication errors
283
    @raise errors.ProgrammerError: when there are data serialization errors
284

285
    """
286
    if self._connected:
287
      raise errors.ProgrammerError("Cannot connect twice")
288

    
289
    self._check_socket()
290

    
291
    # Check file existance/stuff
292
    try:
293
      self.sock.connect(self.monitor_filename)
294
    except EnvironmentError:
295
      raise errors.HypervisorError("Can't connect to qmp socket")
296
    self._connected = True
297

    
298
    # Check if we receive a correct greeting message from the server
299
    # (As per the QEMU Protocol Specification 0.1 - section 2.2)
300
    greeting = self._Recv()
301
    if not greeting[self._FIRST_MESSAGE_KEY]:
302
      self._connected = False
303
      raise errors.HypervisorError("kvm: QMP communication error (wrong"
304
                                   " server greeting")
305

    
306
    # Let's put the monitor in command mode using the qmp_capabilities
307
    # command, or else no command will be executable.
308
    # (As per the QEMU Protocol Specification 0.1 - section 4)
309
    self.Execute(self._CAPABILITIES_COMMAND)
310

    
311
  def _ParseMessage(self, buf):
312
    """Extract and parse a QMP message from the given buffer.
313

314
    Seeks for a QMP message in the given buf. If found, it parses it and
315
    returns it together with the rest of the characters in the buf.
316
    If no message is found, returns None and the whole buffer.
317

318
    @raise errors.ProgrammerError: when there are data serialization errors
319

320
    """
321
    message = None
322
    # Check if we got the message end token (CRLF, as per the QEMU Protocol
323
    # Specification 0.1 - Section 2.1.1)
324
    pos = buf.find(self._MESSAGE_END_TOKEN)
325
    if pos >= 0:
326
      try:
327
        message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
328
      except Exception, err:
329
        raise errors.ProgrammerError("QMP data serialization error: %s" % err)
330
      buf = buf[pos + 1:]
331

    
332
    return (message, buf)
333

    
334
  def _Recv(self):
335
    """Receives a message from QMP and decodes the received JSON object.
336

337
    @rtype: QmpMessage
338
    @return: the received message
339
    @raise errors.HypervisorError: when there are communication errors
340
    @raise errors.ProgrammerError: when there are data serialization errors
341

342
    """
343
    self._check_connection()
344

    
345
    # Check if there is already a message in the buffer
346
    (message, self._buf) = self._ParseMessage(self._buf)
347
    if message:
348
      return message
349

    
350
    recv_buffer = StringIO.StringIO(self._buf)
351
    recv_buffer.seek(len(self._buf))
352
    try:
353
      while True:
354
        data = self.sock.recv(4096)
355
        if not data:
356
          break
357
        recv_buffer.write(data)
358

    
359
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
360
        if message:
361
          return message
362

    
363
    except socket.timeout, err:
364
      raise errors.HypervisorError("Timeout while receiving a QMP message: "
365
                                   "%s" % (err))
366
    except socket.error, err:
367
      raise errors.HypervisorError("Unable to receive data from KVM using the"
368
                                   " QMP protocol: %s" % err)
369

    
370
  def _Send(self, message):
371
    """Encodes and sends a message to KVM using QMP.
372

373
    @type message: QmpMessage
374
    @param message: message to send to KVM
375
    @raise errors.HypervisorError: when there are communication errors
376
    @raise errors.ProgrammerError: when there are data serialization errors
377

378
    """
379
    self._check_connection()
380
    try:
381
      message_str = str(message)
382
    except Exception, err:
383
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
384

    
385
    try:
386
      self.sock.sendall(message_str)
387
    except socket.timeout, err:
388
      raise errors.HypervisorError("Timeout while sending a QMP message: "
389
                                   "%s (%s)" % (err.string, err.errno))
390
    except socket.error, err:
391
      raise errors.HypervisorError("Unable to send data from KVM using the"
392
                                   " QMP protocol: %s" % err)
393

    
394
  def Execute(self, command, arguments=None):
395
    """Executes a QMP command and returns the response of the server.
396

397
    @type command: str
398
    @param command: the command to execute
399
    @type arguments: dict
400
    @param arguments: dictionary of arguments to be passed to the command
401
    @rtype: dict
402
    @return: dictionary representing the received JSON object
403
    @raise errors.HypervisorError: when there are communication errors
404
    @raise errors.ProgrammerError: when there are data serialization errors
405

406
    """
407
    self._check_connection()
408
    message = QmpMessage({self._EXECUTE_KEY: command})
409
    if arguments:
410
      message[self._ARGUMENTS_KEY] = arguments
411
    self._Send(message)
412

    
413
    # Events can occur between the sending of the command and the reception
414
    # of the response, so we need to filter out messages with the event key.
415
    while True:
416
      response = self._Recv()
417
      err = response[self._ERROR_KEY]
418
      if err:
419
        raise errors.HypervisorError("kvm: error executing the %s"
420
                                     " command: %s (%s, %s):" %
421
                                     (command,
422
                                      err[self._ERROR_DESC_KEY],
423
                                      err[self._ERROR_CLASS_KEY],
424
                                      err[self._ERROR_DATA_KEY]))
425

    
426
      elif not response[self._EVENT_KEY]:
427
        return response
428

    
429

    
430
class KVMHypervisor(hv_base.BaseHypervisor):
431
  """KVM hypervisor interface
432

433
  """
434
  CAN_MIGRATE = True
435

    
436
  _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
437
  _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
438
  _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
439
  _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
440
  _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
441
  _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
442
  _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
443
  # KVM instances with chroot enabled are started in empty chroot directories.
444
  _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
445
  # After an instance is stopped, its chroot directory is removed.
446
  # If the chroot directory is not empty, it can't be removed.
447
  # A non-empty chroot directory indicates a possible security incident.
448
  # To support forensics, the non-empty chroot directory is quarantined in
449
  # a separate directory, called 'chroot-quarantine'.
450
  _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
451
  _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
452
           _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
453

    
454
  PARAMETERS = {
455
    constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
456
    constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
457
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
458
    constants.HV_ROOT_PATH: hv_base.NO_CHECK,
459
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
460
    constants.HV_ACPI: hv_base.NO_CHECK,
461
    constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
462
    constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
463
    constants.HV_VNC_BIND_ADDRESS:
464
      (False, lambda x: (netutils.IP4Address.IsValid(x) or
465
                         utils.IsNormAbsPath(x)),
466
       "The VNC bind address must be either a valid IP address or an absolute"
467
       " pathname", None, None),
468
    constants.HV_VNC_TLS: hv_base.NO_CHECK,
469
    constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
470
    constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
471
    constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
472
    constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
473
    constants.HV_KVM_SPICE_IP_VERSION:
474
      (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
475
                         x in constants.VALID_IP_VERSIONS),
476
       "The SPICE IP version should be 4 or 6",
477
       None, None),
478
    constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
479
    constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
480
      hv_base.ParamInSet(
481
        False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
482
    constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
483
      hv_base.ParamInSet(
484
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
485
    constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
486
      hv_base.ParamInSet(
487
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
488
    constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
489
      hv_base.ParamInSet(
490
        False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
491
    constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
492
    constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
493
    constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
494
    constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
495
    constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
496
    constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
497
    constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
498
    constants.HV_BOOT_ORDER:
499
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
500
    constants.HV_NIC_TYPE:
501
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
502
    constants.HV_DISK_TYPE:
503
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
504
    constants.HV_KVM_CDROM_DISK_TYPE:
505
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
506
    constants.HV_USB_MOUSE:
507
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
508
    constants.HV_KEYMAP: hv_base.NO_CHECK,
509
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
510
    constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
511
    constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
512
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
513
    constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
514
    constants.HV_DISK_CACHE:
515
      hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
516
    constants.HV_SECURITY_MODEL:
517
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
518
    constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
519
    constants.HV_KVM_FLAG:
520
      hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
521
    constants.HV_VHOST_NET: hv_base.NO_CHECK,
522
    constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
523
    constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
524
    constants.HV_REBOOT_BEHAVIOR:
525
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
526
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
527
    constants.HV_CPU_TYPE: hv_base.NO_CHECK,
528
    constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
529
    constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
530
    constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
531
    constants.HV_SOUNDHW: hv_base.NO_CHECK,
532
    constants.HV_USB_DEVICES: hv_base.NO_CHECK,
533
    constants.HV_VGA: hv_base.NO_CHECK,
534
    constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
535
    constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
536
    }
537

    
538
  _VIRTIO = "virtio"
539
  _VIRTIO_NET_PCI = "virtio-net-pci"
540

    
541
  _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
542
                                    re.M | re.I)
543
  _MIGRATION_PROGRESS_RE = \
544
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
545
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
546
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
547

    
548
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
549
  _MIGRATION_INFO_RETRY_DELAY = 2
550

    
551
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
552

    
553
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
554
  _CPU_INFO_CMD = "info cpus"
555
  _CONT_CMD = "cont"
556

    
557
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
558
  _CHECK_MACHINE_VERSION_RE = \
559
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
560

    
561
  _QMP_RE = re.compile(r"^-qmp\s", re.M)
562
  _SPICE_RE = re.compile(r"^-spice\s", re.M)
563
  _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
564
  _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
565
  _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
566
  _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
567
  _DISPLAY_RE = re.compile(r"^-display\s", re.M)
568
  _MACHINE_RE = re.compile(r"^-machine\s", re.M)
569
  _NEW_VIRTIO_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
570
  # match  -drive.*boot=on|off on different lines, but in between accept only
571
  # dashes not preceeded by a new line (which would mean another option
572
  # different than -drive is starting)
573
  _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
574

    
575
  ANCILLARY_FILES = [
576
    _KVM_NETWORK_SCRIPT,
577
    ]
578
  ANCILLARY_FILES_OPT = [
579
    _KVM_NETWORK_SCRIPT,
580
    ]
581

    
582
  # Supported kvm options to get output from
583
  _KVMOPT_HELP = "help"
584
  _KVMOPT_MLIST = "mlist"
585
  _KVMOPT_DEVICELIST = "devicelist"
586

    
587
  # Command to execute to get the output from kvm, and whether to
588
  # accept the output even on failure.
589
  _KVMOPTS_CMDS = {
590
    _KVMOPT_HELP: (["--help"], False),
591
    _KVMOPT_MLIST: (["-M", "?"], False),
592
    _KVMOPT_DEVICELIST: (["-device", "?"], True),
593
  }
594

    
595
  def __init__(self):
596
    hv_base.BaseHypervisor.__init__(self)
597
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
598
    # in a tmpfs filesystem or has been otherwise wiped out.
599
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
600
    utils.EnsureDirs(dirs)
601

    
602
  @classmethod
603
  def _InstancePidFile(cls, instance_name):
604
    """Returns the instance pidfile.
605

606
    """
607
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
608

    
609
  @classmethod
610
  def _InstanceUidFile(cls, instance_name):
611
    """Returns the instance uidfile.
612

613
    """
614
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
615

    
616
  @classmethod
617
  def _InstancePidInfo(cls, pid):
618
    """Check pid file for instance information.
619

620
    Check that a pid file is associated with an instance, and retrieve
621
    information from its command line.
622

623
    @type pid: string or int
624
    @param pid: process id of the instance to check
625
    @rtype: tuple
626
    @return: (instance_name, memory, vcpus)
627
    @raise errors.HypervisorError: when an instance cannot be found
628

629
    """
630
    alive = utils.IsProcessAlive(pid)
631
    if not alive:
632
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
633

    
634
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
635
    try:
636
      cmdline = utils.ReadFile(cmdline_file)
637
    except EnvironmentError, err:
638
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
639
                                   (pid, err))
640

    
641
    instance = None
642
    memory = 0
643
    vcpus = 0
644

    
645
    arg_list = cmdline.split("\x00")
646
    while arg_list:
647
      arg = arg_list.pop(0)
648
      if arg == "-name":
649
        instance = arg_list.pop(0)
650
      elif arg == "-m":
651
        memory = int(arg_list.pop(0))
652
      elif arg == "-smp":
653
        vcpus = int(arg_list.pop(0).split(",")[0])
654

    
655
    if instance is None:
656
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
657
                                   " instance" % pid)
658

    
659
    return (instance, memory, vcpus)
660

    
661
  def _InstancePidAlive(self, instance_name):
662
    """Returns the instance pidfile, pid, and liveness.
663

664
    @type instance_name: string
665
    @param instance_name: instance name
666
    @rtype: tuple
667
    @return: (pid file name, pid, liveness)
668

669
    """
670
    pidfile = self._InstancePidFile(instance_name)
671
    pid = utils.ReadPidFile(pidfile)
672

    
673
    alive = False
674
    try:
675
      cmd_instance = self._InstancePidInfo(pid)[0]
676
      alive = (cmd_instance == instance_name)
677
    except errors.HypervisorError:
678
      pass
679

    
680
    return (pidfile, pid, alive)
681

    
682
  def _CheckDown(self, instance_name):
683
    """Raises an error unless the given instance is down.
684

685
    """
686
    alive = self._InstancePidAlive(instance_name)[2]
687
    if alive:
688
      raise errors.HypervisorError("Failed to start instance %s: %s" %
689
                                   (instance_name, "already running"))
690

    
691
  @classmethod
692
  def _InstanceMonitor(cls, instance_name):
693
    """Returns the instance monitor socket name
694

695
    """
696
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
697

    
698
  @classmethod
699
  def _InstanceSerial(cls, instance_name):
700
    """Returns the instance serial socket name
701

702
    """
703
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
704

    
705
  @classmethod
706
  def _InstanceQmpMonitor(cls, instance_name):
707
    """Returns the instance serial QMP socket name
708

709
    """
710
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
711

    
712
  @staticmethod
713
  def _SocatUnixConsoleParams():
714
    """Returns the correct parameters for socat
715

716
    If we have a new-enough socat we can use raw mode with an escape character.
717

718
    """
719
    if constants.SOCAT_USE_ESCAPE:
720
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
721
    else:
722
      return "echo=0,icanon=0"
723

    
724
  @classmethod
725
  def _InstanceKVMRuntime(cls, instance_name):
726
    """Returns the instance KVM runtime filename
727

728
    """
729
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
730

    
731
  @classmethod
732
  def _InstanceChrootDir(cls, instance_name):
733
    """Returns the name of the KVM chroot dir of the instance
734

735
    """
736
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
737

    
738
  @classmethod
739
  def _InstanceNICDir(cls, instance_name):
740
    """Returns the name of the directory holding the tap device files for a
741
    given instance.
742

743
    """
744
    return utils.PathJoin(cls._NICS_DIR, instance_name)
745

    
746
  @classmethod
747
  def _InstanceNICFile(cls, instance_name, seq):
748
    """Returns the name of the file containing the tap device for a given NIC
749

750
    """
751
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
752

    
753
  @classmethod
754
  def _InstanceKeymapFile(cls, instance_name):
755
    """Returns the name of the file containing the keymap for a given instance
756

757
    """
758
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
759

    
760
  @classmethod
761
  def _TryReadUidFile(cls, uid_file):
762
    """Try to read a uid file
763

764
    """
765
    if os.path.exists(uid_file):
766
      try:
767
        uid = int(utils.ReadOneLineFile(uid_file))
768
        return uid
769
      except EnvironmentError:
770
        logging.warning("Can't read uid file", exc_info=True)
771
      except (TypeError, ValueError):
772
        logging.warning("Can't parse uid file contents", exc_info=True)
773
    return None
774

    
775
  @classmethod
776
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
777
    """Removes an instance's rutime sockets/files/dirs.
778

779
    """
780
    utils.RemoveFile(pidfile)
781
    utils.RemoveFile(cls._InstanceMonitor(instance_name))
782
    utils.RemoveFile(cls._InstanceSerial(instance_name))
783
    utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
784
    utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
785
    utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
786
    uid_file = cls._InstanceUidFile(instance_name)
787
    uid = cls._TryReadUidFile(uid_file)
788
    utils.RemoveFile(uid_file)
789
    if uid is not None:
790
      uidpool.ReleaseUid(uid)
791
    try:
792
      shutil.rmtree(cls._InstanceNICDir(instance_name))
793
    except OSError, err:
794
      if err.errno != errno.ENOENT:
795
        raise
796
    try:
797
      chroot_dir = cls._InstanceChrootDir(instance_name)
798
      utils.RemoveDir(chroot_dir)
799
    except OSError, err:
800
      if err.errno == errno.ENOTEMPTY:
801
        # The chroot directory is expected to be empty, but it isn't.
802
        new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
803
                                          prefix="%s-%s-" %
804
                                          (instance_name,
805
                                           utils.TimestampForFilename()))
806
        logging.warning("The chroot directory of instance %s can not be"
807
                        " removed as it is not empty. Moving it to the"
808
                        " quarantine instead. Please investigate the"
809
                        " contents (%s) and clean up manually",
810
                        instance_name, new_chroot_dir)
811
        utils.RenameFile(chroot_dir, new_chroot_dir)
812
      else:
813
        raise
814

    
815
  @staticmethod
816
  def _ConfigureNIC(instance, seq, nic, tap):
817
    """Run the network configuration script for a specified NIC
818

819
    @param instance: instance we're acting on
820
    @type instance: instance object
821
    @param seq: nic sequence number
822
    @type seq: int
823
    @param nic: nic we're acting on
824
    @type nic: nic object
825
    @param tap: the host's tap interface this NIC corresponds to
826
    @type tap: str
827

828
    """
829
    if instance.tags:
830
      tags = " ".join(instance.tags)
831
    else:
832
      tags = ""
833

    
834
    env = {
835
      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
836
      "INSTANCE": instance.name,
837
      "MAC": nic.mac,
838
      "MODE": nic.nicparams[constants.NIC_MODE],
839
      "INTERFACE": tap,
840
      "INTERFACE_INDEX": str(seq),
841
      "TAGS": tags,
842
    }
843

    
844
    if nic.ip:
845
      env["IP"] = nic.ip
846

    
847
    if nic.nicparams[constants.NIC_LINK]:
848
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
849

    
850
    if nic.network:
851
      n = objects.Network.FromDict(nic.netinfo)
852
      env.update(n.HooksDict())
853

    
854
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
855
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
856

    
857
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
858
    if result.failed:
859
      raise errors.HypervisorError("Failed to configure interface %s: %s;"
860
                                   " network configuration script output: %s" %
861
                                   (tap, result.fail_reason, result.output))
862

    
863
  @staticmethod
864
  def _VerifyAffinityPackage():
865
    if affinity is None:
866
      raise errors.HypervisorError("affinity Python package not"
867
                                   " found; cannot use CPU pinning under KVM")
868

    
869
  @staticmethod
870
  def _BuildAffinityCpuMask(cpu_list):
871
    """Create a CPU mask suitable for sched_setaffinity from a list of
872
    CPUs.
873

874
    See man taskset for more info on sched_setaffinity masks.
875
    For example: [ 0, 2, 5, 6 ] will return 101 (0x65, 0..01100101).
876

877
    @type cpu_list: list of int
878
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
879
    @rtype: int
880
    @return: a bit mask of CPU affinities
881

882
    """
883
    if cpu_list == constants.CPU_PINNING_OFF:
884
      return constants.CPU_PINNING_ALL_KVM
885
    else:
886
      return sum(2 ** cpu for cpu in cpu_list)
887

    
888
  @classmethod
889
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
890
    """Change CPU affinity for running VM according to given CPU mask.
891

892
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
893
    @type cpu_mask: string
894
    @param process_id: process ID of KVM process. Used to pin entire VM
895
                       to physical CPUs.
896
    @type process_id: int
897
    @param thread_dict: map of virtual CPUs to KVM thread IDs
898
    @type thread_dict: dict int:int
899

900
    """
901
    # Convert the string CPU mask to a list of list of int's
902
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
903

    
904
    if len(cpu_list) == 1:
905
      all_cpu_mapping = cpu_list[0]
906
      if all_cpu_mapping == constants.CPU_PINNING_OFF:
907
        # If CPU pinning has 1 entry that's "all", then do nothing
908
        pass
909
      else:
910
        # If CPU pinning has one non-all entry, map the entire VM to
911
        # one set of physical CPUs
912
        cls._VerifyAffinityPackage()
913
        affinity.set_process_affinity_mask(
914
          process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
915
    else:
916
      # The number of vCPUs mapped should match the number of vCPUs
917
      # reported by KVM. This was already verified earlier, so
918
      # here only as a sanity check.
919
      assert len(thread_dict) == len(cpu_list)
920
      cls._VerifyAffinityPackage()
921

    
922
      # For each vCPU, map it to the proper list of physical CPUs
923
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
924
        affinity.set_process_affinity_mask(thread_dict[i],
925
                                           cls._BuildAffinityCpuMask(vcpu))
926

    
927
  def _GetVcpuThreadIds(self, instance_name):
928
    """Get a mapping of vCPU no. to thread IDs for the instance
929

930
    @type instance_name: string
931
    @param instance_name: instance in question
932
    @rtype: dictionary of int:int
933
    @return: a dictionary mapping vCPU numbers to thread IDs
934

935
    """
936
    result = {}
937
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
938
    for line in output.stdout.splitlines():
939
      match = self._CPU_INFO_RE.search(line)
940
      if not match:
941
        continue
942
      grp = map(int, match.groups())
943
      result[grp[0]] = grp[1]
944

    
945
    return result
946

    
947
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
948
    """Complete CPU pinning.
949

950
    @type instance_name: string
951
    @param instance_name: name of instance
952
    @type cpu_mask: string
953
    @param cpu_mask: CPU pinning mask as entered by user
954

955
    """
956
    # Get KVM process ID, to be used if need to pin entire VM
957
    _, pid, _ = self._InstancePidAlive(instance_name)
958
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
959
    thread_dict = self._GetVcpuThreadIds(instance_name)
960
    # Run CPU pinning, based on configured mask
961
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
962

    
963
  def ListInstances(self):
964
    """Get the list of running instances.
965

966
    We can do this by listing our live instances directory and
967
    checking whether the associated kvm process is still alive.
968

969
    """
970
    result = []
971
    for name in os.listdir(self._PIDS_DIR):
972
      if self._InstancePidAlive(name)[2]:
973
        result.append(name)
974
    return result
975

    
976
  def GetInstanceInfo(self, instance_name):
977
    """Get instance properties.
978

979
    @type instance_name: string
980
    @param instance_name: the instance name
981
    @rtype: tuple of strings
982
    @return: (name, id, memory, vcpus, stat, times)
983

984
    """
985
    _, pid, alive = self._InstancePidAlive(instance_name)
986
    if not alive:
987
      return None
988

    
989
    _, memory, vcpus = self._InstancePidInfo(pid)
990
    istat = "---b-"
991
    times = "0"
992

    
993
    try:
994
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
995
      qmp.connect()
996
      vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
997
      # Will fail if ballooning is not enabled, but we can then just resort to
998
      # the value above.
999
      mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1000
      memory = mem_bytes / 1048576
1001
    except errors.HypervisorError:
1002
      pass
1003

    
1004
    return (instance_name, pid, memory, vcpus, istat, times)
1005

    
1006
  def GetAllInstancesInfo(self):
1007
    """Get properties of all instances.
1008

1009
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1010

1011
    """
1012
    data = []
1013
    for name in os.listdir(self._PIDS_DIR):
1014
      try:
1015
        info = self.GetInstanceInfo(name)
1016
      except errors.HypervisorError:
1017
        # Ignore exceptions due to instances being shut down
1018
        continue
1019
      if info:
1020
        data.append(info)
1021
    return data
1022

    
1023
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1024
                          kvmhelp):
1025
    """Generate KVM information to start an instance.
1026

1027
    @type kvmhelp: string
1028
    @param kvmhelp: output of kvm --help
1029
    @attention: this function must not have any side-effects; for
1030
        example, it must not write to the filesystem, or read values
1031
        from the current system the are expected to differ between
1032
        nodes, since it is only run once at instance startup;
1033
        actions/kvm arguments that can vary between systems should be
1034
        done in L{_ExecuteKVMRuntime}
1035

1036
    """
1037
    # pylint: disable=R0912,R0914,R0915
1038
    hvp = instance.hvparams
1039
    self.ValidateParameters(hvp)
1040

    
1041
    pidfile = self._InstancePidFile(instance.name)
1042
    kvm = hvp[constants.HV_KVM_PATH]
1043
    kvm_cmd = [kvm]
1044
    # used just by the vnc server, if enabled
1045
    kvm_cmd.extend(["-name", instance.name])
1046
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1047

    
1048
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1049
    if hvp[constants.HV_CPU_CORES]:
1050
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1051
    if hvp[constants.HV_CPU_THREADS]:
1052
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1053
    if hvp[constants.HV_CPU_SOCKETS]:
1054
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1055

    
1056
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1057

    
1058
    kvm_cmd.extend(["-pidfile", pidfile])
1059
    kvm_cmd.extend(["-balloon", "virtio"])
1060
    kvm_cmd.extend(["-daemonize"])
1061
    if not instance.hvparams[constants.HV_ACPI]:
1062
      kvm_cmd.extend(["-no-acpi"])
1063
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1064
        constants.INSTANCE_REBOOT_EXIT:
1065
      kvm_cmd.extend(["-no-reboot"])
1066

    
1067
    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1068
    if not mversion:
1069
      mversion = self._GetDefaultMachineVersion(kvm)
1070
    if self._MACHINE_RE.search(kvmhelp):
1071
      # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1072
      # extra hypervisor parameters. We should also investigate whether and how
1073
      # shadow_mem should be considered for the resource model.
1074
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1075
        specprop = ",accel=kvm"
1076
      else:
1077
        specprop = ""
1078
      machinespec = "%s%s" % (mversion, specprop)
1079
      kvm_cmd.extend(["-machine", machinespec])
1080
    else:
1081
      kvm_cmd.extend(["-M", mversion])
1082
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1083
          self._ENABLE_KVM_RE.search(kvmhelp)):
1084
        kvm_cmd.extend(["-enable-kvm"])
1085
      elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1086
            self._DISABLE_KVM_RE.search(kvmhelp)):
1087
        kvm_cmd.extend(["-disable-kvm"])
1088

    
1089
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1090
    if kernel_path:
1091
      boot_disk = boot_cdrom = boot_floppy = boot_network = False
1092
    else:
1093
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1094
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1095
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1096
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1097

    
1098
    if startup_paused:
1099
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1100

    
1101
    if boot_network:
1102
      kvm_cmd.extend(["-boot", "n"])
1103

    
1104
    # whether this is an older KVM version that uses the boot=on flag
1105
    # on devices
1106
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1107

    
1108
    disk_type = hvp[constants.HV_DISK_TYPE]
1109
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
1110
      if_val = ",if=virtio"
1111
    else:
1112
      if_val = ",if=%s" % disk_type
1113
    # Cache mode
1114
    disk_cache = hvp[constants.HV_DISK_CACHE]
1115
    if instance.disk_template in constants.DTS_EXT_MIRROR:
1116
      if disk_cache != "none":
1117
        # TODO: make this a hard error, instead of a silent overwrite
1118
        logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1119
                        " to prevent shared storage corruption on migration",
1120
                        disk_cache)
1121
      cache_val = ",cache=none"
1122
    elif disk_cache != constants.HT_CACHE_DEFAULT:
1123
      cache_val = ",cache=%s" % disk_cache
1124
    else:
1125
      cache_val = ""
1126
    for cfdev, dev_path in block_devices:
1127
      if cfdev.mode != constants.DISK_RDWR:
1128
        raise errors.HypervisorError("Instance has read-only disks which"
1129
                                     " are not supported by KVM")
1130
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
1131
      boot_val = ""
1132
      if boot_disk:
1133
        kvm_cmd.extend(["-boot", "c"])
1134
        boot_disk = False
1135
        if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1136
          boot_val = ",boot=on"
1137

    
1138
      drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
1139
                                                cache_val)
1140
      kvm_cmd.extend(["-drive", drive_val])
1141

    
1142
    #Now we can specify a different device type for CDROM devices.
1143
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1144
    if not cdrom_disk_type:
1145
      cdrom_disk_type = disk_type
1146

    
1147
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1148
    if iso_image:
1149
      options = ",format=raw,media=cdrom"
1150
      # set cdrom 'if' type
1151
      if boot_cdrom:
1152
        actual_cdrom_type = constants.HT_DISK_IDE
1153
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1154
        actual_cdrom_type = "virtio"
1155
      else:
1156
        actual_cdrom_type = cdrom_disk_type
1157
      if_val = ",if=%s" % actual_cdrom_type
1158
      # set boot flag, if needed
1159
      boot_val = ""
1160
      if boot_cdrom:
1161
        kvm_cmd.extend(["-boot", "d"])
1162
        if needs_boot_flag:
1163
          boot_val = ",boot=on"
1164
      # and finally build the entire '-drive' value
1165
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1166
      kvm_cmd.extend(["-drive", drive_val])
1167

    
1168
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1169
    if iso_image2:
1170
      options = ",format=raw,media=cdrom"
1171
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1172
        if_val = ",if=virtio"
1173
      else:
1174
        if_val = ",if=%s" % cdrom_disk_type
1175
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1176
      kvm_cmd.extend(["-drive", drive_val])
1177

    
1178
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1179
    if floppy_image:
1180
      options = ",format=raw,media=disk"
1181
      if boot_floppy:
1182
        kvm_cmd.extend(["-boot", "a"])
1183
        options = "%s,boot=on" % options
1184
      if_val = ",if=floppy"
1185
      options = "%s%s" % (options, if_val)
1186
      drive_val = "file=%s%s" % (floppy_image, options)
1187
      kvm_cmd.extend(["-drive", drive_val])
1188

    
1189
    if kernel_path:
1190
      kvm_cmd.extend(["-kernel", kernel_path])
1191
      initrd_path = hvp[constants.HV_INITRD_PATH]
1192
      if initrd_path:
1193
        kvm_cmd.extend(["-initrd", initrd_path])
1194
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1195
                     hvp[constants.HV_KERNEL_ARGS]]
1196
      if hvp[constants.HV_SERIAL_CONSOLE]:
1197
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1198
        root_append.append("console=ttyS0,%s" % serial_speed)
1199
      kvm_cmd.extend(["-append", " ".join(root_append)])
1200

    
1201
    mem_path = hvp[constants.HV_MEM_PATH]
1202
    if mem_path:
1203
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1204

    
1205
    monitor_dev = ("unix:%s,server,nowait" %
1206
                   self._InstanceMonitor(instance.name))
1207
    kvm_cmd.extend(["-monitor", monitor_dev])
1208
    if hvp[constants.HV_SERIAL_CONSOLE]:
1209
      serial_dev = ("unix:%s,server,nowait" %
1210
                    self._InstanceSerial(instance.name))
1211
      kvm_cmd.extend(["-serial", serial_dev])
1212
    else:
1213
      kvm_cmd.extend(["-serial", "none"])
1214

    
1215
    mouse_type = hvp[constants.HV_USB_MOUSE]
1216
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1217
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1218
    spice_ip_version = None
1219

    
1220
    kvm_cmd.extend(["-usb"])
1221

    
1222
    if mouse_type:
1223
      kvm_cmd.extend(["-usbdevice", mouse_type])
1224
    elif vnc_bind_address:
1225
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1226

    
1227
    if vnc_bind_address:
1228
      if netutils.IP4Address.IsValid(vnc_bind_address):
1229
        if instance.network_port > constants.VNC_BASE_PORT:
1230
          display = instance.network_port - constants.VNC_BASE_PORT
1231
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1232
            vnc_arg = ":%d" % (display)
1233
          else:
1234
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1235
        else:
1236
          logging.error("Network port is not a valid VNC display (%d < %d),"
1237
                        " not starting VNC",
1238
                        instance.network_port, constants.VNC_BASE_PORT)
1239
          vnc_arg = "none"
1240

    
1241
        # Only allow tls and other option when not binding to a file, for now.
1242
        # kvm/qemu gets confused otherwise about the filename to use.
1243
        vnc_append = ""
1244
        if hvp[constants.HV_VNC_TLS]:
1245
          vnc_append = "%s,tls" % vnc_append
1246
          if hvp[constants.HV_VNC_X509_VERIFY]:
1247
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1248
                                               hvp[constants.HV_VNC_X509])
1249
          elif hvp[constants.HV_VNC_X509]:
1250
            vnc_append = "%s,x509=%s" % (vnc_append,
1251
                                         hvp[constants.HV_VNC_X509])
1252
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1253
          vnc_append = "%s,password" % vnc_append
1254

    
1255
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1256

    
1257
      else:
1258
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1259

    
1260
      kvm_cmd.extend(["-vnc", vnc_arg])
1261
    elif spice_bind:
1262
      # FIXME: this is wrong here; the iface ip address differs
1263
      # between systems, so it should be done in _ExecuteKVMRuntime
1264
      if netutils.IsValidInterface(spice_bind):
1265
        # The user specified a network interface, we have to figure out the IP
1266
        # address.
1267
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1268
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1269

    
1270
        # if the user specified an IP version and the interface does not
1271
        # have that kind of IP addresses, throw an exception
1272
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1273
          if not addresses[spice_ip_version]:
1274
            raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1275
                                         " for %s" % (spice_ip_version,
1276
                                                      spice_bind))
1277

    
1278
        # the user did not specify an IP version, we have to figure it out
1279
        elif (addresses[constants.IP4_VERSION] and
1280
              addresses[constants.IP6_VERSION]):
1281
          # we have both ipv4 and ipv6, let's use the cluster default IP
1282
          # version
1283
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1284
          spice_ip_version = \
1285
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1286
        elif addresses[constants.IP4_VERSION]:
1287
          spice_ip_version = constants.IP4_VERSION
1288
        elif addresses[constants.IP6_VERSION]:
1289
          spice_ip_version = constants.IP6_VERSION
1290
        else:
1291
          raise errors.HypervisorError("SPICE: Unable to get an IP address"
1292
                                       " for %s" % (spice_bind))
1293

    
1294
        spice_address = addresses[spice_ip_version][0]
1295

    
1296
      else:
1297
        # spice_bind is known to be a valid IP address, because
1298
        # ValidateParameters checked it.
1299
        spice_address = spice_bind
1300

    
1301
      spice_arg = "addr=%s" % spice_address
1302
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1303
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1304
                     (spice_arg, instance.network_port,
1305
                      pathutils.SPICE_CACERT_FILE))
1306
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1307
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1308
                      pathutils.SPICE_CERT_FILE))
1309
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1310
        if tls_ciphers:
1311
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1312
      else:
1313
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1314

    
1315
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1316
        spice_arg = "%s,disable-ticketing" % spice_arg
1317

    
1318
      if spice_ip_version:
1319
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1320

    
1321
      # Image compression options
1322
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1323
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1324
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1325
      if img_lossless:
1326
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1327
      if img_jpeg:
1328
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1329
      if img_zlib_glz:
1330
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1331

    
1332
      # Video stream detection
1333
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1334
      if video_streaming:
1335
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1336

    
1337
      # Audio compression, by default in qemu-kvm it is on
1338
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1339
        spice_arg = "%s,playback-compression=off" % spice_arg
1340
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1341
        spice_arg = "%s,agent-mouse=off" % spice_arg
1342
      else:
1343
        # Enable the spice agent communication channel between the host and the
1344
        # agent.
1345
        kvm_cmd.extend(["-device", "virtio-serial-pci"])
1346
        kvm_cmd.extend([
1347
          "-device",
1348
          "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1349
          ])
1350
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1351

    
1352
      logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1353
      kvm_cmd.extend(["-spice", spice_arg])
1354

    
1355
    else:
1356
      # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1357
      # also works in earlier versions though (tested with 1.1 and 1.3)
1358
      if self._DISPLAY_RE.search(kvmhelp):
1359
        kvm_cmd.extend(["-display", "none"])
1360
      else:
1361
        kvm_cmd.extend(["-nographic"])
1362

    
1363
    if hvp[constants.HV_USE_LOCALTIME]:
1364
      kvm_cmd.extend(["-localtime"])
1365

    
1366
    if hvp[constants.HV_KVM_USE_CHROOT]:
1367
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1368

    
1369
    # Add qemu-KVM -cpu param
1370
    if hvp[constants.HV_CPU_TYPE]:
1371
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1372

    
1373
    # As requested by music lovers
1374
    if hvp[constants.HV_SOUNDHW]:
1375
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1376

    
1377
    # Pass a -vga option if requested, or if spice is used, for backwards
1378
    # compatibility.
1379
    if hvp[constants.HV_VGA]:
1380
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1381
    elif spice_bind:
1382
      kvm_cmd.extend(["-vga", "qxl"])
1383

    
1384
    # Various types of usb devices, comma separated
1385
    if hvp[constants.HV_USB_DEVICES]:
1386
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1387
        kvm_cmd.extend(["-usbdevice", dev])
1388

    
1389
    if hvp[constants.HV_KVM_EXTRA]:
1390
      kvm_cmd.extend([hvp[constants.HV_KVM_EXTRA]])
1391

    
1392
    # Save the current instance nics, but defer their expansion as parameters,
1393
    # as we'll need to generate executable temp files for them.
1394
    kvm_nics = instance.nics
1395
    hvparams = hvp
1396

    
1397
    return (kvm_cmd, kvm_nics, hvparams)
1398

    
1399
  def _WriteKVMRuntime(self, instance_name, data):
1400
    """Write an instance's KVM runtime
1401

1402
    """
1403
    try:
1404
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1405
                      data=data)
1406
    except EnvironmentError, err:
1407
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1408

    
1409
  def _ReadKVMRuntime(self, instance_name):
1410
    """Read an instance's KVM runtime
1411

1412
    """
1413
    try:
1414
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1415
    except EnvironmentError, err:
1416
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1417
    return file_content
1418

    
1419
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1420
    """Save an instance's KVM runtime
1421

1422
    """
1423
    kvm_cmd, kvm_nics, hvparams = kvm_runtime
1424
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1425
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1426
    self._WriteKVMRuntime(instance.name, serialized_form)
1427

    
1428
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1429
    """Load an instance's KVM runtime
1430

1431
    """
1432
    if not serialized_runtime:
1433
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1434
    loaded_runtime = serializer.Load(serialized_runtime)
1435
    kvm_cmd, serialized_nics, hvparams = loaded_runtime
1436
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1437
    return (kvm_cmd, kvm_nics, hvparams)
1438

    
1439
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1440
    """Run the KVM cmd and check for errors
1441

1442
    @type name: string
1443
    @param name: instance name
1444
    @type kvm_cmd: list of strings
1445
    @param kvm_cmd: runcmd input for kvm
1446
    @type tap_fds: list of int
1447
    @param tap_fds: fds of tap devices opened by Ganeti
1448

1449
    """
1450
    try:
1451
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1452
    finally:
1453
      for fd in tap_fds:
1454
        utils_wrapper.CloseFdNoError(fd)
1455

    
1456
    if result.failed:
1457
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1458
                                   (name, result.fail_reason, result.output))
1459
    if not self._InstancePidAlive(name)[2]:
1460
      raise errors.HypervisorError("Failed to start instance %s" % name)
1461

    
1462
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1463
    """Execute a KVM cmd, after completing it with some last minute data.
1464

1465
    @type incoming: tuple of strings
1466
    @param incoming: (target_host_ip, port)
1467
    @type kvmhelp: string
1468
    @param kvmhelp: output of kvm --help
1469

1470
    """
1471
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1472
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1473
    #    have changed since the instance started; only use them if the change
1474
    #    won't affect the inside of the instance (which hasn't been rebooted).
1475
    #  - up_hvp contains the parameters as they were when the instance was
1476
    #    started, plus any new parameter which has been added between ganeti
1477
    #    versions: it is paramount that those default to a value which won't
1478
    #    affect the inside of the instance as well.
1479
    conf_hvp = instance.hvparams
1480
    name = instance.name
1481
    self._CheckDown(name)
1482

    
1483
    temp_files = []
1484

    
1485
    kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1486
    # the first element of kvm_cmd is always the path to the kvm binary
1487
    kvm_path = kvm_cmd[0]
1488
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1489

    
1490
    # We know it's safe to run as a different user upon migration, so we'll use
1491
    # the latest conf, from conf_hvp.
1492
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1493
    if security_model == constants.HT_SM_USER:
1494
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1495

    
1496
    keymap = conf_hvp[constants.HV_KEYMAP]
1497
    if keymap:
1498
      keymap_path = self._InstanceKeymapFile(name)
1499
      # If a keymap file is specified, KVM won't use its internal defaults. By
1500
      # first including the "en-us" layout, an error on loading the actual
1501
      # layout (e.g. because it can't be found) won't lead to a non-functional
1502
      # keyboard. A keyboard with incorrect keys is still better than none.
1503
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1504
      kvm_cmd.extend(["-k", keymap_path])
1505

    
1506
    # We have reasons to believe changing something like the nic driver/type
1507
    # upon migration won't exactly fly with the instance kernel, so for nic
1508
    # related parameters we'll use up_hvp
1509
    tapfds = []
1510
    taps = []
1511
    if not kvm_nics:
1512
      kvm_cmd.extend(["-net", "none"])
1513
    else:
1514
      vnet_hdr = False
1515
      tap_extra = ""
1516
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1517
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1518
        nic_model = self._VIRTIO
1519
        try:
1520
          devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1521
          if self._NEW_VIRTIO_RE.search(devlist):
1522
            nic_model = self._VIRTIO_NET_PCI
1523
            vnet_hdr = True
1524
        except errors.HypervisorError, _:
1525
          # Older versions of kvm don't support DEVICE_LIST, but they don't
1526
          # have new virtio syntax either.
1527
          pass
1528

    
1529
        if up_hvp[constants.HV_VHOST_NET]:
1530
          # check for vhost_net support
1531
          if self._VHOST_RE.search(kvmhelp):
1532
            tap_extra = ",vhost=on"
1533
          else:
1534
            raise errors.HypervisorError("vhost_net is configured"
1535
                                         " but it is not available")
1536
      else:
1537
        nic_model = nic_type
1538

    
1539
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1540

    
1541
      for nic_seq, nic in enumerate(kvm_nics):
1542
        tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1543
        tapfds.append(tapfd)
1544
        taps.append(tapname)
1545
        if kvm_supports_netdev:
1546
          nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1547
          tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1548
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1549
        else:
1550
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1551
                                                         nic.mac, nic_model)
1552
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1553
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1554

    
1555
    if incoming:
1556
      target, port = incoming
1557
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1558

    
1559
    # Changing the vnc password doesn't bother the guest that much. At most it
1560
    # will surprise people who connect to it. Whether positively or negatively
1561
    # it's debatable.
1562
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1563
    vnc_pwd = None
1564
    if vnc_pwd_file:
1565
      try:
1566
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1567
      except EnvironmentError, err:
1568
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1569
                                     % (vnc_pwd_file, err))
1570

    
1571
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1572
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1573
                         constants.SECURE_DIR_MODE)])
1574

    
1575
    # Automatically enable QMP if version is >= 0.14
1576
    if self._QMP_RE.search(kvmhelp):
1577
      logging.debug("Enabling QMP")
1578
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1579
                      self._InstanceQmpMonitor(instance.name)])
1580

    
1581
    # Configure the network now for starting instances and bridged interfaces,
1582
    # during FinalizeMigration for incoming instances' routed interfaces
1583
    for nic_seq, nic in enumerate(kvm_nics):
1584
      if (incoming and
1585
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1586
        continue
1587
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1588

    
1589
    # CPU affinity requires kvm to start paused, so we set this flag if the
1590
    # instance is not already paused and if we are not going to accept a
1591
    # migrating instance. In the latter case, pausing is not needed.
1592
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1593
    if start_kvm_paused:
1594
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1595

    
1596
    # Note: CPU pinning is using up_hvp since changes take effect
1597
    # during instance startup anyway, and to avoid problems when soft
1598
    # rebooting the instance.
1599
    cpu_pinning = False
1600
    if up_hvp.get(constants.HV_CPU_MASK, None):
1601
      cpu_pinning = True
1602

    
1603
    if security_model == constants.HT_SM_POOL:
1604
      ss = ssconf.SimpleStore()
1605
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1606
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1607
      uid = uidpool.RequestUnusedUid(all_uids)
1608
      try:
1609
        username = pwd.getpwuid(uid.GetUid()).pw_name
1610
        kvm_cmd.extend(["-runas", username])
1611
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1612
      except:
1613
        uidpool.ReleaseUid(uid)
1614
        raise
1615
      else:
1616
        uid.Unlock()
1617
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1618
    else:
1619
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1620

    
1621
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1622
                     constants.RUN_DIRS_MODE)])
1623
    for nic_seq, tap in enumerate(taps):
1624
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1625
                      data=tap)
1626

    
1627
    if vnc_pwd:
1628
      change_cmd = "change vnc password %s" % vnc_pwd
1629
      self._CallMonitorCommand(instance.name, change_cmd)
1630

    
1631
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1632
    # connection attempts because SPICE by default does not allow connections
1633
    # if neither a password nor the "disable_ticketing" options are specified.
1634
    # As soon as we send the password via QMP, that password is a valid ticket
1635
    # for connection.
1636
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1637
    if spice_password_file:
1638
      spice_pwd = ""
1639
      try:
1640
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1641
      except EnvironmentError, err:
1642
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1643
                                     % (spice_password_file, err))
1644

    
1645
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1646
      qmp.connect()
1647
      arguments = {
1648
          "protocol": "spice",
1649
          "password": spice_pwd,
1650
      }
1651
      qmp.Execute("set_password", arguments)
1652

    
1653
    for filename in temp_files:
1654
      utils.RemoveFile(filename)
1655

    
1656
    # If requested, set CPU affinity and resume instance execution
1657
    if cpu_pinning:
1658
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1659

    
1660
    start_memory = self._InstanceStartupMemory(instance)
1661
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1662
      self.BalloonInstanceMemory(instance, start_memory)
1663

    
1664
    if start_kvm_paused:
1665
      # To control CPU pinning, ballooning, and vnc/spice passwords
1666
      # the VM was started in a frozen state. If freezing was not
1667
      # explicitly requested resume the vm status.
1668
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1669

    
1670
  def StartInstance(self, instance, block_devices, startup_paused):
1671
    """Start an instance.
1672

1673
    """
1674
    self._CheckDown(instance.name)
1675
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1676
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1677
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1678
                                           startup_paused, kvmhelp)
1679
    self._SaveKVMRuntime(instance, kvm_runtime)
1680
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1681

    
1682
  def _CallMonitorCommand(self, instance_name, command):
1683
    """Invoke a command on the instance monitor.
1684

1685
    """
1686
    # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1687
    # version. The monitor protocol is designed for human consumption, whereas
1688
    # QMP is made for programmatic usage. In the worst case QMP can also
1689
    # execute monitor commands. As it is, all calls to socat take at least
1690
    # 500ms and likely more: socat can't detect the end of the reply and waits
1691
    # for 500ms of no data received before exiting (500 ms is the default for
1692
    # the "-t" parameter).
1693
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1694
             (utils.ShellQuote(command),
1695
              constants.SOCAT_PATH,
1696
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1697
    result = utils.RunCmd(socat)
1698
    if result.failed:
1699
      msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1700
             " output: %s" %
1701
             (command, instance_name, result.fail_reason, result.output))
1702
      raise errors.HypervisorError(msg)
1703

    
1704
    return result
1705

    
1706
  @classmethod
1707
  def _ParseKVMVersion(cls, text):
1708
    """Parse the KVM version from the --help output.
1709

1710
    @type text: string
1711
    @param text: output of kvm --help
1712
    @return: (version, v_maj, v_min, v_rev)
1713
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1714

1715
    """
1716
    match = cls._VERSION_RE.search(text.splitlines()[0])
1717
    if not match:
1718
      raise errors.HypervisorError("Unable to get KVM version")
1719

    
1720
    v_all = match.group(0)
1721
    v_maj = int(match.group(1))
1722
    v_min = int(match.group(2))
1723
    if match.group(4):
1724
      v_rev = int(match.group(4))
1725
    else:
1726
      v_rev = 0
1727
    return (v_all, v_maj, v_min, v_rev)
1728

    
1729
  @classmethod
1730
  def _GetKVMOutput(cls, kvm_path, option):
1731
    """Return the output of a kvm invocation
1732

1733
    @type kvm_path: string
1734
    @param kvm_path: path to the kvm executable
1735
    @type option: a key of _KVMOPTS_CMDS
1736
    @param option: kvm option to fetch the output from
1737
    @return: output a supported kvm invocation
1738
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1739

1740
    """
1741
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
1742

    
1743
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
1744

    
1745
    result = utils.RunCmd([kvm_path] + optlist)
1746
    if result.failed and not can_fail:
1747
      raise errors.HypervisorError("Unable to get KVM %s output" %
1748
                                    " ".join(cls._KVMOPTS_CMDS[option]))
1749
    return result.output
1750

    
1751
  @classmethod
1752
  def _GetKVMVersion(cls, kvm_path):
1753
    """Return the installed KVM version.
1754

1755
    @return: (version, v_maj, v_min, v_rev)
1756
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1757

1758
    """
1759
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
1760

    
1761
  @classmethod
1762
  def _GetDefaultMachineVersion(cls, kvm_path):
1763
    """Return the default hardware revision (e.g. pc-1.1)
1764

1765
    """
1766
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
1767
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
1768
    if match:
1769
      return match.group(1)
1770
    else:
1771
      return "pc"
1772

    
1773
  def StopInstance(self, instance, force=False, retry=False, name=None):
1774
    """Stop an instance.
1775

1776
    """
1777
    if name is not None and not force:
1778
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1779
    if name is None:
1780
      name = instance.name
1781
      acpi = instance.hvparams[constants.HV_ACPI]
1782
    else:
1783
      acpi = False
1784
    _, pid, alive = self._InstancePidAlive(name)
1785
    if pid > 0 and alive:
1786
      if force or not acpi:
1787
        utils.KillProcess(pid)
1788
      else:
1789
        self._CallMonitorCommand(name, "system_powerdown")
1790

    
1791
  def CleanupInstance(self, instance_name):
1792
    """Cleanup after a stopped instance
1793

1794
    """
1795
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
1796
    if pid > 0 and alive:
1797
      raise errors.HypervisorError("Cannot cleanup a live instance")
1798
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1799

    
1800
  def RebootInstance(self, instance):
1801
    """Reboot an instance.
1802

1803
    """
1804
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1805
    # socket the instance will stop, but now power up again. So we'll resort
1806
    # to shutdown and restart.
1807
    _, _, alive = self._InstancePidAlive(instance.name)
1808
    if not alive:
1809
      raise errors.HypervisorError("Failed to reboot instance %s:"
1810
                                   " not running" % instance.name)
1811
    # StopInstance will delete the saved KVM runtime so:
1812
    # ...first load it...
1813
    kvm_runtime = self._LoadKVMRuntime(instance)
1814
    # ...now we can safely call StopInstance...
1815
    if not self.StopInstance(instance):
1816
      self.StopInstance(instance, force=True)
1817
    # ...and finally we can save it again, and execute it...
1818
    self._SaveKVMRuntime(instance, kvm_runtime)
1819
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1820
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1821
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1822

    
1823
  def MigrationInfo(self, instance):
1824
    """Get instance information to perform a migration.
1825

1826
    @type instance: L{objects.Instance}
1827
    @param instance: instance to be migrated
1828
    @rtype: string
1829
    @return: content of the KVM runtime file
1830

1831
    """
1832
    return self._ReadKVMRuntime(instance.name)
1833

    
1834
  def AcceptInstance(self, instance, info, target):
1835
    """Prepare to accept an instance.
1836

1837
    @type instance: L{objects.Instance}
1838
    @param instance: instance to be accepted
1839
    @type info: string
1840
    @param info: content of the KVM runtime file on the source node
1841
    @type target: string
1842
    @param target: target host (usually ip), on this node
1843

1844
    """
1845
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1846
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1847
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1848
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1849
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
1850
                            incoming=incoming_address)
1851

    
1852
  def FinalizeMigrationDst(self, instance, info, success):
1853
    """Finalize the instance migration on the target node.
1854

1855
    Stop the incoming mode KVM.
1856

1857
    @type instance: L{objects.Instance}
1858
    @param instance: instance whose migration is being finalized
1859

1860
    """
1861
    if success:
1862
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1863
      kvm_nics = kvm_runtime[1]
1864

    
1865
      for nic_seq, nic in enumerate(kvm_nics):
1866
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1867
          # Bridged interfaces have already been configured
1868
          continue
1869
        try:
1870
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1871
        except EnvironmentError, err:
1872
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
1873
                          instance.name, nic_seq, str(err))
1874
          continue
1875
        try:
1876
          self._ConfigureNIC(instance, nic_seq, nic, tap)
1877
        except errors.HypervisorError, err:
1878
          logging.warning(str(err))
1879

    
1880
      self._WriteKVMRuntime(instance.name, info)
1881
    else:
1882
      self.StopInstance(instance, force=True)
1883

    
1884
  def MigrateInstance(self, instance, target, live):
1885
    """Migrate an instance to a target node.
1886

1887
    The migration will not be attempted if the instance is not
1888
    currently running.
1889

1890
    @type instance: L{objects.Instance}
1891
    @param instance: the instance to be migrated
1892
    @type target: string
1893
    @param target: ip address of the target node
1894
    @type live: boolean
1895
    @param live: perform a live migration
1896

1897
    """
1898
    instance_name = instance.name
1899
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
1900
    _, _, alive = self._InstancePidAlive(instance_name)
1901
    if not alive:
1902
      raise errors.HypervisorError("Instance not running, cannot migrate")
1903

    
1904
    if not live:
1905
      self._CallMonitorCommand(instance_name, "stop")
1906

    
1907
    migrate_command = ("migrate_set_speed %dm" %
1908
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1909
    self._CallMonitorCommand(instance_name, migrate_command)
1910

    
1911
    migrate_command = ("migrate_set_downtime %dms" %
1912
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1913
    self._CallMonitorCommand(instance_name, migrate_command)
1914

    
1915
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1916
    self._CallMonitorCommand(instance_name, migrate_command)
1917

    
1918
  def FinalizeMigrationSource(self, instance, success, live):
1919
    """Finalize the instance migration on the source node.
1920

1921
    @type instance: L{objects.Instance}
1922
    @param instance: the instance that was migrated
1923
    @type success: bool
1924
    @param success: whether the migration succeeded or not
1925
    @type live: bool
1926
    @param live: whether the user requested a live migration or not
1927

1928
    """
1929
    if success:
1930
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
1931
      utils.KillProcess(pid)
1932
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1933
    elif live:
1934
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1935

    
1936
  def GetMigrationStatus(self, instance):
1937
    """Get the migration status
1938

1939
    @type instance: L{objects.Instance}
1940
    @param instance: the instance that is being migrated
1941
    @rtype: L{objects.MigrationStatus}
1942
    @return: the status of the current migration (one of
1943
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1944
             progress info that can be retrieved from the hypervisor
1945

1946
    """
1947
    info_command = "info migrate"
1948
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
1949
      result = self._CallMonitorCommand(instance.name, info_command)
1950
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
1951
      if not match:
1952
        if not result.stdout:
1953
          logging.info("KVM: empty 'info migrate' result")
1954
        else:
1955
          logging.warning("KVM: unknown 'info migrate' result: %s",
1956
                          result.stdout)
1957
      else:
1958
        status = match.group(1)
1959
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
1960
          migration_status = objects.MigrationStatus(status=status)
1961
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
1962
          if match:
1963
            migration_status.transferred_ram = match.group("transferred")
1964
            migration_status.total_ram = match.group("total")
1965

    
1966
          return migration_status
1967

    
1968
        logging.warning("KVM: unknown migration status '%s'", status)
1969

    
1970
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1971

    
1972
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
1973

    
1974
  def BalloonInstanceMemory(self, instance, mem):
1975
    """Balloon an instance memory to a certain value.
1976

1977
    @type instance: L{objects.Instance}
1978
    @param instance: instance to be accepted
1979
    @type mem: int
1980
    @param mem: actual memory size to use for instance runtime
1981

1982
    """
1983
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
1984

    
1985
  def GetNodeInfo(self):
1986
    """Return information about the node.
1987

1988
    @return: a dict with the following keys (values in MiB):
1989
          - memory_total: the total memory size on the node
1990
          - memory_free: the available memory on the node for instances
1991
          - memory_dom0: the memory used by the node itself, if available
1992
          - hv_version: the hypervisor version in the form (major, minor,
1993
                        revision)
1994

1995
    """
1996
    result = self.GetLinuxNodeInfo()
1997
    # FIXME: this is the global kvm version, but the actual version can be
1998
    # customized as an hv parameter. we should use the nodegroup's default kvm
1999
    # path parameter here.
2000
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2001
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2002
    return result
2003

    
2004
  @classmethod
2005
  def GetInstanceConsole(cls, instance, hvparams, beparams):
2006
    """Return a command for connecting to the console of an instance.
2007

2008
    """
2009
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2010
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2011
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2012
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2013
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2014
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2015
      return objects.InstanceConsole(instance=instance.name,
2016
                                     kind=constants.CONS_SSH,
2017
                                     host=instance.primary_node,
2018
                                     user=constants.SSH_CONSOLE_USER,
2019
                                     command=cmd)
2020

    
2021
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2022
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2023
      display = instance.network_port - constants.VNC_BASE_PORT
2024
      return objects.InstanceConsole(instance=instance.name,
2025
                                     kind=constants.CONS_VNC,
2026
                                     host=vnc_bind_address,
2027
                                     port=instance.network_port,
2028
                                     display=display)
2029

    
2030
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2031
    if spice_bind:
2032
      return objects.InstanceConsole(instance=instance.name,
2033
                                     kind=constants.CONS_SPICE,
2034
                                     host=spice_bind,
2035
                                     port=instance.network_port)
2036

    
2037
    return objects.InstanceConsole(instance=instance.name,
2038
                                   kind=constants.CONS_MESSAGE,
2039
                                   message=("No serial shell for instance %s" %
2040
                                            instance.name))
2041

    
2042
  def Verify(self):
2043
    """Verify the hypervisor.
2044

2045
    Check that the required binaries exist.
2046

2047
    @return: Problem description if something is wrong, C{None} otherwise
2048

2049
    """
2050
    msgs = []
2051
    # FIXME: this is the global kvm binary, but the actual path can be
2052
    # customized as an hv parameter; we should use the nodegroup's
2053
    # default kvm path parameter here.
2054
    if not os.path.exists(constants.KVM_PATH):
2055
      msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2056
    if not os.path.exists(constants.SOCAT_PATH):
2057
      msgs.append("The socat binary ('%s') does not exist" %
2058
                  constants.SOCAT_PATH)
2059

    
2060
    return self._FormatVerifyResults(msgs)
2061

    
2062
  @classmethod
2063
  def CheckParameterSyntax(cls, hvparams):
2064
    """Check the given parameters for validity.
2065

2066
    @type hvparams:  dict
2067
    @param hvparams: dictionary with parameter names/value
2068
    @raise errors.HypervisorError: when a parameter is not valid
2069

2070
    """
2071
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2072

    
2073
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2074
    if kernel_path:
2075
      if not hvparams[constants.HV_ROOT_PATH]:
2076
        raise errors.HypervisorError("Need a root partition for the instance,"
2077
                                     " if a kernel is defined")
2078

    
2079
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2080
        not hvparams[constants.HV_VNC_X509]):
2081
      raise errors.HypervisorError("%s must be defined, if %s is" %
2082
                                   (constants.HV_VNC_X509,
2083
                                    constants.HV_VNC_X509_VERIFY))
2084

    
2085
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2086
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2087
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2088
      if not serial_speed or serial_speed not in valid_speeds:
2089
        raise errors.HypervisorError("Invalid serial console speed, must be"
2090
                                     " one of: %s" %
2091
                                     utils.CommaJoin(valid_speeds))
2092

    
2093
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2094
    if (boot_order == constants.HT_BO_CDROM and
2095
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2096
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2097
                                   " ISO path")
2098

    
2099
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2100
    if security_model == constants.HT_SM_USER:
2101
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2102
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2103
                                     " must be specified")
2104
    elif (security_model == constants.HT_SM_NONE or
2105
          security_model == constants.HT_SM_POOL):
2106
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2107
        raise errors.HypervisorError("Cannot have a security domain when the"
2108
                                     " security model is 'none' or 'pool'")
2109

    
2110
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2111
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2112
    if spice_bind:
2113
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2114
        # if an IP version is specified, the spice_bind parameter must be an
2115
        # IP of that family
2116
        if (netutils.IP4Address.IsValid(spice_bind) and
2117
            spice_ip_version != constants.IP4_VERSION):
2118
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2119
                                       " the specified IP version is %s" %
2120
                                       (spice_bind, spice_ip_version))
2121

    
2122
        if (netutils.IP6Address.IsValid(spice_bind) and
2123
            spice_ip_version != constants.IP6_VERSION):
2124
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2125
                                       " the specified IP version is %s" %
2126
                                       (spice_bind, spice_ip_version))
2127
    else:
2128
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2129
      # error if any of them is set without it.
2130
      for param in _SPICE_ADDITIONAL_PARAMS:
2131
        if hvparams[param]:
2132
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2133
                                       (param, constants.HV_KVM_SPICE_BIND))
2134

    
2135
  @classmethod
2136
  def ValidateParameters(cls, hvparams):
2137
    """Check the given parameters for validity.
2138

2139
    @type hvparams:  dict
2140
    @param hvparams: dictionary with parameter names/value
2141
    @raise errors.HypervisorError: when a parameter is not valid
2142

2143
    """
2144
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2145

    
2146
    kvm_path = hvparams[constants.HV_KVM_PATH]
2147

    
2148
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2149
    if security_model == constants.HT_SM_USER:
2150
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2151
      try:
2152
        pwd.getpwnam(username)
2153
      except KeyError:
2154
        raise errors.HypervisorError("Unknown security domain user %s"
2155
                                     % username)
2156

    
2157
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2158
    if spice_bind:
2159
      # only one of VNC and SPICE can be used currently.
2160
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2161
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2162
                                     " only one of them can be used at a"
2163
                                     " given time")
2164

    
2165
      # check that KVM supports SPICE
2166
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2167
      if not cls._SPICE_RE.search(kvmhelp):
2168
        raise errors.HypervisorError("SPICE is configured, but it is not"
2169
                                     " supported according to 'kvm --help'")
2170

    
2171
      # if spice_bind is not an IP address, it must be a valid interface
2172
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2173
                       netutils.IP6Address.IsValid(spice_bind))
2174
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2175
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2176
                                     " a valid IP address or interface name" %
2177
                                     constants.HV_KVM_SPICE_BIND)
2178

    
2179
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2180
    if machine_version:
2181
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2182
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2183
        raise errors.HypervisorError("Unsupported machine version: %s" %
2184
                                     machine_version)
2185

    
2186
  @classmethod
2187
  def PowercycleNode(cls):
2188
    """KVM powercycle, just a wrapper over Linux powercycle.
2189

2190
    """
2191
    cls.LinuxPowercycle()