Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 5e34123e

History | View | Annotate | Download (81.6 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_DATA_KEY = "data"
244
  _ERROR_DESC_KEY = "desc"
245
  _EXECUTE_KEY = "execute"
246
  _ARGUMENTS_KEY = "arguments"
247
  _CAPABILITIES_COMMAND = "qmp_capabilities"
248
  _MESSAGE_END_TOKEN = "\r\n"
249
  _SOCKET_TIMEOUT = 5
250

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

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

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

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

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

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

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

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

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

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

    
301
    self._check_socket()
302

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

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

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

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

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

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

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

    
344
    return (message, buf)
345

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

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

354
    """
355
    self._check_connection()
356

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

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

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

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

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

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

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

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

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

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

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

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

    
438
      elif not response[self._EVENT_KEY]:
439
        return response
440

    
441

    
442
class KVMHypervisor(hv_base.BaseHypervisor):
443
  """KVM hypervisor interface
444

445
  """
446
  CAN_MIGRATE = True
447

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

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

    
547
  _VIRTIO = "virtio"
548
  _VIRTIO_NET_PCI = "virtio-net-pci"
549

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

    
557
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
558
  _MIGRATION_INFO_RETRY_DELAY = 2
559

    
560
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
561

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

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

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

    
585
  ANCILLARY_FILES = [
586
    _KVM_NETWORK_SCRIPT,
587
    ]
588
  ANCILLARY_FILES_OPT = [
589
    _KVM_NETWORK_SCRIPT,
590
    ]
591

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

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

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

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

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

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

623
    """
624
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
625

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

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

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

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

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

    
651
    instance = None
652
    memory = 0
653
    vcpus = 0
654

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

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

    
669
    return (instance, memory, vcpus)
670

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

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

679
    """
680
    pidfile = self._InstancePidFile(instance_name)
681
    pid = utils.ReadPidFile(pidfile)
682

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

    
690
    return (pidfile, pid, alive)
691

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

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

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

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

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

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

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

719
    """
720
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
721

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

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

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

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

738
    """
739
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
740

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

745
    """
746
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
747

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

753
    """
754
    return utils.PathJoin(cls._NICS_DIR, instance_name)
755

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

760
    """
761
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
762

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

767
    """
768
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
769

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

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

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

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

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

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

838
    """
839
    if instance.tags:
840
      tags = " ".join(instance.tags)
841
    else:
842
      tags = ""
843

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

    
854
    if nic.ip:
855
      env["IP"] = nic.ip
856

    
857
    if nic.nicparams[constants.NIC_LINK]:
858
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
859

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
955
    return result
956

    
957
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
958
    """Complete CPU pinning.
959

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

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

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

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

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

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

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

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

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

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

    
1016
    return (instance_name, pid, memory, vcpus, istat, times)
1017

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

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

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

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

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

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

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

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

    
1070
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1071

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

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

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

    
1112
    if startup_paused:
1113
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1114

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

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

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

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

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

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

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

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

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

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

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

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

    
1234
    kvm_cmd.extend(["-usb"])
1235

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

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

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

    
1277
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1278

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

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

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

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

    
1316
        spice_address = addresses[spice_ip_version][0]
1317

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

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

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

    
1340
      if spice_ip_version:
1341
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1342

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

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

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

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

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

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

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

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

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

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

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

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

    
1415
    if hvp[constants.HV_KVM_EXTRA]:
1416
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1417

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

    
1423
    return (kvm_cmd, kvm_nics, hvparams)
1424

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1509
    temp_files = []
1510

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

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

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

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

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

    
1565
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1566

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1679
    for filename in temp_files:
1680
      utils.RemoveFile(filename)
1681

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

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

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

    
1696
  def StartInstance(self, instance, block_devices, startup_paused):
1697
    """Start an instance.
1698

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

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

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

    
1730
    return result
1731

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

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

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

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

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

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

1766
    """
1767
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
1768

    
1769
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
1770

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

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

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

1784
    """
1785
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
1786

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

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

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

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

    
1817
  def CleanupInstance(self, instance_name):
1818
    """Cleanup after a stopped instance
1819

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

    
1826
  def RebootInstance(self, instance):
1827
    """Reboot an instance.
1828

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

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

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

1857
    """
1858
    return self._ReadKVMRuntime(instance.name)
1859

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

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

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

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

1881
    Stop the incoming mode KVM.
1882

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

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

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

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

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

1913
    The migration will not be attempted if the instance is not
1914
    currently running.
1915

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

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

    
1932
    if not live:
1933
      self._CallMonitorCommand(instance_name, "stop")
1934

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

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

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

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

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

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

    
1964
  def GetMigrationStatus(self, instance):
1965
    """Get the migration status
1966

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

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

    
1994
          return migration_status
1995

    
1996
        logging.warning("KVM: unknown migration status '%s'", status)
1997

    
1998
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1999

    
2000
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2001

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

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

2010
    """
2011
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2012

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

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

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

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

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

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

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

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

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

    
2071
  def Verify(self, hvparams=None):
2072
    """Verify the hypervisor.
2073

2074
    Check that the required binaries exist.
2075

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

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

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

    
2092
    return self._FormatVerifyResults(msgs)
2093

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2178
    kvm_path = hvparams[constants.HV_KVM_PATH]
2179

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

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

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

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

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

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

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

2235
    """
2236
    cls.LinuxPowercycle()