Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 02d17fe3

History | View | Annotate | Download (81.4 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
  def __len__(self):
198
    """Return the number of fields stored in this QmpMessage.
199

200
    """
201
    return len(self.data)
202

    
203
  def __delitem__(self, key):
204
    """Delete the specified element from the QmpMessage.
205

206
    """
207
    del(self.data[key])
208

    
209
  @staticmethod
210
  def BuildFromJsonString(json_string):
211
    """Build a QmpMessage from a JSON encoded string.
212

213
    @type json_string: str
214
    @param json_string: JSON string representing the message
215
    @rtype: L{QmpMessage}
216
    @return: a L{QmpMessage} built from json_string
217

218
    """
219
    # Parse the string
220
    data = serializer.LoadJson(json_string)
221
    return QmpMessage(data)
222

    
223
  def __str__(self):
224
    # The protocol expects the JSON object to be sent as a single line.
225
    return serializer.DumpJson(self.data)
226

    
227
  def __eq__(self, other):
228
    # When comparing two QmpMessages, we are interested in comparing
229
    # their internal representation of the message data
230
    return self.data == other.data
231

    
232

    
233
class QmpConnection:
234
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
235

236
  """
237
  _FIRST_MESSAGE_KEY = "QMP"
238
  _EVENT_KEY = "event"
239
  _ERROR_KEY = "error"
240
  _RETURN_KEY = RETURN_KEY = "return"
241
  _ACTUAL_KEY = ACTUAL_KEY = "actual"
242
  _ERROR_CLASS_KEY = "class"
243
  _ERROR_DESC_KEY = "desc"
244
  _EXECUTE_KEY = "execute"
245
  _ARGUMENTS_KEY = "arguments"
246
  _CAPABILITIES_COMMAND = "qmp_capabilities"
247
  _MESSAGE_END_TOKEN = "\r\n"
248
  _SOCKET_TIMEOUT = 5
249

    
250
  def __init__(self, monitor_filename):
251
    """Instantiates the QmpConnection object.
252

253
    @type monitor_filename: string
254
    @param monitor_filename: the filename of the UNIX raw socket on which the
255
                             QMP monitor is listening
256

257
    """
258
    self.monitor_filename = monitor_filename
259
    self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
260
    # We want to fail if the server doesn't send a complete message
261
    # in a reasonable amount of time
262
    self.sock.settimeout(self._SOCKET_TIMEOUT)
263
    self._connected = False
264
    self._buf = ""
265

    
266
  def _check_socket(self):
267
    sock_stat = None
268
    try:
269
      sock_stat = os.stat(self.monitor_filename)
270
    except EnvironmentError, err:
271
      if err.errno == errno.ENOENT:
272
        raise errors.HypervisorError("No qmp socket found")
273
      else:
274
        raise errors.HypervisorError("Error checking qmp socket: %s",
275
                                     utils.ErrnoOrStr(err))
276
    if not stat.S_ISSOCK(sock_stat.st_mode):
277
      raise errors.HypervisorError("Qmp socket is not a socket")
278

    
279
  def _check_connection(self):
280
    """Make sure that the connection is established.
281

282
    """
283
    if not self._connected:
284
      raise errors.ProgrammerError("To use a QmpConnection you need to first"
285
                                   " invoke connect() on it")
286

    
287
  def connect(self):
288
    """Connects to the QMP monitor.
289

290
    Connects to the UNIX socket and makes sure that we can actually send and
291
    receive data to the kvm instance via QMP.
292

293
    @raise errors.HypervisorError: when there are communication errors
294
    @raise errors.ProgrammerError: when there are data serialization errors
295

296
    """
297
    if self._connected:
298
      raise errors.ProgrammerError("Cannot connect twice")
299

    
300
    self._check_socket()
301

    
302
    # Check file existance/stuff
303
    try:
304
      self.sock.connect(self.monitor_filename)
305
    except EnvironmentError:
306
      raise errors.HypervisorError("Can't connect to qmp socket")
307
    self._connected = True
308

    
309
    # Check if we receive a correct greeting message from the server
310
    # (As per the QEMU Protocol Specification 0.1 - section 2.2)
311
    greeting = self._Recv()
312
    if not greeting[self._FIRST_MESSAGE_KEY]:
313
      self._connected = False
314
      raise errors.HypervisorError("kvm: QMP communication error (wrong"
315
                                   " server greeting")
316

    
317
    # Let's put the monitor in command mode using the qmp_capabilities
318
    # command, or else no command will be executable.
319
    # (As per the QEMU Protocol Specification 0.1 - section 4)
320
    self.Execute(self._CAPABILITIES_COMMAND)
321

    
322
  def _ParseMessage(self, buf):
323
    """Extract and parse a QMP message from the given buffer.
324

325
    Seeks for a QMP message in the given buf. If found, it parses it and
326
    returns it together with the rest of the characters in the buf.
327
    If no message is found, returns None and the whole buffer.
328

329
    @raise errors.ProgrammerError: when there are data serialization errors
330

331
    """
332
    message = None
333
    # Check if we got the message end token (CRLF, as per the QEMU Protocol
334
    # Specification 0.1 - Section 2.1.1)
335
    pos = buf.find(self._MESSAGE_END_TOKEN)
336
    if pos >= 0:
337
      try:
338
        message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
339
      except Exception, err:
340
        raise errors.ProgrammerError("QMP data serialization error: %s" % err)
341
      buf = buf[pos + 1:]
342

    
343
    return (message, buf)
344

    
345
  def _Recv(self):
346
    """Receives a message from QMP and decodes the received JSON object.
347

348
    @rtype: QmpMessage
349
    @return: the received message
350
    @raise errors.HypervisorError: when there are communication errors
351
    @raise errors.ProgrammerError: when there are data serialization errors
352

353
    """
354
    self._check_connection()
355

    
356
    # Check if there is already a message in the buffer
357
    (message, self._buf) = self._ParseMessage(self._buf)
358
    if message:
359
      return message
360

    
361
    recv_buffer = StringIO.StringIO(self._buf)
362
    recv_buffer.seek(len(self._buf))
363
    try:
364
      while True:
365
        data = self.sock.recv(4096)
366
        if not data:
367
          break
368
        recv_buffer.write(data)
369

    
370
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
371
        if message:
372
          return message
373

    
374
    except socket.timeout, err:
375
      raise errors.HypervisorError("Timeout while receiving a QMP message: "
376
                                   "%s" % (err))
377
    except socket.error, err:
378
      raise errors.HypervisorError("Unable to receive data from KVM using the"
379
                                   " QMP protocol: %s" % err)
380

    
381
  def _Send(self, message):
382
    """Encodes and sends a message to KVM using QMP.
383

384
    @type message: QmpMessage
385
    @param message: message to send to KVM
386
    @raise errors.HypervisorError: when there are communication errors
387
    @raise errors.ProgrammerError: when there are data serialization errors
388

389
    """
390
    self._check_connection()
391
    try:
392
      message_str = str(message)
393
    except Exception, err:
394
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
395

    
396
    try:
397
      self.sock.sendall(message_str)
398
    except socket.timeout, err:
399
      raise errors.HypervisorError("Timeout while sending a QMP message: "
400
                                   "%s (%s)" % (err.string, err.errno))
401
    except socket.error, err:
402
      raise errors.HypervisorError("Unable to send data from KVM using the"
403
                                   " QMP protocol: %s" % err)
404

    
405
  def Execute(self, command, arguments=None):
406
    """Executes a QMP command and returns the response of the server.
407

408
    @type command: str
409
    @param command: the command to execute
410
    @type arguments: dict
411
    @param arguments: dictionary of arguments to be passed to the command
412
    @rtype: dict
413
    @return: dictionary representing the received JSON object
414
    @raise errors.HypervisorError: when there are communication errors
415
    @raise errors.ProgrammerError: when there are data serialization errors
416

417
    """
418
    self._check_connection()
419
    message = QmpMessage({self._EXECUTE_KEY: command})
420
    if arguments:
421
      message[self._ARGUMENTS_KEY] = arguments
422
    self._Send(message)
423

    
424
    # Events can occur between the sending of the command and the reception
425
    # of the response, so we need to filter out messages with the event key.
426
    while True:
427
      response = self._Recv()
428
      err = response[self._ERROR_KEY]
429
      if err:
430
        raise errors.HypervisorError("kvm: error executing the %s"
431
                                     " command: %s (%s):" %
432
                                     (command,
433
                                      err[self._ERROR_DESC_KEY],
434
                                      err[self._ERROR_CLASS_KEY]))
435

    
436
      elif not response[self._EVENT_KEY]:
437
        return response
438

    
439

    
440
class KVMHypervisor(hv_base.BaseHypervisor):
441
  """KVM hypervisor interface
442

443
  """
444
  CAN_MIGRATE = True
445

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

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

    
545
  _VIRTIO = "virtio"
546
  _VIRTIO_NET_PCI = "virtio-net-pci"
547

    
548
  _MIGRATION_STATUS_RE = re.compile(r"Migration\s+status:\s+(\w+)",
549
                                    re.M | re.I)
550
  _MIGRATION_PROGRESS_RE = \
551
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
552
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
553
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
554

    
555
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
556
  _MIGRATION_INFO_RETRY_DELAY = 2
557

    
558
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
559

    
560
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
561
  _CPU_INFO_CMD = "info cpus"
562
  _CONT_CMD = "cont"
563

    
564
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
565
  _CHECK_MACHINE_VERSION_RE = \
566
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
567

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

    
583
  ANCILLARY_FILES = [
584
    _KVM_NETWORK_SCRIPT,
585
    ]
586
  ANCILLARY_FILES_OPT = [
587
    _KVM_NETWORK_SCRIPT,
588
    ]
589

    
590
  # Supported kvm options to get output from
591
  _KVMOPT_HELP = "help"
592
  _KVMOPT_MLIST = "mlist"
593
  _KVMOPT_DEVICELIST = "devicelist"
594

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

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

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

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

    
617
  @classmethod
618
  def _InstanceUidFile(cls, instance_name):
619
    """Returns the instance uidfile.
620

621
    """
622
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
623

    
624
  @classmethod
625
  def _InstancePidInfo(cls, pid):
626
    """Check pid file for instance information.
627

628
    Check that a pid file is associated with an instance, and retrieve
629
    information from its command line.
630

631
    @type pid: string or int
632
    @param pid: process id of the instance to check
633
    @rtype: tuple
634
    @return: (instance_name, memory, vcpus)
635
    @raise errors.HypervisorError: when an instance cannot be found
636

637
    """
638
    alive = utils.IsProcessAlive(pid)
639
    if not alive:
640
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
641

    
642
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
643
    try:
644
      cmdline = utils.ReadFile(cmdline_file)
645
    except EnvironmentError, err:
646
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
647
                                   (pid, err))
648

    
649
    instance = None
650
    memory = 0
651
    vcpus = 0
652

    
653
    arg_list = cmdline.split("\x00")
654
    while arg_list:
655
      arg = arg_list.pop(0)
656
      if arg == "-name":
657
        instance = arg_list.pop(0)
658
      elif arg == "-m":
659
        memory = int(arg_list.pop(0))
660
      elif arg == "-smp":
661
        vcpus = int(arg_list.pop(0).split(",")[0])
662

    
663
    if instance is None:
664
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
665
                                   " instance" % pid)
666

    
667
    return (instance, memory, vcpus)
668

    
669
  def _InstancePidAlive(self, instance_name):
670
    """Returns the instance pidfile, pid, and liveness.
671

672
    @type instance_name: string
673
    @param instance_name: instance name
674
    @rtype: tuple
675
    @return: (pid file name, pid, liveness)
676

677
    """
678
    pidfile = self._InstancePidFile(instance_name)
679
    pid = utils.ReadPidFile(pidfile)
680

    
681
    alive = False
682
    try:
683
      cmd_instance = self._InstancePidInfo(pid)[0]
684
      alive = (cmd_instance == instance_name)
685
    except errors.HypervisorError:
686
      pass
687

    
688
    return (pidfile, pid, alive)
689

    
690
  def _CheckDown(self, instance_name):
691
    """Raises an error unless the given instance is down.
692

693
    """
694
    alive = self._InstancePidAlive(instance_name)[2]
695
    if alive:
696
      raise errors.HypervisorError("Failed to start instance %s: %s" %
697
                                   (instance_name, "already running"))
698

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

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

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

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

    
713
  @classmethod
714
  def _InstanceQmpMonitor(cls, instance_name):
715
    """Returns the instance serial QMP socket name
716

717
    """
718
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
719

    
720
  @staticmethod
721
  def _SocatUnixConsoleParams():
722
    """Returns the correct parameters for socat
723

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

726
    """
727
    if constants.SOCAT_USE_ESCAPE:
728
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
729
    else:
730
      return "echo=0,icanon=0"
731

    
732
  @classmethod
733
  def _InstanceKVMRuntime(cls, instance_name):
734
    """Returns the instance KVM runtime filename
735

736
    """
737
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
738

    
739
  @classmethod
740
  def _InstanceChrootDir(cls, instance_name):
741
    """Returns the name of the KVM chroot dir of the instance
742

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

    
746
  @classmethod
747
  def _InstanceNICDir(cls, instance_name):
748
    """Returns the name of the directory holding the tap device files for a
749
    given instance.
750

751
    """
752
    return utils.PathJoin(cls._NICS_DIR, instance_name)
753

    
754
  @classmethod
755
  def _InstanceNICFile(cls, instance_name, seq):
756
    """Returns the name of the file containing the tap device for a given NIC
757

758
    """
759
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
760

    
761
  @classmethod
762
  def _InstanceKeymapFile(cls, instance_name):
763
    """Returns the name of the file containing the keymap for a given instance
764

765
    """
766
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
767

    
768
  @classmethod
769
  def _TryReadUidFile(cls, uid_file):
770
    """Try to read a uid file
771

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

    
783
  @classmethod
784
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
785
    """Removes an instance's rutime sockets/files/dirs.
786

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

    
823
  @staticmethod
824
  def _ConfigureNIC(instance, seq, nic, tap):
825
    """Run the network configuration script for a specified NIC
826

827
    @param instance: instance we're acting on
828
    @type instance: instance object
829
    @param seq: nic sequence number
830
    @type seq: int
831
    @param nic: nic we're acting on
832
    @type nic: nic object
833
    @param tap: the host's tap interface this NIC corresponds to
834
    @type tap: str
835

836
    """
837
    if instance.tags:
838
      tags = " ".join(instance.tags)
839
    else:
840
      tags = ""
841

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

    
852
    if nic.ip:
853
      env["IP"] = nic.ip
854

    
855
    if nic.nicparams[constants.NIC_LINK]:
856
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
857

    
858
    if nic.network:
859
      n = objects.Network.FromDict(nic.netinfo)
860
      env.update(n.HooksDict())
861

    
862
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
863
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
864

    
865
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
866
    if result.failed:
867
      raise errors.HypervisorError("Failed to configure interface %s: %s;"
868
                                   " network configuration script output: %s" %
869
                                   (tap, result.fail_reason, result.output))
870

    
871
  @staticmethod
872
  def _VerifyAffinityPackage():
873
    if affinity is None:
874
      raise errors.HypervisorError("affinity Python package not"
875
                                   " found; cannot use CPU pinning under KVM")
876

    
877
  @staticmethod
878
  def _BuildAffinityCpuMask(cpu_list):
879
    """Create a CPU mask suitable for sched_setaffinity from a list of
880
    CPUs.
881

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

885
    @type cpu_list: list of int
886
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
887
    @rtype: int
888
    @return: a bit mask of CPU affinities
889

890
    """
891
    if cpu_list == constants.CPU_PINNING_OFF:
892
      return constants.CPU_PINNING_ALL_KVM
893
    else:
894
      return sum(2 ** cpu for cpu in cpu_list)
895

    
896
  @classmethod
897
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
898
    """Change CPU affinity for running VM according to given CPU mask.
899

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

908
    """
909
    # Convert the string CPU mask to a list of list of int's
910
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
911

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

    
930
      # For each vCPU, map it to the proper list of physical CPUs
931
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
932
        affinity.set_process_affinity_mask(thread_dict[i],
933
                                           cls._BuildAffinityCpuMask(vcpu))
934

    
935
  def _GetVcpuThreadIds(self, instance_name):
936
    """Get a mapping of vCPU no. to thread IDs for the instance
937

938
    @type instance_name: string
939
    @param instance_name: instance in question
940
    @rtype: dictionary of int:int
941
    @return: a dictionary mapping vCPU numbers to thread IDs
942

943
    """
944
    result = {}
945
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
946
    for line in output.stdout.splitlines():
947
      match = self._CPU_INFO_RE.search(line)
948
      if not match:
949
        continue
950
      grp = map(int, match.groups())
951
      result[grp[0]] = grp[1]
952

    
953
    return result
954

    
955
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
956
    """Complete CPU pinning.
957

958
    @type instance_name: string
959
    @param instance_name: name of instance
960
    @type cpu_mask: string
961
    @param cpu_mask: CPU pinning mask as entered by user
962

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

    
971
  def ListInstances(self, hvparams=None):
972
    """Get the list of running instances.
973

974
    We can do this by listing our live instances directory and
975
    checking whether the associated kvm process is still alive.
976

977
    """
978
    result = []
979
    for name in os.listdir(self._PIDS_DIR):
980
      if self._InstancePidAlive(name)[2]:
981
        result.append(name)
982
    return result
983

    
984
  def GetInstanceInfo(self, instance_name, hvparams=None):
985
    """Get instance properties.
986

987
    @type instance_name: string
988
    @param instance_name: the instance name
989
    @type hvparams: dict of strings
990
    @param hvparams: hvparams to be used with this instance
991
    @rtype: tuple of strings
992
    @return: (name, id, memory, vcpus, stat, times)
993

994
    """
995
    _, pid, alive = self._InstancePidAlive(instance_name)
996
    if not alive:
997
      return None
998

    
999
    _, memory, vcpus = self._InstancePidInfo(pid)
1000
    istat = "---b-"
1001
    times = "0"
1002

    
1003
    try:
1004
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1005
      qmp.connect()
1006
      vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1007
      # Will fail if ballooning is not enabled, but we can then just resort to
1008
      # the value above.
1009
      mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1010
      memory = mem_bytes / 1048576
1011
    except errors.HypervisorError:
1012
      pass
1013

    
1014
    return (instance_name, pid, memory, vcpus, istat, times)
1015

    
1016
  def GetAllInstancesInfo(self, hvparams=None):
1017
    """Get properties of all instances.
1018

1019
    @type hvparams: dict of strings
1020
    @param hvparams: hypervisor parameter
1021
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1022

1023
    """
1024
    data = []
1025
    for name in os.listdir(self._PIDS_DIR):
1026
      try:
1027
        info = self.GetInstanceInfo(name)
1028
      except errors.HypervisorError:
1029
        # Ignore exceptions due to instances being shut down
1030
        continue
1031
      if info:
1032
        data.append(info)
1033
    return data
1034

    
1035
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1036
                          kvmhelp):
1037
    """Generate KVM information to start an instance.
1038

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

1048
    """
1049
    # pylint: disable=R0912,R0914,R0915
1050
    hvp = instance.hvparams
1051
    self.ValidateParameters(hvp)
1052

    
1053
    pidfile = self._InstancePidFile(instance.name)
1054
    kvm = hvp[constants.HV_KVM_PATH]
1055
    kvm_cmd = [kvm]
1056
    # used just by the vnc server, if enabled
1057
    kvm_cmd.extend(["-name", instance.name])
1058
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1059

    
1060
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1061
    if hvp[constants.HV_CPU_CORES]:
1062
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1063
    if hvp[constants.HV_CPU_THREADS]:
1064
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1065
    if hvp[constants.HV_CPU_SOCKETS]:
1066
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1067

    
1068
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1069

    
1070
    kvm_cmd.extend(["-pidfile", pidfile])
1071
    kvm_cmd.extend(["-balloon", "virtio"])
1072
    kvm_cmd.extend(["-daemonize"])
1073
    if not instance.hvparams[constants.HV_ACPI]:
1074
      kvm_cmd.extend(["-no-acpi"])
1075
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1076
        constants.INSTANCE_REBOOT_EXIT:
1077
      kvm_cmd.extend(["-no-reboot"])
1078

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

    
1101
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1102
    if kernel_path:
1103
      boot_disk = boot_cdrom = boot_floppy = boot_network = False
1104
    else:
1105
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1106
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1107
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1108
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1109

    
1110
    if startup_paused:
1111
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1112

    
1113
    if boot_network:
1114
      kvm_cmd.extend(["-boot", "n"])
1115

    
1116
    # whether this is an older KVM version that uses the boot=on flag
1117
    # on devices
1118
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1119

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

    
1150
      drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
1151
                                                cache_val)
1152
      kvm_cmd.extend(["-drive", drive_val])
1153

    
1154
    #Now we can specify a different device type for CDROM devices.
1155
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1156
    if not cdrom_disk_type:
1157
      cdrom_disk_type = disk_type
1158

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

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

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

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

    
1213
    mem_path = hvp[constants.HV_MEM_PATH]
1214
    if mem_path:
1215
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1216

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

    
1227
    mouse_type = hvp[constants.HV_USB_MOUSE]
1228
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1229
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1230
    spice_ip_version = None
1231

    
1232
    kvm_cmd.extend(["-usb"])
1233

    
1234
    if mouse_type:
1235
      kvm_cmd.extend(["-usbdevice", mouse_type])
1236
    elif vnc_bind_address:
1237
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1238

    
1239
    if vnc_bind_address:
1240
      if netutils.IsValidInterface(vnc_bind_address):
1241
        if_addresses = netutils.GetInterfaceIpAddresses(vnc_bind_address)
1242
        if_ip4_addresses = if_addresses[constants.IP4_VERSION]
1243
        if len(if_ip4_addresses) < 1:
1244
          logging.error("Could not determine IPv4 address of interface %s",
1245
                        vnc_bind_address)
1246
        else:
1247
          vnc_bind_address = if_ip4_addresses[0]
1248
      if netutils.IP4Address.IsValid(vnc_bind_address):
1249
        if instance.network_port > constants.VNC_BASE_PORT:
1250
          display = instance.network_port - constants.VNC_BASE_PORT
1251
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1252
            vnc_arg = ":%d" % (display)
1253
          else:
1254
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1255
        else:
1256
          logging.error("Network port is not a valid VNC display (%d < %d),"
1257
                        " not starting VNC",
1258
                        instance.network_port, constants.VNC_BASE_PORT)
1259
          vnc_arg = "none"
1260

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

    
1275
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1276

    
1277
      else:
1278
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1279

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

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

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

    
1314
        spice_address = addresses[spice_ip_version][0]
1315

    
1316
      else:
1317
        # spice_bind is known to be a valid IP address, because
1318
        # ValidateParameters checked it.
1319
        spice_address = spice_bind
1320

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

    
1335
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1336
        spice_arg = "%s,disable-ticketing" % spice_arg
1337

    
1338
      if spice_ip_version:
1339
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1340

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

    
1352
      # Video stream detection
1353
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1354
      if video_streaming:
1355
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1356

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

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

    
1375
    else:
1376
      # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1377
      # also works in earlier versions though (tested with 1.1 and 1.3)
1378
      if self._DISPLAY_RE.search(kvmhelp):
1379
        kvm_cmd.extend(["-display", "none"])
1380
      else:
1381
        kvm_cmd.extend(["-nographic"])
1382

    
1383
    if hvp[constants.HV_USE_LOCALTIME]:
1384
      kvm_cmd.extend(["-localtime"])
1385

    
1386
    if hvp[constants.HV_KVM_USE_CHROOT]:
1387
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1388

    
1389
    # Add qemu-KVM -cpu param
1390
    if hvp[constants.HV_CPU_TYPE]:
1391
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1392

    
1393
    # As requested by music lovers
1394
    if hvp[constants.HV_SOUNDHW]:
1395
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1396

    
1397
    # Pass a -vga option if requested, or if spice is used, for backwards
1398
    # compatibility.
1399
    if hvp[constants.HV_VGA]:
1400
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1401
    elif spice_bind:
1402
      kvm_cmd.extend(["-vga", "qxl"])
1403

    
1404
    # Various types of usb devices, comma separated
1405
    if hvp[constants.HV_USB_DEVICES]:
1406
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1407
        kvm_cmd.extend(["-usbdevice", dev])
1408

    
1409
    # Set system UUID to instance UUID
1410
    if self._UUID_RE.search(kvmhelp):
1411
      kvm_cmd.extend(["-uuid", instance.uuid])
1412

    
1413
    if hvp[constants.HV_KVM_EXTRA]:
1414
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1415

    
1416
    # Save the current instance nics, but defer their expansion as parameters,
1417
    # as we'll need to generate executable temp files for them.
1418
    kvm_nics = instance.nics
1419
    hvparams = hvp
1420

    
1421
    return (kvm_cmd, kvm_nics, hvparams)
1422

    
1423
  def _WriteKVMRuntime(self, instance_name, data):
1424
    """Write an instance's KVM runtime
1425

1426
    """
1427
    try:
1428
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1429
                      data=data)
1430
    except EnvironmentError, err:
1431
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1432

    
1433
  def _ReadKVMRuntime(self, instance_name):
1434
    """Read an instance's KVM runtime
1435

1436
    """
1437
    try:
1438
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1439
    except EnvironmentError, err:
1440
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1441
    return file_content
1442

    
1443
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1444
    """Save an instance's KVM runtime
1445

1446
    """
1447
    kvm_cmd, kvm_nics, hvparams = kvm_runtime
1448
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1449
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1450
    self._WriteKVMRuntime(instance.name, serialized_form)
1451

    
1452
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1453
    """Load an instance's KVM runtime
1454

1455
    """
1456
    if not serialized_runtime:
1457
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1458
    loaded_runtime = serializer.Load(serialized_runtime)
1459
    kvm_cmd, serialized_nics, hvparams = loaded_runtime
1460
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1461
    return (kvm_cmd, kvm_nics, hvparams)
1462

    
1463
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1464
    """Run the KVM cmd and check for errors
1465

1466
    @type name: string
1467
    @param name: instance name
1468
    @type kvm_cmd: list of strings
1469
    @param kvm_cmd: runcmd input for kvm
1470
    @type tap_fds: list of int
1471
    @param tap_fds: fds of tap devices opened by Ganeti
1472

1473
    """
1474
    try:
1475
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1476
    finally:
1477
      for fd in tap_fds:
1478
        utils_wrapper.CloseFdNoError(fd)
1479

    
1480
    if result.failed:
1481
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1482
                                   (name, result.fail_reason, result.output))
1483
    if not self._InstancePidAlive(name)[2]:
1484
      raise errors.HypervisorError("Failed to start instance %s" % name)
1485

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

1489
    @type incoming: tuple of strings
1490
    @param incoming: (target_host_ip, port)
1491
    @type kvmhelp: string
1492
    @param kvmhelp: output of kvm --help
1493

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

    
1507
    temp_files = []
1508

    
1509
    kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1510
    # the first element of kvm_cmd is always the path to the kvm binary
1511
    kvm_path = kvm_cmd[0]
1512
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1513

    
1514
    # We know it's safe to run as a different user upon migration, so we'll use
1515
    # the latest conf, from conf_hvp.
1516
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1517
    if security_model == constants.HT_SM_USER:
1518
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1519

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

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

    
1553
        if up_hvp[constants.HV_VHOST_NET]:
1554
          # check for vhost_net support
1555
          if self._VHOST_RE.search(kvmhelp):
1556
            tap_extra = ",vhost=on"
1557
          else:
1558
            raise errors.HypervisorError("vhost_net is configured"
1559
                                         " but it is not available")
1560
      else:
1561
        nic_model = nic_type
1562

    
1563
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1564

    
1565
      for nic_seq, nic in enumerate(kvm_nics):
1566
        tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1567
        tapfds.append(tapfd)
1568
        taps.append(tapname)
1569
        if kvm_supports_netdev:
1570
          nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1571
          tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1572
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1573
        else:
1574
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1575
                                                         nic.mac, nic_model)
1576
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1577
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1578

    
1579
    if incoming:
1580
      target, port = incoming
1581
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1582

    
1583
    # Changing the vnc password doesn't bother the guest that much. At most it
1584
    # will surprise people who connect to it. Whether positively or negatively
1585
    # it's debatable.
1586
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1587
    vnc_pwd = None
1588
    if vnc_pwd_file:
1589
      try:
1590
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1591
      except EnvironmentError, err:
1592
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1593
                                     % (vnc_pwd_file, err))
1594

    
1595
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1596
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1597
                         constants.SECURE_DIR_MODE)])
1598

    
1599
    # Automatically enable QMP if version is >= 0.14
1600
    if self._QMP_RE.search(kvmhelp):
1601
      logging.debug("Enabling QMP")
1602
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1603
                      self._InstanceQmpMonitor(instance.name)])
1604

    
1605
    # Configure the network now for starting instances and bridged interfaces,
1606
    # during FinalizeMigration for incoming instances' routed interfaces
1607
    for nic_seq, nic in enumerate(kvm_nics):
1608
      if (incoming and
1609
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1610
        continue
1611
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1612

    
1613
    # CPU affinity requires kvm to start paused, so we set this flag if the
1614
    # instance is not already paused and if we are not going to accept a
1615
    # migrating instance. In the latter case, pausing is not needed.
1616
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1617
    if start_kvm_paused:
1618
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1619

    
1620
    # Note: CPU pinning is using up_hvp since changes take effect
1621
    # during instance startup anyway, and to avoid problems when soft
1622
    # rebooting the instance.
1623
    cpu_pinning = False
1624
    if up_hvp.get(constants.HV_CPU_MASK, None):
1625
      cpu_pinning = True
1626

    
1627
    if security_model == constants.HT_SM_POOL:
1628
      ss = ssconf.SimpleStore()
1629
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1630
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1631
      uid = uidpool.RequestUnusedUid(all_uids)
1632
      try:
1633
        username = pwd.getpwuid(uid.GetUid()).pw_name
1634
        kvm_cmd.extend(["-runas", username])
1635
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1636
      except:
1637
        uidpool.ReleaseUid(uid)
1638
        raise
1639
      else:
1640
        uid.Unlock()
1641
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1642
    else:
1643
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1644

    
1645
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1646
                     constants.RUN_DIRS_MODE)])
1647
    for nic_seq, tap in enumerate(taps):
1648
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1649
                      data=tap)
1650

    
1651
    if vnc_pwd:
1652
      change_cmd = "change vnc password %s" % vnc_pwd
1653
      self._CallMonitorCommand(instance.name, change_cmd)
1654

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

    
1669
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1670
      qmp.connect()
1671
      arguments = {
1672
          "protocol": "spice",
1673
          "password": spice_pwd,
1674
      }
1675
      qmp.Execute("set_password", arguments)
1676

    
1677
    for filename in temp_files:
1678
      utils.RemoveFile(filename)
1679

    
1680
    # If requested, set CPU affinity and resume instance execution
1681
    if cpu_pinning:
1682
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1683

    
1684
    start_memory = self._InstanceStartupMemory(instance)
1685
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1686
      self.BalloonInstanceMemory(instance, start_memory)
1687

    
1688
    if start_kvm_paused:
1689
      # To control CPU pinning, ballooning, and vnc/spice passwords
1690
      # the VM was started in a frozen state. If freezing was not
1691
      # explicitly requested resume the vm status.
1692
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1693

    
1694
  def StartInstance(self, instance, block_devices, startup_paused):
1695
    """Start an instance.
1696

1697
    """
1698
    self._CheckDown(instance.name)
1699
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1700
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1701
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1702
                                           startup_paused, kvmhelp)
1703
    self._SaveKVMRuntime(instance, kvm_runtime)
1704
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1705

    
1706
  def _CallMonitorCommand(self, instance_name, command):
1707
    """Invoke a command on the instance monitor.
1708

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

    
1728
    return result
1729

    
1730
  @classmethod
1731
  def _ParseKVMVersion(cls, text):
1732
    """Parse the KVM version from the --help output.
1733

1734
    @type text: string
1735
    @param text: output of kvm --help
1736
    @return: (version, v_maj, v_min, v_rev)
1737
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1738

1739
    """
1740
    match = cls._VERSION_RE.search(text.splitlines()[0])
1741
    if not match:
1742
      raise errors.HypervisorError("Unable to get KVM version")
1743

    
1744
    v_all = match.group(0)
1745
    v_maj = int(match.group(1))
1746
    v_min = int(match.group(2))
1747
    if match.group(4):
1748
      v_rev = int(match.group(4))
1749
    else:
1750
      v_rev = 0
1751
    return (v_all, v_maj, v_min, v_rev)
1752

    
1753
  @classmethod
1754
  def _GetKVMOutput(cls, kvm_path, option):
1755
    """Return the output of a kvm invocation
1756

1757
    @type kvm_path: string
1758
    @param kvm_path: path to the kvm executable
1759
    @type option: a key of _KVMOPTS_CMDS
1760
    @param option: kvm option to fetch the output from
1761
    @return: output a supported kvm invocation
1762
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1763

1764
    """
1765
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
1766

    
1767
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
1768

    
1769
    result = utils.RunCmd([kvm_path] + optlist)
1770
    if result.failed and not can_fail:
1771
      raise errors.HypervisorError("Unable to get KVM %s output" %
1772
                                    " ".join(optlist))
1773
    return result.output
1774

    
1775
  @classmethod
1776
  def _GetKVMVersion(cls, kvm_path):
1777
    """Return the installed KVM version.
1778

1779
    @return: (version, v_maj, v_min, v_rev)
1780
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1781

1782
    """
1783
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
1784

    
1785
  @classmethod
1786
  def _GetDefaultMachineVersion(cls, kvm_path):
1787
    """Return the default hardware revision (e.g. pc-1.1)
1788

1789
    """
1790
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
1791
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
1792
    if match:
1793
      return match.group(1)
1794
    else:
1795
      return "pc"
1796

    
1797
  def StopInstance(self, instance, force=False, retry=False, name=None):
1798
    """Stop an instance.
1799

1800
    """
1801
    if name is not None and not force:
1802
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1803
    if name is None:
1804
      name = instance.name
1805
      acpi = instance.hvparams[constants.HV_ACPI]
1806
    else:
1807
      acpi = False
1808
    _, pid, alive = self._InstancePidAlive(name)
1809
    if pid > 0 and alive:
1810
      if force or not acpi:
1811
        utils.KillProcess(pid)
1812
      else:
1813
        self._CallMonitorCommand(name, "system_powerdown")
1814

    
1815
  def CleanupInstance(self, instance_name):
1816
    """Cleanup after a stopped instance
1817

1818
    """
1819
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
1820
    if pid > 0 and alive:
1821
      raise errors.HypervisorError("Cannot cleanup a live instance")
1822
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1823

    
1824
  def RebootInstance(self, instance):
1825
    """Reboot an instance.
1826

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

    
1847
  def MigrationInfo(self, instance):
1848
    """Get instance information to perform a migration.
1849

1850
    @type instance: L{objects.Instance}
1851
    @param instance: instance to be migrated
1852
    @rtype: string
1853
    @return: content of the KVM runtime file
1854

1855
    """
1856
    return self._ReadKVMRuntime(instance.name)
1857

    
1858
  def AcceptInstance(self, instance, info, target):
1859
    """Prepare to accept an instance.
1860

1861
    @type instance: L{objects.Instance}
1862
    @param instance: instance to be accepted
1863
    @type info: string
1864
    @param info: content of the KVM runtime file on the source node
1865
    @type target: string
1866
    @param target: target host (usually ip), on this node
1867

1868
    """
1869
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1870
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1871
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1872
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1873
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
1874
                            incoming=incoming_address)
1875

    
1876
  def FinalizeMigrationDst(self, instance, info, success):
1877
    """Finalize the instance migration on the target node.
1878

1879
    Stop the incoming mode KVM.
1880

1881
    @type instance: L{objects.Instance}
1882
    @param instance: instance whose migration is being finalized
1883

1884
    """
1885
    if success:
1886
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1887
      kvm_nics = kvm_runtime[1]
1888

    
1889
      for nic_seq, nic in enumerate(kvm_nics):
1890
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1891
          # Bridged interfaces have already been configured
1892
          continue
1893
        try:
1894
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1895
        except EnvironmentError, err:
1896
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
1897
                          instance.name, nic_seq, str(err))
1898
          continue
1899
        try:
1900
          self._ConfigureNIC(instance, nic_seq, nic, tap)
1901
        except errors.HypervisorError, err:
1902
          logging.warning(str(err))
1903

    
1904
      self._WriteKVMRuntime(instance.name, info)
1905
    else:
1906
      self.StopInstance(instance, force=True)
1907

    
1908
  def MigrateInstance(self, cluster_name, instance, target, live):
1909
    """Migrate an instance to a target node.
1910

1911
    The migration will not be attempted if the instance is not
1912
    currently running.
1913

1914
    @type cluster_name: string
1915
    @param cluster_name: name of the cluster
1916
    @type instance: L{objects.Instance}
1917
    @param instance: the instance to be migrated
1918
    @type target: string
1919
    @param target: ip address of the target node
1920
    @type live: boolean
1921
    @param live: perform a live migration
1922

1923
    """
1924
    instance_name = instance.name
1925
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
1926
    _, _, alive = self._InstancePidAlive(instance_name)
1927
    if not alive:
1928
      raise errors.HypervisorError("Instance not running, cannot migrate")
1929

    
1930
    if not live:
1931
      self._CallMonitorCommand(instance_name, "stop")
1932

    
1933
    migrate_command = ("migrate_set_speed %dm" %
1934
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1935
    self._CallMonitorCommand(instance_name, migrate_command)
1936

    
1937
    migrate_command = ("migrate_set_downtime %dms" %
1938
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1939
    self._CallMonitorCommand(instance_name, migrate_command)
1940

    
1941
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1942
    self._CallMonitorCommand(instance_name, migrate_command)
1943

    
1944
  def FinalizeMigrationSource(self, instance, success, live):
1945
    """Finalize the instance migration on the source node.
1946

1947
    @type instance: L{objects.Instance}
1948
    @param instance: the instance that was migrated
1949
    @type success: bool
1950
    @param success: whether the migration succeeded or not
1951
    @type live: bool
1952
    @param live: whether the user requested a live migration or not
1953

1954
    """
1955
    if success:
1956
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
1957
      utils.KillProcess(pid)
1958
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1959
    elif live:
1960
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1961

    
1962
  def GetMigrationStatus(self, instance):
1963
    """Get the migration status
1964

1965
    @type instance: L{objects.Instance}
1966
    @param instance: the instance that is being migrated
1967
    @rtype: L{objects.MigrationStatus}
1968
    @return: the status of the current migration (one of
1969
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1970
             progress info that can be retrieved from the hypervisor
1971

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

    
1992
          return migration_status
1993

    
1994
        logging.warning("KVM: unknown migration status '%s'", status)
1995

    
1996
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1997

    
1998
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
1999

    
2000
  def BalloonInstanceMemory(self, instance, mem):
2001
    """Balloon an instance memory to a certain value.
2002

2003
    @type instance: L{objects.Instance}
2004
    @param instance: instance to be accepted
2005
    @type mem: int
2006
    @param mem: actual memory size to use for instance runtime
2007

2008
    """
2009
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2010

    
2011
  def GetNodeInfo(self, hvparams=None):
2012
    """Return information about the node.
2013

2014
    @type hvparams: dict of strings
2015
    @param hvparams: hypervisor parameters, not used in this class
2016

2017
    @return: a dict as returned by L{BaseHypervisor.GetLinuxNodeInfo} plus
2018
        the following keys:
2019
          - hv_version: the hypervisor version in the form (major, minor,
2020
                        revision)
2021

2022
    """
2023
    result = self.GetLinuxNodeInfo()
2024
    kvmpath = constants.KVM_PATH
2025
    if hvparams is not None:
2026
      kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2027
    _, v_major, v_min, v_rev = self._GetKVMVersion(kvmpath)
2028
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2029
    return result
2030

    
2031
  @classmethod
2032
  def GetInstanceConsole(cls, instance, primary_node, hvparams, beparams):
2033
    """Return a command for connecting to the console of an instance.
2034

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

    
2048
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2049
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2050
      display = instance.network_port - constants.VNC_BASE_PORT
2051
      return objects.InstanceConsole(instance=instance.name,
2052
                                     kind=constants.CONS_VNC,
2053
                                     host=vnc_bind_address,
2054
                                     port=instance.network_port,
2055
                                     display=display)
2056

    
2057
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2058
    if spice_bind:
2059
      return objects.InstanceConsole(instance=instance.name,
2060
                                     kind=constants.CONS_SPICE,
2061
                                     host=spice_bind,
2062
                                     port=instance.network_port)
2063

    
2064
    return objects.InstanceConsole(instance=instance.name,
2065
                                   kind=constants.CONS_MESSAGE,
2066
                                   message=("No serial shell for instance %s" %
2067
                                            instance.name))
2068

    
2069
  def Verify(self, hvparams=None):
2070
    """Verify the hypervisor.
2071

2072
    Check that the required binaries exist.
2073

2074
    @type hvparams: dict of strings
2075
    @param hvparams: hypervisor parameters to be verified against, not used here
2076

2077
    @return: Problem description if something is wrong, C{None} otherwise
2078

2079
    """
2080
    msgs = []
2081
    kvmpath = constants.KVM_PATH
2082
    if hvparams is not None:
2083
      kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2084
    if not os.path.exists(kvmpath):
2085
      msgs.append("The KVM binary ('%s') does not exist" % kvmpath)
2086
    if not os.path.exists(constants.SOCAT_PATH):
2087
      msgs.append("The socat binary ('%s') does not exist" %
2088
                  constants.SOCAT_PATH)
2089

    
2090
    return self._FormatVerifyResults(msgs)
2091

    
2092
  @classmethod
2093
  def CheckParameterSyntax(cls, hvparams):
2094
    """Check the given parameters for validity.
2095

2096
    @type hvparams:  dict
2097
    @param hvparams: dictionary with parameter names/value
2098
    @raise errors.HypervisorError: when a parameter is not valid
2099

2100
    """
2101
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2102

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

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

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

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

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

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

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

    
2165
  @classmethod
2166
  def ValidateParameters(cls, hvparams):
2167
    """Check the given parameters for validity.
2168

2169
    @type hvparams:  dict
2170
    @param hvparams: dictionary with parameter names/value
2171
    @raise errors.HypervisorError: when a parameter is not valid
2172

2173
    """
2174
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2175

    
2176
    kvm_path = hvparams[constants.HV_KVM_PATH]
2177

    
2178
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2179
    if security_model == constants.HT_SM_USER:
2180
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2181
      try:
2182
        pwd.getpwnam(username)
2183
      except KeyError:
2184
        raise errors.HypervisorError("Unknown security domain user %s"
2185
                                     % username)
2186
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2187
    if vnc_bind_address:
2188
      bound_to_addr = netutils.IP4Address.IsValid(vnc_bind_address)
2189
      is_interface = netutils.IsValidInterface(vnc_bind_address)
2190
      is_path = utils.IsNormAbsPath(vnc_bind_address)
2191
      if not bound_to_addr and not is_interface and not is_path:
2192
        raise errors.HypervisorError("VNC: The %s parameter must be either"
2193
                                     " a valid IP address, an interface name,"
2194
                                     " or an absolute path" %
2195
                                     constants.HV_KVM_SPICE_BIND)
2196

    
2197
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2198
    if spice_bind:
2199
      # only one of VNC and SPICE can be used currently.
2200
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2201
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2202
                                     " only one of them can be used at a"
2203
                                     " given time")
2204

    
2205
      # check that KVM supports SPICE
2206
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2207
      if not cls._SPICE_RE.search(kvmhelp):
2208
        raise errors.HypervisorError("SPICE is configured, but it is not"
2209
                                     " supported according to 'kvm --help'")
2210

    
2211
      # if spice_bind is not an IP address, it must be a valid interface
2212
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2213
                       netutils.IP6Address.IsValid(spice_bind))
2214
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2215
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2216
                                     " a valid IP address or interface name" %
2217
                                     constants.HV_KVM_SPICE_BIND)
2218

    
2219
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2220
    if machine_version:
2221
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2222
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2223
        raise errors.HypervisorError("Unsupported machine version: %s" %
2224
                                     machine_version)
2225

    
2226
  @classmethod
2227
  def PowercycleNode(cls, hvparams=None):
2228
    """KVM powercycle, just a wrapper over Linux powercycle.
2229

2230
    @type hvparams: dict of strings
2231
    @param hvparams: hypervisor params to be used on this node
2232

2233
    """
2234
    cls.LinuxPowercycle()