Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 8ef418bb

History | View | Annotate | Download (80.5 kB)

1
#
2
#
3

    
4
# Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

    
21

    
22
"""KVM hypervisor
23

24
"""
25

    
26
import errno
27
import os
28
import os.path
29
import re
30
import tempfile
31
import time
32
import logging
33
import pwd
34
import struct
35
import fcntl
36
import shutil
37
import socket
38
import stat
39
import StringIO
40
try:
41
  import affinity   # pylint: disable=F0401
42
except ImportError:
43
  affinity = None
44

    
45
from ganeti import utils
46
from ganeti import constants
47
from ganeti import errors
48
from ganeti import serializer
49
from ganeti import objects
50
from ganeti import uidpool
51
from ganeti import ssconf
52
from ganeti import netutils
53
from ganeti import pathutils
54
from ganeti.hypervisor import hv_base
55
from ganeti.utils import wrapper as utils_wrapper
56

    
57

    
58
_KVM_NETWORK_SCRIPT = pathutils.CONF_DIR + "/kvm-vif-bridge"
59
_KVM_START_PAUSED_FLAG = "-S"
60

    
61
# TUN/TAP driver constants, taken from <linux/if_tun.h>
62
# They are architecture-independent and already hardcoded in qemu-kvm source,
63
# so we can safely include them here.
64
TUNSETIFF = 0x400454ca
65
TUNGETIFF = 0x800454d2
66
TUNGETFEATURES = 0x800454cf
67
IFF_TAP = 0x0002
68
IFF_NO_PI = 0x1000
69
IFF_VNET_HDR = 0x4000
70

    
71
#: SPICE parameters which depend on L{constants.HV_KVM_SPICE_BIND}
72
_SPICE_ADDITIONAL_PARAMS = frozenset([
73
  constants.HV_KVM_SPICE_IP_VERSION,
74
  constants.HV_KVM_SPICE_PASSWORD_FILE,
75
  constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR,
76
  constants.HV_KVM_SPICE_JPEG_IMG_COMPR,
77
  constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR,
78
  constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION,
79
  constants.HV_KVM_SPICE_USE_TLS,
80
  ])
81

    
82

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

86
  @see: L{_ProbeTapVnetHdr}
87

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

    
99

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

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

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

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

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

    
123
  result = bool(flags & IFF_VNET_HDR)
124

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

    
128
  return result
129

    
130

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

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

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

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

    
148
  flags = IFF_TAP | IFF_NO_PI
149

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

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

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

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

    
166

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

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

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

    
178
    self.data = data
179

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

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

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

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

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

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

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

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

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

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

    
220

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

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

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

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

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

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

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

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

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

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

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

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

    
289
    self._check_socket()
290

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

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

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

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

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

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

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

    
332
    return (message, buf)
333

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

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

342
    """
343
    self._check_connection()
344

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

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

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

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

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

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

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

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

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

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

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

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

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

    
429

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

433
  """
434
  CAN_MIGRATE = True
435

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

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

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

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

    
548
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
549
  _MIGRATION_INFO_RETRY_DELAY = 2
550

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
660
    return (instance, memory, vcpus)
661

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

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

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

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

    
681
    return (pidfile, pid, alive)
682

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
946
    return result
947

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

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

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

    
964
  def ListInstances(self, hvparams=None):
965
    """Get the list of running instances.
966

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

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

    
977
  def GetInstanceInfo(self, instance_name, hvparams=None):
978
    """Get instance properties.
979

980
    @type instance_name: string
981
    @param instance_name: the instance name
982
    @type hvparams: dict of strings
983
    @param hvparams: hvparams to be used with this instance
984
    @rtype: tuple of strings
985
    @return: (name, id, memory, vcpus, stat, times)
986

987
    """
988
    _, pid, alive = self._InstancePidAlive(instance_name)
989
    if not alive:
990
      return None
991

    
992
    _, memory, vcpus = self._InstancePidInfo(pid)
993
    istat = "---b-"
994
    times = "0"
995

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

    
1007
    return (instance_name, pid, memory, vcpus, istat, times)
1008

    
1009
  def GetAllInstancesInfo(self, hvparams=None):
1010
    """Get properties of all instances.
1011

1012
    @type hvparams: dict of strings
1013
    @param hvparams: hypervisor parameter
1014
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1015

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

    
1028
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1029
                          kvmhelp):
1030
    """Generate KVM information to start an instance.
1031

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

1041
    """
1042
    # pylint: disable=R0912,R0914,R0915
1043
    hvp = instance.hvparams
1044
    self.ValidateParameters(hvp)
1045

    
1046
    pidfile = self._InstancePidFile(instance.name)
1047
    kvm = hvp[constants.HV_KVM_PATH]
1048
    kvm_cmd = [kvm]
1049
    # used just by the vnc server, if enabled
1050
    kvm_cmd.extend(["-name", instance.name])
1051
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1052

    
1053
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1054
    if hvp[constants.HV_CPU_CORES]:
1055
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1056
    if hvp[constants.HV_CPU_THREADS]:
1057
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1058
    if hvp[constants.HV_CPU_SOCKETS]:
1059
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1060

    
1061
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1062

    
1063
    kvm_cmd.extend(["-pidfile", pidfile])
1064
    kvm_cmd.extend(["-balloon", "virtio"])
1065
    kvm_cmd.extend(["-daemonize"])
1066
    if not instance.hvparams[constants.HV_ACPI]:
1067
      kvm_cmd.extend(["-no-acpi"])
1068
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1069
        constants.INSTANCE_REBOOT_EXIT:
1070
      kvm_cmd.extend(["-no-reboot"])
1071

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

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

    
1103
    if startup_paused:
1104
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1105

    
1106
    if boot_network:
1107
      kvm_cmd.extend(["-boot", "n"])
1108

    
1109
    # whether this is an older KVM version that uses the boot=on flag
1110
    # on devices
1111
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1112

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

    
1143
      drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
1144
                                                cache_val)
1145
      kvm_cmd.extend(["-drive", drive_val])
1146

    
1147
    #Now we can specify a different device type for CDROM devices.
1148
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1149
    if not cdrom_disk_type:
1150
      cdrom_disk_type = disk_type
1151

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

    
1173
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1174
    if iso_image2:
1175
      options = ",format=raw,media=cdrom"
1176
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1177
        if_val = ",if=virtio"
1178
      else:
1179
        if_val = ",if=%s" % cdrom_disk_type
1180
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1181
      kvm_cmd.extend(["-drive", drive_val])
1182

    
1183
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1184
    if floppy_image:
1185
      options = ",format=raw,media=disk"
1186
      if boot_floppy:
1187
        kvm_cmd.extend(["-boot", "a"])
1188
        options = "%s,boot=on" % options
1189
      if_val = ",if=floppy"
1190
      options = "%s%s" % (options, if_val)
1191
      drive_val = "file=%s%s" % (floppy_image, options)
1192
      kvm_cmd.extend(["-drive", drive_val])
1193

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

    
1206
    mem_path = hvp[constants.HV_MEM_PATH]
1207
    if mem_path:
1208
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1209

    
1210
    monitor_dev = ("unix:%s,server,nowait" %
1211
                   self._InstanceMonitor(instance.name))
1212
    kvm_cmd.extend(["-monitor", monitor_dev])
1213
    if hvp[constants.HV_SERIAL_CONSOLE]:
1214
      serial_dev = ("unix:%s,server,nowait" %
1215
                    self._InstanceSerial(instance.name))
1216
      kvm_cmd.extend(["-serial", serial_dev])
1217
    else:
1218
      kvm_cmd.extend(["-serial", "none"])
1219

    
1220
    mouse_type = hvp[constants.HV_USB_MOUSE]
1221
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1222
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1223
    spice_ip_version = None
1224

    
1225
    kvm_cmd.extend(["-usb"])
1226

    
1227
    if mouse_type:
1228
      kvm_cmd.extend(["-usbdevice", mouse_type])
1229
    elif vnc_bind_address:
1230
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1231

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

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

    
1260
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1261

    
1262
      else:
1263
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1264

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

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

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

    
1299
        spice_address = addresses[spice_ip_version][0]
1300

    
1301
      else:
1302
        # spice_bind is known to be a valid IP address, because
1303
        # ValidateParameters checked it.
1304
        spice_address = spice_bind
1305

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

    
1320
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1321
        spice_arg = "%s,disable-ticketing" % spice_arg
1322

    
1323
      if spice_ip_version:
1324
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1325

    
1326
      # Image compression options
1327
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1328
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1329
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1330
      if img_lossless:
1331
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1332
      if img_jpeg:
1333
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1334
      if img_zlib_glz:
1335
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1336

    
1337
      # Video stream detection
1338
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1339
      if video_streaming:
1340
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1341

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

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

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

    
1368
    if hvp[constants.HV_USE_LOCALTIME]:
1369
      kvm_cmd.extend(["-localtime"])
1370

    
1371
    if hvp[constants.HV_KVM_USE_CHROOT]:
1372
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1373

    
1374
    # Add qemu-KVM -cpu param
1375
    if hvp[constants.HV_CPU_TYPE]:
1376
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1377

    
1378
    # As requested by music lovers
1379
    if hvp[constants.HV_SOUNDHW]:
1380
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1381

    
1382
    # Pass a -vga option if requested, or if spice is used, for backwards
1383
    # compatibility.
1384
    if hvp[constants.HV_VGA]:
1385
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1386
    elif spice_bind:
1387
      kvm_cmd.extend(["-vga", "qxl"])
1388

    
1389
    # Various types of usb devices, comma separated
1390
    if hvp[constants.HV_USB_DEVICES]:
1391
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1392
        kvm_cmd.extend(["-usbdevice", dev])
1393

    
1394
    # Set system UUID to instance UUID
1395
    if self._UUID_RE.search(kvmhelp):
1396
      kvm_cmd.extend(["-uuid", instance.uuid])
1397

    
1398
    if hvp[constants.HV_KVM_EXTRA]:
1399
      kvm_cmd.extend([hvp[constants.HV_KVM_EXTRA]])
1400

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

    
1406
    return (kvm_cmd, kvm_nics, hvparams)
1407

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1492
    temp_files = []
1493

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

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

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

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

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

    
1548
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1549

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1662
    for filename in temp_files:
1663
      utils.RemoveFile(filename)
1664

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

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

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

    
1679
  def StartInstance(self, instance, block_devices, startup_paused):
1680
    """Start an instance.
1681

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

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

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

    
1713
    return result
1714

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

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

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

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

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

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

1749
    """
1750
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
1751

    
1752
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
1753

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

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

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

1767
    """
1768
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
1769

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

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

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

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

    
1800
  def CleanupInstance(self, instance_name):
1801
    """Cleanup after a stopped instance
1802

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

    
1809
  def RebootInstance(self, instance):
1810
    """Reboot an instance.
1811

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

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

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

1840
    """
1841
    return self._ReadKVMRuntime(instance.name)
1842

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

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

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

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

1864
    Stop the incoming mode KVM.
1865

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

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

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

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

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

1896
    The migration will not be attempted if the instance is not
1897
    currently running.
1898

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

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

    
1913
    if not live:
1914
      self._CallMonitorCommand(instance_name, "stop")
1915

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

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

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

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

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

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

    
1945
  def GetMigrationStatus(self, instance):
1946
    """Get the migration status
1947

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

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

    
1975
          return migration_status
1976

    
1977
        logging.warning("KVM: unknown migration status '%s'", status)
1978

    
1979
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1980

    
1981
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
1982

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

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

1991
    """
1992
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
1993

    
1994
  def GetNodeInfo(self, hvparams=None):
1995
    """Return information about the node.
1996

1997
    @type hvparams: dict of strings
1998
    @param hvparams: hypervisor parameters, not used in this class
1999

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

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

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

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

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

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

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

    
2054
  def Verify(self, hvparams=None):
2055
    """Verify the hypervisor.
2056

2057
    Check that the required binaries exist.
2058

2059
    @type hvparams: dict of strings
2060
    @param hvparams: hypervisor parameters to be verified against, not used here
2061

2062
    @return: Problem description if something is wrong, C{None} otherwise
2063

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

    
2075
    return self._FormatVerifyResults(msgs)
2076

    
2077
  @classmethod
2078
  def CheckParameterSyntax(cls, hvparams):
2079
    """Check the given parameters for validity.
2080

2081
    @type hvparams:  dict
2082
    @param hvparams: dictionary with parameter names/value
2083
    @raise errors.HypervisorError: when a parameter is not valid
2084

2085
    """
2086
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2087

    
2088
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2089
    if kernel_path:
2090
      if not hvparams[constants.HV_ROOT_PATH]:
2091
        raise errors.HypervisorError("Need a root partition for the instance,"
2092
                                     " if a kernel is defined")
2093

    
2094
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2095
        not hvparams[constants.HV_VNC_X509]):
2096
      raise errors.HypervisorError("%s must be defined, if %s is" %
2097
                                   (constants.HV_VNC_X509,
2098
                                    constants.HV_VNC_X509_VERIFY))
2099

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

    
2108
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2109
    if (boot_order == constants.HT_BO_CDROM and
2110
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2111
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2112
                                   " ISO path")
2113

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

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

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

    
2150
  @classmethod
2151
  def ValidateParameters(cls, hvparams):
2152
    """Check the given parameters for validity.
2153

2154
    @type hvparams:  dict
2155
    @param hvparams: dictionary with parameter names/value
2156
    @raise errors.HypervisorError: when a parameter is not valid
2157

2158
    """
2159
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2160

    
2161
    kvm_path = hvparams[constants.HV_KVM_PATH]
2162

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

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

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

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

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

    
2201
  @classmethod
2202
  def PowercycleNode(cls, hvparams=None):
2203
    """KVM powercycle, just a wrapper over Linux powercycle.
2204

2205
    @type hvparams: dict of strings
2206
    @param hvparams: hypervisor params to be used on this node
2207

2208
    """
2209
    cls.LinuxPowercycle()