Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 994ccaf2

History | View | Annotate | Download (80.9 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
    constants.HV_VNET_HDR: hv_base.NO_CHECK,
537
    }
538

    
539
  _VIRTIO = "virtio"
540
  _VIRTIO_NET_PCI = "virtio-net-pci"
541
  _VIRTIO_BLK_PCI = "virtio-blk-pci"
542

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

    
550
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
551
  _MIGRATION_INFO_RETRY_DELAY = 2
552

    
553
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
554

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

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

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

    
578
  ANCILLARY_FILES = [
579
    _KVM_NETWORK_SCRIPT,
580
    ]
581
  ANCILLARY_FILES_OPT = [
582
    _KVM_NETWORK_SCRIPT,
583
    ]
584

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

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

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

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

609
    """
610
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
611

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

616
    """
617
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
618

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

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

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

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

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

    
644
    instance = None
645
    memory = 0
646
    vcpus = 0
647

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

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

    
662
    return (instance, memory, vcpus)
663

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

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

672
    """
673
    pidfile = self._InstancePidFile(instance_name)
674
    pid = utils.ReadPidFile(pidfile)
675

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

    
683
    return (pidfile, pid, alive)
684

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

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

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

698
    """
699
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
700

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

705
    """
706
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
707

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

712
    """
713
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
714

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

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

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

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

731
    """
732
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
733

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

738
    """
739
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
740

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

746
    """
747
    return utils.PathJoin(cls._NICS_DIR, instance_name)
748

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

753
    """
754
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
755

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

760
    """
761
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
762

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

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

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

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

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

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

831
    """
832
    if instance.tags:
833
      tags = " ".join(instance.tags)
834
    else:
835
      tags = ""
836

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

    
847
    if nic.ip:
848
      env["IP"] = nic.ip
849

    
850
    if nic.nicparams[constants.NIC_LINK]:
851
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
852

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
948
    return result
949

    
950
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
951
    """Complete CPU pinning.
952

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

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

    
966
  def ListInstances(self):
967
    """Get the list of running instances.
968

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

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

    
979
  def GetInstanceInfo(self, instance_name):
980
    """Get instance properties.
981

982
    @type instance_name: string
983
    @param instance_name: the instance name
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):
1010
    """Get properties of all instances.
1011

1012
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1013

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

    
1026
  def _GenerateKVMBlockDevicesOptions(self, instance, block_devices, kvmhelp):
1027

    
1028
    hvp = instance.hvparams
1029
    boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1030
    kvm_path = hvp[constants.HV_KVM_PATH]
1031

    
1032
    # whether this is an older KVM version that uses the boot=on flag
1033
    # on devices
1034
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1035

    
1036
    dev_opts = []
1037
    device_driver = None
1038
    disk_type = hvp[constants.HV_DISK_TYPE]
1039
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
1040
      if_val = ",if=%s" % self._VIRTIO
1041
      try:
1042
        devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1043
        if self._VIRTIO_BLK_RE.search(devlist):
1044
          # TODO: uncomment when -device is used
1045
          # if_val = ",if=none"
1046
          # will be passed in -device option as driver
1047
          device_driver = self._VIRTIO_BLK_PCI
1048
      except errors.HypervisorError, _:
1049
        pass
1050
    else:
1051
      if_val = ",if=%s" % disk_type
1052
    # Cache mode
1053
    disk_cache = hvp[constants.HV_DISK_CACHE]
1054
    if instance.disk_template in constants.DTS_EXT_MIRROR:
1055
      if disk_cache != "none":
1056
        # TODO: make this a hard error, instead of a silent overwrite
1057
        logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1058
                        " to prevent shared storage corruption on migration",
1059
                        disk_cache)
1060
      cache_val = ",cache=none"
1061
    elif disk_cache != constants.HT_CACHE_DEFAULT:
1062
      cache_val = ",cache=%s" % disk_cache
1063
    else:
1064
      cache_val = ""
1065
    for cfdev, dev_path in block_devices:
1066
      if cfdev.mode != constants.DISK_RDWR:
1067
        raise errors.HypervisorError("Instance has read-only disks which"
1068
                                     " are not supported by KVM")
1069
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
1070
      boot_val = ""
1071
      if boot_disk:
1072
        dev_opts.extend(["-boot", "c"])
1073
        boot_disk = False
1074
        if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1075
          boot_val = ",boot=on"
1076
      drive_val = "file=%s,format=raw%s%s%s" % \
1077
                  (dev_path, if_val, boot_val, cache_val)
1078

    
1079
      if device_driver:
1080
        pass
1081
      dev_opts.extend(["-drive", drive_val])
1082

    
1083
    return dev_opts
1084

    
1085
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1086
                          kvmhelp):
1087
    """Generate KVM information to start an instance.
1088

1089
    @type kvmhelp: string
1090
    @param kvmhelp: output of kvm --help
1091
    @attention: this function must not have any side-effects; for
1092
        example, it must not write to the filesystem, or read values
1093
        from the current system the are expected to differ between
1094
        nodes, since it is only run once at instance startup;
1095
        actions/kvm arguments that can vary between systems should be
1096
        done in L{_ExecuteKVMRuntime}
1097

1098
    """
1099
    # pylint: disable=R0912,R0914,R0915
1100
    hvp = instance.hvparams
1101
    self.ValidateParameters(hvp)
1102

    
1103
    pidfile = self._InstancePidFile(instance.name)
1104
    kvm = hvp[constants.HV_KVM_PATH]
1105
    kvm_cmd = [kvm]
1106
    # used just by the vnc server, if enabled
1107
    kvm_cmd.extend(["-name", instance.name])
1108
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1109

    
1110
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1111
    if hvp[constants.HV_CPU_CORES]:
1112
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1113
    if hvp[constants.HV_CPU_THREADS]:
1114
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1115
    if hvp[constants.HV_CPU_SOCKETS]:
1116
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1117

    
1118
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1119

    
1120
    kvm_cmd.extend(["-pidfile", pidfile])
1121
    kvm_cmd.extend(["-balloon", "virtio"])
1122
    kvm_cmd.extend(["-daemonize"])
1123
    if not instance.hvparams[constants.HV_ACPI]:
1124
      kvm_cmd.extend(["-no-acpi"])
1125
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1126
        constants.INSTANCE_REBOOT_EXIT:
1127
      kvm_cmd.extend(["-no-reboot"])
1128

    
1129
    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1130
    if not mversion:
1131
      mversion = self._GetDefaultMachineVersion(kvm)
1132
    if self._MACHINE_RE.search(kvmhelp):
1133
      # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1134
      # extra hypervisor parameters. We should also investigate whether and how
1135
      # shadow_mem should be considered for the resource model.
1136
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1137
        specprop = ",accel=kvm"
1138
      else:
1139
        specprop = ""
1140
      machinespec = "%s%s" % (mversion, specprop)
1141
      kvm_cmd.extend(["-machine", machinespec])
1142
    else:
1143
      kvm_cmd.extend(["-M", mversion])
1144
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1145
          self._ENABLE_KVM_RE.search(kvmhelp)):
1146
        kvm_cmd.extend(["-enable-kvm"])
1147
      elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1148
            self._DISABLE_KVM_RE.search(kvmhelp)):
1149
        kvm_cmd.extend(["-disable-kvm"])
1150

    
1151
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1152
    if kernel_path:
1153
      boot_cdrom = boot_floppy = boot_network = False
1154
    else:
1155
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1156
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1157
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1158

    
1159
    if startup_paused:
1160
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1161

    
1162
    if boot_network:
1163
      kvm_cmd.extend(["-boot", "n"])
1164

    
1165
    # whether this is an older KVM version that uses the boot=on flag
1166
    # on devices
1167
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1168

    
1169
    disk_type = hvp[constants.HV_DISK_TYPE]
1170

    
1171
    #Now we can specify a different device type for CDROM devices.
1172
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1173
    if not cdrom_disk_type:
1174
      cdrom_disk_type = disk_type
1175

    
1176
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1177
    if iso_image:
1178
      options = ",format=raw,media=cdrom"
1179
      # set cdrom 'if' type
1180
      if boot_cdrom:
1181
        actual_cdrom_type = constants.HT_DISK_IDE
1182
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1183
        actual_cdrom_type = "virtio"
1184
      else:
1185
        actual_cdrom_type = cdrom_disk_type
1186
      if_val = ",if=%s" % actual_cdrom_type
1187
      # set boot flag, if needed
1188
      boot_val = ""
1189
      if boot_cdrom:
1190
        kvm_cmd.extend(["-boot", "d"])
1191
        if needs_boot_flag:
1192
          boot_val = ",boot=on"
1193
      # and finally build the entire '-drive' value
1194
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1195
      kvm_cmd.extend(["-drive", drive_val])
1196

    
1197
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1198
    if iso_image2:
1199
      options = ",format=raw,media=cdrom"
1200
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1201
        if_val = ",if=virtio"
1202
      else:
1203
        if_val = ",if=%s" % cdrom_disk_type
1204
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1205
      kvm_cmd.extend(["-drive", drive_val])
1206

    
1207
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1208
    if floppy_image:
1209
      options = ",format=raw,media=disk"
1210
      if boot_floppy:
1211
        kvm_cmd.extend(["-boot", "a"])
1212
        options = "%s,boot=on" % options
1213
      if_val = ",if=floppy"
1214
      options = "%s%s" % (options, if_val)
1215
      drive_val = "file=%s%s" % (floppy_image, options)
1216
      kvm_cmd.extend(["-drive", drive_val])
1217

    
1218
    if kernel_path:
1219
      kvm_cmd.extend(["-kernel", kernel_path])
1220
      initrd_path = hvp[constants.HV_INITRD_PATH]
1221
      if initrd_path:
1222
        kvm_cmd.extend(["-initrd", initrd_path])
1223
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1224
                     hvp[constants.HV_KERNEL_ARGS]]
1225
      if hvp[constants.HV_SERIAL_CONSOLE]:
1226
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1227
        root_append.append("console=ttyS0,%s" % serial_speed)
1228
      kvm_cmd.extend(["-append", " ".join(root_append)])
1229

    
1230
    mem_path = hvp[constants.HV_MEM_PATH]
1231
    if mem_path:
1232
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1233

    
1234
    monitor_dev = ("unix:%s,server,nowait" %
1235
                   self._InstanceMonitor(instance.name))
1236
    kvm_cmd.extend(["-monitor", monitor_dev])
1237
    if hvp[constants.HV_SERIAL_CONSOLE]:
1238
      serial_dev = ("unix:%s,server,nowait" %
1239
                    self._InstanceSerial(instance.name))
1240
      kvm_cmd.extend(["-serial", serial_dev])
1241
    else:
1242
      kvm_cmd.extend(["-serial", "none"])
1243

    
1244
    mouse_type = hvp[constants.HV_USB_MOUSE]
1245
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1246
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1247
    spice_ip_version = None
1248

    
1249
    kvm_cmd.extend(["-usb"])
1250

    
1251
    if mouse_type:
1252
      kvm_cmd.extend(["-usbdevice", mouse_type])
1253
    elif vnc_bind_address:
1254
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1255

    
1256
    if vnc_bind_address:
1257
      if netutils.IP4Address.IsValid(vnc_bind_address):
1258
        if instance.network_port > constants.VNC_BASE_PORT:
1259
          display = instance.network_port - constants.VNC_BASE_PORT
1260
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1261
            vnc_arg = ":%d" % (display)
1262
          else:
1263
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1264
        else:
1265
          logging.error("Network port is not a valid VNC display (%d < %d),"
1266
                        " not starting VNC",
1267
                        instance.network_port, constants.VNC_BASE_PORT)
1268
          vnc_arg = "none"
1269

    
1270
        # Only allow tls and other option when not binding to a file, for now.
1271
        # kvm/qemu gets confused otherwise about the filename to use.
1272
        vnc_append = ""
1273
        if hvp[constants.HV_VNC_TLS]:
1274
          vnc_append = "%s,tls" % vnc_append
1275
          if hvp[constants.HV_VNC_X509_VERIFY]:
1276
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1277
                                               hvp[constants.HV_VNC_X509])
1278
          elif hvp[constants.HV_VNC_X509]:
1279
            vnc_append = "%s,x509=%s" % (vnc_append,
1280
                                         hvp[constants.HV_VNC_X509])
1281
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1282
          vnc_append = "%s,password" % vnc_append
1283

    
1284
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1285

    
1286
      else:
1287
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1288

    
1289
      kvm_cmd.extend(["-vnc", vnc_arg])
1290
    elif spice_bind:
1291
      # FIXME: this is wrong here; the iface ip address differs
1292
      # between systems, so it should be done in _ExecuteKVMRuntime
1293
      if netutils.IsValidInterface(spice_bind):
1294
        # The user specified a network interface, we have to figure out the IP
1295
        # address.
1296
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1297
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1298

    
1299
        # if the user specified an IP version and the interface does not
1300
        # have that kind of IP addresses, throw an exception
1301
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1302
          if not addresses[spice_ip_version]:
1303
            raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1304
                                         " for %s" % (spice_ip_version,
1305
                                                      spice_bind))
1306

    
1307
        # the user did not specify an IP version, we have to figure it out
1308
        elif (addresses[constants.IP4_VERSION] and
1309
              addresses[constants.IP6_VERSION]):
1310
          # we have both ipv4 and ipv6, let's use the cluster default IP
1311
          # version
1312
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1313
          spice_ip_version = \
1314
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1315
        elif addresses[constants.IP4_VERSION]:
1316
          spice_ip_version = constants.IP4_VERSION
1317
        elif addresses[constants.IP6_VERSION]:
1318
          spice_ip_version = constants.IP6_VERSION
1319
        else:
1320
          raise errors.HypervisorError("SPICE: Unable to get an IP address"
1321
                                       " for %s" % (spice_bind))
1322

    
1323
        spice_address = addresses[spice_ip_version][0]
1324

    
1325
      else:
1326
        # spice_bind is known to be a valid IP address, because
1327
        # ValidateParameters checked it.
1328
        spice_address = spice_bind
1329

    
1330
      spice_arg = "addr=%s" % spice_address
1331
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1332
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1333
                     (spice_arg, instance.network_port,
1334
                      pathutils.SPICE_CACERT_FILE))
1335
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1336
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1337
                      pathutils.SPICE_CERT_FILE))
1338
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1339
        if tls_ciphers:
1340
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1341
      else:
1342
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1343

    
1344
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1345
        spice_arg = "%s,disable-ticketing" % spice_arg
1346

    
1347
      if spice_ip_version:
1348
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1349

    
1350
      # Image compression options
1351
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1352
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1353
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1354
      if img_lossless:
1355
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1356
      if img_jpeg:
1357
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1358
      if img_zlib_glz:
1359
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1360

    
1361
      # Video stream detection
1362
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1363
      if video_streaming:
1364
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1365

    
1366
      # Audio compression, by default in qemu-kvm it is on
1367
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1368
        spice_arg = "%s,playback-compression=off" % spice_arg
1369
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1370
        spice_arg = "%s,agent-mouse=off" % spice_arg
1371
      else:
1372
        # Enable the spice agent communication channel between the host and the
1373
        # agent.
1374
        kvm_cmd.extend(["-device", "virtio-serial-pci"])
1375
        kvm_cmd.extend([
1376
          "-device",
1377
          "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1378
          ])
1379
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1380

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

    
1384
    else:
1385
      # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1386
      # also works in earlier versions though (tested with 1.1 and 1.3)
1387
      if self._DISPLAY_RE.search(kvmhelp):
1388
        kvm_cmd.extend(["-display", "none"])
1389
      else:
1390
        kvm_cmd.extend(["-nographic"])
1391

    
1392
    if hvp[constants.HV_USE_LOCALTIME]:
1393
      kvm_cmd.extend(["-localtime"])
1394

    
1395
    if hvp[constants.HV_KVM_USE_CHROOT]:
1396
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1397

    
1398
    # Add qemu-KVM -cpu param
1399
    if hvp[constants.HV_CPU_TYPE]:
1400
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1401

    
1402
    # As requested by music lovers
1403
    if hvp[constants.HV_SOUNDHW]:
1404
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1405

    
1406
    # Pass a -vga option if requested, or if spice is used, for backwards
1407
    # compatibility.
1408
    if hvp[constants.HV_VGA]:
1409
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1410
    elif spice_bind:
1411
      kvm_cmd.extend(["-vga", "qxl"])
1412

    
1413
    # Various types of usb devices, comma separated
1414
    if hvp[constants.HV_USB_DEVICES]:
1415
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1416
        kvm_cmd.extend(["-usbdevice", dev])
1417

    
1418
    if hvp[constants.HV_KVM_EXTRA]:
1419
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1420

    
1421
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1422
                                                     block_devices,
1423
                                                     kvmhelp)
1424
    kvm_cmd.extend(bdev_opts)
1425
    # Save the current instance nics, but defer their expansion as parameters,
1426
    # as we'll need to generate executable temp files for them.
1427
    kvm_nics = instance.nics
1428
    hvparams = hvp
1429

    
1430
    return (kvm_cmd, kvm_nics, hvparams)
1431

    
1432
  def _WriteKVMRuntime(self, instance_name, data):
1433
    """Write an instance's KVM runtime
1434

1435
    """
1436
    try:
1437
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1438
                      data=data)
1439
    except EnvironmentError, err:
1440
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1441

    
1442
  def _ReadKVMRuntime(self, instance_name):
1443
    """Read an instance's KVM runtime
1444

1445
    """
1446
    try:
1447
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1448
    except EnvironmentError, err:
1449
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1450
    return file_content
1451

    
1452
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1453
    """Save an instance's KVM runtime
1454

1455
    """
1456
    kvm_cmd, kvm_nics, hvparams = kvm_runtime
1457
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1458
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1459
    self._WriteKVMRuntime(instance.name, serialized_form)
1460

    
1461
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1462
    """Load an instance's KVM runtime
1463

1464
    """
1465
    if not serialized_runtime:
1466
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1467
    loaded_runtime = serializer.Load(serialized_runtime)
1468
    kvm_cmd, serialized_nics, hvparams = loaded_runtime
1469
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1470
    return (kvm_cmd, kvm_nics, hvparams)
1471

    
1472
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1473
    """Run the KVM cmd and check for errors
1474

1475
    @type name: string
1476
    @param name: instance name
1477
    @type kvm_cmd: list of strings
1478
    @param kvm_cmd: runcmd input for kvm
1479
    @type tap_fds: list of int
1480
    @param tap_fds: fds of tap devices opened by Ganeti
1481

1482
    """
1483
    try:
1484
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1485
    finally:
1486
      for fd in tap_fds:
1487
        utils_wrapper.CloseFdNoError(fd)
1488

    
1489
    if result.failed:
1490
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1491
                                   (name, result.fail_reason, result.output))
1492
    if not self._InstancePidAlive(name)[2]:
1493
      raise errors.HypervisorError("Failed to start instance %s" % name)
1494

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

1498
    @type incoming: tuple of strings
1499
    @param incoming: (target_host_ip, port)
1500
    @type kvmhelp: string
1501
    @param kvmhelp: output of kvm --help
1502

1503
    """
1504
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1505
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1506
    #    have changed since the instance started; only use them if the change
1507
    #    won't affect the inside of the instance (which hasn't been rebooted).
1508
    #  - up_hvp contains the parameters as they were when the instance was
1509
    #    started, plus any new parameter which has been added between ganeti
1510
    #    versions: it is paramount that those default to a value which won't
1511
    #    affect the inside of the instance as well.
1512
    conf_hvp = instance.hvparams
1513
    name = instance.name
1514
    self._CheckDown(name)
1515

    
1516
    temp_files = []
1517

    
1518
    kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1519
    # the first element of kvm_cmd is always the path to the kvm binary
1520
    kvm_path = kvm_cmd[0]
1521
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1522

    
1523
    # We know it's safe to run as a different user upon migration, so we'll use
1524
    # the latest conf, from conf_hvp.
1525
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1526
    if security_model == constants.HT_SM_USER:
1527
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1528

    
1529
    keymap = conf_hvp[constants.HV_KEYMAP]
1530
    if keymap:
1531
      keymap_path = self._InstanceKeymapFile(name)
1532
      # If a keymap file is specified, KVM won't use its internal defaults. By
1533
      # first including the "en-us" layout, an error on loading the actual
1534
      # layout (e.g. because it can't be found) won't lead to a non-functional
1535
      # keyboard. A keyboard with incorrect keys is still better than none.
1536
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1537
      kvm_cmd.extend(["-k", keymap_path])
1538

    
1539
    # We have reasons to believe changing something like the nic driver/type
1540
    # upon migration won't exactly fly with the instance kernel, so for nic
1541
    # related parameters we'll use up_hvp
1542
    tapfds = []
1543
    taps = []
1544
    if not kvm_nics:
1545
      kvm_cmd.extend(["-net", "none"])
1546
    else:
1547
      vnet_hdr = False
1548
      tap_extra = ""
1549
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1550
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1551
        nic_model = self._VIRTIO
1552
        try:
1553
          devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1554
          if self._VIRTIO_NET_RE.search(devlist):
1555
            nic_model = self._VIRTIO_NET_PCI
1556
            vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1557
        except errors.HypervisorError, _:
1558
          # Older versions of kvm don't support DEVICE_LIST, but they don't
1559
          # have new virtio syntax either.
1560
          pass
1561

    
1562
        if up_hvp[constants.HV_VHOST_NET]:
1563
          # check for vhost_net support
1564
          if self._VHOST_RE.search(kvmhelp):
1565
            tap_extra = ",vhost=on"
1566
          else:
1567
            raise errors.HypervisorError("vhost_net is configured"
1568
                                         " but it is not available")
1569
      else:
1570
        nic_model = nic_type
1571

    
1572
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1573

    
1574
      for nic_seq, nic in enumerate(kvm_nics):
1575
        tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1576
        tapfds.append(tapfd)
1577
        taps.append(tapname)
1578
        if kvm_supports_netdev:
1579
          nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1580
          tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1581
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1582
        else:
1583
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1584
                                                         nic.mac, nic_model)
1585
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1586
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1587

    
1588
    if incoming:
1589
      target, port = incoming
1590
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1591

    
1592
    # Changing the vnc password doesn't bother the guest that much. At most it
1593
    # will surprise people who connect to it. Whether positively or negatively
1594
    # it's debatable.
1595
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1596
    vnc_pwd = None
1597
    if vnc_pwd_file:
1598
      try:
1599
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1600
      except EnvironmentError, err:
1601
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1602
                                     % (vnc_pwd_file, err))
1603

    
1604
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1605
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1606
                         constants.SECURE_DIR_MODE)])
1607

    
1608
    # Automatically enable QMP if version is >= 0.14
1609
    if self._QMP_RE.search(kvmhelp):
1610
      logging.debug("Enabling QMP")
1611
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1612
                      self._InstanceQmpMonitor(instance.name)])
1613

    
1614
    # Configure the network now for starting instances and bridged interfaces,
1615
    # during FinalizeMigration for incoming instances' routed interfaces
1616
    for nic_seq, nic in enumerate(kvm_nics):
1617
      if (incoming and
1618
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1619
        continue
1620
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1621

    
1622
    # CPU affinity requires kvm to start paused, so we set this flag if the
1623
    # instance is not already paused and if we are not going to accept a
1624
    # migrating instance. In the latter case, pausing is not needed.
1625
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1626
    if start_kvm_paused:
1627
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1628

    
1629
    # Note: CPU pinning is using up_hvp since changes take effect
1630
    # during instance startup anyway, and to avoid problems when soft
1631
    # rebooting the instance.
1632
    cpu_pinning = False
1633
    if up_hvp.get(constants.HV_CPU_MASK, None):
1634
      cpu_pinning = True
1635

    
1636
    if security_model == constants.HT_SM_POOL:
1637
      ss = ssconf.SimpleStore()
1638
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1639
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1640
      uid = uidpool.RequestUnusedUid(all_uids)
1641
      try:
1642
        username = pwd.getpwuid(uid.GetUid()).pw_name
1643
        kvm_cmd.extend(["-runas", username])
1644
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1645
      except:
1646
        uidpool.ReleaseUid(uid)
1647
        raise
1648
      else:
1649
        uid.Unlock()
1650
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1651
    else:
1652
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1653

    
1654
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1655
                     constants.RUN_DIRS_MODE)])
1656
    for nic_seq, tap in enumerate(taps):
1657
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1658
                      data=tap)
1659

    
1660
    if vnc_pwd:
1661
      change_cmd = "change vnc password %s" % vnc_pwd
1662
      self._CallMonitorCommand(instance.name, change_cmd)
1663

    
1664
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1665
    # connection attempts because SPICE by default does not allow connections
1666
    # if neither a password nor the "disable_ticketing" options are specified.
1667
    # As soon as we send the password via QMP, that password is a valid ticket
1668
    # for connection.
1669
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1670
    if spice_password_file:
1671
      spice_pwd = ""
1672
      try:
1673
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1674
      except EnvironmentError, err:
1675
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1676
                                     % (spice_password_file, err))
1677

    
1678
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1679
      qmp.connect()
1680
      arguments = {
1681
          "protocol": "spice",
1682
          "password": spice_pwd,
1683
      }
1684
      qmp.Execute("set_password", arguments)
1685

    
1686
    for filename in temp_files:
1687
      utils.RemoveFile(filename)
1688

    
1689
    # If requested, set CPU affinity and resume instance execution
1690
    if cpu_pinning:
1691
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1692

    
1693
    start_memory = self._InstanceStartupMemory(instance)
1694
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1695
      self.BalloonInstanceMemory(instance, start_memory)
1696

    
1697
    if start_kvm_paused:
1698
      # To control CPU pinning, ballooning, and vnc/spice passwords
1699
      # the VM was started in a frozen state. If freezing was not
1700
      # explicitly requested resume the vm status.
1701
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1702

    
1703
  def StartInstance(self, instance, block_devices, startup_paused):
1704
    """Start an instance.
1705

1706
    """
1707
    self._CheckDown(instance.name)
1708
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1709
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1710
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1711
                                           startup_paused, kvmhelp)
1712
    self._SaveKVMRuntime(instance, kvm_runtime)
1713
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1714

    
1715
  def _CallMonitorCommand(self, instance_name, command):
1716
    """Invoke a command on the instance monitor.
1717

1718
    """
1719
    # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1720
    # version. The monitor protocol is designed for human consumption, whereas
1721
    # QMP is made for programmatic usage. In the worst case QMP can also
1722
    # execute monitor commands. As it is, all calls to socat take at least
1723
    # 500ms and likely more: socat can't detect the end of the reply and waits
1724
    # for 500ms of no data received before exiting (500 ms is the default for
1725
    # the "-t" parameter).
1726
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1727
             (utils.ShellQuote(command),
1728
              constants.SOCAT_PATH,
1729
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1730
    result = utils.RunCmd(socat)
1731
    if result.failed:
1732
      msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1733
             " output: %s" %
1734
             (command, instance_name, result.fail_reason, result.output))
1735
      raise errors.HypervisorError(msg)
1736

    
1737
    return result
1738

    
1739
  @classmethod
1740
  def _ParseKVMVersion(cls, text):
1741
    """Parse the KVM version from the --help output.
1742

1743
    @type text: string
1744
    @param text: output of kvm --help
1745
    @return: (version, v_maj, v_min, v_rev)
1746
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1747

1748
    """
1749
    match = cls._VERSION_RE.search(text.splitlines()[0])
1750
    if not match:
1751
      raise errors.HypervisorError("Unable to get KVM version")
1752

    
1753
    v_all = match.group(0)
1754
    v_maj = int(match.group(1))
1755
    v_min = int(match.group(2))
1756
    if match.group(4):
1757
      v_rev = int(match.group(4))
1758
    else:
1759
      v_rev = 0
1760
    return (v_all, v_maj, v_min, v_rev)
1761

    
1762
  @classmethod
1763
  def _GetKVMOutput(cls, kvm_path, option):
1764
    """Return the output of a kvm invocation
1765

1766
    @type kvm_path: string
1767
    @param kvm_path: path to the kvm executable
1768
    @type option: a key of _KVMOPTS_CMDS
1769
    @param option: kvm option to fetch the output from
1770
    @return: output a supported kvm invocation
1771
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1772

1773
    """
1774
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
1775

    
1776
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
1777

    
1778
    result = utils.RunCmd([kvm_path] + optlist)
1779
    if result.failed and not can_fail:
1780
      raise errors.HypervisorError("Unable to get KVM %s output" %
1781
                                    " ".join(optlist))
1782
    return result.output
1783

    
1784
  @classmethod
1785
  def _GetKVMVersion(cls, kvm_path):
1786
    """Return the installed KVM version.
1787

1788
    @return: (version, v_maj, v_min, v_rev)
1789
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1790

1791
    """
1792
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
1793

    
1794
  @classmethod
1795
  def _GetDefaultMachineVersion(cls, kvm_path):
1796
    """Return the default hardware revision (e.g. pc-1.1)
1797

1798
    """
1799
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
1800
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
1801
    if match:
1802
      return match.group(1)
1803
    else:
1804
      return "pc"
1805

    
1806
  def StopInstance(self, instance, force=False, retry=False, name=None):
1807
    """Stop an instance.
1808

1809
    """
1810
    if name is not None and not force:
1811
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1812
    if name is None:
1813
      name = instance.name
1814
      acpi = instance.hvparams[constants.HV_ACPI]
1815
    else:
1816
      acpi = False
1817
    _, pid, alive = self._InstancePidAlive(name)
1818
    if pid > 0 and alive:
1819
      if force or not acpi:
1820
        utils.KillProcess(pid)
1821
      else:
1822
        self._CallMonitorCommand(name, "system_powerdown")
1823

    
1824
  def CleanupInstance(self, instance_name):
1825
    """Cleanup after a stopped instance
1826

1827
    """
1828
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
1829
    if pid > 0 and alive:
1830
      raise errors.HypervisorError("Cannot cleanup a live instance")
1831
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1832

    
1833
  def RebootInstance(self, instance):
1834
    """Reboot an instance.
1835

1836
    """
1837
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1838
    # socket the instance will stop, but now power up again. So we'll resort
1839
    # to shutdown and restart.
1840
    _, _, alive = self._InstancePidAlive(instance.name)
1841
    if not alive:
1842
      raise errors.HypervisorError("Failed to reboot instance %s:"
1843
                                   " not running" % instance.name)
1844
    # StopInstance will delete the saved KVM runtime so:
1845
    # ...first load it...
1846
    kvm_runtime = self._LoadKVMRuntime(instance)
1847
    # ...now we can safely call StopInstance...
1848
    if not self.StopInstance(instance):
1849
      self.StopInstance(instance, force=True)
1850
    # ...and finally we can save it again, and execute it...
1851
    self._SaveKVMRuntime(instance, kvm_runtime)
1852
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1853
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1854
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1855

    
1856
  def MigrationInfo(self, instance):
1857
    """Get instance information to perform a migration.
1858

1859
    @type instance: L{objects.Instance}
1860
    @param instance: instance to be migrated
1861
    @rtype: string
1862
    @return: content of the KVM runtime file
1863

1864
    """
1865
    return self._ReadKVMRuntime(instance.name)
1866

    
1867
  def AcceptInstance(self, instance, info, target):
1868
    """Prepare to accept an instance.
1869

1870
    @type instance: L{objects.Instance}
1871
    @param instance: instance to be accepted
1872
    @type info: string
1873
    @param info: content of the KVM runtime file on the source node
1874
    @type target: string
1875
    @param target: target host (usually ip), on this node
1876

1877
    """
1878
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1879
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1880
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1881
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1882
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
1883
                            incoming=incoming_address)
1884

    
1885
  def FinalizeMigrationDst(self, instance, info, success):
1886
    """Finalize the instance migration on the target node.
1887

1888
    Stop the incoming mode KVM.
1889

1890
    @type instance: L{objects.Instance}
1891
    @param instance: instance whose migration is being finalized
1892

1893
    """
1894
    if success:
1895
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1896
      kvm_nics = kvm_runtime[1]
1897

    
1898
      for nic_seq, nic in enumerate(kvm_nics):
1899
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1900
          # Bridged interfaces have already been configured
1901
          continue
1902
        try:
1903
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1904
        except EnvironmentError, err:
1905
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
1906
                          instance.name, nic_seq, str(err))
1907
          continue
1908
        try:
1909
          self._ConfigureNIC(instance, nic_seq, nic, tap)
1910
        except errors.HypervisorError, err:
1911
          logging.warning(str(err))
1912

    
1913
      self._WriteKVMRuntime(instance.name, info)
1914
    else:
1915
      self.StopInstance(instance, force=True)
1916

    
1917
  def MigrateInstance(self, instance, target, live):
1918
    """Migrate an instance to a target node.
1919

1920
    The migration will not be attempted if the instance is not
1921
    currently running.
1922

1923
    @type instance: L{objects.Instance}
1924
    @param instance: the instance to be migrated
1925
    @type target: string
1926
    @param target: ip address of the target node
1927
    @type live: boolean
1928
    @param live: perform a live migration
1929

1930
    """
1931
    instance_name = instance.name
1932
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
1933
    _, _, alive = self._InstancePidAlive(instance_name)
1934
    if not alive:
1935
      raise errors.HypervisorError("Instance not running, cannot migrate")
1936

    
1937
    if not live:
1938
      self._CallMonitorCommand(instance_name, "stop")
1939

    
1940
    migrate_command = ("migrate_set_speed %dm" %
1941
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1942
    self._CallMonitorCommand(instance_name, migrate_command)
1943

    
1944
    migrate_command = ("migrate_set_downtime %dms" %
1945
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1946
    self._CallMonitorCommand(instance_name, migrate_command)
1947

    
1948
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1949
    self._CallMonitorCommand(instance_name, migrate_command)
1950

    
1951
  def FinalizeMigrationSource(self, instance, success, live):
1952
    """Finalize the instance migration on the source node.
1953

1954
    @type instance: L{objects.Instance}
1955
    @param instance: the instance that was migrated
1956
    @type success: bool
1957
    @param success: whether the migration succeeded or not
1958
    @type live: bool
1959
    @param live: whether the user requested a live migration or not
1960

1961
    """
1962
    if success:
1963
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
1964
      utils.KillProcess(pid)
1965
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1966
    elif live:
1967
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1968

    
1969
  def GetMigrationStatus(self, instance):
1970
    """Get the migration status
1971

1972
    @type instance: L{objects.Instance}
1973
    @param instance: the instance that is being migrated
1974
    @rtype: L{objects.MigrationStatus}
1975
    @return: the status of the current migration (one of
1976
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1977
             progress info that can be retrieved from the hypervisor
1978

1979
    """
1980
    info_command = "info migrate"
1981
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
1982
      result = self._CallMonitorCommand(instance.name, info_command)
1983
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
1984
      if not match:
1985
        if not result.stdout:
1986
          logging.info("KVM: empty 'info migrate' result")
1987
        else:
1988
          logging.warning("KVM: unknown 'info migrate' result: %s",
1989
                          result.stdout)
1990
      else:
1991
        status = match.group(1)
1992
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
1993
          migration_status = objects.MigrationStatus(status=status)
1994
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
1995
          if match:
1996
            migration_status.transferred_ram = match.group("transferred")
1997
            migration_status.total_ram = match.group("total")
1998

    
1999
          return migration_status
2000

    
2001
        logging.warning("KVM: unknown migration status '%s'", status)
2002

    
2003
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2004

    
2005
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2006

    
2007
  def BalloonInstanceMemory(self, instance, mem):
2008
    """Balloon an instance memory to a certain value.
2009

2010
    @type instance: L{objects.Instance}
2011
    @param instance: instance to be accepted
2012
    @type mem: int
2013
    @param mem: actual memory size to use for instance runtime
2014

2015
    """
2016
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2017

    
2018
  def GetNodeInfo(self):
2019
    """Return information about the node.
2020

2021
    @return: a dict with the following keys (values in MiB):
2022
          - memory_total: the total memory size on the node
2023
          - memory_free: the available memory on the node for instances
2024
          - memory_dom0: the memory used by the node itself, if available
2025
          - hv_version: the hypervisor version in the form (major, minor,
2026
                        revision)
2027

2028
    """
2029
    result = self.GetLinuxNodeInfo()
2030
    # FIXME: this is the global kvm version, but the actual version can be
2031
    # customized as an hv parameter. we should use the nodegroup's default kvm
2032
    # path parameter here.
2033
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2034
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2035
    return result
2036

    
2037
  @classmethod
2038
  def GetInstanceConsole(cls, instance, hvparams, beparams):
2039
    """Return a command for connecting to the console of an instance.
2040

2041
    """
2042
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2043
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2044
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2045
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2046
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2047
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2048
      return objects.InstanceConsole(instance=instance.name,
2049
                                     kind=constants.CONS_SSH,
2050
                                     host=instance.primary_node,
2051
                                     user=constants.SSH_CONSOLE_USER,
2052
                                     command=cmd)
2053

    
2054
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2055
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2056
      display = instance.network_port - constants.VNC_BASE_PORT
2057
      return objects.InstanceConsole(instance=instance.name,
2058
                                     kind=constants.CONS_VNC,
2059
                                     host=vnc_bind_address,
2060
                                     port=instance.network_port,
2061
                                     display=display)
2062

    
2063
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2064
    if spice_bind:
2065
      return objects.InstanceConsole(instance=instance.name,
2066
                                     kind=constants.CONS_SPICE,
2067
                                     host=spice_bind,
2068
                                     port=instance.network_port)
2069

    
2070
    return objects.InstanceConsole(instance=instance.name,
2071
                                   kind=constants.CONS_MESSAGE,
2072
                                   message=("No serial shell for instance %s" %
2073
                                            instance.name))
2074

    
2075
  def Verify(self):
2076
    """Verify the hypervisor.
2077

2078
    Check that the required binaries exist.
2079

2080
    @return: Problem description if something is wrong, C{None} otherwise
2081

2082
    """
2083
    msgs = []
2084
    # FIXME: this is the global kvm binary, but the actual path can be
2085
    # customized as an hv parameter; we should use the nodegroup's
2086
    # default kvm path parameter here.
2087
    if not os.path.exists(constants.KVM_PATH):
2088
      msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2089
    if not os.path.exists(constants.SOCAT_PATH):
2090
      msgs.append("The socat binary ('%s') does not exist" %
2091
                  constants.SOCAT_PATH)
2092

    
2093
    return self._FormatVerifyResults(msgs)
2094

    
2095
  @classmethod
2096
  def CheckParameterSyntax(cls, hvparams):
2097
    """Check the given parameters for validity.
2098

2099
    @type hvparams:  dict
2100
    @param hvparams: dictionary with parameter names/value
2101
    @raise errors.HypervisorError: when a parameter is not valid
2102

2103
    """
2104
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2105

    
2106
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2107
    if kernel_path:
2108
      if not hvparams[constants.HV_ROOT_PATH]:
2109
        raise errors.HypervisorError("Need a root partition for the instance,"
2110
                                     " if a kernel is defined")
2111

    
2112
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2113
        not hvparams[constants.HV_VNC_X509]):
2114
      raise errors.HypervisorError("%s must be defined, if %s is" %
2115
                                   (constants.HV_VNC_X509,
2116
                                    constants.HV_VNC_X509_VERIFY))
2117

    
2118
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2119
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2120
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2121
      if not serial_speed or serial_speed not in valid_speeds:
2122
        raise errors.HypervisorError("Invalid serial console speed, must be"
2123
                                     " one of: %s" %
2124
                                     utils.CommaJoin(valid_speeds))
2125

    
2126
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2127
    if (boot_order == constants.HT_BO_CDROM and
2128
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2129
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2130
                                   " ISO path")
2131

    
2132
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2133
    if security_model == constants.HT_SM_USER:
2134
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2135
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2136
                                     " must be specified")
2137
    elif (security_model == constants.HT_SM_NONE or
2138
          security_model == constants.HT_SM_POOL):
2139
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2140
        raise errors.HypervisorError("Cannot have a security domain when the"
2141
                                     " security model is 'none' or 'pool'")
2142

    
2143
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2144
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2145
    if spice_bind:
2146
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2147
        # if an IP version is specified, the spice_bind parameter must be an
2148
        # IP of that family
2149
        if (netutils.IP4Address.IsValid(spice_bind) and
2150
            spice_ip_version != constants.IP4_VERSION):
2151
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2152
                                       " the specified IP version is %s" %
2153
                                       (spice_bind, spice_ip_version))
2154

    
2155
        if (netutils.IP6Address.IsValid(spice_bind) and
2156
            spice_ip_version != constants.IP6_VERSION):
2157
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2158
                                       " the specified IP version is %s" %
2159
                                       (spice_bind, spice_ip_version))
2160
    else:
2161
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2162
      # error if any of them is set without it.
2163
      for param in _SPICE_ADDITIONAL_PARAMS:
2164
        if hvparams[param]:
2165
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2166
                                       (param, constants.HV_KVM_SPICE_BIND))
2167

    
2168
  @classmethod
2169
  def ValidateParameters(cls, hvparams):
2170
    """Check the given parameters for validity.
2171

2172
    @type hvparams:  dict
2173
    @param hvparams: dictionary with parameter names/value
2174
    @raise errors.HypervisorError: when a parameter is not valid
2175

2176
    """
2177
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2178

    
2179
    kvm_path = hvparams[constants.HV_KVM_PATH]
2180

    
2181
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2182
    if security_model == constants.HT_SM_USER:
2183
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2184
      try:
2185
        pwd.getpwnam(username)
2186
      except KeyError:
2187
        raise errors.HypervisorError("Unknown security domain user %s"
2188
                                     % username)
2189

    
2190
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2191
    if spice_bind:
2192
      # only one of VNC and SPICE can be used currently.
2193
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2194
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2195
                                     " only one of them can be used at a"
2196
                                     " given time")
2197

    
2198
      # check that KVM supports SPICE
2199
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2200
      if not cls._SPICE_RE.search(kvmhelp):
2201
        raise errors.HypervisorError("SPICE is configured, but it is not"
2202
                                     " supported according to 'kvm --help'")
2203

    
2204
      # if spice_bind is not an IP address, it must be a valid interface
2205
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2206
                       netutils.IP6Address.IsValid(spice_bind))
2207
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2208
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2209
                                     " a valid IP address or interface name" %
2210
                                     constants.HV_KVM_SPICE_BIND)
2211

    
2212
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2213
    if machine_version:
2214
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2215
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2216
        raise errors.HypervisorError("Unsupported machine version: %s" %
2217
                                     machine_version)
2218

    
2219
  @classmethod
2220
  def PowercycleNode(cls):
2221
    """KVM powercycle, just a wrapper over Linux powercycle.
2222

2223
    """
2224
    cls.LinuxPowercycle()