Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ ce9283c1

History | View | Annotate | Download (78.9 kB)

1
#
2
#
3

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

    
21

    
22
"""KVM hypervisor
23

24
"""
25

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

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

    
57

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

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

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

    
82

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

86
  @see: L{_ProbeTapVnetHdr}
87

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

    
99

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

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

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

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

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

    
123
  result = bool(flags & IFF_VNET_HDR)
124

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

    
128
  return result
129

    
130

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

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

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

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

    
148
  flags = IFF_TAP | IFF_NO_PI
149

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

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

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

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

    
166

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

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

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

    
178
    self.data = data
179

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

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

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

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

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

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

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

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

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

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

    
220

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

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

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

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

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

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

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

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

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

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

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

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

    
289
    self._check_socket()
290

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

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

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

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

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

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

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

    
332
    return (message, buf)
333

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

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

342
    """
343
    self._check_connection()
344

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

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

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

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

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

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

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

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

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

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

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

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

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

    
429

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

433
  """
434
  CAN_MIGRATE = True
435

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

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

    
538
  _VIRTIO = "virtio"
539
  _VIRTIO_NET_PCI = "virtio-net-pci"
540

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

    
548
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
549
  _MIGRATION_INFO_RETRY_DELAY = 2
550

    
551
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
552

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
657
    return (instance, memory, vcpus)
658

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

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

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

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

    
678
    return (pidfile, pid, alive)
679

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
943
    return result
944

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

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

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

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

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

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

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

977
    @type instance_name: string
978
    @param instance_name: the instance name
979
    @rtype: tuple of strings
980
    @return: (name, id, memory, vcpus, stat, times)
981

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

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

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

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

    
1004
  def GetAllInstancesInfo(self):
1005
    """Get properties of all instances.
1006

1007
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1008

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

    
1021
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1022
                          kvmhelp):
1023
    """Generate KVM information to start an instance.
1024

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

1034
    """
1035
    # pylint: disable=R0912,R0914,R0915
1036
    hvp = instance.hvparams
1037

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

    
1045
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1046
    if hvp[constants.HV_CPU_CORES]:
1047
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1048
    if hvp[constants.HV_CPU_THREADS]:
1049
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1050
    if hvp[constants.HV_CPU_SOCKETS]:
1051
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1052

    
1053
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1054

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

    
1064
    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1065
    if not mversion:
1066
      mversion = self._GetDefaultMachineVersion(kvm)
1067
    kvm_cmd.extend(["-M", mversion])
1068

    
1069
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1070
    if kernel_path:
1071
      boot_disk = boot_cdrom = boot_floppy = boot_network = False
1072
    else:
1073
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1074
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1075
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1076
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1077

    
1078
    self.ValidateParameters(hvp)
1079

    
1080
    if startup_paused:
1081
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1082

    
1083
    if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1084
        self._ENABLE_KVM_RE.search(kvmhelp)):
1085
      kvm_cmd.extend(["-enable-kvm"])
1086
    elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1087
          self._DISABLE_KVM_RE.search(kvmhelp)):
1088
      kvm_cmd.extend(["-disable-kvm"])
1089

    
1090
    if boot_network:
1091
      kvm_cmd.extend(["-boot", "n"])
1092

    
1093
    # whether this is an older KVM version that uses the boot=on flag
1094
    # on devices
1095
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1096

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

    
1127
      drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
1128
                                                cache_val)
1129
      kvm_cmd.extend(["-drive", drive_val])
1130

    
1131
    #Now we can specify a different device type for CDROM devices.
1132
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1133
    if not cdrom_disk_type:
1134
      cdrom_disk_type = disk_type
1135

    
1136
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1137
    if iso_image:
1138
      options = ",format=raw,media=cdrom"
1139
      # set cdrom 'if' type
1140
      if boot_cdrom:
1141
        actual_cdrom_type = constants.HT_DISK_IDE
1142
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1143
        actual_cdrom_type = "virtio"
1144
      else:
1145
        actual_cdrom_type = cdrom_disk_type
1146
      if_val = ",if=%s" % actual_cdrom_type
1147
      # set boot flag, if needed
1148
      boot_val = ""
1149
      if boot_cdrom:
1150
        kvm_cmd.extend(["-boot", "d"])
1151
        if needs_boot_flag:
1152
          boot_val = ",boot=on"
1153
      # and finally build the entire '-drive' value
1154
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1155
      kvm_cmd.extend(["-drive", drive_val])
1156

    
1157
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1158
    if iso_image2:
1159
      options = ",format=raw,media=cdrom"
1160
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1161
        if_val = ",if=virtio"
1162
      else:
1163
        if_val = ",if=%s" % cdrom_disk_type
1164
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1165
      kvm_cmd.extend(["-drive", drive_val])
1166

    
1167
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1168
    if floppy_image:
1169
      options = ",format=raw,media=disk"
1170
      if boot_floppy:
1171
        kvm_cmd.extend(["-boot", "a"])
1172
        options = "%s,boot=on" % options
1173
      if_val = ",if=floppy"
1174
      options = "%s%s" % (options, if_val)
1175
      drive_val = "file=%s%s" % (floppy_image, options)
1176
      kvm_cmd.extend(["-drive", drive_val])
1177

    
1178
    if kernel_path:
1179
      kvm_cmd.extend(["-kernel", kernel_path])
1180
      initrd_path = hvp[constants.HV_INITRD_PATH]
1181
      if initrd_path:
1182
        kvm_cmd.extend(["-initrd", initrd_path])
1183
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1184
                     hvp[constants.HV_KERNEL_ARGS]]
1185
      if hvp[constants.HV_SERIAL_CONSOLE]:
1186
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1187
        root_append.append("console=ttyS0,%s" % serial_speed)
1188
      kvm_cmd.extend(["-append", " ".join(root_append)])
1189

    
1190
    mem_path = hvp[constants.HV_MEM_PATH]
1191
    if mem_path:
1192
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1193

    
1194
    monitor_dev = ("unix:%s,server,nowait" %
1195
                   self._InstanceMonitor(instance.name))
1196
    kvm_cmd.extend(["-monitor", monitor_dev])
1197
    if hvp[constants.HV_SERIAL_CONSOLE]:
1198
      serial_dev = ("unix:%s,server,nowait" %
1199
                    self._InstanceSerial(instance.name))
1200
      kvm_cmd.extend(["-serial", serial_dev])
1201
    else:
1202
      kvm_cmd.extend(["-serial", "none"])
1203

    
1204
    mouse_type = hvp[constants.HV_USB_MOUSE]
1205
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1206
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1207
    spice_ip_version = None
1208

    
1209
    kvm_cmd.extend(["-usb"])
1210

    
1211
    if mouse_type:
1212
      kvm_cmd.extend(["-usbdevice", mouse_type])
1213
    elif vnc_bind_address:
1214
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1215

    
1216
    if vnc_bind_address:
1217
      if netutils.IP4Address.IsValid(vnc_bind_address):
1218
        if instance.network_port > constants.VNC_BASE_PORT:
1219
          display = instance.network_port - constants.VNC_BASE_PORT
1220
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1221
            vnc_arg = ":%d" % (display)
1222
          else:
1223
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1224
        else:
1225
          logging.error("Network port is not a valid VNC display (%d < %d),"
1226
                        " not starting VNC",
1227
                        instance.network_port, constants.VNC_BASE_PORT)
1228
          vnc_arg = "none"
1229

    
1230
        # Only allow tls and other option when not binding to a file, for now.
1231
        # kvm/qemu gets confused otherwise about the filename to use.
1232
        vnc_append = ""
1233
        if hvp[constants.HV_VNC_TLS]:
1234
          vnc_append = "%s,tls" % vnc_append
1235
          if hvp[constants.HV_VNC_X509_VERIFY]:
1236
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1237
                                               hvp[constants.HV_VNC_X509])
1238
          elif hvp[constants.HV_VNC_X509]:
1239
            vnc_append = "%s,x509=%s" % (vnc_append,
1240
                                         hvp[constants.HV_VNC_X509])
1241
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1242
          vnc_append = "%s,password" % vnc_append
1243

    
1244
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1245

    
1246
      else:
1247
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1248

    
1249
      kvm_cmd.extend(["-vnc", vnc_arg])
1250
    elif spice_bind:
1251
      # FIXME: this is wrong here; the iface ip address differs
1252
      # between systems, so it should be done in _ExecuteKVMRuntime
1253
      if netutils.IsValidInterface(spice_bind):
1254
        # The user specified a network interface, we have to figure out the IP
1255
        # address.
1256
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1257
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1258

    
1259
        # if the user specified an IP version and the interface does not
1260
        # have that kind of IP addresses, throw an exception
1261
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1262
          if not addresses[spice_ip_version]:
1263
            raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1264
                                         " for %s" % (spice_ip_version,
1265
                                                      spice_bind))
1266

    
1267
        # the user did not specify an IP version, we have to figure it out
1268
        elif (addresses[constants.IP4_VERSION] and
1269
              addresses[constants.IP6_VERSION]):
1270
          # we have both ipv4 and ipv6, let's use the cluster default IP
1271
          # version
1272
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1273
          spice_ip_version = \
1274
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1275
        elif addresses[constants.IP4_VERSION]:
1276
          spice_ip_version = constants.IP4_VERSION
1277
        elif addresses[constants.IP6_VERSION]:
1278
          spice_ip_version = constants.IP6_VERSION
1279
        else:
1280
          raise errors.HypervisorError("SPICE: Unable to get an IP address"
1281
                                       " for %s" % (spice_bind))
1282

    
1283
        spice_address = addresses[spice_ip_version][0]
1284

    
1285
      else:
1286
        # spice_bind is known to be a valid IP address, because
1287
        # ValidateParameters checked it.
1288
        spice_address = spice_bind
1289

    
1290
      spice_arg = "addr=%s" % spice_address
1291
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1292
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1293
                     (spice_arg, instance.network_port,
1294
                      pathutils.SPICE_CACERT_FILE))
1295
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1296
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1297
                      pathutils.SPICE_CERT_FILE))
1298
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1299
        if tls_ciphers:
1300
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1301
      else:
1302
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1303

    
1304
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1305
        spice_arg = "%s,disable-ticketing" % spice_arg
1306

    
1307
      if spice_ip_version:
1308
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1309

    
1310
      # Image compression options
1311
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1312
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1313
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1314
      if img_lossless:
1315
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1316
      if img_jpeg:
1317
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1318
      if img_zlib_glz:
1319
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1320

    
1321
      # Video stream detection
1322
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1323
      if video_streaming:
1324
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1325

    
1326
      # Audio compression, by default in qemu-kvm it is on
1327
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1328
        spice_arg = "%s,playback-compression=off" % spice_arg
1329
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1330
        spice_arg = "%s,agent-mouse=off" % spice_arg
1331
      else:
1332
        # Enable the spice agent communication channel between the host and the
1333
        # agent.
1334
        kvm_cmd.extend(["-device", "virtio-serial-pci"])
1335
        kvm_cmd.extend([
1336
          "-device",
1337
          "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1338
          ])
1339
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1340

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

    
1344
    else:
1345
      kvm_cmd.extend(["-nographic"])
1346

    
1347
    if hvp[constants.HV_USE_LOCALTIME]:
1348
      kvm_cmd.extend(["-localtime"])
1349

    
1350
    if hvp[constants.HV_KVM_USE_CHROOT]:
1351
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1352

    
1353
    # Add qemu-KVM -cpu param
1354
    if hvp[constants.HV_CPU_TYPE]:
1355
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1356

    
1357
    # As requested by music lovers
1358
    if hvp[constants.HV_SOUNDHW]:
1359
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1360

    
1361
    # Pass a -vga option if requested, or if spice is used, for backwards
1362
    # compatibility.
1363
    if hvp[constants.HV_VGA]:
1364
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1365
    elif spice_bind:
1366
      kvm_cmd.extend(["-vga", "qxl"])
1367

    
1368
    # Various types of usb devices, comma separated
1369
    if hvp[constants.HV_USB_DEVICES]:
1370
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1371
        kvm_cmd.extend(["-usbdevice", dev])
1372

    
1373
    if hvp[constants.HV_KVM_EXTRA]:
1374
      kvm_cmd.extend([hvp[constants.HV_KVM_EXTRA]])
1375

    
1376
    # Save the current instance nics, but defer their expansion as parameters,
1377
    # as we'll need to generate executable temp files for them.
1378
    kvm_nics = instance.nics
1379
    hvparams = hvp
1380

    
1381
    return (kvm_cmd, kvm_nics, hvparams)
1382

    
1383
  def _WriteKVMRuntime(self, instance_name, data):
1384
    """Write an instance's KVM runtime
1385

1386
    """
1387
    try:
1388
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1389
                      data=data)
1390
    except EnvironmentError, err:
1391
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1392

    
1393
  def _ReadKVMRuntime(self, instance_name):
1394
    """Read an instance's KVM runtime
1395

1396
    """
1397
    try:
1398
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1399
    except EnvironmentError, err:
1400
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1401
    return file_content
1402

    
1403
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1404
    """Save an instance's KVM runtime
1405

1406
    """
1407
    kvm_cmd, kvm_nics, hvparams = kvm_runtime
1408
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1409
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1410
    self._WriteKVMRuntime(instance.name, serialized_form)
1411

    
1412
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1413
    """Load an instance's KVM runtime
1414

1415
    """
1416
    if not serialized_runtime:
1417
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1418
    loaded_runtime = serializer.Load(serialized_runtime)
1419
    kvm_cmd, serialized_nics, hvparams = loaded_runtime
1420
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1421
    return (kvm_cmd, kvm_nics, hvparams)
1422

    
1423
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1424
    """Run the KVM cmd and check for errors
1425

1426
    @type name: string
1427
    @param name: instance name
1428
    @type kvm_cmd: list of strings
1429
    @param kvm_cmd: runcmd input for kvm
1430
    @type tap_fds: list of int
1431
    @param tap_fds: fds of tap devices opened by Ganeti
1432

1433
    """
1434
    try:
1435
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1436
    finally:
1437
      for fd in tap_fds:
1438
        utils_wrapper.CloseFdNoError(fd)
1439

    
1440
    if result.failed:
1441
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1442
                                   (name, result.fail_reason, result.output))
1443
    if not self._InstancePidAlive(name)[2]:
1444
      raise errors.HypervisorError("Failed to start instance %s" % name)
1445

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

1449
    @type incoming: tuple of strings
1450
    @param incoming: (target_host_ip, port)
1451
    @type kvmhelp: string
1452
    @param kvmhelp: output of kvm --help
1453

1454
    """
1455
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1456
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1457
    #    have changed since the instance started; only use them if the change
1458
    #    won't affect the inside of the instance (which hasn't been rebooted).
1459
    #  - up_hvp contains the parameters as they were when the instance was
1460
    #    started, plus any new parameter which has been added between ganeti
1461
    #    versions: it is paramount that those default to a value which won't
1462
    #    affect the inside of the instance as well.
1463
    conf_hvp = instance.hvparams
1464
    name = instance.name
1465
    self._CheckDown(name)
1466

    
1467
    temp_files = []
1468

    
1469
    kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1470
    # the first element of kvm_cmd is always the path to the kvm binary
1471
    kvm_path = kvm_cmd[0]
1472
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1473

    
1474
    # We know it's safe to run as a different user upon migration, so we'll use
1475
    # the latest conf, from conf_hvp.
1476
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1477
    if security_model == constants.HT_SM_USER:
1478
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1479

    
1480
    keymap = conf_hvp[constants.HV_KEYMAP]
1481
    if keymap:
1482
      keymap_path = self._InstanceKeymapFile(name)
1483
      # If a keymap file is specified, KVM won't use its internal defaults. By
1484
      # first including the "en-us" layout, an error on loading the actual
1485
      # layout (e.g. because it can't be found) won't lead to a non-functional
1486
      # keyboard. A keyboard with incorrect keys is still better than none.
1487
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1488
      kvm_cmd.extend(["-k", keymap_path])
1489

    
1490
    # We have reasons to believe changing something like the nic driver/type
1491
    # upon migration won't exactly fly with the instance kernel, so for nic
1492
    # related parameters we'll use up_hvp
1493
    tapfds = []
1494
    taps = []
1495
    if not kvm_nics:
1496
      kvm_cmd.extend(["-net", "none"])
1497
    else:
1498
      vnet_hdr = False
1499
      tap_extra = ""
1500
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1501
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1502
        nic_model = self._VIRTIO
1503
        try:
1504
          devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1505
          if self._NEW_VIRTIO_RE.search(devlist):
1506
            nic_model = self._VIRTIO_NET_PCI
1507
            vnet_hdr = True
1508
        except errors.HypervisorError, _:
1509
          # Older versions of kvm don't support DEVICE_LIST, but they don't
1510
          # have new virtio syntax either.
1511
          pass
1512

    
1513
        if up_hvp[constants.HV_VHOST_NET]:
1514
          # check for vhost_net support
1515
          if self._VHOST_RE.search(kvmhelp):
1516
            tap_extra = ",vhost=on"
1517
          else:
1518
            raise errors.HypervisorError("vhost_net is configured"
1519
                                         " but it is not available")
1520
      else:
1521
        nic_model = nic_type
1522

    
1523
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1524

    
1525
      for nic_seq, nic in enumerate(kvm_nics):
1526
        tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1527
        tapfds.append(tapfd)
1528
        taps.append(tapname)
1529
        if kvm_supports_netdev:
1530
          nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1531
          tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1532
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1533
        else:
1534
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1535
                                                         nic.mac, nic_model)
1536
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1537
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1538

    
1539
    if incoming:
1540
      target, port = incoming
1541
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1542

    
1543
    # Changing the vnc password doesn't bother the guest that much. At most it
1544
    # will surprise people who connect to it. Whether positively or negatively
1545
    # it's debatable.
1546
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1547
    vnc_pwd = None
1548
    if vnc_pwd_file:
1549
      try:
1550
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1551
      except EnvironmentError, err:
1552
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1553
                                     % (vnc_pwd_file, err))
1554

    
1555
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1556
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1557
                         constants.SECURE_DIR_MODE)])
1558

    
1559
    # Automatically enable QMP if version is >= 0.14
1560
    if self._QMP_RE.search(kvmhelp):
1561
      logging.debug("Enabling QMP")
1562
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1563
                      self._InstanceQmpMonitor(instance.name)])
1564

    
1565
    # Configure the network now for starting instances and bridged interfaces,
1566
    # during FinalizeMigration for incoming instances' routed interfaces
1567
    for nic_seq, nic in enumerate(kvm_nics):
1568
      if (incoming and
1569
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1570
        continue
1571
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1572

    
1573
    # CPU affinity requires kvm to start paused, so we set this flag if the
1574
    # instance is not already paused and if we are not going to accept a
1575
    # migrating instance. In the latter case, pausing is not needed.
1576
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1577
    if start_kvm_paused:
1578
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1579

    
1580
    # Note: CPU pinning is using up_hvp since changes take effect
1581
    # during instance startup anyway, and to avoid problems when soft
1582
    # rebooting the instance.
1583
    cpu_pinning = False
1584
    if up_hvp.get(constants.HV_CPU_MASK, None):
1585
      cpu_pinning = True
1586

    
1587
    if security_model == constants.HT_SM_POOL:
1588
      ss = ssconf.SimpleStore()
1589
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1590
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1591
      uid = uidpool.RequestUnusedUid(all_uids)
1592
      try:
1593
        username = pwd.getpwuid(uid.GetUid()).pw_name
1594
        kvm_cmd.extend(["-runas", username])
1595
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1596
      except:
1597
        uidpool.ReleaseUid(uid)
1598
        raise
1599
      else:
1600
        uid.Unlock()
1601
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1602
    else:
1603
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1604

    
1605
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1606
                     constants.RUN_DIRS_MODE)])
1607
    for nic_seq, tap in enumerate(taps):
1608
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1609
                      data=tap)
1610

    
1611
    if vnc_pwd:
1612
      change_cmd = "change vnc password %s" % vnc_pwd
1613
      self._CallMonitorCommand(instance.name, change_cmd)
1614

    
1615
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1616
    # connection attempts because SPICE by default does not allow connections
1617
    # if neither a password nor the "disable_ticketing" options are specified.
1618
    # As soon as we send the password via QMP, that password is a valid ticket
1619
    # for connection.
1620
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1621
    if spice_password_file:
1622
      spice_pwd = ""
1623
      try:
1624
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1625
      except EnvironmentError, err:
1626
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1627
                                     % (spice_password_file, err))
1628

    
1629
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1630
      qmp.connect()
1631
      arguments = {
1632
          "protocol": "spice",
1633
          "password": spice_pwd,
1634
      }
1635
      qmp.Execute("set_password", arguments)
1636

    
1637
    for filename in temp_files:
1638
      utils.RemoveFile(filename)
1639

    
1640
    # If requested, set CPU affinity and resume instance execution
1641
    if cpu_pinning:
1642
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1643

    
1644
    start_memory = self._InstanceStartupMemory(instance)
1645
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1646
      self.BalloonInstanceMemory(instance, start_memory)
1647

    
1648
    if start_kvm_paused:
1649
      # To control CPU pinning, ballooning, and vnc/spice passwords
1650
      # the VM was started in a frozen state. If freezing was not
1651
      # explicitly requested resume the vm status.
1652
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1653

    
1654
  def StartInstance(self, instance, block_devices, startup_paused):
1655
    """Start an instance.
1656

1657
    """
1658
    self._CheckDown(instance.name)
1659
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1660
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1661
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1662
                                           startup_paused, kvmhelp)
1663
    self._SaveKVMRuntime(instance, kvm_runtime)
1664
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1665

    
1666
  def _CallMonitorCommand(self, instance_name, command):
1667
    """Invoke a command on the instance monitor.
1668

1669
    """
1670
    # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1671
    # version. The monitor protocol is designed for human consumption, whereas
1672
    # QMP is made for programmatic usage. In the worst case QMP can also
1673
    # execute monitor commands. As it is, all calls to socat take at least
1674
    # 500ms and likely more: socat can't detect the end of the reply and waits
1675
    # for 500ms of no data received before exiting (500 ms is the default for
1676
    # the "-t" parameter).
1677
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1678
             (utils.ShellQuote(command),
1679
              constants.SOCAT_PATH,
1680
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1681
    result = utils.RunCmd(socat)
1682
    if result.failed:
1683
      msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1684
             " output: %s" %
1685
             (command, instance_name, result.fail_reason, result.output))
1686
      raise errors.HypervisorError(msg)
1687

    
1688
    return result
1689

    
1690
  @classmethod
1691
  def _ParseKVMVersion(cls, text):
1692
    """Parse the KVM version from the --help output.
1693

1694
    @type text: string
1695
    @param text: output of kvm --help
1696
    @return: (version, v_maj, v_min, v_rev)
1697
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1698

1699
    """
1700
    match = cls._VERSION_RE.search(text.splitlines()[0])
1701
    if not match:
1702
      raise errors.HypervisorError("Unable to get KVM version")
1703

    
1704
    v_all = match.group(0)
1705
    v_maj = int(match.group(1))
1706
    v_min = int(match.group(2))
1707
    if match.group(4):
1708
      v_rev = int(match.group(4))
1709
    else:
1710
      v_rev = 0
1711
    return (v_all, v_maj, v_min, v_rev)
1712

    
1713
  @classmethod
1714
  def _GetKVMOutput(cls, kvm_path, option):
1715
    """Return the output of a kvm invocation
1716

1717
    @type kvm_path: string
1718
    @param kvm_path: path to the kvm executable
1719
    @type option: a key of _KVMOPTS_CMDS
1720
    @param option: kvm option to fetch the output from
1721
    @return: output a supported kvm invocation
1722
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1723

1724
    """
1725
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
1726

    
1727
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
1728

    
1729
    result = utils.RunCmd([kvm_path] + optlist)
1730
    if result.failed and not can_fail:
1731
      raise errors.HypervisorError("Unable to get KVM %s output" %
1732
                                    " ".join(cls._KVMOPTS_CMDS[option]))
1733
    return result.output
1734

    
1735
  @classmethod
1736
  def _GetKVMVersion(cls, kvm_path):
1737
    """Return the installed KVM version.
1738

1739
    @return: (version, v_maj, v_min, v_rev)
1740
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1741

1742
    """
1743
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
1744

    
1745
  @classmethod
1746
  def _GetDefaultMachineVersion(cls, kvm_path):
1747
    """Return the default hardware revision (e.g. pc-1.1)
1748

1749
    """
1750
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
1751
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
1752
    if match:
1753
      return match.group(1)
1754
    else:
1755
      return "pc"
1756

    
1757
  def StopInstance(self, instance, force=False, retry=False, name=None):
1758
    """Stop an instance.
1759

1760
    """
1761
    if name is not None and not force:
1762
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1763
    if name is None:
1764
      name = instance.name
1765
      acpi = instance.hvparams[constants.HV_ACPI]
1766
    else:
1767
      acpi = False
1768
    _, pid, alive = self._InstancePidAlive(name)
1769
    if pid > 0 and alive:
1770
      if force or not acpi:
1771
        utils.KillProcess(pid)
1772
      else:
1773
        self._CallMonitorCommand(name, "system_powerdown")
1774

    
1775
  def CleanupInstance(self, instance_name):
1776
    """Cleanup after a stopped instance
1777

1778
    """
1779
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
1780
    if pid > 0 and alive:
1781
      raise errors.HypervisorError("Cannot cleanup a live instance")
1782
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1783

    
1784
  def RebootInstance(self, instance):
1785
    """Reboot an instance.
1786

1787
    """
1788
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1789
    # socket the instance will stop, but now power up again. So we'll resort
1790
    # to shutdown and restart.
1791
    _, _, alive = self._InstancePidAlive(instance.name)
1792
    if not alive:
1793
      raise errors.HypervisorError("Failed to reboot instance %s:"
1794
                                   " not running" % instance.name)
1795
    # StopInstance will delete the saved KVM runtime so:
1796
    # ...first load it...
1797
    kvm_runtime = self._LoadKVMRuntime(instance)
1798
    # ...now we can safely call StopInstance...
1799
    if not self.StopInstance(instance):
1800
      self.StopInstance(instance, force=True)
1801
    # ...and finally we can save it again, and execute it...
1802
    self._SaveKVMRuntime(instance, kvm_runtime)
1803
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1804
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1805
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1806

    
1807
  def MigrationInfo(self, instance):
1808
    """Get instance information to perform a migration.
1809

1810
    @type instance: L{objects.Instance}
1811
    @param instance: instance to be migrated
1812
    @rtype: string
1813
    @return: content of the KVM runtime file
1814

1815
    """
1816
    return self._ReadKVMRuntime(instance.name)
1817

    
1818
  def AcceptInstance(self, instance, info, target):
1819
    """Prepare to accept an instance.
1820

1821
    @type instance: L{objects.Instance}
1822
    @param instance: instance to be accepted
1823
    @type info: string
1824
    @param info: content of the KVM runtime file on the source node
1825
    @type target: string
1826
    @param target: target host (usually ip), on this node
1827

1828
    """
1829
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1830
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1831
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1832
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1833
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
1834
                            incoming=incoming_address)
1835

    
1836
  def FinalizeMigrationDst(self, instance, info, success):
1837
    """Finalize the instance migration on the target node.
1838

1839
    Stop the incoming mode KVM.
1840

1841
    @type instance: L{objects.Instance}
1842
    @param instance: instance whose migration is being finalized
1843

1844
    """
1845
    if success:
1846
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1847
      kvm_nics = kvm_runtime[1]
1848

    
1849
      for nic_seq, nic in enumerate(kvm_nics):
1850
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1851
          # Bridged interfaces have already been configured
1852
          continue
1853
        try:
1854
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1855
        except EnvironmentError, err:
1856
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
1857
                          instance.name, nic_seq, str(err))
1858
          continue
1859
        try:
1860
          self._ConfigureNIC(instance, nic_seq, nic, tap)
1861
        except errors.HypervisorError, err:
1862
          logging.warning(str(err))
1863

    
1864
      self._WriteKVMRuntime(instance.name, info)
1865
    else:
1866
      self.StopInstance(instance, force=True)
1867

    
1868
  def MigrateInstance(self, instance, target, live):
1869
    """Migrate an instance to a target node.
1870

1871
    The migration will not be attempted if the instance is not
1872
    currently running.
1873

1874
    @type instance: L{objects.Instance}
1875
    @param instance: the instance to be migrated
1876
    @type target: string
1877
    @param target: ip address of the target node
1878
    @type live: boolean
1879
    @param live: perform a live migration
1880

1881
    """
1882
    instance_name = instance.name
1883
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
1884
    _, _, alive = self._InstancePidAlive(instance_name)
1885
    if not alive:
1886
      raise errors.HypervisorError("Instance not running, cannot migrate")
1887

    
1888
    if not live:
1889
      self._CallMonitorCommand(instance_name, "stop")
1890

    
1891
    migrate_command = ("migrate_set_speed %dm" %
1892
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1893
    self._CallMonitorCommand(instance_name, migrate_command)
1894

    
1895
    migrate_command = ("migrate_set_downtime %dms" %
1896
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1897
    self._CallMonitorCommand(instance_name, migrate_command)
1898

    
1899
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1900
    self._CallMonitorCommand(instance_name, migrate_command)
1901

    
1902
  def FinalizeMigrationSource(self, instance, success, live):
1903
    """Finalize the instance migration on the source node.
1904

1905
    @type instance: L{objects.Instance}
1906
    @param instance: the instance that was migrated
1907
    @type success: bool
1908
    @param success: whether the migration succeeded or not
1909
    @type live: bool
1910
    @param live: whether the user requested a live migration or not
1911

1912
    """
1913
    if success:
1914
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
1915
      utils.KillProcess(pid)
1916
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1917
    elif live:
1918
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1919

    
1920
  def GetMigrationStatus(self, instance):
1921
    """Get the migration status
1922

1923
    @type instance: L{objects.Instance}
1924
    @param instance: the instance that is being migrated
1925
    @rtype: L{objects.MigrationStatus}
1926
    @return: the status of the current migration (one of
1927
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1928
             progress info that can be retrieved from the hypervisor
1929

1930
    """
1931
    info_command = "info migrate"
1932
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
1933
      result = self._CallMonitorCommand(instance.name, info_command)
1934
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
1935
      if not match:
1936
        if not result.stdout:
1937
          logging.info("KVM: empty 'info migrate' result")
1938
        else:
1939
          logging.warning("KVM: unknown 'info migrate' result: %s",
1940
                          result.stdout)
1941
      else:
1942
        status = match.group(1)
1943
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
1944
          migration_status = objects.MigrationStatus(status=status)
1945
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
1946
          if match:
1947
            migration_status.transferred_ram = match.group("transferred")
1948
            migration_status.total_ram = match.group("total")
1949

    
1950
          return migration_status
1951

    
1952
        logging.warning("KVM: unknown migration status '%s'", status)
1953

    
1954
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1955

    
1956
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
1957

    
1958
  def BalloonInstanceMemory(self, instance, mem):
1959
    """Balloon an instance memory to a certain value.
1960

1961
    @type instance: L{objects.Instance}
1962
    @param instance: instance to be accepted
1963
    @type mem: int
1964
    @param mem: actual memory size to use for instance runtime
1965

1966
    """
1967
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
1968

    
1969
  def GetNodeInfo(self):
1970
    """Return information about the node.
1971

1972
    @return: a dict with the following keys (values in MiB):
1973
          - memory_total: the total memory size on the node
1974
          - memory_free: the available memory on the node for instances
1975
          - memory_dom0: the memory used by the node itself, if available
1976
          - hv_version: the hypervisor version in the form (major, minor,
1977
                        revision)
1978

1979
    """
1980
    result = self.GetLinuxNodeInfo()
1981
    # FIXME: this is the global kvm version, but the actual version can be
1982
    # customized as an hv parameter. we should use the nodegroup's default kvm
1983
    # path parameter here.
1984
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
1985
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
1986
    return result
1987

    
1988
  @classmethod
1989
  def GetInstanceConsole(cls, instance, hvparams, beparams):
1990
    """Return a command for connecting to the console of an instance.
1991

1992
    """
1993
    if hvparams[constants.HV_SERIAL_CONSOLE]:
1994
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
1995
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1996
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1997
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
1998
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1999
      return objects.InstanceConsole(instance=instance.name,
2000
                                     kind=constants.CONS_SSH,
2001
                                     host=instance.primary_node,
2002
                                     user=constants.SSH_CONSOLE_USER,
2003
                                     command=cmd)
2004

    
2005
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2006
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2007
      display = instance.network_port - constants.VNC_BASE_PORT
2008
      return objects.InstanceConsole(instance=instance.name,
2009
                                     kind=constants.CONS_VNC,
2010
                                     host=vnc_bind_address,
2011
                                     port=instance.network_port,
2012
                                     display=display)
2013

    
2014
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2015
    if spice_bind:
2016
      return objects.InstanceConsole(instance=instance.name,
2017
                                     kind=constants.CONS_SPICE,
2018
                                     host=spice_bind,
2019
                                     port=instance.network_port)
2020

    
2021
    return objects.InstanceConsole(instance=instance.name,
2022
                                   kind=constants.CONS_MESSAGE,
2023
                                   message=("No serial shell for instance %s" %
2024
                                            instance.name))
2025

    
2026
  def Verify(self):
2027
    """Verify the hypervisor.
2028

2029
    Check that the required binaries exist.
2030

2031
    @return: Problem description if something is wrong, C{None} otherwise
2032

2033
    """
2034
    msgs = []
2035
    # FIXME: this is the global kvm binary, but the actual path can be
2036
    # customized as an hv parameter; we should use the nodegroup's
2037
    # default kvm path parameter here.
2038
    if not os.path.exists(constants.KVM_PATH):
2039
      msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2040
    if not os.path.exists(constants.SOCAT_PATH):
2041
      msgs.append("The socat binary ('%s') does not exist" %
2042
                  constants.SOCAT_PATH)
2043

    
2044
    return self._FormatVerifyResults(msgs)
2045

    
2046
  @classmethod
2047
  def CheckParameterSyntax(cls, hvparams):
2048
    """Check the given parameters for validity.
2049

2050
    @type hvparams:  dict
2051
    @param hvparams: dictionary with parameter names/value
2052
    @raise errors.HypervisorError: when a parameter is not valid
2053

2054
    """
2055
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2056

    
2057
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2058
    if kernel_path:
2059
      if not hvparams[constants.HV_ROOT_PATH]:
2060
        raise errors.HypervisorError("Need a root partition for the instance,"
2061
                                     " if a kernel is defined")
2062

    
2063
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2064
        not hvparams[constants.HV_VNC_X509]):
2065
      raise errors.HypervisorError("%s must be defined, if %s is" %
2066
                                   (constants.HV_VNC_X509,
2067
                                    constants.HV_VNC_X509_VERIFY))
2068

    
2069
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2070
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2071
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2072
      if not serial_speed or serial_speed not in valid_speeds:
2073
        raise errors.HypervisorError("Invalid serial console speed, must be"
2074
                                     " one of: %s" %
2075
                                     utils.CommaJoin(valid_speeds))
2076

    
2077
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2078
    if (boot_order == constants.HT_BO_CDROM and
2079
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2080
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2081
                                   " ISO path")
2082

    
2083
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2084
    if security_model == constants.HT_SM_USER:
2085
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2086
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2087
                                     " must be specified")
2088
    elif (security_model == constants.HT_SM_NONE or
2089
          security_model == constants.HT_SM_POOL):
2090
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2091
        raise errors.HypervisorError("Cannot have a security domain when the"
2092
                                     " security model is 'none' or 'pool'")
2093

    
2094
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2095
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2096
    if spice_bind:
2097
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2098
        # if an IP version is specified, the spice_bind parameter must be an
2099
        # IP of that family
2100
        if (netutils.IP4Address.IsValid(spice_bind) and
2101
            spice_ip_version != constants.IP4_VERSION):
2102
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2103
                                       " the specified IP version is %s" %
2104
                                       (spice_bind, spice_ip_version))
2105

    
2106
        if (netutils.IP6Address.IsValid(spice_bind) and
2107
            spice_ip_version != constants.IP6_VERSION):
2108
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2109
                                       " the specified IP version is %s" %
2110
                                       (spice_bind, spice_ip_version))
2111
    else:
2112
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2113
      # error if any of them is set without it.
2114
      for param in _SPICE_ADDITIONAL_PARAMS:
2115
        if hvparams[param]:
2116
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2117
                                       (param, constants.HV_KVM_SPICE_BIND))
2118

    
2119
  @classmethod
2120
  def ValidateParameters(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).ValidateParameters(hvparams)
2129

    
2130
    kvm_path = hvparams[constants.HV_KVM_PATH]
2131

    
2132
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2133
    if security_model == constants.HT_SM_USER:
2134
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2135
      try:
2136
        pwd.getpwnam(username)
2137
      except KeyError:
2138
        raise errors.HypervisorError("Unknown security domain user %s"
2139
                                     % username)
2140

    
2141
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2142
    if spice_bind:
2143
      # only one of VNC and SPICE can be used currently.
2144
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2145
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2146
                                     " only one of them can be used at a"
2147
                                     " given time")
2148

    
2149
      # check that KVM supports SPICE
2150
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2151
      if not cls._SPICE_RE.search(kvmhelp):
2152
        raise errors.HypervisorError("SPICE is configured, but it is not"
2153
                                     " supported according to 'kvm --help'")
2154

    
2155
      # if spice_bind is not an IP address, it must be a valid interface
2156
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2157
                       netutils.IP6Address.IsValid(spice_bind))
2158
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2159
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2160
                                     " a valid IP address or interface name" %
2161
                                     constants.HV_KVM_SPICE_BIND)
2162

    
2163
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2164
    if machine_version:
2165
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2166
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2167
        raise errors.HypervisorError("Unsupported machine version: %s" %
2168
                                     machine_version)
2169

    
2170
  @classmethod
2171
  def PowercycleNode(cls):
2172
    """KVM powercycle, just a wrapper over Linux powercycle.
2173

2174
    """
2175
    cls.LinuxPowercycle()