Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ afa9bb2e

History | View | Annotate | Download (79.7 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
def _BuildNetworkEnv(name, network, gateway, network6, gateway6,
168
                     network_type, mac_prefix, tags, env):
169
  """Build environment variables concerning a Network.
170

171
  """
172
  if name:
173
    env["NETWORK_NAME"] = name
174
  if network:
175
    env["NETWORK_SUBNET"] = network
176
  if gateway:
177
    env["NETWORK_GATEWAY"] = gateway
178
  if network6:
179
    env["NETWORK_SUBNET6"] = network6
180
  if gateway6:
181
    env["NETWORK_GATEWAY6"] = gateway6
182
  if mac_prefix:
183
    env["NETWORK_MAC_PREFIX"] = mac_prefix
184
  if network_type:
185
    env["NETWORK_TYPE"] = network_type
186
  if tags:
187
    env["NETWORK_TAGS"] = " ".join(tags)
188

    
189
  return env
190

    
191

    
192
class QmpMessage:
193
  """QEMU Messaging Protocol (QMP) message.
194

195
  """
196
  def __init__(self, data):
197
    """Creates a new QMP message based on the passed data.
198

199
    """
200
    if not isinstance(data, dict):
201
      raise TypeError("QmpMessage must be initialized with a dict")
202

    
203
    self.data = data
204

    
205
  def __getitem__(self, field_name):
206
    """Get the value of the required field if present, or None.
207

208
    Overrides the [] operator to provide access to the message data,
209
    returning None if the required item is not in the message
210
    @return: the value of the field_name field, or None if field_name
211
             is not contained in the message
212

213
    """
214
    return self.data.get(field_name, None)
215

    
216
  def __setitem__(self, field_name, field_value):
217
    """Set the value of the required field_name to field_value.
218

219
    """
220
    self.data[field_name] = field_value
221

    
222
  @staticmethod
223
  def BuildFromJsonString(json_string):
224
    """Build a QmpMessage from a JSON encoded string.
225

226
    @type json_string: str
227
    @param json_string: JSON string representing the message
228
    @rtype: L{QmpMessage}
229
    @return: a L{QmpMessage} built from json_string
230

231
    """
232
    # Parse the string
233
    data = serializer.LoadJson(json_string)
234
    return QmpMessage(data)
235

    
236
  def __str__(self):
237
    # The protocol expects the JSON object to be sent as a single line.
238
    return serializer.DumpJson(self.data)
239

    
240
  def __eq__(self, other):
241
    # When comparing two QmpMessages, we are interested in comparing
242
    # their internal representation of the message data
243
    return self.data == other.data
244

    
245

    
246
class QmpConnection:
247
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
248

249
  """
250
  _FIRST_MESSAGE_KEY = "QMP"
251
  _EVENT_KEY = "event"
252
  _ERROR_KEY = "error"
253
  _RETURN_KEY = RETURN_KEY = "return"
254
  _ACTUAL_KEY = ACTUAL_KEY = "actual"
255
  _ERROR_CLASS_KEY = "class"
256
  _ERROR_DATA_KEY = "data"
257
  _ERROR_DESC_KEY = "desc"
258
  _EXECUTE_KEY = "execute"
259
  _ARGUMENTS_KEY = "arguments"
260
  _CAPABILITIES_COMMAND = "qmp_capabilities"
261
  _MESSAGE_END_TOKEN = "\r\n"
262
  _SOCKET_TIMEOUT = 5
263

    
264
  def __init__(self, monitor_filename):
265
    """Instantiates the QmpConnection object.
266

267
    @type monitor_filename: string
268
    @param monitor_filename: the filename of the UNIX raw socket on which the
269
                             QMP monitor is listening
270

271
    """
272
    self.monitor_filename = monitor_filename
273
    self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
274
    # We want to fail if the server doesn't send a complete message
275
    # in a reasonable amount of time
276
    self.sock.settimeout(self._SOCKET_TIMEOUT)
277
    self._connected = False
278
    self._buf = ""
279

    
280
  def _check_socket(self):
281
    sock_stat = None
282
    try:
283
      sock_stat = os.stat(self.monitor_filename)
284
    except EnvironmentError, err:
285
      if err.errno == errno.ENOENT:
286
        raise errors.HypervisorError("No qmp socket found")
287
      else:
288
        raise errors.HypervisorError("Error checking qmp socket: %s",
289
                                     utils.ErrnoOrStr(err))
290
    if not stat.S_ISSOCK(sock_stat.st_mode):
291
      raise errors.HypervisorError("Qmp socket is not a socket")
292

    
293
  def _check_connection(self):
294
    """Make sure that the connection is established.
295

296
    """
297
    if not self._connected:
298
      raise errors.ProgrammerError("To use a QmpConnection you need to first"
299
                                   " invoke connect() on it")
300

    
301
  def connect(self):
302
    """Connects to the QMP monitor.
303

304
    Connects to the UNIX socket and makes sure that we can actually send and
305
    receive data to the kvm instance via QMP.
306

307
    @raise errors.HypervisorError: when there are communication errors
308
    @raise errors.ProgrammerError: when there are data serialization errors
309

310
    """
311
    if self._connected:
312
      raise errors.ProgrammerError("Cannot connect twice")
313

    
314
    self._check_socket()
315

    
316
    # Check file existance/stuff
317
    try:
318
      self.sock.connect(self.monitor_filename)
319
    except EnvironmentError:
320
      raise errors.HypervisorError("Can't connect to qmp socket")
321
    self._connected = True
322

    
323
    # Check if we receive a correct greeting message from the server
324
    # (As per the QEMU Protocol Specification 0.1 - section 2.2)
325
    greeting = self._Recv()
326
    if not greeting[self._FIRST_MESSAGE_KEY]:
327
      self._connected = False
328
      raise errors.HypervisorError("kvm: QMP communication error (wrong"
329
                                   " server greeting")
330

    
331
    # Let's put the monitor in command mode using the qmp_capabilities
332
    # command, or else no command will be executable.
333
    # (As per the QEMU Protocol Specification 0.1 - section 4)
334
    self.Execute(self._CAPABILITIES_COMMAND)
335

    
336
  def _ParseMessage(self, buf):
337
    """Extract and parse a QMP message from the given buffer.
338

339
    Seeks for a QMP message in the given buf. If found, it parses it and
340
    returns it together with the rest of the characters in the buf.
341
    If no message is found, returns None and the whole buffer.
342

343
    @raise errors.ProgrammerError: when there are data serialization errors
344

345
    """
346
    message = None
347
    # Check if we got the message end token (CRLF, as per the QEMU Protocol
348
    # Specification 0.1 - Section 2.1.1)
349
    pos = buf.find(self._MESSAGE_END_TOKEN)
350
    if pos >= 0:
351
      try:
352
        message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
353
      except Exception, err:
354
        raise errors.ProgrammerError("QMP data serialization error: %s" % err)
355
      buf = buf[pos + 1:]
356

    
357
    return (message, buf)
358

    
359
  def _Recv(self):
360
    """Receives a message from QMP and decodes the received JSON object.
361

362
    @rtype: QmpMessage
363
    @return: the received message
364
    @raise errors.HypervisorError: when there are communication errors
365
    @raise errors.ProgrammerError: when there are data serialization errors
366

367
    """
368
    self._check_connection()
369

    
370
    # Check if there is already a message in the buffer
371
    (message, self._buf) = self._ParseMessage(self._buf)
372
    if message:
373
      return message
374

    
375
    recv_buffer = StringIO.StringIO(self._buf)
376
    recv_buffer.seek(len(self._buf))
377
    try:
378
      while True:
379
        data = self.sock.recv(4096)
380
        if not data:
381
          break
382
        recv_buffer.write(data)
383

    
384
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
385
        if message:
386
          return message
387

    
388
    except socket.timeout, err:
389
      raise errors.HypervisorError("Timeout while receiving a QMP message: "
390
                                   "%s" % (err))
391
    except socket.error, err:
392
      raise errors.HypervisorError("Unable to receive data from KVM using the"
393
                                   " QMP protocol: %s" % err)
394

    
395
  def _Send(self, message):
396
    """Encodes and sends a message to KVM using QMP.
397

398
    @type message: QmpMessage
399
    @param message: message to send to KVM
400
    @raise errors.HypervisorError: when there are communication errors
401
    @raise errors.ProgrammerError: when there are data serialization errors
402

403
    """
404
    self._check_connection()
405
    try:
406
      message_str = str(message)
407
    except Exception, err:
408
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
409

    
410
    try:
411
      self.sock.sendall(message_str)
412
    except socket.timeout, err:
413
      raise errors.HypervisorError("Timeout while sending a QMP message: "
414
                                   "%s (%s)" % (err.string, err.errno))
415
    except socket.error, err:
416
      raise errors.HypervisorError("Unable to send data from KVM using the"
417
                                   " QMP protocol: %s" % err)
418

    
419
  def Execute(self, command, arguments=None):
420
    """Executes a QMP command and returns the response of the server.
421

422
    @type command: str
423
    @param command: the command to execute
424
    @type arguments: dict
425
    @param arguments: dictionary of arguments to be passed to the command
426
    @rtype: dict
427
    @return: dictionary representing the received JSON object
428
    @raise errors.HypervisorError: when there are communication errors
429
    @raise errors.ProgrammerError: when there are data serialization errors
430

431
    """
432
    self._check_connection()
433
    message = QmpMessage({self._EXECUTE_KEY: command})
434
    if arguments:
435
      message[self._ARGUMENTS_KEY] = arguments
436
    self._Send(message)
437

    
438
    # Events can occur between the sending of the command and the reception
439
    # of the response, so we need to filter out messages with the event key.
440
    while True:
441
      response = self._Recv()
442
      err = response[self._ERROR_KEY]
443
      if err:
444
        raise errors.HypervisorError("kvm: error executing the %s"
445
                                     " command: %s (%s, %s):" %
446
                                     (command,
447
                                      err[self._ERROR_DESC_KEY],
448
                                      err[self._ERROR_CLASS_KEY],
449
                                      err[self._ERROR_DATA_KEY]))
450

    
451
      elif not response[self._EVENT_KEY]:
452
        return response
453

    
454

    
455
class KVMHypervisor(hv_base.BaseHypervisor):
456
  """KVM hypervisor interface
457

458
  """
459
  CAN_MIGRATE = True
460

    
461
  _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
462
  _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
463
  _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
464
  _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
465
  _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
466
  _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
467
  _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
468
  # KVM instances with chroot enabled are started in empty chroot directories.
469
  _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
470
  # After an instance is stopped, its chroot directory is removed.
471
  # If the chroot directory is not empty, it can't be removed.
472
  # A non-empty chroot directory indicates a possible security incident.
473
  # To support forensics, the non-empty chroot directory is quarantined in
474
  # a separate directory, called 'chroot-quarantine'.
475
  _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
476
  _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
477
           _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
478

    
479
  PARAMETERS = {
480
    constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
481
    constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
482
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
483
    constants.HV_ROOT_PATH: hv_base.NO_CHECK,
484
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
485
    constants.HV_ACPI: hv_base.NO_CHECK,
486
    constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
487
    constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
488
    constants.HV_VNC_BIND_ADDRESS:
489
      (False, lambda x: (netutils.IP4Address.IsValid(x) or
490
                         utils.IsNormAbsPath(x)),
491
       "The VNC bind address must be either a valid IP address or an absolute"
492
       " pathname", None, None),
493
    constants.HV_VNC_TLS: hv_base.NO_CHECK,
494
    constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
495
    constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
496
    constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
497
    constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
498
    constants.HV_KVM_SPICE_IP_VERSION:
499
      (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
500
                         x in constants.VALID_IP_VERSIONS),
501
       "The SPICE IP version should be 4 or 6",
502
       None, None),
503
    constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
504
    constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
505
      hv_base.ParamInSet(
506
        False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
507
    constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
508
      hv_base.ParamInSet(
509
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
510
    constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
511
      hv_base.ParamInSet(
512
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
513
    constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
514
      hv_base.ParamInSet(
515
        False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
516
    constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
517
    constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
518
    constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
519
    constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
520
    constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
521
    constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
522
    constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
523
    constants.HV_BOOT_ORDER:
524
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
525
    constants.HV_NIC_TYPE:
526
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
527
    constants.HV_DISK_TYPE:
528
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
529
    constants.HV_KVM_CDROM_DISK_TYPE:
530
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
531
    constants.HV_USB_MOUSE:
532
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
533
    constants.HV_KEYMAP: hv_base.NO_CHECK,
534
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
535
    constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
536
    constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
537
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
538
    constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
539
    constants.HV_DISK_CACHE:
540
      hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
541
    constants.HV_SECURITY_MODEL:
542
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
543
    constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
544
    constants.HV_KVM_FLAG:
545
      hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
546
    constants.HV_VHOST_NET: hv_base.NO_CHECK,
547
    constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
548
    constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
549
    constants.HV_REBOOT_BEHAVIOR:
550
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
551
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
552
    constants.HV_CPU_TYPE: hv_base.NO_CHECK,
553
    constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
554
    constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
555
    constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
556
    constants.HV_SOUNDHW: hv_base.NO_CHECK,
557
    constants.HV_USB_DEVICES: hv_base.NO_CHECK,
558
    constants.HV_VGA: hv_base.NO_CHECK,
559
    constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
560
    constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
561
    }
562

    
563
  _VIRTIO = "virtio"
564
  _VIRTIO_NET_PCI = "virtio-net-pci"
565

    
566
  _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
567
                                    re.M | re.I)
568
  _MIGRATION_PROGRESS_RE = \
569
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
570
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
571
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
572

    
573
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
574
  _MIGRATION_INFO_RETRY_DELAY = 2
575

    
576
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
577

    
578
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
579
  _CPU_INFO_CMD = "info cpus"
580
  _CONT_CMD = "cont"
581

    
582
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
583
  _CHECK_MACHINE_VERSION_RE = \
584
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
585

    
586
  _QMP_RE = re.compile(r"^-qmp\s", re.M)
587
  _SPICE_RE = re.compile(r"^-spice\s", re.M)
588
  _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
589
  _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
590
  _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
591
  _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
592
  _NEW_VIRTIO_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
593
  # match  -drive.*boot=on|off on different lines, but in between accept only
594
  # dashes not preceeded by a new line (which would mean another option
595
  # different than -drive is starting)
596
  _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
597

    
598
  ANCILLARY_FILES = [
599
    _KVM_NETWORK_SCRIPT,
600
    ]
601
  ANCILLARY_FILES_OPT = [
602
    _KVM_NETWORK_SCRIPT,
603
    ]
604

    
605
  # Supported kvm options to get output from
606
  _KVMOPT_HELP = "help"
607
  _KVMOPT_MLIST = "mlist"
608
  _KVMOPT_DEVICELIST = "devicelist"
609

    
610
  # Command to execute to get the output from kvm, and whether to
611
  # accept the output even on failure.
612
  _KVMOPTS_CMDS = {
613
    _KVMOPT_HELP: (["--help"], False),
614
    _KVMOPT_MLIST: (["-M", "?"], False),
615
    _KVMOPT_DEVICELIST: (["-device", "?"], True),
616
  }
617

    
618
  def __init__(self):
619
    hv_base.BaseHypervisor.__init__(self)
620
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
621
    # in a tmpfs filesystem or has been otherwise wiped out.
622
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
623
    utils.EnsureDirs(dirs)
624

    
625
  @classmethod
626
  def _InstancePidFile(cls, instance_name):
627
    """Returns the instance pidfile.
628

629
    """
630
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
631

    
632
  @classmethod
633
  def _InstanceUidFile(cls, instance_name):
634
    """Returns the instance uidfile.
635

636
    """
637
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
638

    
639
  @classmethod
640
  def _InstancePidInfo(cls, pid):
641
    """Check pid file for instance information.
642

643
    Check that a pid file is associated with an instance, and retrieve
644
    information from its command line.
645

646
    @type pid: string or int
647
    @param pid: process id of the instance to check
648
    @rtype: tuple
649
    @return: (instance_name, memory, vcpus)
650
    @raise errors.HypervisorError: when an instance cannot be found
651

652
    """
653
    alive = utils.IsProcessAlive(pid)
654
    if not alive:
655
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
656

    
657
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
658
    try:
659
      cmdline = utils.ReadFile(cmdline_file)
660
    except EnvironmentError, err:
661
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
662
                                   (pid, err))
663

    
664
    instance = None
665
    memory = 0
666
    vcpus = 0
667

    
668
    arg_list = cmdline.split("\x00")
669
    while arg_list:
670
      arg = arg_list.pop(0)
671
      if arg == "-name":
672
        instance = arg_list.pop(0)
673
      elif arg == "-m":
674
        memory = int(arg_list.pop(0))
675
      elif arg == "-smp":
676
        vcpus = int(arg_list.pop(0).split(",")[0])
677

    
678
    if instance is None:
679
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
680
                                   " instance" % pid)
681

    
682
    return (instance, memory, vcpus)
683

    
684
  def _InstancePidAlive(self, instance_name):
685
    """Returns the instance pidfile, pid, and liveness.
686

687
    @type instance_name: string
688
    @param instance_name: instance name
689
    @rtype: tuple
690
    @return: (pid file name, pid, liveness)
691

692
    """
693
    pidfile = self._InstancePidFile(instance_name)
694
    pid = utils.ReadPidFile(pidfile)
695

    
696
    alive = False
697
    try:
698
      cmd_instance = self._InstancePidInfo(pid)[0]
699
      alive = (cmd_instance == instance_name)
700
    except errors.HypervisorError:
701
      pass
702

    
703
    return (pidfile, pid, alive)
704

    
705
  def _CheckDown(self, instance_name):
706
    """Raises an error unless the given instance is down.
707

708
    """
709
    alive = self._InstancePidAlive(instance_name)[2]
710
    if alive:
711
      raise errors.HypervisorError("Failed to start instance %s: %s" %
712
                                   (instance_name, "already running"))
713

    
714
  @classmethod
715
  def _InstanceMonitor(cls, instance_name):
716
    """Returns the instance monitor socket name
717

718
    """
719
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
720

    
721
  @classmethod
722
  def _InstanceSerial(cls, instance_name):
723
    """Returns the instance serial socket name
724

725
    """
726
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
727

    
728
  @classmethod
729
  def _InstanceQmpMonitor(cls, instance_name):
730
    """Returns the instance serial QMP socket name
731

732
    """
733
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
734

    
735
  @staticmethod
736
  def _SocatUnixConsoleParams():
737
    """Returns the correct parameters for socat
738

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

741
    """
742
    if constants.SOCAT_USE_ESCAPE:
743
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
744
    else:
745
      return "echo=0,icanon=0"
746

    
747
  @classmethod
748
  def _InstanceKVMRuntime(cls, instance_name):
749
    """Returns the instance KVM runtime filename
750

751
    """
752
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
753

    
754
  @classmethod
755
  def _InstanceChrootDir(cls, instance_name):
756
    """Returns the name of the KVM chroot dir of the instance
757

758
    """
759
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
760

    
761
  @classmethod
762
  def _InstanceNICDir(cls, instance_name):
763
    """Returns the name of the directory holding the tap device files for a
764
    given instance.
765

766
    """
767
    return utils.PathJoin(cls._NICS_DIR, instance_name)
768

    
769
  @classmethod
770
  def _InstanceNICFile(cls, instance_name, seq):
771
    """Returns the name of the file containing the tap device for a given NIC
772

773
    """
774
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
775

    
776
  @classmethod
777
  def _InstanceKeymapFile(cls, instance_name):
778
    """Returns the name of the file containing the keymap for a given instance
779

780
    """
781
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
782

    
783
  @classmethod
784
  def _TryReadUidFile(cls, uid_file):
785
    """Try to read a uid file
786

787
    """
788
    if os.path.exists(uid_file):
789
      try:
790
        uid = int(utils.ReadOneLineFile(uid_file))
791
        return uid
792
      except EnvironmentError:
793
        logging.warning("Can't read uid file", exc_info=True)
794
      except (TypeError, ValueError):
795
        logging.warning("Can't parse uid file contents", exc_info=True)
796
    return None
797

    
798
  @classmethod
799
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
800
    """Removes an instance's rutime sockets/files/dirs.
801

802
    """
803
    utils.RemoveFile(pidfile)
804
    utils.RemoveFile(cls._InstanceMonitor(instance_name))
805
    utils.RemoveFile(cls._InstanceSerial(instance_name))
806
    utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
807
    utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
808
    utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
809
    uid_file = cls._InstanceUidFile(instance_name)
810
    uid = cls._TryReadUidFile(uid_file)
811
    utils.RemoveFile(uid_file)
812
    if uid is not None:
813
      uidpool.ReleaseUid(uid)
814
    try:
815
      shutil.rmtree(cls._InstanceNICDir(instance_name))
816
    except OSError, err:
817
      if err.errno != errno.ENOENT:
818
        raise
819
    try:
820
      chroot_dir = cls._InstanceChrootDir(instance_name)
821
      utils.RemoveDir(chroot_dir)
822
    except OSError, err:
823
      if err.errno == errno.ENOTEMPTY:
824
        # The chroot directory is expected to be empty, but it isn't.
825
        new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
826
                                          prefix="%s-%s-" %
827
                                          (instance_name,
828
                                           utils.TimestampForFilename()))
829
        logging.warning("The chroot directory of instance %s can not be"
830
                        " removed as it is not empty. Moving it to the"
831
                        " quarantine instead. Please investigate the"
832
                        " contents (%s) and clean up manually",
833
                        instance_name, new_chroot_dir)
834
        utils.RenameFile(chroot_dir, new_chroot_dir)
835
      else:
836
        raise
837

    
838
  @staticmethod
839
  def _ConfigureNIC(instance, seq, nic, tap):
840
    """Run the network configuration script for a specified NIC
841

842
    @param instance: instance we're acting on
843
    @type instance: instance object
844
    @param seq: nic sequence number
845
    @type seq: int
846
    @param nic: nic we're acting on
847
    @type nic: nic object
848
    @param tap: the host's tap interface this NIC corresponds to
849
    @type tap: str
850

851
    """
852
    if instance.tags:
853
      tags = " ".join(instance.tags)
854
    else:
855
      tags = ""
856

    
857
    env = {
858
      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
859
      "INSTANCE": instance.name,
860
      "MAC": nic.mac,
861
      "MODE": nic.nicparams[constants.NIC_MODE],
862
      "INTERFACE": tap,
863
      "INTERFACE_INDEX": str(seq),
864
      "TAGS": tags,
865
    }
866

    
867
    if nic.ip:
868
      env["IP"] = nic.ip
869

    
870
    if nic.nicparams[constants.NIC_LINK]:
871
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
872

    
873
    if nic.network:
874
      n = objects.Network.FromDict(nic.netinfo)
875
      _BuildNetworkEnv(nic.network, n.network, n.gateway,
876
                       n.network6, n.gateway6, n.network_type,
877
                       n.mac_prefix, n.tags, env)
878

    
879
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
880
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
881

    
882
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
883
    if result.failed:
884
      raise errors.HypervisorError("Failed to configure interface %s: %s;"
885
                                   " network configuration script output: %s" %
886
                                   (tap, result.fail_reason, result.output))
887

    
888
  @staticmethod
889
  def _VerifyAffinityPackage():
890
    if affinity is None:
891
      raise errors.HypervisorError("affinity Python package not"
892
                                   " found; cannot use CPU pinning under KVM")
893

    
894
  @staticmethod
895
  def _BuildAffinityCpuMask(cpu_list):
896
    """Create a CPU mask suitable for sched_setaffinity from a list of
897
    CPUs.
898

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

902
    @type cpu_list: list of int
903
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
904
    @rtype: int
905
    @return: a bit mask of CPU affinities
906

907
    """
908
    if cpu_list == constants.CPU_PINNING_OFF:
909
      return constants.CPU_PINNING_ALL_KVM
910
    else:
911
      return sum(2 ** cpu for cpu in cpu_list)
912

    
913
  @classmethod
914
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
915
    """Change CPU affinity for running VM according to given CPU mask.
916

917
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
918
    @type cpu_mask: string
919
    @param process_id: process ID of KVM process. Used to pin entire VM
920
                       to physical CPUs.
921
    @type process_id: int
922
    @param thread_dict: map of virtual CPUs to KVM thread IDs
923
    @type thread_dict: dict int:int
924

925
    """
926
    # Convert the string CPU mask to a list of list of int's
927
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
928

    
929
    if len(cpu_list) == 1:
930
      all_cpu_mapping = cpu_list[0]
931
      if all_cpu_mapping == constants.CPU_PINNING_OFF:
932
        # If CPU pinning has 1 entry that's "all", then do nothing
933
        pass
934
      else:
935
        # If CPU pinning has one non-all entry, map the entire VM to
936
        # one set of physical CPUs
937
        cls._VerifyAffinityPackage()
938
        affinity.set_process_affinity_mask(
939
          process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
940
    else:
941
      # The number of vCPUs mapped should match the number of vCPUs
942
      # reported by KVM. This was already verified earlier, so
943
      # here only as a sanity check.
944
      assert len(thread_dict) == len(cpu_list)
945
      cls._VerifyAffinityPackage()
946

    
947
      # For each vCPU, map it to the proper list of physical CPUs
948
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
949
        affinity.set_process_affinity_mask(thread_dict[i],
950
                                           cls._BuildAffinityCpuMask(vcpu))
951

    
952
  def _GetVcpuThreadIds(self, instance_name):
953
    """Get a mapping of vCPU no. to thread IDs for the instance
954

955
    @type instance_name: string
956
    @param instance_name: instance in question
957
    @rtype: dictionary of int:int
958
    @return: a dictionary mapping vCPU numbers to thread IDs
959

960
    """
961
    result = {}
962
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
963
    for line in output.stdout.splitlines():
964
      match = self._CPU_INFO_RE.search(line)
965
      if not match:
966
        continue
967
      grp = map(int, match.groups())
968
      result[grp[0]] = grp[1]
969

    
970
    return result
971

    
972
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
973
    """Complete CPU pinning.
974

975
    @type instance_name: string
976
    @param instance_name: name of instance
977
    @type cpu_mask: string
978
    @param cpu_mask: CPU pinning mask as entered by user
979

980
    """
981
    # Get KVM process ID, to be used if need to pin entire VM
982
    _, pid, _ = self._InstancePidAlive(instance_name)
983
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
984
    thread_dict = self._GetVcpuThreadIds(instance_name)
985
    # Run CPU pinning, based on configured mask
986
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
987

    
988
  def ListInstances(self):
989
    """Get the list of running instances.
990

991
    We can do this by listing our live instances directory and
992
    checking whether the associated kvm process is still alive.
993

994
    """
995
    result = []
996
    for name in os.listdir(self._PIDS_DIR):
997
      if self._InstancePidAlive(name)[2]:
998
        result.append(name)
999
    return result
1000

    
1001
  def GetInstanceInfo(self, instance_name):
1002
    """Get instance properties.
1003

1004
    @type instance_name: string
1005
    @param instance_name: the instance name
1006
    @rtype: tuple of strings
1007
    @return: (name, id, memory, vcpus, stat, times)
1008

1009
    """
1010
    _, pid, alive = self._InstancePidAlive(instance_name)
1011
    if not alive:
1012
      return None
1013

    
1014
    _, memory, vcpus = self._InstancePidInfo(pid)
1015
    istat = "---b-"
1016
    times = "0"
1017

    
1018
    try:
1019
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1020
      qmp.connect()
1021
      vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1022
      # Will fail if ballooning is not enabled, but we can then just resort to
1023
      # the value above.
1024
      mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1025
      memory = mem_bytes / 1048576
1026
    except errors.HypervisorError:
1027
      pass
1028

    
1029
    return (instance_name, pid, memory, vcpus, istat, times)
1030

    
1031
  def GetAllInstancesInfo(self):
1032
    """Get properties of all instances.
1033

1034
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1035

1036
    """
1037
    data = []
1038
    for name in os.listdir(self._PIDS_DIR):
1039
      try:
1040
        info = self.GetInstanceInfo(name)
1041
      except errors.HypervisorError:
1042
        # Ignore exceptions due to instances being shut down
1043
        continue
1044
      if info:
1045
        data.append(info)
1046
    return data
1047

    
1048
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1049
                          kvmhelp):
1050
    """Generate KVM information to start an instance.
1051

1052
    @type kvmhelp: string
1053
    @param kvmhelp: output of kvm --help
1054
    @attention: this function must not have any side-effects; for
1055
        example, it must not write to the filesystem, or read values
1056
        from the current system the are expected to differ between
1057
        nodes, since it is only run once at instance startup;
1058
        actions/kvm arguments that can vary between systems should be
1059
        done in L{_ExecuteKVMRuntime}
1060

1061
    """
1062
    # pylint: disable=R0912,R0914,R0915
1063
    hvp = instance.hvparams
1064

    
1065
    pidfile = self._InstancePidFile(instance.name)
1066
    kvm = hvp[constants.HV_KVM_PATH]
1067
    kvm_cmd = [kvm]
1068
    # used just by the vnc server, if enabled
1069
    kvm_cmd.extend(["-name", instance.name])
1070
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1071

    
1072
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1073
    if hvp[constants.HV_CPU_CORES]:
1074
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1075
    if hvp[constants.HV_CPU_THREADS]:
1076
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1077
    if hvp[constants.HV_CPU_SOCKETS]:
1078
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1079

    
1080
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1081

    
1082
    kvm_cmd.extend(["-pidfile", pidfile])
1083
    kvm_cmd.extend(["-balloon", "virtio"])
1084
    kvm_cmd.extend(["-daemonize"])
1085
    if not instance.hvparams[constants.HV_ACPI]:
1086
      kvm_cmd.extend(["-no-acpi"])
1087
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1088
        constants.INSTANCE_REBOOT_EXIT:
1089
      kvm_cmd.extend(["-no-reboot"])
1090

    
1091
    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1092
    if not mversion:
1093
      mversion = self._GetDefaultMachineVersion(kvm)
1094
    kvm_cmd.extend(["-M", mversion])
1095

    
1096
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1097
    if kernel_path:
1098
      boot_disk = boot_cdrom = boot_floppy = boot_network = False
1099
    else:
1100
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1101
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1102
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1103
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1104

    
1105
    self.ValidateParameters(hvp)
1106

    
1107
    if startup_paused:
1108
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1109

    
1110
    if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1111
        self._ENABLE_KVM_RE.search(kvmhelp)):
1112
      kvm_cmd.extend(["-enable-kvm"])
1113
    elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1114
          self._DISABLE_KVM_RE.search(kvmhelp)):
1115
      kvm_cmd.extend(["-disable-kvm"])
1116

    
1117
    if boot_network:
1118
      kvm_cmd.extend(["-boot", "n"])
1119

    
1120
    # whether this is an older KVM version that uses the boot=on flag
1121
    # on devices
1122
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1123

    
1124
    disk_type = hvp[constants.HV_DISK_TYPE]
1125
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
1126
      if_val = ",if=virtio"
1127
    else:
1128
      if_val = ",if=%s" % disk_type
1129
    # Cache mode
1130
    disk_cache = hvp[constants.HV_DISK_CACHE]
1131
    if instance.disk_template in constants.DTS_EXT_MIRROR:
1132
      if disk_cache != "none":
1133
        # TODO: make this a hard error, instead of a silent overwrite
1134
        logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1135
                        " to prevent shared storage corruption on migration",
1136
                        disk_cache)
1137
      cache_val = ",cache=none"
1138
    elif disk_cache != constants.HT_CACHE_DEFAULT:
1139
      cache_val = ",cache=%s" % disk_cache
1140
    else:
1141
      cache_val = ""
1142
    for cfdev, dev_path in block_devices:
1143
      if cfdev.mode != constants.DISK_RDWR:
1144
        raise errors.HypervisorError("Instance has read-only disks which"
1145
                                     " are not supported by KVM")
1146
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
1147
      boot_val = ""
1148
      if boot_disk:
1149
        kvm_cmd.extend(["-boot", "c"])
1150
        boot_disk = False
1151
        if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1152
          boot_val = ",boot=on"
1153

    
1154
      drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
1155
                                                cache_val)
1156
      kvm_cmd.extend(["-drive", drive_val])
1157

    
1158
    #Now we can specify a different device type for CDROM devices.
1159
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1160
    if not cdrom_disk_type:
1161
      cdrom_disk_type = disk_type
1162

    
1163
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1164
    if iso_image:
1165
      options = ",format=raw,media=cdrom"
1166
      # set cdrom 'if' type
1167
      if boot_cdrom:
1168
        actual_cdrom_type = constants.HT_DISK_IDE
1169
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1170
        actual_cdrom_type = "virtio"
1171
      else:
1172
        actual_cdrom_type = cdrom_disk_type
1173
      if_val = ",if=%s" % actual_cdrom_type
1174
      # set boot flag, if needed
1175
      boot_val = ""
1176
      if boot_cdrom:
1177
        kvm_cmd.extend(["-boot", "d"])
1178
        if needs_boot_flag:
1179
          boot_val = ",boot=on"
1180
      # and finally build the entire '-drive' value
1181
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1182
      kvm_cmd.extend(["-drive", drive_val])
1183

    
1184
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1185
    if iso_image2:
1186
      options = ",format=raw,media=cdrom"
1187
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1188
        if_val = ",if=virtio"
1189
      else:
1190
        if_val = ",if=%s" % cdrom_disk_type
1191
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1192
      kvm_cmd.extend(["-drive", drive_val])
1193

    
1194
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1195
    if floppy_image:
1196
      options = ",format=raw,media=disk"
1197
      if boot_floppy:
1198
        kvm_cmd.extend(["-boot", "a"])
1199
        options = "%s,boot=on" % options
1200
      if_val = ",if=floppy"
1201
      options = "%s%s" % (options, if_val)
1202
      drive_val = "file=%s%s" % (floppy_image, options)
1203
      kvm_cmd.extend(["-drive", drive_val])
1204

    
1205
    if kernel_path:
1206
      kvm_cmd.extend(["-kernel", kernel_path])
1207
      initrd_path = hvp[constants.HV_INITRD_PATH]
1208
      if initrd_path:
1209
        kvm_cmd.extend(["-initrd", initrd_path])
1210
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1211
                     hvp[constants.HV_KERNEL_ARGS]]
1212
      if hvp[constants.HV_SERIAL_CONSOLE]:
1213
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1214
        root_append.append("console=ttyS0,%s" % serial_speed)
1215
      kvm_cmd.extend(["-append", " ".join(root_append)])
1216

    
1217
    mem_path = hvp[constants.HV_MEM_PATH]
1218
    if mem_path:
1219
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1220

    
1221
    monitor_dev = ("unix:%s,server,nowait" %
1222
                   self._InstanceMonitor(instance.name))
1223
    kvm_cmd.extend(["-monitor", monitor_dev])
1224
    if hvp[constants.HV_SERIAL_CONSOLE]:
1225
      serial_dev = ("unix:%s,server,nowait" %
1226
                    self._InstanceSerial(instance.name))
1227
      kvm_cmd.extend(["-serial", serial_dev])
1228
    else:
1229
      kvm_cmd.extend(["-serial", "none"])
1230

    
1231
    mouse_type = hvp[constants.HV_USB_MOUSE]
1232
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1233
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1234
    spice_ip_version = None
1235

    
1236
    kvm_cmd.extend(["-usb"])
1237

    
1238
    if mouse_type:
1239
      kvm_cmd.extend(["-usbdevice", mouse_type])
1240
    elif vnc_bind_address:
1241
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1242

    
1243
    if vnc_bind_address:
1244
      if netutils.IP4Address.IsValid(vnc_bind_address):
1245
        if instance.network_port > constants.VNC_BASE_PORT:
1246
          display = instance.network_port - constants.VNC_BASE_PORT
1247
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1248
            vnc_arg = ":%d" % (display)
1249
          else:
1250
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1251
        else:
1252
          logging.error("Network port is not a valid VNC display (%d < %d),"
1253
                        " not starting VNC",
1254
                        instance.network_port, constants.VNC_BASE_PORT)
1255
          vnc_arg = "none"
1256

    
1257
        # Only allow tls and other option when not binding to a file, for now.
1258
        # kvm/qemu gets confused otherwise about the filename to use.
1259
        vnc_append = ""
1260
        if hvp[constants.HV_VNC_TLS]:
1261
          vnc_append = "%s,tls" % vnc_append
1262
          if hvp[constants.HV_VNC_X509_VERIFY]:
1263
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1264
                                               hvp[constants.HV_VNC_X509])
1265
          elif hvp[constants.HV_VNC_X509]:
1266
            vnc_append = "%s,x509=%s" % (vnc_append,
1267
                                         hvp[constants.HV_VNC_X509])
1268
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1269
          vnc_append = "%s,password" % vnc_append
1270

    
1271
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1272

    
1273
      else:
1274
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1275

    
1276
      kvm_cmd.extend(["-vnc", vnc_arg])
1277
    elif spice_bind:
1278
      # FIXME: this is wrong here; the iface ip address differs
1279
      # between systems, so it should be done in _ExecuteKVMRuntime
1280
      if netutils.IsValidInterface(spice_bind):
1281
        # The user specified a network interface, we have to figure out the IP
1282
        # address.
1283
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1284
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1285

    
1286
        # if the user specified an IP version and the interface does not
1287
        # have that kind of IP addresses, throw an exception
1288
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1289
          if not addresses[spice_ip_version]:
1290
            raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1291
                                         " for %s" % (spice_ip_version,
1292
                                                      spice_bind))
1293

    
1294
        # the user did not specify an IP version, we have to figure it out
1295
        elif (addresses[constants.IP4_VERSION] and
1296
              addresses[constants.IP6_VERSION]):
1297
          # we have both ipv4 and ipv6, let's use the cluster default IP
1298
          # version
1299
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1300
          spice_ip_version = \
1301
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1302
        elif addresses[constants.IP4_VERSION]:
1303
          spice_ip_version = constants.IP4_VERSION
1304
        elif addresses[constants.IP6_VERSION]:
1305
          spice_ip_version = constants.IP6_VERSION
1306
        else:
1307
          raise errors.HypervisorError("SPICE: Unable to get an IP address"
1308
                                       " for %s" % (spice_bind))
1309

    
1310
        spice_address = addresses[spice_ip_version][0]
1311

    
1312
      else:
1313
        # spice_bind is known to be a valid IP address, because
1314
        # ValidateParameters checked it.
1315
        spice_address = spice_bind
1316

    
1317
      spice_arg = "addr=%s" % spice_address
1318
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1319
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1320
                     (spice_arg, instance.network_port,
1321
                      pathutils.SPICE_CACERT_FILE))
1322
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1323
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1324
                      pathutils.SPICE_CERT_FILE))
1325
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1326
        if tls_ciphers:
1327
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1328
      else:
1329
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1330

    
1331
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1332
        spice_arg = "%s,disable-ticketing" % spice_arg
1333

    
1334
      if spice_ip_version:
1335
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1336

    
1337
      # Image compression options
1338
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1339
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1340
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1341
      if img_lossless:
1342
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1343
      if img_jpeg:
1344
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1345
      if img_zlib_glz:
1346
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1347

    
1348
      # Video stream detection
1349
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1350
      if video_streaming:
1351
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1352

    
1353
      # Audio compression, by default in qemu-kvm it is on
1354
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1355
        spice_arg = "%s,playback-compression=off" % spice_arg
1356
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1357
        spice_arg = "%s,agent-mouse=off" % spice_arg
1358
      else:
1359
        # Enable the spice agent communication channel between the host and the
1360
        # agent.
1361
        kvm_cmd.extend(["-device", "virtio-serial-pci"])
1362
        kvm_cmd.extend([
1363
          "-device",
1364
          "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1365
          ])
1366
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1367

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

    
1371
    else:
1372
      kvm_cmd.extend(["-nographic"])
1373

    
1374
    if hvp[constants.HV_USE_LOCALTIME]:
1375
      kvm_cmd.extend(["-localtime"])
1376

    
1377
    if hvp[constants.HV_KVM_USE_CHROOT]:
1378
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1379

    
1380
    # Add qemu-KVM -cpu param
1381
    if hvp[constants.HV_CPU_TYPE]:
1382
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1383

    
1384
    # As requested by music lovers
1385
    if hvp[constants.HV_SOUNDHW]:
1386
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1387

    
1388
    # Pass a -vga option if requested, or if spice is used, for backwards
1389
    # compatibility.
1390
    if hvp[constants.HV_VGA]:
1391
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1392
    elif spice_bind:
1393
      kvm_cmd.extend(["-vga", "qxl"])
1394

    
1395
    # Various types of usb devices, comma separated
1396
    if hvp[constants.HV_USB_DEVICES]:
1397
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1398
        kvm_cmd.extend(["-usbdevice", dev])
1399

    
1400
    if hvp[constants.HV_KVM_EXTRA]:
1401
      kvm_cmd.extend([hvp[constants.HV_KVM_EXTRA]])
1402

    
1403
    # Save the current instance nics, but defer their expansion as parameters,
1404
    # as we'll need to generate executable temp files for them.
1405
    kvm_nics = instance.nics
1406
    hvparams = hvp
1407

    
1408
    return (kvm_cmd, kvm_nics, hvparams)
1409

    
1410
  def _WriteKVMRuntime(self, instance_name, data):
1411
    """Write an instance's KVM runtime
1412

1413
    """
1414
    try:
1415
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1416
                      data=data)
1417
    except EnvironmentError, err:
1418
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1419

    
1420
  def _ReadKVMRuntime(self, instance_name):
1421
    """Read an instance's KVM runtime
1422

1423
    """
1424
    try:
1425
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1426
    except EnvironmentError, err:
1427
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1428
    return file_content
1429

    
1430
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1431
    """Save an instance's KVM runtime
1432

1433
    """
1434
    kvm_cmd, kvm_nics, hvparams = kvm_runtime
1435
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1436
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1437
    self._WriteKVMRuntime(instance.name, serialized_form)
1438

    
1439
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1440
    """Load an instance's KVM runtime
1441

1442
    """
1443
    if not serialized_runtime:
1444
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1445
    loaded_runtime = serializer.Load(serialized_runtime)
1446
    kvm_cmd, serialized_nics, hvparams = loaded_runtime
1447
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1448
    return (kvm_cmd, kvm_nics, hvparams)
1449

    
1450
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1451
    """Run the KVM cmd and check for errors
1452

1453
    @type name: string
1454
    @param name: instance name
1455
    @type kvm_cmd: list of strings
1456
    @param kvm_cmd: runcmd input for kvm
1457
    @type tap_fds: list of int
1458
    @param tap_fds: fds of tap devices opened by Ganeti
1459

1460
    """
1461
    try:
1462
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1463
    finally:
1464
      for fd in tap_fds:
1465
        utils_wrapper.CloseFdNoError(fd)
1466

    
1467
    if result.failed:
1468
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1469
                                   (name, result.fail_reason, result.output))
1470
    if not self._InstancePidAlive(name)[2]:
1471
      raise errors.HypervisorError("Failed to start instance %s" % name)
1472

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

1476
    @type incoming: tuple of strings
1477
    @param incoming: (target_host_ip, port)
1478
    @type kvmhelp: string
1479
    @param kvmhelp: output of kvm --help
1480

1481
    """
1482
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1483
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1484
    #    have changed since the instance started; only use them if the change
1485
    #    won't affect the inside of the instance (which hasn't been rebooted).
1486
    #  - up_hvp contains the parameters as they were when the instance was
1487
    #    started, plus any new parameter which has been added between ganeti
1488
    #    versions: it is paramount that those default to a value which won't
1489
    #    affect the inside of the instance as well.
1490
    conf_hvp = instance.hvparams
1491
    name = instance.name
1492
    self._CheckDown(name)
1493

    
1494
    temp_files = []
1495

    
1496
    kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1497
    # the first element of kvm_cmd is always the path to the kvm binary
1498
    kvm_path = kvm_cmd[0]
1499
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1500

    
1501
    # We know it's safe to run as a different user upon migration, so we'll use
1502
    # the latest conf, from conf_hvp.
1503
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1504
    if security_model == constants.HT_SM_USER:
1505
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1506

    
1507
    keymap = conf_hvp[constants.HV_KEYMAP]
1508
    if keymap:
1509
      keymap_path = self._InstanceKeymapFile(name)
1510
      # If a keymap file is specified, KVM won't use its internal defaults. By
1511
      # first including the "en-us" layout, an error on loading the actual
1512
      # layout (e.g. because it can't be found) won't lead to a non-functional
1513
      # keyboard. A keyboard with incorrect keys is still better than none.
1514
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1515
      kvm_cmd.extend(["-k", keymap_path])
1516

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

    
1540
        if up_hvp[constants.HV_VHOST_NET]:
1541
          # check for vhost_net support
1542
          if self._VHOST_RE.search(kvmhelp):
1543
            tap_extra = ",vhost=on"
1544
          else:
1545
            raise errors.HypervisorError("vhost_net is configured"
1546
                                         " but it is not available")
1547
      else:
1548
        nic_model = nic_type
1549

    
1550
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1551

    
1552
      for nic_seq, nic in enumerate(kvm_nics):
1553
        tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1554
        tapfds.append(tapfd)
1555
        taps.append(tapname)
1556
        if kvm_supports_netdev:
1557
          nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1558
          tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1559
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1560
        else:
1561
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1562
                                                         nic.mac, nic_model)
1563
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1564
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1565

    
1566
    if incoming:
1567
      target, port = incoming
1568
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1569

    
1570
    # Changing the vnc password doesn't bother the guest that much. At most it
1571
    # will surprise people who connect to it. Whether positively or negatively
1572
    # it's debatable.
1573
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1574
    vnc_pwd = None
1575
    if vnc_pwd_file:
1576
      try:
1577
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1578
      except EnvironmentError, err:
1579
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1580
                                     % (vnc_pwd_file, err))
1581

    
1582
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1583
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1584
                         constants.SECURE_DIR_MODE)])
1585

    
1586
    # Automatically enable QMP if version is >= 0.14
1587
    if self._QMP_RE.search(kvmhelp):
1588
      logging.debug("Enabling QMP")
1589
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1590
                      self._InstanceQmpMonitor(instance.name)])
1591

    
1592
    # Configure the network now for starting instances and bridged interfaces,
1593
    # during FinalizeMigration for incoming instances' routed interfaces
1594
    for nic_seq, nic in enumerate(kvm_nics):
1595
      if (incoming and
1596
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1597
        continue
1598
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1599

    
1600
    # CPU affinity requires kvm to start paused, so we set this flag if the
1601
    # instance is not already paused and if we are not going to accept a
1602
    # migrating instance. In the latter case, pausing is not needed.
1603
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1604
    if start_kvm_paused:
1605
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1606

    
1607
    # Note: CPU pinning is using up_hvp since changes take effect
1608
    # during instance startup anyway, and to avoid problems when soft
1609
    # rebooting the instance.
1610
    cpu_pinning = False
1611
    if up_hvp.get(constants.HV_CPU_MASK, None):
1612
      cpu_pinning = True
1613

    
1614
    if security_model == constants.HT_SM_POOL:
1615
      ss = ssconf.SimpleStore()
1616
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1617
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1618
      uid = uidpool.RequestUnusedUid(all_uids)
1619
      try:
1620
        username = pwd.getpwuid(uid.GetUid()).pw_name
1621
        kvm_cmd.extend(["-runas", username])
1622
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1623
      except:
1624
        uidpool.ReleaseUid(uid)
1625
        raise
1626
      else:
1627
        uid.Unlock()
1628
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1629
    else:
1630
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1631

    
1632
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1633
                     constants.RUN_DIRS_MODE)])
1634
    for nic_seq, tap in enumerate(taps):
1635
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1636
                      data=tap)
1637

    
1638
    if vnc_pwd:
1639
      change_cmd = "change vnc password %s" % vnc_pwd
1640
      self._CallMonitorCommand(instance.name, change_cmd)
1641

    
1642
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1643
    # connection attempts because SPICE by default does not allow connections
1644
    # if neither a password nor the "disable_ticketing" options are specified.
1645
    # As soon as we send the password via QMP, that password is a valid ticket
1646
    # for connection.
1647
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1648
    if spice_password_file:
1649
      spice_pwd = ""
1650
      try:
1651
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1652
      except EnvironmentError, err:
1653
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1654
                                     % (spice_password_file, err))
1655

    
1656
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1657
      qmp.connect()
1658
      arguments = {
1659
          "protocol": "spice",
1660
          "password": spice_pwd,
1661
      }
1662
      qmp.Execute("set_password", arguments)
1663

    
1664
    for filename in temp_files:
1665
      utils.RemoveFile(filename)
1666

    
1667
    # If requested, set CPU affinity and resume instance execution
1668
    if cpu_pinning:
1669
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1670

    
1671
    start_memory = self._InstanceStartupMemory(instance)
1672
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1673
      self.BalloonInstanceMemory(instance, start_memory)
1674

    
1675
    if start_kvm_paused:
1676
      # To control CPU pinning, ballooning, and vnc/spice passwords
1677
      # the VM was started in a frozen state. If freezing was not
1678
      # explicitly requested resume the vm status.
1679
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1680

    
1681
  def StartInstance(self, instance, block_devices, startup_paused):
1682
    """Start an instance.
1683

1684
    """
1685
    self._CheckDown(instance.name)
1686
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1687
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1688
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1689
                                           startup_paused, kvmhelp)
1690
    self._SaveKVMRuntime(instance, kvm_runtime)
1691
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1692

    
1693
  def _CallMonitorCommand(self, instance_name, command):
1694
    """Invoke a command on the instance monitor.
1695

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

    
1715
    return result
1716

    
1717
  @classmethod
1718
  def _ParseKVMVersion(cls, text):
1719
    """Parse the KVM version from the --help output.
1720

1721
    @type text: string
1722
    @param text: output of kvm --help
1723
    @return: (version, v_maj, v_min, v_rev)
1724
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1725

1726
    """
1727
    match = cls._VERSION_RE.search(text.splitlines()[0])
1728
    if not match:
1729
      raise errors.HypervisorError("Unable to get KVM version")
1730

    
1731
    v_all = match.group(0)
1732
    v_maj = int(match.group(1))
1733
    v_min = int(match.group(2))
1734
    if match.group(4):
1735
      v_rev = int(match.group(4))
1736
    else:
1737
      v_rev = 0
1738
    return (v_all, v_maj, v_min, v_rev)
1739

    
1740
  @classmethod
1741
  def _GetKVMOutput(cls, kvm_path, option):
1742
    """Return the output of a kvm invocation
1743

1744
    @type kvm_path: string
1745
    @param kvm_path: path to the kvm executable
1746
    @type option: a key of _KVMOPTS_CMDS
1747
    @param option: kvm option to fetch the output from
1748
    @return: output a supported kvm invocation
1749
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1750

1751
    """
1752
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
1753

    
1754
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
1755

    
1756
    result = utils.RunCmd([kvm_path] + optlist)
1757
    if result.failed and not can_fail:
1758
      raise errors.HypervisorError("Unable to get KVM %s output" %
1759
                                    " ".join(cls._KVMOPTS_CMDS[option]))
1760
    return result.output
1761

    
1762
  @classmethod
1763
  def _GetKVMVersion(cls, kvm_path):
1764
    """Return the installed KVM version.
1765

1766
    @return: (version, v_maj, v_min, v_rev)
1767
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1768

1769
    """
1770
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
1771

    
1772
  @classmethod
1773
  def _GetDefaultMachineVersion(cls, kvm_path):
1774
    """Return the default hardware revision (e.g. pc-1.1)
1775

1776
    """
1777
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
1778
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
1779
    if match:
1780
      return match.group(1)
1781
    else:
1782
      return "pc"
1783

    
1784
  def StopInstance(self, instance, force=False, retry=False, name=None):
1785
    """Stop an instance.
1786

1787
    """
1788
    if name is not None and not force:
1789
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1790
    if name is None:
1791
      name = instance.name
1792
      acpi = instance.hvparams[constants.HV_ACPI]
1793
    else:
1794
      acpi = False
1795
    _, pid, alive = self._InstancePidAlive(name)
1796
    if pid > 0 and alive:
1797
      if force or not acpi:
1798
        utils.KillProcess(pid)
1799
      else:
1800
        self._CallMonitorCommand(name, "system_powerdown")
1801

    
1802
  def CleanupInstance(self, instance_name):
1803
    """Cleanup after a stopped instance
1804

1805
    """
1806
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
1807
    if pid > 0 and alive:
1808
      raise errors.HypervisorError("Cannot cleanup a live instance")
1809
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1810

    
1811
  def RebootInstance(self, instance):
1812
    """Reboot an instance.
1813

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

    
1834
  def MigrationInfo(self, instance):
1835
    """Get instance information to perform a migration.
1836

1837
    @type instance: L{objects.Instance}
1838
    @param instance: instance to be migrated
1839
    @rtype: string
1840
    @return: content of the KVM runtime file
1841

1842
    """
1843
    return self._ReadKVMRuntime(instance.name)
1844

    
1845
  def AcceptInstance(self, instance, info, target):
1846
    """Prepare to accept an instance.
1847

1848
    @type instance: L{objects.Instance}
1849
    @param instance: instance to be accepted
1850
    @type info: string
1851
    @param info: content of the KVM runtime file on the source node
1852
    @type target: string
1853
    @param target: target host (usually ip), on this node
1854

1855
    """
1856
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1857
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1858
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1859
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1860
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
1861
                            incoming=incoming_address)
1862

    
1863
  def FinalizeMigrationDst(self, instance, info, success):
1864
    """Finalize the instance migration on the target node.
1865

1866
    Stop the incoming mode KVM.
1867

1868
    @type instance: L{objects.Instance}
1869
    @param instance: instance whose migration is being finalized
1870

1871
    """
1872
    if success:
1873
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1874
      kvm_nics = kvm_runtime[1]
1875

    
1876
      for nic_seq, nic in enumerate(kvm_nics):
1877
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1878
          # Bridged interfaces have already been configured
1879
          continue
1880
        try:
1881
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1882
        except EnvironmentError, err:
1883
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
1884
                          instance.name, nic_seq, str(err))
1885
          continue
1886
        try:
1887
          self._ConfigureNIC(instance, nic_seq, nic, tap)
1888
        except errors.HypervisorError, err:
1889
          logging.warning(str(err))
1890

    
1891
      self._WriteKVMRuntime(instance.name, info)
1892
    else:
1893
      self.StopInstance(instance, force=True)
1894

    
1895
  def MigrateInstance(self, instance, target, live):
1896
    """Migrate an instance to a target node.
1897

1898
    The migration will not be attempted if the instance is not
1899
    currently running.
1900

1901
    @type instance: L{objects.Instance}
1902
    @param instance: the instance to be migrated
1903
    @type target: string
1904
    @param target: ip address of the target node
1905
    @type live: boolean
1906
    @param live: perform a live migration
1907

1908
    """
1909
    instance_name = instance.name
1910
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
1911
    _, _, alive = self._InstancePidAlive(instance_name)
1912
    if not alive:
1913
      raise errors.HypervisorError("Instance not running, cannot migrate")
1914

    
1915
    if not live:
1916
      self._CallMonitorCommand(instance_name, "stop")
1917

    
1918
    migrate_command = ("migrate_set_speed %dm" %
1919
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1920
    self._CallMonitorCommand(instance_name, migrate_command)
1921

    
1922
    migrate_command = ("migrate_set_downtime %dms" %
1923
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1924
    self._CallMonitorCommand(instance_name, migrate_command)
1925

    
1926
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1927
    self._CallMonitorCommand(instance_name, migrate_command)
1928

    
1929
  def FinalizeMigrationSource(self, instance, success, live):
1930
    """Finalize the instance migration on the source node.
1931

1932
    @type instance: L{objects.Instance}
1933
    @param instance: the instance that was migrated
1934
    @type success: bool
1935
    @param success: whether the migration succeeded or not
1936
    @type live: bool
1937
    @param live: whether the user requested a live migration or not
1938

1939
    """
1940
    if success:
1941
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
1942
      utils.KillProcess(pid)
1943
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1944
    elif live:
1945
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1946

    
1947
  def GetMigrationStatus(self, instance):
1948
    """Get the migration status
1949

1950
    @type instance: L{objects.Instance}
1951
    @param instance: the instance that is being migrated
1952
    @rtype: L{objects.MigrationStatus}
1953
    @return: the status of the current migration (one of
1954
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1955
             progress info that can be retrieved from the hypervisor
1956

1957
    """
1958
    info_command = "info migrate"
1959
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
1960
      result = self._CallMonitorCommand(instance.name, info_command)
1961
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
1962
      if not match:
1963
        if not result.stdout:
1964
          logging.info("KVM: empty 'info migrate' result")
1965
        else:
1966
          logging.warning("KVM: unknown 'info migrate' result: %s",
1967
                          result.stdout)
1968
      else:
1969
        status = match.group(1)
1970
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
1971
          migration_status = objects.MigrationStatus(status=status)
1972
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
1973
          if match:
1974
            migration_status.transferred_ram = match.group("transferred")
1975
            migration_status.total_ram = match.group("total")
1976

    
1977
          return migration_status
1978

    
1979
        logging.warning("KVM: unknown migration status '%s'", status)
1980

    
1981
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1982

    
1983
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
1984

    
1985
  def BalloonInstanceMemory(self, instance, mem):
1986
    """Balloon an instance memory to a certain value.
1987

1988
    @type instance: L{objects.Instance}
1989
    @param instance: instance to be accepted
1990
    @type mem: int
1991
    @param mem: actual memory size to use for instance runtime
1992

1993
    """
1994
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
1995

    
1996
  def GetNodeInfo(self):
1997
    """Return information about the node.
1998

1999
    @return: a dict with the following keys (values in MiB):
2000
          - memory_total: the total memory size on the node
2001
          - memory_free: the available memory on the node for instances
2002
          - memory_dom0: the memory used by the node itself, if available
2003
          - hv_version: the hypervisor version in the form (major, minor,
2004
                        revision)
2005

2006
    """
2007
    result = self.GetLinuxNodeInfo()
2008
    # FIXME: this is the global kvm version, but the actual version can be
2009
    # customized as an hv parameter. we should use the nodegroup's default kvm
2010
    # path parameter here.
2011
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2012
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2013
    return result
2014

    
2015
  @classmethod
2016
  def GetInstanceConsole(cls, instance, hvparams, beparams):
2017
    """Return a command for connecting to the console of an instance.
2018

2019
    """
2020
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2021
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2022
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2023
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2024
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2025
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2026
      return objects.InstanceConsole(instance=instance.name,
2027
                                     kind=constants.CONS_SSH,
2028
                                     host=instance.primary_node,
2029
                                     user=constants.SSH_CONSOLE_USER,
2030
                                     command=cmd)
2031

    
2032
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2033
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2034
      display = instance.network_port - constants.VNC_BASE_PORT
2035
      return objects.InstanceConsole(instance=instance.name,
2036
                                     kind=constants.CONS_VNC,
2037
                                     host=vnc_bind_address,
2038
                                     port=instance.network_port,
2039
                                     display=display)
2040

    
2041
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2042
    if spice_bind:
2043
      return objects.InstanceConsole(instance=instance.name,
2044
                                     kind=constants.CONS_SPICE,
2045
                                     host=spice_bind,
2046
                                     port=instance.network_port)
2047

    
2048
    return objects.InstanceConsole(instance=instance.name,
2049
                                   kind=constants.CONS_MESSAGE,
2050
                                   message=("No serial shell for instance %s" %
2051
                                            instance.name))
2052

    
2053
  def Verify(self):
2054
    """Verify the hypervisor.
2055

2056
    Check that the required binaries exist.
2057

2058
    @return: Problem description if something is wrong, C{None} otherwise
2059

2060
    """
2061
    msgs = []
2062
    # FIXME: this is the global kvm binary, but the actual path can be
2063
    # customized as an hv parameter; we should use the nodegroup's
2064
    # default kvm path parameter here.
2065
    if not os.path.exists(constants.KVM_PATH):
2066
      msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2067
    if not os.path.exists(constants.SOCAT_PATH):
2068
      msgs.append("The socat binary ('%s') does not exist" %
2069
                  constants.SOCAT_PATH)
2070

    
2071
    return self._FormatVerifyResults(msgs)
2072

    
2073
  @classmethod
2074
  def CheckParameterSyntax(cls, hvparams):
2075
    """Check the given parameters for validity.
2076

2077
    @type hvparams:  dict
2078
    @param hvparams: dictionary with parameter names/value
2079
    @raise errors.HypervisorError: when a parameter is not valid
2080

2081
    """
2082
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2083

    
2084
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2085
    if kernel_path:
2086
      if not hvparams[constants.HV_ROOT_PATH]:
2087
        raise errors.HypervisorError("Need a root partition for the instance,"
2088
                                     " if a kernel is defined")
2089

    
2090
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2091
        not hvparams[constants.HV_VNC_X509]):
2092
      raise errors.HypervisorError("%s must be defined, if %s is" %
2093
                                   (constants.HV_VNC_X509,
2094
                                    constants.HV_VNC_X509_VERIFY))
2095

    
2096
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2097
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2098
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2099
      if not serial_speed or serial_speed not in valid_speeds:
2100
        raise errors.HypervisorError("Invalid serial console speed, must be"
2101
                                     " one of: %s" %
2102
                                     utils.CommaJoin(valid_speeds))
2103

    
2104
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2105
    if (boot_order == constants.HT_BO_CDROM and
2106
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2107
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2108
                                   " ISO path")
2109

    
2110
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2111
    if security_model == constants.HT_SM_USER:
2112
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2113
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2114
                                     " must be specified")
2115
    elif (security_model == constants.HT_SM_NONE or
2116
          security_model == constants.HT_SM_POOL):
2117
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2118
        raise errors.HypervisorError("Cannot have a security domain when the"
2119
                                     " security model is 'none' or 'pool'")
2120

    
2121
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2122
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2123
    if spice_bind:
2124
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2125
        # if an IP version is specified, the spice_bind parameter must be an
2126
        # IP of that family
2127
        if (netutils.IP4Address.IsValid(spice_bind) and
2128
            spice_ip_version != constants.IP4_VERSION):
2129
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2130
                                       " the specified IP version is %s" %
2131
                                       (spice_bind, spice_ip_version))
2132

    
2133
        if (netutils.IP6Address.IsValid(spice_bind) and
2134
            spice_ip_version != constants.IP6_VERSION):
2135
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2136
                                       " the specified IP version is %s" %
2137
                                       (spice_bind, spice_ip_version))
2138
    else:
2139
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2140
      # error if any of them is set without it.
2141
      for param in _SPICE_ADDITIONAL_PARAMS:
2142
        if hvparams[param]:
2143
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2144
                                       (param, constants.HV_KVM_SPICE_BIND))
2145

    
2146
  @classmethod
2147
  def ValidateParameters(cls, hvparams):
2148
    """Check the given parameters for validity.
2149

2150
    @type hvparams:  dict
2151
    @param hvparams: dictionary with parameter names/value
2152
    @raise errors.HypervisorError: when a parameter is not valid
2153

2154
    """
2155
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2156

    
2157
    kvm_path = hvparams[constants.HV_KVM_PATH]
2158

    
2159
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2160
    if security_model == constants.HT_SM_USER:
2161
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2162
      try:
2163
        pwd.getpwnam(username)
2164
      except KeyError:
2165
        raise errors.HypervisorError("Unknown security domain user %s"
2166
                                     % username)
2167

    
2168
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2169
    if spice_bind:
2170
      # only one of VNC and SPICE can be used currently.
2171
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2172
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2173
                                     " only one of them can be used at a"
2174
                                     " given time")
2175

    
2176
      # check that KVM supports SPICE
2177
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2178
      if not cls._SPICE_RE.search(kvmhelp):
2179
        raise errors.HypervisorError("SPICE is configured, but it is not"
2180
                                     " supported according to 'kvm --help'")
2181

    
2182
      # if spice_bind is not an IP address, it must be a valid interface
2183
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2184
                       netutils.IP6Address.IsValid(spice_bind))
2185
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2186
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2187
                                     " a valid IP address or interface name" %
2188
                                     constants.HV_KVM_SPICE_BIND)
2189

    
2190
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2191
    if machine_version:
2192
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2193
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2194
        raise errors.HypervisorError("Unsupported machine version: %s" %
2195
                                     machine_version)
2196

    
2197
  @classmethod
2198
  def PowercycleNode(cls):
2199
    """KVM powercycle, just a wrapper over Linux powercycle.
2200

2201
    """
2202
    cls.LinuxPowercycle()