Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ af5db30c

History | View | Annotate | Download (82.4 kB)

1
#
2
#
3

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

    
21

    
22
"""KVM hypervisor
23

24
"""
25

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

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

    
57

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

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

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

    
82

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

86
  @see: L{_ProbeTapVnetHdr}
87

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

    
99

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

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

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

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

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

    
123
  result = bool(flags & IFF_VNET_HDR)
124

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

    
128
  return result
129

    
130

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

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

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

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

    
148
  flags = IFF_TAP | IFF_NO_PI
149

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

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

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

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

    
166

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

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

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

    
178
    self.data = data
179

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

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

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

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

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

    
197
  def __len__(self):
198
    """Return the number of fields stored in this QmpMessage.
199

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

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

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

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

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

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

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

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

    
232

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

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

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

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

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

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

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

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

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

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

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

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

    
301
    self._check_socket()
302

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

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

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

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

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

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

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

    
344
    return (message, buf)
345

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

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

354
    """
355
    self._check_connection()
356

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

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

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

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

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

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

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

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

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

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

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

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

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

    
441

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

445
  """
446
  CAN_MIGRATE = True
447

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

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

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

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

    
557
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
558
  _MIGRATION_INFO_RETRY_DELAY = 2
559

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
669
    return (instance, memory, vcpus)
670

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

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

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

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

    
690
    return (pidfile, pid, alive)
691

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
955
    return result
956

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1037
  def _GenerateKVMBlockDevicesOptions(self, instance, block_devices, kvmhelp):
1038

    
1039
    hvp = instance.hvparams
1040
    boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1041

    
1042
    # whether this is an older KVM version that uses the boot=on flag
1043
    # on devices
1044
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1045

    
1046
    dev_opts = []
1047
    disk_type = hvp[constants.HV_DISK_TYPE]
1048
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
1049
      if_val = ",if=%s" % self._VIRTIO
1050
    else:
1051
      if_val = ",if=%s" % disk_type
1052
    # Cache mode
1053
    disk_cache = hvp[constants.HV_DISK_CACHE]
1054
    if instance.disk_template in constants.DTS_EXT_MIRROR:
1055
      if disk_cache != "none":
1056
        # TODO: make this a hard error, instead of a silent overwrite
1057
        logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1058
                        " to prevent shared storage corruption on migration",
1059
                        disk_cache)
1060
      cache_val = ",cache=none"
1061
    elif disk_cache != constants.HT_CACHE_DEFAULT:
1062
      cache_val = ",cache=%s" % disk_cache
1063
    else:
1064
      cache_val = ""
1065
    for cfdev, dev_path, device in block_devices:
1066
      if cfdev.mode != constants.DISK_RDWR:
1067
        raise errors.HypervisorError("Instance has read-only disks which"
1068
                                     " are not supported by KVM")
1069
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
1070
      boot_val = ""
1071
      if boot_disk:
1072
        dev_opts.extend(["-boot", "c"])
1073
        boot_disk = False
1074
        if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1075
          boot_val = ",boot=on"
1076

    
1077
      access_mode = cfdev.params.get(constants.LDP_ACCESS,
1078
                                     constants.DISK_KERNELSPACE)
1079
      if access_mode == constants.DISK_USERSPACE:
1080
        drive_uri = device.GetUserspaceAccessUri(constants.HT_KVM)
1081
      else:
1082
        drive_uri = dev_path
1083

    
1084
      drive_val = "file=%s,format=raw%s%s%s" % \
1085
                  (drive_uri, if_val, boot_val, cache_val)
1086

    
1087
      dev_opts.extend(["-drive", drive_val])
1088

    
1089
    return dev_opts
1090

    
1091
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1092
                          kvmhelp):
1093
    """Generate KVM information to start an instance.
1094

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

1104
    """
1105
    # pylint: disable=R0912,R0914,R0915
1106
    hvp = instance.hvparams
1107
    self.ValidateParameters(hvp)
1108

    
1109
    pidfile = self._InstancePidFile(instance.name)
1110
    kvm = hvp[constants.HV_KVM_PATH]
1111
    kvm_cmd = [kvm]
1112
    # used just by the vnc server, if enabled
1113
    kvm_cmd.extend(["-name", instance.name])
1114
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1115

    
1116
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1117
    if hvp[constants.HV_CPU_CORES]:
1118
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1119
    if hvp[constants.HV_CPU_THREADS]:
1120
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1121
    if hvp[constants.HV_CPU_SOCKETS]:
1122
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1123

    
1124
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1125

    
1126
    kvm_cmd.extend(["-pidfile", pidfile])
1127
    kvm_cmd.extend(["-balloon", "virtio"])
1128
    kvm_cmd.extend(["-daemonize"])
1129
    if not instance.hvparams[constants.HV_ACPI]:
1130
      kvm_cmd.extend(["-no-acpi"])
1131
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1132
        constants.INSTANCE_REBOOT_EXIT:
1133
      kvm_cmd.extend(["-no-reboot"])
1134

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

    
1157
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1158
    if kernel_path:
1159
      boot_cdrom = boot_floppy = boot_network = False
1160
    else:
1161
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1162
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1163
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1164

    
1165
    if startup_paused:
1166
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1167

    
1168
    if boot_network:
1169
      kvm_cmd.extend(["-boot", "n"])
1170

    
1171
    # whether this is an older KVM version that uses the boot=on flag
1172
    # on devices
1173
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1174

    
1175
    disk_type = hvp[constants.HV_DISK_TYPE]
1176

    
1177
    #Now we can specify a different device type for CDROM devices.
1178
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1179
    if not cdrom_disk_type:
1180
      cdrom_disk_type = disk_type
1181

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

    
1203
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1204
    if iso_image2:
1205
      options = ",format=raw,media=cdrom"
1206
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1207
        if_val = ",if=virtio"
1208
      else:
1209
        if_val = ",if=%s" % cdrom_disk_type
1210
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1211
      kvm_cmd.extend(["-drive", drive_val])
1212

    
1213
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1214
    if floppy_image:
1215
      options = ",format=raw,media=disk"
1216
      if boot_floppy:
1217
        kvm_cmd.extend(["-boot", "a"])
1218
        options = "%s,boot=on" % options
1219
      if_val = ",if=floppy"
1220
      options = "%s%s" % (options, if_val)
1221
      drive_val = "file=%s%s" % (floppy_image, options)
1222
      kvm_cmd.extend(["-drive", drive_val])
1223

    
1224
    if kernel_path:
1225
      kvm_cmd.extend(["-kernel", kernel_path])
1226
      initrd_path = hvp[constants.HV_INITRD_PATH]
1227
      if initrd_path:
1228
        kvm_cmd.extend(["-initrd", initrd_path])
1229
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1230
                     hvp[constants.HV_KERNEL_ARGS]]
1231
      if hvp[constants.HV_SERIAL_CONSOLE]:
1232
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1233
        root_append.append("console=ttyS0,%s" % serial_speed)
1234
      kvm_cmd.extend(["-append", " ".join(root_append)])
1235

    
1236
    mem_path = hvp[constants.HV_MEM_PATH]
1237
    if mem_path:
1238
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1239

    
1240
    monitor_dev = ("unix:%s,server,nowait" %
1241
                   self._InstanceMonitor(instance.name))
1242
    kvm_cmd.extend(["-monitor", monitor_dev])
1243
    if hvp[constants.HV_SERIAL_CONSOLE]:
1244
      serial_dev = ("unix:%s,server,nowait" %
1245
                    self._InstanceSerial(instance.name))
1246
      kvm_cmd.extend(["-serial", serial_dev])
1247
    else:
1248
      kvm_cmd.extend(["-serial", "none"])
1249

    
1250
    mouse_type = hvp[constants.HV_USB_MOUSE]
1251
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1252
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1253
    spice_ip_version = None
1254

    
1255
    kvm_cmd.extend(["-usb"])
1256

    
1257
    if mouse_type:
1258
      kvm_cmd.extend(["-usbdevice", mouse_type])
1259
    elif vnc_bind_address:
1260
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1261

    
1262
    if vnc_bind_address:
1263
      if netutils.IsValidInterface(vnc_bind_address):
1264
        if_addresses = netutils.GetInterfaceIpAddresses(vnc_bind_address)
1265
        if_ip4_addresses = if_addresses[constants.IP4_VERSION]
1266
        if len(if_ip4_addresses) < 1:
1267
          logging.error("Could not determine IPv4 address of interface %s",
1268
                        vnc_bind_address)
1269
        else:
1270
          vnc_bind_address = if_ip4_addresses[0]
1271
      if netutils.IP4Address.IsValid(vnc_bind_address):
1272
        if instance.network_port > constants.VNC_BASE_PORT:
1273
          display = instance.network_port - constants.VNC_BASE_PORT
1274
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1275
            vnc_arg = ":%d" % (display)
1276
          else:
1277
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1278
        else:
1279
          logging.error("Network port is not a valid VNC display (%d < %d),"
1280
                        " not starting VNC",
1281
                        instance.network_port, constants.VNC_BASE_PORT)
1282
          vnc_arg = "none"
1283

    
1284
        # Only allow tls and other option when not binding to a file, for now.
1285
        # kvm/qemu gets confused otherwise about the filename to use.
1286
        vnc_append = ""
1287
        if hvp[constants.HV_VNC_TLS]:
1288
          vnc_append = "%s,tls" % vnc_append
1289
          if hvp[constants.HV_VNC_X509_VERIFY]:
1290
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1291
                                               hvp[constants.HV_VNC_X509])
1292
          elif hvp[constants.HV_VNC_X509]:
1293
            vnc_append = "%s,x509=%s" % (vnc_append,
1294
                                         hvp[constants.HV_VNC_X509])
1295
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1296
          vnc_append = "%s,password" % vnc_append
1297

    
1298
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1299

    
1300
      else:
1301
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1302

    
1303
      kvm_cmd.extend(["-vnc", vnc_arg])
1304
    elif spice_bind:
1305
      # FIXME: this is wrong here; the iface ip address differs
1306
      # between systems, so it should be done in _ExecuteKVMRuntime
1307
      if netutils.IsValidInterface(spice_bind):
1308
        # The user specified a network interface, we have to figure out the IP
1309
        # address.
1310
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1311
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1312

    
1313
        # if the user specified an IP version and the interface does not
1314
        # have that kind of IP addresses, throw an exception
1315
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1316
          if not addresses[spice_ip_version]:
1317
            raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1318
                                         " for %s" % (spice_ip_version,
1319
                                                      spice_bind))
1320

    
1321
        # the user did not specify an IP version, we have to figure it out
1322
        elif (addresses[constants.IP4_VERSION] and
1323
              addresses[constants.IP6_VERSION]):
1324
          # we have both ipv4 and ipv6, let's use the cluster default IP
1325
          # version
1326
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1327
          spice_ip_version = \
1328
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1329
        elif addresses[constants.IP4_VERSION]:
1330
          spice_ip_version = constants.IP4_VERSION
1331
        elif addresses[constants.IP6_VERSION]:
1332
          spice_ip_version = constants.IP6_VERSION
1333
        else:
1334
          raise errors.HypervisorError("SPICE: Unable to get an IP address"
1335
                                       " for %s" % (spice_bind))
1336

    
1337
        spice_address = addresses[spice_ip_version][0]
1338

    
1339
      else:
1340
        # spice_bind is known to be a valid IP address, because
1341
        # ValidateParameters checked it.
1342
        spice_address = spice_bind
1343

    
1344
      spice_arg = "addr=%s" % spice_address
1345
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1346
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1347
                     (spice_arg, instance.network_port,
1348
                      pathutils.SPICE_CACERT_FILE))
1349
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1350
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1351
                      pathutils.SPICE_CERT_FILE))
1352
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1353
        if tls_ciphers:
1354
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1355
      else:
1356
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1357

    
1358
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1359
        spice_arg = "%s,disable-ticketing" % spice_arg
1360

    
1361
      if spice_ip_version:
1362
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1363

    
1364
      # Image compression options
1365
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1366
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1367
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1368
      if img_lossless:
1369
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1370
      if img_jpeg:
1371
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1372
      if img_zlib_glz:
1373
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1374

    
1375
      # Video stream detection
1376
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1377
      if video_streaming:
1378
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1379

    
1380
      # Audio compression, by default in qemu-kvm it is on
1381
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1382
        spice_arg = "%s,playback-compression=off" % spice_arg
1383
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1384
        spice_arg = "%s,agent-mouse=off" % spice_arg
1385
      else:
1386
        # Enable the spice agent communication channel between the host and the
1387
        # agent.
1388
        kvm_cmd.extend(["-device", "virtio-serial-pci"])
1389
        kvm_cmd.extend([
1390
          "-device",
1391
          "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1392
          ])
1393
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1394

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

    
1398
    else:
1399
      # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1400
      # also works in earlier versions though (tested with 1.1 and 1.3)
1401
      if self._DISPLAY_RE.search(kvmhelp):
1402
        kvm_cmd.extend(["-display", "none"])
1403
      else:
1404
        kvm_cmd.extend(["-nographic"])
1405

    
1406
    if hvp[constants.HV_USE_LOCALTIME]:
1407
      kvm_cmd.extend(["-localtime"])
1408

    
1409
    if hvp[constants.HV_KVM_USE_CHROOT]:
1410
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1411

    
1412
    # Add qemu-KVM -cpu param
1413
    if hvp[constants.HV_CPU_TYPE]:
1414
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1415

    
1416
    # As requested by music lovers
1417
    if hvp[constants.HV_SOUNDHW]:
1418
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1419

    
1420
    # Pass a -vga option if requested, or if spice is used, for backwards
1421
    # compatibility.
1422
    if hvp[constants.HV_VGA]:
1423
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1424
    elif spice_bind:
1425
      kvm_cmd.extend(["-vga", "qxl"])
1426

    
1427
    # Various types of usb devices, comma separated
1428
    if hvp[constants.HV_USB_DEVICES]:
1429
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1430
        kvm_cmd.extend(["-usbdevice", dev])
1431

    
1432
    # Set system UUID to instance UUID
1433
    if self._UUID_RE.search(kvmhelp):
1434
      kvm_cmd.extend(["-uuid", instance.uuid])
1435

    
1436
    if hvp[constants.HV_KVM_EXTRA]:
1437
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1438

    
1439
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1440
                                                     block_devices,
1441
                                                     kvmhelp)
1442
    kvm_cmd.extend(bdev_opts)
1443
    # Save the current instance nics, but defer their expansion as parameters,
1444
    # as we'll need to generate executable temp files for them.
1445
    kvm_nics = instance.nics
1446
    hvparams = hvp
1447

    
1448
    return (kvm_cmd, kvm_nics, hvparams)
1449

    
1450
  def _WriteKVMRuntime(self, instance_name, data):
1451
    """Write an instance's KVM runtime
1452

1453
    """
1454
    try:
1455
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1456
                      data=data)
1457
    except EnvironmentError, err:
1458
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1459

    
1460
  def _ReadKVMRuntime(self, instance_name):
1461
    """Read an instance's KVM runtime
1462

1463
    """
1464
    try:
1465
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1466
    except EnvironmentError, err:
1467
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1468
    return file_content
1469

    
1470
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1471
    """Save an instance's KVM runtime
1472

1473
    """
1474
    kvm_cmd, kvm_nics, hvparams = kvm_runtime
1475
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1476
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1477
    self._WriteKVMRuntime(instance.name, serialized_form)
1478

    
1479
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1480
    """Load an instance's KVM runtime
1481

1482
    """
1483
    if not serialized_runtime:
1484
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1485
    loaded_runtime = serializer.Load(serialized_runtime)
1486
    kvm_cmd, serialized_nics, hvparams = loaded_runtime
1487
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1488
    return (kvm_cmd, kvm_nics, hvparams)
1489

    
1490
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1491
    """Run the KVM cmd and check for errors
1492

1493
    @type name: string
1494
    @param name: instance name
1495
    @type kvm_cmd: list of strings
1496
    @param kvm_cmd: runcmd input for kvm
1497
    @type tap_fds: list of int
1498
    @param tap_fds: fds of tap devices opened by Ganeti
1499

1500
    """
1501
    try:
1502
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1503
    finally:
1504
      for fd in tap_fds:
1505
        utils_wrapper.CloseFdNoError(fd)
1506

    
1507
    if result.failed:
1508
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1509
                                   (name, result.fail_reason, result.output))
1510
    if not self._InstancePidAlive(name)[2]:
1511
      raise errors.HypervisorError("Failed to start instance %s" % name)
1512

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

1516
    @type incoming: tuple of strings
1517
    @param incoming: (target_host_ip, port)
1518
    @type kvmhelp: string
1519
    @param kvmhelp: output of kvm --help
1520

1521
    """
1522
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1523
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1524
    #    have changed since the instance started; only use them if the change
1525
    #    won't affect the inside of the instance (which hasn't been rebooted).
1526
    #  - up_hvp contains the parameters as they were when the instance was
1527
    #    started, plus any new parameter which has been added between ganeti
1528
    #    versions: it is paramount that those default to a value which won't
1529
    #    affect the inside of the instance as well.
1530
    conf_hvp = instance.hvparams
1531
    name = instance.name
1532
    self._CheckDown(name)
1533

    
1534
    temp_files = []
1535

    
1536
    kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1537
    # the first element of kvm_cmd is always the path to the kvm binary
1538
    kvm_path = kvm_cmd[0]
1539
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1540

    
1541
    # We know it's safe to run as a different user upon migration, so we'll use
1542
    # the latest conf, from conf_hvp.
1543
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1544
    if security_model == constants.HT_SM_USER:
1545
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1546

    
1547
    keymap = conf_hvp[constants.HV_KEYMAP]
1548
    if keymap:
1549
      keymap_path = self._InstanceKeymapFile(name)
1550
      # If a keymap file is specified, KVM won't use its internal defaults. By
1551
      # first including the "en-us" layout, an error on loading the actual
1552
      # layout (e.g. because it can't be found) won't lead to a non-functional
1553
      # keyboard. A keyboard with incorrect keys is still better than none.
1554
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1555
      kvm_cmd.extend(["-k", keymap_path])
1556

    
1557
    # We have reasons to believe changing something like the nic driver/type
1558
    # upon migration won't exactly fly with the instance kernel, so for nic
1559
    # related parameters we'll use up_hvp
1560
    tapfds = []
1561
    taps = []
1562
    if not kvm_nics:
1563
      kvm_cmd.extend(["-net", "none"])
1564
    else:
1565
      vnet_hdr = False
1566
      tap_extra = ""
1567
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1568
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1569
        nic_model = self._VIRTIO
1570
        try:
1571
          devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1572
          if self._NEW_VIRTIO_RE.search(devlist):
1573
            nic_model = self._VIRTIO_NET_PCI
1574
            vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1575
        except errors.HypervisorError, _:
1576
          # Older versions of kvm don't support DEVICE_LIST, but they don't
1577
          # have new virtio syntax either.
1578
          pass
1579

    
1580
        if up_hvp[constants.HV_VHOST_NET]:
1581
          # check for vhost_net support
1582
          if self._VHOST_RE.search(kvmhelp):
1583
            tap_extra = ",vhost=on"
1584
          else:
1585
            raise errors.HypervisorError("vhost_net is configured"
1586
                                         " but it is not available")
1587
      else:
1588
        nic_model = nic_type
1589

    
1590
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1591

    
1592
      for nic_seq, nic in enumerate(kvm_nics):
1593
        tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1594
        tapfds.append(tapfd)
1595
        taps.append(tapname)
1596
        if kvm_supports_netdev:
1597
          nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1598
          tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1599
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1600
        else:
1601
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1602
                                                         nic.mac, nic_model)
1603
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1604
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1605

    
1606
    if incoming:
1607
      target, port = incoming
1608
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1609

    
1610
    # Changing the vnc password doesn't bother the guest that much. At most it
1611
    # will surprise people who connect to it. Whether positively or negatively
1612
    # it's debatable.
1613
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1614
    vnc_pwd = None
1615
    if vnc_pwd_file:
1616
      try:
1617
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1618
      except EnvironmentError, err:
1619
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1620
                                     % (vnc_pwd_file, err))
1621

    
1622
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1623
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1624
                         constants.SECURE_DIR_MODE)])
1625

    
1626
    # Automatically enable QMP if version is >= 0.14
1627
    if self._QMP_RE.search(kvmhelp):
1628
      logging.debug("Enabling QMP")
1629
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1630
                      self._InstanceQmpMonitor(instance.name)])
1631

    
1632
    # Configure the network now for starting instances and bridged interfaces,
1633
    # during FinalizeMigration for incoming instances' routed interfaces
1634
    for nic_seq, nic in enumerate(kvm_nics):
1635
      if (incoming and
1636
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1637
        continue
1638
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1639

    
1640
    # CPU affinity requires kvm to start paused, so we set this flag if the
1641
    # instance is not already paused and if we are not going to accept a
1642
    # migrating instance. In the latter case, pausing is not needed.
1643
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1644
    if start_kvm_paused:
1645
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1646

    
1647
    # Note: CPU pinning is using up_hvp since changes take effect
1648
    # during instance startup anyway, and to avoid problems when soft
1649
    # rebooting the instance.
1650
    cpu_pinning = False
1651
    if up_hvp.get(constants.HV_CPU_MASK, None):
1652
      cpu_pinning = True
1653

    
1654
    if security_model == constants.HT_SM_POOL:
1655
      ss = ssconf.SimpleStore()
1656
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1657
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1658
      uid = uidpool.RequestUnusedUid(all_uids)
1659
      try:
1660
        username = pwd.getpwuid(uid.GetUid()).pw_name
1661
        kvm_cmd.extend(["-runas", username])
1662
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1663
      except:
1664
        uidpool.ReleaseUid(uid)
1665
        raise
1666
      else:
1667
        uid.Unlock()
1668
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1669
    else:
1670
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1671

    
1672
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1673
                     constants.RUN_DIRS_MODE)])
1674
    for nic_seq, tap in enumerate(taps):
1675
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1676
                      data=tap)
1677

    
1678
    if vnc_pwd:
1679
      change_cmd = "change vnc password %s" % vnc_pwd
1680
      self._CallMonitorCommand(instance.name, change_cmd)
1681

    
1682
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1683
    # connection attempts because SPICE by default does not allow connections
1684
    # if neither a password nor the "disable_ticketing" options are specified.
1685
    # As soon as we send the password via QMP, that password is a valid ticket
1686
    # for connection.
1687
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1688
    if spice_password_file:
1689
      spice_pwd = ""
1690
      try:
1691
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1692
      except EnvironmentError, err:
1693
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1694
                                     % (spice_password_file, err))
1695

    
1696
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1697
      qmp.connect()
1698
      arguments = {
1699
          "protocol": "spice",
1700
          "password": spice_pwd,
1701
      }
1702
      qmp.Execute("set_password", arguments)
1703

    
1704
    for filename in temp_files:
1705
      utils.RemoveFile(filename)
1706

    
1707
    # If requested, set CPU affinity and resume instance execution
1708
    if cpu_pinning:
1709
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1710

    
1711
    start_memory = self._InstanceStartupMemory(instance)
1712
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1713
      self.BalloonInstanceMemory(instance, start_memory)
1714

    
1715
    if start_kvm_paused:
1716
      # To control CPU pinning, ballooning, and vnc/spice passwords
1717
      # the VM was started in a frozen state. If freezing was not
1718
      # explicitly requested resume the vm status.
1719
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1720

    
1721
  def StartInstance(self, instance, block_devices, startup_paused):
1722
    """Start an instance.
1723

1724
    """
1725
    self._CheckDown(instance.name)
1726
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1727
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1728
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1729
                                           startup_paused, kvmhelp)
1730
    self._SaveKVMRuntime(instance, kvm_runtime)
1731
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1732

    
1733
  def _CallMonitorCommand(self, instance_name, command):
1734
    """Invoke a command on the instance monitor.
1735

1736
    """
1737
    # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1738
    # version. The monitor protocol is designed for human consumption, whereas
1739
    # QMP is made for programmatic usage. In the worst case QMP can also
1740
    # execute monitor commands. As it is, all calls to socat take at least
1741
    # 500ms and likely more: socat can't detect the end of the reply and waits
1742
    # for 500ms of no data received before exiting (500 ms is the default for
1743
    # the "-t" parameter).
1744
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1745
             (utils.ShellQuote(command),
1746
              constants.SOCAT_PATH,
1747
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1748
    result = utils.RunCmd(socat)
1749
    if result.failed:
1750
      msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1751
             " output: %s" %
1752
             (command, instance_name, result.fail_reason, result.output))
1753
      raise errors.HypervisorError(msg)
1754

    
1755
    return result
1756

    
1757
  @classmethod
1758
  def _ParseKVMVersion(cls, text):
1759
    """Parse the KVM version from the --help output.
1760

1761
    @type text: string
1762
    @param text: output of kvm --help
1763
    @return: (version, v_maj, v_min, v_rev)
1764
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1765

1766
    """
1767
    match = cls._VERSION_RE.search(text.splitlines()[0])
1768
    if not match:
1769
      raise errors.HypervisorError("Unable to get KVM version")
1770

    
1771
    v_all = match.group(0)
1772
    v_maj = int(match.group(1))
1773
    v_min = int(match.group(2))
1774
    if match.group(4):
1775
      v_rev = int(match.group(4))
1776
    else:
1777
      v_rev = 0
1778
    return (v_all, v_maj, v_min, v_rev)
1779

    
1780
  @classmethod
1781
  def _GetKVMOutput(cls, kvm_path, option):
1782
    """Return the output of a kvm invocation
1783

1784
    @type kvm_path: string
1785
    @param kvm_path: path to the kvm executable
1786
    @type option: a key of _KVMOPTS_CMDS
1787
    @param option: kvm option to fetch the output from
1788
    @return: output a supported kvm invocation
1789
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1790

1791
    """
1792
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
1793

    
1794
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
1795

    
1796
    result = utils.RunCmd([kvm_path] + optlist)
1797
    if result.failed and not can_fail:
1798
      raise errors.HypervisorError("Unable to get KVM %s output" %
1799
                                    " ".join(cls._KVMOPTS_CMDS[option]))
1800
    return result.output
1801

    
1802
  @classmethod
1803
  def _GetKVMVersion(cls, kvm_path):
1804
    """Return the installed KVM version.
1805

1806
    @return: (version, v_maj, v_min, v_rev)
1807
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1808

1809
    """
1810
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
1811

    
1812
  @classmethod
1813
  def _GetDefaultMachineVersion(cls, kvm_path):
1814
    """Return the default hardware revision (e.g. pc-1.1)
1815

1816
    """
1817
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
1818
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
1819
    if match:
1820
      return match.group(1)
1821
    else:
1822
      return "pc"
1823

    
1824
  def StopInstance(self, instance, force=False, retry=False, name=None):
1825
    """Stop an instance.
1826

1827
    """
1828
    if name is not None and not force:
1829
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1830
    if name is None:
1831
      name = instance.name
1832
      acpi = instance.hvparams[constants.HV_ACPI]
1833
    else:
1834
      acpi = False
1835
    _, pid, alive = self._InstancePidAlive(name)
1836
    if pid > 0 and alive:
1837
      if force or not acpi:
1838
        utils.KillProcess(pid)
1839
      else:
1840
        self._CallMonitorCommand(name, "system_powerdown")
1841

    
1842
  def CleanupInstance(self, instance_name):
1843
    """Cleanup after a stopped instance
1844

1845
    """
1846
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
1847
    if pid > 0 and alive:
1848
      raise errors.HypervisorError("Cannot cleanup a live instance")
1849
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1850

    
1851
  def RebootInstance(self, instance):
1852
    """Reboot an instance.
1853

1854
    """
1855
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1856
    # socket the instance will stop, but now power up again. So we'll resort
1857
    # to shutdown and restart.
1858
    _, _, alive = self._InstancePidAlive(instance.name)
1859
    if not alive:
1860
      raise errors.HypervisorError("Failed to reboot instance %s:"
1861
                                   " not running" % instance.name)
1862
    # StopInstance will delete the saved KVM runtime so:
1863
    # ...first load it...
1864
    kvm_runtime = self._LoadKVMRuntime(instance)
1865
    # ...now we can safely call StopInstance...
1866
    if not self.StopInstance(instance):
1867
      self.StopInstance(instance, force=True)
1868
    # ...and finally we can save it again, and execute it...
1869
    self._SaveKVMRuntime(instance, kvm_runtime)
1870
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1871
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1872
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1873

    
1874
  def MigrationInfo(self, instance):
1875
    """Get instance information to perform a migration.
1876

1877
    @type instance: L{objects.Instance}
1878
    @param instance: instance to be migrated
1879
    @rtype: string
1880
    @return: content of the KVM runtime file
1881

1882
    """
1883
    return self._ReadKVMRuntime(instance.name)
1884

    
1885
  def AcceptInstance(self, instance, info, target):
1886
    """Prepare to accept an instance.
1887

1888
    @type instance: L{objects.Instance}
1889
    @param instance: instance to be accepted
1890
    @type info: string
1891
    @param info: content of the KVM runtime file on the source node
1892
    @type target: string
1893
    @param target: target host (usually ip), on this node
1894

1895
    """
1896
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1897
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1898
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1899
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1900
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
1901
                            incoming=incoming_address)
1902

    
1903
  def FinalizeMigrationDst(self, instance, info, success):
1904
    """Finalize the instance migration on the target node.
1905

1906
    Stop the incoming mode KVM.
1907

1908
    @type instance: L{objects.Instance}
1909
    @param instance: instance whose migration is being finalized
1910

1911
    """
1912
    if success:
1913
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1914
      kvm_nics = kvm_runtime[1]
1915

    
1916
      for nic_seq, nic in enumerate(kvm_nics):
1917
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1918
          # Bridged interfaces have already been configured
1919
          continue
1920
        try:
1921
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1922
        except EnvironmentError, err:
1923
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
1924
                          instance.name, nic_seq, str(err))
1925
          continue
1926
        try:
1927
          self._ConfigureNIC(instance, nic_seq, nic, tap)
1928
        except errors.HypervisorError, err:
1929
          logging.warning(str(err))
1930

    
1931
      self._WriteKVMRuntime(instance.name, info)
1932
    else:
1933
      self.StopInstance(instance, force=True)
1934

    
1935
  def MigrateInstance(self, cluster_name, instance, target, live):
1936
    """Migrate an instance to a target node.
1937

1938
    The migration will not be attempted if the instance is not
1939
    currently running.
1940

1941
    @type cluster_name: string
1942
    @param cluster_name: name of the cluster
1943
    @type instance: L{objects.Instance}
1944
    @param instance: the instance to be migrated
1945
    @type target: string
1946
    @param target: ip address of the target node
1947
    @type live: boolean
1948
    @param live: perform a live migration
1949

1950
    """
1951
    instance_name = instance.name
1952
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
1953
    _, _, alive = self._InstancePidAlive(instance_name)
1954
    if not alive:
1955
      raise errors.HypervisorError("Instance not running, cannot migrate")
1956

    
1957
    if not live:
1958
      self._CallMonitorCommand(instance_name, "stop")
1959

    
1960
    migrate_command = ("migrate_set_speed %dm" %
1961
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1962
    self._CallMonitorCommand(instance_name, migrate_command)
1963

    
1964
    migrate_command = ("migrate_set_downtime %dms" %
1965
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1966
    self._CallMonitorCommand(instance_name, migrate_command)
1967

    
1968
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1969
    self._CallMonitorCommand(instance_name, migrate_command)
1970

    
1971
  def FinalizeMigrationSource(self, instance, success, live):
1972
    """Finalize the instance migration on the source node.
1973

1974
    @type instance: L{objects.Instance}
1975
    @param instance: the instance that was migrated
1976
    @type success: bool
1977
    @param success: whether the migration succeeded or not
1978
    @type live: bool
1979
    @param live: whether the user requested a live migration or not
1980

1981
    """
1982
    if success:
1983
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
1984
      utils.KillProcess(pid)
1985
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1986
    elif live:
1987
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1988

    
1989
  def GetMigrationStatus(self, instance):
1990
    """Get the migration status
1991

1992
    @type instance: L{objects.Instance}
1993
    @param instance: the instance that is being migrated
1994
    @rtype: L{objects.MigrationStatus}
1995
    @return: the status of the current migration (one of
1996
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1997
             progress info that can be retrieved from the hypervisor
1998

1999
    """
2000
    info_command = "info migrate"
2001
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2002
      result = self._CallMonitorCommand(instance.name, info_command)
2003
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
2004
      if not match:
2005
        if not result.stdout:
2006
          logging.info("KVM: empty 'info migrate' result")
2007
        else:
2008
          logging.warning("KVM: unknown 'info migrate' result: %s",
2009
                          result.stdout)
2010
      else:
2011
        status = match.group(1)
2012
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2013
          migration_status = objects.MigrationStatus(status=status)
2014
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2015
          if match:
2016
            migration_status.transferred_ram = match.group("transferred")
2017
            migration_status.total_ram = match.group("total")
2018

    
2019
          return migration_status
2020

    
2021
        logging.warning("KVM: unknown migration status '%s'", status)
2022

    
2023
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2024

    
2025
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2026

    
2027
  def BalloonInstanceMemory(self, instance, mem):
2028
    """Balloon an instance memory to a certain value.
2029

2030
    @type instance: L{objects.Instance}
2031
    @param instance: instance to be accepted
2032
    @type mem: int
2033
    @param mem: actual memory size to use for instance runtime
2034

2035
    """
2036
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2037

    
2038
  def GetNodeInfo(self, hvparams=None):
2039
    """Return information about the node.
2040

2041
    @type hvparams: dict of strings
2042
    @param hvparams: hypervisor parameters, not used in this class
2043

2044
    @return: a dict as returned by L{BaseHypervisor.GetLinuxNodeInfo} plus
2045
        the following keys:
2046
          - hv_version: the hypervisor version in the form (major, minor,
2047
                        revision)
2048

2049
    """
2050
    result = self.GetLinuxNodeInfo()
2051
    # FIXME: this is the global kvm version, but the actual version can be
2052
    # customized as an hv parameter. we should use the nodegroup's default kvm
2053
    # path parameter here.
2054
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2055
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2056
    return result
2057

    
2058
  @classmethod
2059
  def GetInstanceConsole(cls, instance, primary_node, hvparams, beparams):
2060
    """Return a command for connecting to the console of an instance.
2061

2062
    """
2063
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2064
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2065
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2066
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2067
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2068
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2069
      return objects.InstanceConsole(instance=instance.name,
2070
                                     kind=constants.CONS_SSH,
2071
                                     host=primary_node.name,
2072
                                     user=constants.SSH_CONSOLE_USER,
2073
                                     command=cmd)
2074

    
2075
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2076
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2077
      display = instance.network_port - constants.VNC_BASE_PORT
2078
      return objects.InstanceConsole(instance=instance.name,
2079
                                     kind=constants.CONS_VNC,
2080
                                     host=vnc_bind_address,
2081
                                     port=instance.network_port,
2082
                                     display=display)
2083

    
2084
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2085
    if spice_bind:
2086
      return objects.InstanceConsole(instance=instance.name,
2087
                                     kind=constants.CONS_SPICE,
2088
                                     host=spice_bind,
2089
                                     port=instance.network_port)
2090

    
2091
    return objects.InstanceConsole(instance=instance.name,
2092
                                   kind=constants.CONS_MESSAGE,
2093
                                   message=("No serial shell for instance %s" %
2094
                                            instance.name))
2095

    
2096
  def Verify(self, hvparams=None):
2097
    """Verify the hypervisor.
2098

2099
    Check that the required binaries exist.
2100

2101
    @type hvparams: dict of strings
2102
    @param hvparams: hypervisor parameters to be verified against, not used here
2103

2104
    @return: Problem description if something is wrong, C{None} otherwise
2105

2106
    """
2107
    msgs = []
2108
    # FIXME: this is the global kvm binary, but the actual path can be
2109
    # customized as an hv parameter; we should use the nodegroup's
2110
    # default kvm path parameter here.
2111
    if not os.path.exists(constants.KVM_PATH):
2112
      msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2113
    if not os.path.exists(constants.SOCAT_PATH):
2114
      msgs.append("The socat binary ('%s') does not exist" %
2115
                  constants.SOCAT_PATH)
2116

    
2117
    return self._FormatVerifyResults(msgs)
2118

    
2119
  @classmethod
2120
  def CheckParameterSyntax(cls, hvparams):
2121
    """Check the given parameters for validity.
2122

2123
    @type hvparams:  dict
2124
    @param hvparams: dictionary with parameter names/value
2125
    @raise errors.HypervisorError: when a parameter is not valid
2126

2127
    """
2128
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2129

    
2130
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2131
    if kernel_path:
2132
      if not hvparams[constants.HV_ROOT_PATH]:
2133
        raise errors.HypervisorError("Need a root partition for the instance,"
2134
                                     " if a kernel is defined")
2135

    
2136
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2137
        not hvparams[constants.HV_VNC_X509]):
2138
      raise errors.HypervisorError("%s must be defined, if %s is" %
2139
                                   (constants.HV_VNC_X509,
2140
                                    constants.HV_VNC_X509_VERIFY))
2141

    
2142
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2143
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2144
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2145
      if not serial_speed or serial_speed not in valid_speeds:
2146
        raise errors.HypervisorError("Invalid serial console speed, must be"
2147
                                     " one of: %s" %
2148
                                     utils.CommaJoin(valid_speeds))
2149

    
2150
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2151
    if (boot_order == constants.HT_BO_CDROM and
2152
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2153
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2154
                                   " ISO path")
2155

    
2156
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2157
    if security_model == constants.HT_SM_USER:
2158
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2159
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2160
                                     " must be specified")
2161
    elif (security_model == constants.HT_SM_NONE or
2162
          security_model == constants.HT_SM_POOL):
2163
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2164
        raise errors.HypervisorError("Cannot have a security domain when the"
2165
                                     " security model is 'none' or 'pool'")
2166

    
2167
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2168
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2169
    if spice_bind:
2170
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2171
        # if an IP version is specified, the spice_bind parameter must be an
2172
        # IP of that family
2173
        if (netutils.IP4Address.IsValid(spice_bind) and
2174
            spice_ip_version != constants.IP4_VERSION):
2175
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2176
                                       " the specified IP version is %s" %
2177
                                       (spice_bind, spice_ip_version))
2178

    
2179
        if (netutils.IP6Address.IsValid(spice_bind) and
2180
            spice_ip_version != constants.IP6_VERSION):
2181
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2182
                                       " the specified IP version is %s" %
2183
                                       (spice_bind, spice_ip_version))
2184
    else:
2185
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2186
      # error if any of them is set without it.
2187
      for param in _SPICE_ADDITIONAL_PARAMS:
2188
        if hvparams[param]:
2189
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2190
                                       (param, constants.HV_KVM_SPICE_BIND))
2191

    
2192
  @classmethod
2193
  def ValidateParameters(cls, hvparams):
2194
    """Check the given parameters for validity.
2195

2196
    @type hvparams:  dict
2197
    @param hvparams: dictionary with parameter names/value
2198
    @raise errors.HypervisorError: when a parameter is not valid
2199

2200
    """
2201
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2202

    
2203
    kvm_path = hvparams[constants.HV_KVM_PATH]
2204

    
2205
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2206
    if security_model == constants.HT_SM_USER:
2207
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2208
      try:
2209
        pwd.getpwnam(username)
2210
      except KeyError:
2211
        raise errors.HypervisorError("Unknown security domain user %s"
2212
                                     % username)
2213
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2214
    if vnc_bind_address:
2215
      bound_to_addr = netutils.IP4Address.IsValid(vnc_bind_address)
2216
      is_interface = netutils.IsValidInterface(vnc_bind_address)
2217
      is_path = utils.IsNormAbsPath(vnc_bind_address)
2218
      if not bound_to_addr and not is_interface and not is_path:
2219
        raise errors.HypervisorError("VNC: The %s parameter must be either"
2220
                                     " a valid IP address, an interface name,"
2221
                                     " or an absolute path" %
2222
                                     constants.HV_KVM_SPICE_BIND)
2223

    
2224
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2225
    if spice_bind:
2226
      # only one of VNC and SPICE can be used currently.
2227
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2228
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2229
                                     " only one of them can be used at a"
2230
                                     " given time")
2231

    
2232
      # check that KVM supports SPICE
2233
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2234
      if not cls._SPICE_RE.search(kvmhelp):
2235
        raise errors.HypervisorError("SPICE is configured, but it is not"
2236
                                     " supported according to 'kvm --help'")
2237

    
2238
      # if spice_bind is not an IP address, it must be a valid interface
2239
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2240
                       netutils.IP6Address.IsValid(spice_bind))
2241
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2242
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2243
                                     " a valid IP address or interface name" %
2244
                                     constants.HV_KVM_SPICE_BIND)
2245

    
2246
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2247
    if machine_version:
2248
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2249
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2250
        raise errors.HypervisorError("Unsupported machine version: %s" %
2251
                                     machine_version)
2252

    
2253
  @classmethod
2254
  def PowercycleNode(cls, hvparams=None):
2255
    """KVM powercycle, just a wrapper over Linux powercycle.
2256

2257
    @type hvparams: dict of strings
2258
    @param hvparams: hypervisor params to be used on this node
2259

2260
    """
2261
    cls.LinuxPowercycle()