Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 1c3231aa

History | View | Annotate | Download (81.5 kB)

1
#
2
#
3

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

    
21

    
22
"""KVM hypervisor
23

24
"""
25

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

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

    
57

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

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

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

    
82

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

86
  @see: L{_ProbeTapVnetHdr}
87

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

    
99

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

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

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

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

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

    
123
  result = bool(flags & IFF_VNET_HDR)
124

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

    
128
  return result
129

    
130

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

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

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

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

    
148
  flags = IFF_TAP | IFF_NO_PI
149

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

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

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

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

    
166

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

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

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

    
178
    self.data = data
179

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

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

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

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

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

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

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

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

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

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

    
220

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

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

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

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

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

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

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

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

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

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

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

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

    
289
    self._check_socket()
290

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

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

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

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

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

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

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

    
332
    return (message, buf)
333

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

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

342
    """
343
    self._check_connection()
344

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

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

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

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

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

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

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

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

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

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

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

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

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

    
429

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

433
  """
434
  CAN_MIGRATE = True
435

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

    
454
  PARAMETERS = {
455
    constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
456
    constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
457
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
458
    constants.HV_ROOT_PATH: hv_base.NO_CHECK,
459
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
460
    constants.HV_ACPI: hv_base.NO_CHECK,
461
    constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
462
    constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
463
    constants.HV_VNC_BIND_ADDRESS: 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
    }
533

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

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

    
544
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
545
  _MIGRATION_INFO_RETRY_DELAY = 2
546

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
656
    return (instance, memory, vcpus)
657

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

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

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

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

    
677
    return (pidfile, pid, alive)
678

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
942
    return result
943

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1303
        spice_address = addresses[spice_ip_version][0]
1304

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1402
    if hvp[constants.HV_KVM_EXTRA]:
1403
      kvm_cmd.extend([hvp[constants.HV_KVM_EXTRA]])
1404

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

    
1410
    return (kvm_cmd, kvm_nics, hvparams)
1411

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1496
    temp_files = []
1497

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1717
    return result
1718

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1868
    Stop the incoming mode KVM.
1869

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1981
          return migration_status
1982

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

    
1985
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1986

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

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

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

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

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

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

2006
    @return: a dict with the following keys (values in MiB):
2007
          - memory_total: the total memory size on the node
2008
          - memory_free: the available memory on the node for instances
2009
          - memory_dom0: the memory used by the node itself, if available
2010
          - hv_version: the hypervisor version in the form (major, minor,
2011
                        revision)
2012

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

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

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

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

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

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

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

2063
    Check that the required binaries exist.
2064

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

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

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

    
2081
    return self._FormatVerifyResults(msgs)
2082

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2167
    kvm_path = hvparams[constants.HV_KVM_PATH]
2168

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

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

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

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

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

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

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

2224
    """
2225
    cls.LinuxPowercycle()