Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 78f99abb

History | View | Annotate | Download (81.4 kB)

1
#
2
#
3

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

    
21

    
22
"""KVM hypervisor
23

24
"""
25

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

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

    
57

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

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

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

    
82

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

86
  @see: L{_ProbeTapVnetHdr}
87

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

    
99

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

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

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

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

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

    
123
  result = bool(flags & IFF_VNET_HDR)
124

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

    
128
  return result
129

    
130

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

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

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

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

    
148
  flags = IFF_TAP | IFF_NO_PI
149

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

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

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

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

    
166

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

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

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

    
178
    self.data = data
179

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

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

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

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

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

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

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

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

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

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

    
220

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

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

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

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

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

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

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

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

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

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

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

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

    
289
    self._check_socket()
290

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

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

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

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

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

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

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

    
332
    return (message, buf)
333

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

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

342
    """
343
    self._check_connection()
344

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

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

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

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

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

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

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

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

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

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

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

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

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

    
429

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

433
  """
434
  CAN_MIGRATE = True
435

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

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

    
535
  _VIRTIO = "virtio"
536
  _VIRTIO_NET_PCI = "virtio-net-pci"
537

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

    
545
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
546
  _MIGRATION_INFO_RETRY_DELAY = 2
547

    
548
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
549

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

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

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

    
573
  ANCILLARY_FILES = [
574
    _KVM_NETWORK_SCRIPT,
575
    ]
576
  ANCILLARY_FILES_OPT = [
577
    _KVM_NETWORK_SCRIPT,
578
    ]
579

    
580
  # Supported kvm options to get output from
581
  _KVMOPT_HELP = "help"
582
  _KVMOPT_MLIST = "mlist"
583
  _KVMOPT_DEVICELIST = "devicelist"
584

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

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

    
600
  @classmethod
601
  def _InstancePidFile(cls, instance_name):
602
    """Returns the instance pidfile.
603

604
    """
605
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
606

    
607
  @classmethod
608
  def _InstanceUidFile(cls, instance_name):
609
    """Returns the instance uidfile.
610

611
    """
612
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
613

    
614
  @classmethod
615
  def _InstancePidInfo(cls, pid):
616
    """Check pid file for instance information.
617

618
    Check that a pid file is associated with an instance, and retrieve
619
    information from its command line.
620

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

627
    """
628
    alive = utils.IsProcessAlive(pid)
629
    if not alive:
630
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
631

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

    
639
    instance = None
640
    memory = 0
641
    vcpus = 0
642

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

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

    
657
    return (instance, memory, vcpus)
658

    
659
  def _InstancePidAlive(self, instance_name):
660
    """Returns the instance pidfile, pid, and liveness.
661

662
    @type instance_name: string
663
    @param instance_name: instance name
664
    @rtype: tuple
665
    @return: (pid file name, pid, liveness)
666

667
    """
668
    pidfile = self._InstancePidFile(instance_name)
669
    pid = utils.ReadPidFile(pidfile)
670

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

    
678
    return (pidfile, pid, alive)
679

    
680
  def _CheckDown(self, instance_name):
681
    """Raises an error unless the given instance is down.
682

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

    
689
  @classmethod
690
  def _InstanceMonitor(cls, instance_name):
691
    """Returns the instance monitor socket name
692

693
    """
694
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
695

    
696
  @classmethod
697
  def _InstanceSerial(cls, instance_name):
698
    """Returns the instance serial socket name
699

700
    """
701
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
702

    
703
  @classmethod
704
  def _InstanceQmpMonitor(cls, instance_name):
705
    """Returns the instance serial QMP socket name
706

707
    """
708
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
709

    
710
  @staticmethod
711
  def _SocatUnixConsoleParams():
712
    """Returns the correct parameters for socat
713

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

716
    """
717
    if constants.SOCAT_USE_ESCAPE:
718
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
719
    else:
720
      return "echo=0,icanon=0"
721

    
722
  @classmethod
723
  def _InstanceKVMRuntime(cls, instance_name):
724
    """Returns the instance KVM runtime filename
725

726
    """
727
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
728

    
729
  @classmethod
730
  def _InstanceChrootDir(cls, instance_name):
731
    """Returns the name of the KVM chroot dir of the instance
732

733
    """
734
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
735

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

741
    """
742
    return utils.PathJoin(cls._NICS_DIR, instance_name)
743

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

748
    """
749
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
750

    
751
  @classmethod
752
  def _InstanceKeymapFile(cls, instance_name):
753
    """Returns the name of the file containing the keymap for a given instance
754

755
    """
756
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
757

    
758
  @classmethod
759
  def _TryReadUidFile(cls, uid_file):
760
    """Try to read a uid file
761

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

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

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

    
813
  @staticmethod
814
  def _ConfigureNIC(instance, seq, nic, tap):
815
    """Run the network configuration script for a specified NIC
816

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

826
    """
827
    if instance.tags:
828
      tags = " ".join(instance.tags)
829
    else:
830
      tags = ""
831

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

    
842
    if nic.ip:
843
      env["IP"] = nic.ip
844

    
845
    if nic.nicparams[constants.NIC_LINK]:
846
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
847

    
848
    if nic.network:
849
      n = objects.Network.FromDict(nic.netinfo)
850
      env.update(n.HooksDict())
851

    
852
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
853
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
854

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

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

    
867
  @staticmethod
868
  def _BuildAffinityCpuMask(cpu_list):
869
    """Create a CPU mask suitable for sched_setaffinity from a list of
870
    CPUs.
871

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

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

880
    """
881
    if cpu_list == constants.CPU_PINNING_OFF:
882
      return constants.CPU_PINNING_ALL_KVM
883
    else:
884
      return sum(2 ** cpu for cpu in cpu_list)
885

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

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

898
    """
899
    # Convert the string CPU mask to a list of list of int's
900
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
901

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

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

    
925
  def _GetVcpuThreadIds(self, instance_name):
926
    """Get a mapping of vCPU no. to thread IDs for the instance
927

928
    @type instance_name: string
929
    @param instance_name: instance in question
930
    @rtype: dictionary of int:int
931
    @return: a dictionary mapping vCPU numbers to thread IDs
932

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

    
943
    return result
944

    
945
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
946
    """Complete CPU pinning.
947

948
    @type instance_name: string
949
    @param instance_name: name of instance
950
    @type cpu_mask: string
951
    @param cpu_mask: CPU pinning mask as entered by user
952

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

    
961
  def ListInstances(self, hvparams=None):
962
    """Get the list of running instances.
963

964
    We can do this by listing our live instances directory and
965
    checking whether the associated kvm process is still alive.
966

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

    
974
  def GetInstanceInfo(self, instance_name, hvparams=None):
975
    """Get instance properties.
976

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

984
    """
985
    _, pid, alive = self._InstancePidAlive(instance_name)
986
    if not alive:
987
      return None
988

    
989
    _, memory, vcpus = self._InstancePidInfo(pid)
990
    istat = "---b-"
991
    times = "0"
992

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

    
1004
    return (instance_name, pid, memory, vcpus, istat, times)
1005

    
1006
  def GetAllInstancesInfo(self, hvparams=None):
1007
    """Get properties of all instances.
1008

1009
    @type hvparams: dict of strings
1010
    @param hvparams: hypervisor parameter
1011
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1012

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

    
1025
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1026
                          kvmhelp):
1027
    """Generate KVM information to start an instance.
1028

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

1038
    """
1039
    # pylint: disable=R0912,R0914,R0915
1040
    hvp = instance.hvparams
1041
    self.ValidateParameters(hvp)
1042

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

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

    
1058
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1059

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

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

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

    
1100
    if startup_paused:
1101
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1102

    
1103
    if boot_network:
1104
      kvm_cmd.extend(["-boot", "n"])
1105

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

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

    
1140
      drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
1141
                                                cache_val)
1142
      kvm_cmd.extend(["-drive", drive_val])
1143

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

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

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

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

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

    
1203
    mem_path = hvp[constants.HV_MEM_PATH]
1204
    if mem_path:
1205
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1206

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

    
1217
    mouse_type = hvp[constants.HV_USB_MOUSE]
1218
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1219
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1220
    spice_ip_version = None
1221

    
1222
    kvm_cmd.extend(["-usb"])
1223

    
1224
    if mouse_type:
1225
      kvm_cmd.extend(["-usbdevice", mouse_type])
1226
    elif vnc_bind_address:
1227
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1228

    
1229
    if vnc_bind_address:
1230
      if netutils.IsValidInterface(vnc_bind_address):
1231
        if_addresses = netutils.GetInterfaceIpAddresses(vnc_bind_address)
1232
        if_ip4_addresses = if_addresses[constants.IP4_VERSION]
1233
        if len(if_ip4_addresses) < 1:
1234
          logging.error("Could not determine IPv4 address of interface %s",
1235
                        vnc_bind_address)
1236
        else:
1237
          vnc_bind_address = if_ip4_addresses[0]
1238
      if netutils.IP4Address.IsValid(vnc_bind_address):
1239
        if instance.network_port > constants.VNC_BASE_PORT:
1240
          display = instance.network_port - constants.VNC_BASE_PORT
1241
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1242
            vnc_arg = ":%d" % (display)
1243
          else:
1244
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1245
        else:
1246
          logging.error("Network port is not a valid VNC display (%d < %d),"
1247
                        " not starting VNC",
1248
                        instance.network_port, constants.VNC_BASE_PORT)
1249
          vnc_arg = "none"
1250

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

    
1265
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1266

    
1267
      else:
1268
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1269

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

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

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

    
1304
        spice_address = addresses[spice_ip_version][0]
1305

    
1306
      else:
1307
        # spice_bind is known to be a valid IP address, because
1308
        # ValidateParameters checked it.
1309
        spice_address = spice_bind
1310

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

    
1325
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1326
        spice_arg = "%s,disable-ticketing" % spice_arg
1327

    
1328
      if spice_ip_version:
1329
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1330

    
1331
      # Image compression options
1332
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1333
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1334
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1335
      if img_lossless:
1336
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1337
      if img_jpeg:
1338
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1339
      if img_zlib_glz:
1340
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1341

    
1342
      # Video stream detection
1343
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1344
      if video_streaming:
1345
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1346

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

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

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

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

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

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

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

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

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

    
1399
    # Set system UUID to instance UUID
1400
    if self._UUID_RE.search(kvmhelp):
1401
      kvm_cmd.extend(["-uuid", instance.uuid])
1402

    
1403
    if hvp[constants.HV_KVM_EXTRA]:
1404
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1405

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

    
1411
    return (kvm_cmd, kvm_nics, hvparams)
1412

    
1413
  def _WriteKVMRuntime(self, instance_name, data):
1414
    """Write an instance's KVM runtime
1415

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

    
1423
  def _ReadKVMRuntime(self, instance_name):
1424
    """Read an instance's KVM runtime
1425

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

    
1433
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1434
    """Save an instance's KVM runtime
1435

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

    
1442
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1443
    """Load an instance's KVM runtime
1444

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

    
1453
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1454
    """Run the KVM cmd and check for errors
1455

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

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

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

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

1479
    @type incoming: tuple of strings
1480
    @param incoming: (target_host_ip, port)
1481
    @type kvmhelp: string
1482
    @param kvmhelp: output of kvm --help
1483

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

    
1497
    temp_files = []
1498

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

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

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

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

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

    
1553
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1554

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

    
1569
    if incoming:
1570
      target, port = incoming
1571
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1572

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

    
1585
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1586
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1587
                         constants.SECURE_DIR_MODE)])
1588

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

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

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

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

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

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

    
1641
    if vnc_pwd:
1642
      change_cmd = "change vnc password %s" % vnc_pwd
1643
      self._CallMonitorCommand(instance.name, change_cmd)
1644

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

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

    
1667
    for filename in temp_files:
1668
      utils.RemoveFile(filename)
1669

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

    
1674
    start_memory = self._InstanceStartupMemory(instance)
1675
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1676
      self.BalloonInstanceMemory(instance, start_memory)
1677

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

    
1684
  def StartInstance(self, instance, block_devices, startup_paused):
1685
    """Start an instance.
1686

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

    
1696
  def _CallMonitorCommand(self, instance_name, command):
1697
    """Invoke a command on the instance monitor.
1698

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

    
1718
    return result
1719

    
1720
  @classmethod
1721
  def _ParseKVMVersion(cls, text):
1722
    """Parse the KVM version from the --help output.
1723

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

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

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

    
1743
  @classmethod
1744
  def _GetKVMOutput(cls, kvm_path, option):
1745
    """Return the output of a kvm invocation
1746

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

1754
    """
1755
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
1756

    
1757
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
1758

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

    
1765
  @classmethod
1766
  def _GetKVMVersion(cls, kvm_path):
1767
    """Return the installed KVM version.
1768

1769
    @return: (version, v_maj, v_min, v_rev)
1770
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1771

1772
    """
1773
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
1774

    
1775
  @classmethod
1776
  def _GetDefaultMachineVersion(cls, kvm_path):
1777
    """Return the default hardware revision (e.g. pc-1.1)
1778

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

    
1787
  def StopInstance(self, instance, force=False, retry=False, name=None):
1788
    """Stop an instance.
1789

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

    
1805
  def CleanupInstance(self, instance_name):
1806
    """Cleanup after a stopped instance
1807

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

    
1814
  def RebootInstance(self, instance):
1815
    """Reboot an instance.
1816

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

    
1837
  def MigrationInfo(self, instance):
1838
    """Get instance information to perform a migration.
1839

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

1845
    """
1846
    return self._ReadKVMRuntime(instance.name)
1847

    
1848
  def AcceptInstance(self, instance, info, target):
1849
    """Prepare to accept an instance.
1850

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

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

    
1866
  def FinalizeMigrationDst(self, instance, info, success):
1867
    """Finalize the instance migration on the target node.
1868

1869
    Stop the incoming mode KVM.
1870

1871
    @type instance: L{objects.Instance}
1872
    @param instance: instance whose migration is being finalized
1873

1874
    """
1875
    if success:
1876
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1877
      kvm_nics = kvm_runtime[1]
1878

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

    
1894
      self._WriteKVMRuntime(instance.name, info)
1895
    else:
1896
      self.StopInstance(instance, force=True)
1897

    
1898
  def MigrateInstance(self, cluster_name, instance, target, live):
1899
    """Migrate an instance to a target node.
1900

1901
    The migration will not be attempted if the instance is not
1902
    currently running.
1903

1904
    @type cluster_name: string
1905
    @param cluster_name: name of the cluster
1906
    @type instance: L{objects.Instance}
1907
    @param instance: the instance to be migrated
1908
    @type target: string
1909
    @param target: ip address of the target node
1910
    @type live: boolean
1911
    @param live: perform a live migration
1912

1913
    """
1914
    instance_name = instance.name
1915
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
1916
    _, _, alive = self._InstancePidAlive(instance_name)
1917
    if not alive:
1918
      raise errors.HypervisorError("Instance not running, cannot migrate")
1919

    
1920
    if not live:
1921
      self._CallMonitorCommand(instance_name, "stop")
1922

    
1923
    migrate_command = ("migrate_set_speed %dm" %
1924
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1925
    self._CallMonitorCommand(instance_name, migrate_command)
1926

    
1927
    migrate_command = ("migrate_set_downtime %dms" %
1928
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1929
    self._CallMonitorCommand(instance_name, migrate_command)
1930

    
1931
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1932
    self._CallMonitorCommand(instance_name, migrate_command)
1933

    
1934
  def FinalizeMigrationSource(self, instance, success, live):
1935
    """Finalize the instance migration on the source node.
1936

1937
    @type instance: L{objects.Instance}
1938
    @param instance: the instance that was migrated
1939
    @type success: bool
1940
    @param success: whether the migration succeeded or not
1941
    @type live: bool
1942
    @param live: whether the user requested a live migration or not
1943

1944
    """
1945
    if success:
1946
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
1947
      utils.KillProcess(pid)
1948
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1949
    elif live:
1950
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1951

    
1952
  def GetMigrationStatus(self, instance):
1953
    """Get the migration status
1954

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

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

    
1982
          return migration_status
1983

    
1984
        logging.warning("KVM: unknown migration status '%s'", status)
1985

    
1986
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1987

    
1988
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
1989

    
1990
  def BalloonInstanceMemory(self, instance, mem):
1991
    """Balloon an instance memory to a certain value.
1992

1993
    @type instance: L{objects.Instance}
1994
    @param instance: instance to be accepted
1995
    @type mem: int
1996
    @param mem: actual memory size to use for instance runtime
1997

1998
    """
1999
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2000

    
2001
  def GetNodeInfo(self, hvparams=None):
2002
    """Return information about the node.
2003

2004
    @type hvparams: dict of strings
2005
    @param hvparams: hypervisor parameters, not used in this class
2006

2007
    @return: a dict as returned by L{BaseHypervisor.GetLinuxNodeInfo} plus
2008
        the following keys:
2009
          - hv_version: the hypervisor version in the form (major, minor,
2010
                        revision)
2011

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

    
2021
  @classmethod
2022
  def GetInstanceConsole(cls, instance, primary_node, hvparams, beparams):
2023
    """Return a command for connecting to the console of an instance.
2024

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

    
2038
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2039
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2040
      display = instance.network_port - constants.VNC_BASE_PORT
2041
      return objects.InstanceConsole(instance=instance.name,
2042
                                     kind=constants.CONS_VNC,
2043
                                     host=vnc_bind_address,
2044
                                     port=instance.network_port,
2045
                                     display=display)
2046

    
2047
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2048
    if spice_bind:
2049
      return objects.InstanceConsole(instance=instance.name,
2050
                                     kind=constants.CONS_SPICE,
2051
                                     host=spice_bind,
2052
                                     port=instance.network_port)
2053

    
2054
    return objects.InstanceConsole(instance=instance.name,
2055
                                   kind=constants.CONS_MESSAGE,
2056
                                   message=("No serial shell for instance %s" %
2057
                                            instance.name))
2058

    
2059
  def Verify(self, hvparams=None):
2060
    """Verify the hypervisor.
2061

2062
    Check that the required binaries exist.
2063

2064
    @type hvparams: dict of strings
2065
    @param hvparams: hypervisor parameters to be verified against, not used here
2066

2067
    @return: Problem description if something is wrong, C{None} otherwise
2068

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

    
2080
    return self._FormatVerifyResults(msgs)
2081

    
2082
  @classmethod
2083
  def CheckParameterSyntax(cls, hvparams):
2084
    """Check the given parameters for validity.
2085

2086
    @type hvparams:  dict
2087
    @param hvparams: dictionary with parameter names/value
2088
    @raise errors.HypervisorError: when a parameter is not valid
2089

2090
    """
2091
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2092

    
2093
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2094
    if kernel_path:
2095
      if not hvparams[constants.HV_ROOT_PATH]:
2096
        raise errors.HypervisorError("Need a root partition for the instance,"
2097
                                     " if a kernel is defined")
2098

    
2099
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2100
        not hvparams[constants.HV_VNC_X509]):
2101
      raise errors.HypervisorError("%s must be defined, if %s is" %
2102
                                   (constants.HV_VNC_X509,
2103
                                    constants.HV_VNC_X509_VERIFY))
2104

    
2105
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2106
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2107
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2108
      if not serial_speed or serial_speed not in valid_speeds:
2109
        raise errors.HypervisorError("Invalid serial console speed, must be"
2110
                                     " one of: %s" %
2111
                                     utils.CommaJoin(valid_speeds))
2112

    
2113
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2114
    if (boot_order == constants.HT_BO_CDROM and
2115
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2116
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2117
                                   " ISO path")
2118

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

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

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

    
2155
  @classmethod
2156
  def ValidateParameters(cls, hvparams):
2157
    """Check the given parameters for validity.
2158

2159
    @type hvparams:  dict
2160
    @param hvparams: dictionary with parameter names/value
2161
    @raise errors.HypervisorError: when a parameter is not valid
2162

2163
    """
2164
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2165

    
2166
    kvm_path = hvparams[constants.HV_KVM_PATH]
2167

    
2168
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2169
    if security_model == constants.HT_SM_USER:
2170
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2171
      try:
2172
        pwd.getpwnam(username)
2173
      except KeyError:
2174
        raise errors.HypervisorError("Unknown security domain user %s"
2175
                                     % username)
2176
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2177
    if vnc_bind_address:
2178
      bound_to_addr = netutils.IP4Address.IsValid(vnc_bind_address)
2179
      is_interface = netutils.IsValidInterface(vnc_bind_address)
2180
      is_path = utils.IsNormAbsPath(vnc_bind_address)
2181
      if not bound_to_addr and not is_interface and not is_path:
2182
        raise errors.HypervisorError("VNC: The %s parameter must be either"
2183
                                     " a valid IP address, an interface name,"
2184
                                     " or an absolute path" %
2185
                                     constants.HV_KVM_SPICE_BIND)
2186

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

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

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

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

    
2216
  @classmethod
2217
  def PowercycleNode(cls, hvparams=None):
2218
    """KVM powercycle, just a wrapper over Linux powercycle.
2219

2220
    @type hvparams: dict of strings
2221
    @param hvparams: hypervisor params to be used on this node
2222

2223
    """
2224
    cls.LinuxPowercycle()