Statistics
| Branch: | Tag: | Revision:

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

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 _ProbeTapVnetHdr(fd):
84
  """Check whether to enable the IFF_VNET_HDR flag.
85

86
  To do this, _all_ of the following conditions must be met:
87
   1. TUNGETFEATURES ioctl() *must* be implemented
88
   2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
89
   3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
90
      drivers/net/tun.c there is no way to test this until after the tap device
91
      has been created using TUNSETIFF, and there is no way to change the
92
      IFF_VNET_HDR flag after creating the interface, catch-22! However both
93
      TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
94
      thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
95

96
   @type fd: int
97
   @param fd: the file descriptor of /dev/net/tun
98

99
  """
100
  req = struct.pack("I", 0)
101
  try:
102
    res = fcntl.ioctl(fd, TUNGETFEATURES, req)
103
  except EnvironmentError:
104
    logging.warning("TUNGETFEATURES ioctl() not implemented")
105
    return False
106

    
107
  tunflags = struct.unpack("I", res)[0]
108
  if tunflags & IFF_VNET_HDR:
109
    return True
110
  else:
111
    logging.warning("Host does not support IFF_VNET_HDR, not enabling")
112
    return False
113

    
114

    
115
def _OpenTap(vnet_hdr=True):
116
  """Open a new tap device and return its file descriptor.
117

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

121
  @type vnet_hdr: boolean
122
  @param vnet_hdr: Enable the VNET Header
123
  @return: (ifname, tapfd)
124
  @rtype: tuple
125

126
  """
127
  try:
128
    tapfd = os.open("/dev/net/tun", os.O_RDWR)
129
  except EnvironmentError:
130
    raise errors.HypervisorError("Failed to open /dev/net/tun")
131

    
132
  flags = IFF_TAP | IFF_NO_PI
133

    
134
  if vnet_hdr and _ProbeTapVnetHdr(tapfd):
135
    flags |= IFF_VNET_HDR
136

    
137
  # The struct ifreq ioctl request (see netdevice(7))
138
  ifr = struct.pack("16sh", "", flags)
139

    
140
  try:
141
    res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
142
  except EnvironmentError, err:
143
    raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
144
                                 err)
145

    
146
  # Get the interface name from the ioctl
147
  ifname = struct.unpack("16sh", res)[0].strip("\x00")
148
  return (ifname, tapfd)
149

    
150

    
151
def _BuildNetworkEnv(name, network, gateway, network6, gateway6,
152
                     mac_prefix, tags, env):
153
  """Build environment variables concerning a Network.
154

155
  """
156
  if name:
157
    env["NETWORK_NAME"] = name
158
  if network:
159
    env["NETWORK_SUBNET"] = network
160
  if gateway:
161
    env["NETWORK_GATEWAY"] = gateway
162
  if network6:
163
    env["NETWORK_SUBNET6"] = network6
164
  if gateway6:
165
    env["NETWORK_GATEWAY6"] = gateway6
166
  if mac_prefix:
167
    env["NETWORK_MAC_PREFIX"] = mac_prefix
168
  if tags:
169
    env["NETWORK_TAGS"] = " ".join(tags)
170

    
171
  return env
172

    
173

    
174
class QmpMessage:
175
  """QEMU Messaging Protocol (QMP) message.
176

177
  """
178
  def __init__(self, data):
179
    """Creates a new QMP message based on the passed data.
180

181
    """
182
    if not isinstance(data, dict):
183
      raise TypeError("QmpMessage must be initialized with a dict")
184

    
185
    self.data = data
186

    
187
  def __getitem__(self, field_name):
188
    """Get the value of the required field if present, or None.
189

190
    Overrides the [] operator to provide access to the message data,
191
    returning None if the required item is not in the message
192
    @return: the value of the field_name field, or None if field_name
193
             is not contained in the message
194

195
    """
196
    return self.data.get(field_name, None)
197

    
198
  def __setitem__(self, field_name, field_value):
199
    """Set the value of the required field_name to field_value.
200

201
    """
202
    self.data[field_name] = field_value
203

    
204
  @staticmethod
205
  def BuildFromJsonString(json_string):
206
    """Build a QmpMessage from a JSON encoded string.
207

208
    @type json_string: str
209
    @param json_string: JSON string representing the message
210
    @rtype: L{QmpMessage}
211
    @return: a L{QmpMessage} built from json_string
212

213
    """
214
    # Parse the string
215
    data = serializer.LoadJson(json_string)
216
    return QmpMessage(data)
217

    
218
  def __str__(self):
219
    # The protocol expects the JSON object to be sent as a single line.
220
    return serializer.DumpJson(self.data)
221

    
222
  def __eq__(self, other):
223
    # When comparing two QmpMessages, we are interested in comparing
224
    # their internal representation of the message data
225
    return self.data == other.data
226

    
227

    
228
class QmpConnection:
229
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
230

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

    
246
  def __init__(self, monitor_filename):
247
    """Instantiates the QmpConnection object.
248

249
    @type monitor_filename: string
250
    @param monitor_filename: the filename of the UNIX raw socket on which the
251
                             QMP monitor is listening
252

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

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

    
275
  def _check_connection(self):
276
    """Make sure that the connection is established.
277

278
    """
279
    if not self._connected:
280
      raise errors.ProgrammerError("To use a QmpConnection you need to first"
281
                                   " invoke connect() on it")
282

    
283
  def connect(self):
284
    """Connects to the QMP monitor.
285

286
    Connects to the UNIX socket and makes sure that we can actually send and
287
    receive data to the kvm instance via QMP.
288

289
    @raise errors.HypervisorError: when there are communication errors
290
    @raise errors.ProgrammerError: when there are data serialization errors
291

292
    """
293
    if self._connected:
294
      raise errors.ProgrammerError("Cannot connect twice")
295

    
296
    self._check_socket()
297

    
298
    # Check file existance/stuff
299
    try:
300
      self.sock.connect(self.monitor_filename)
301
    except EnvironmentError:
302
      raise errors.HypervisorError("Can't connect to qmp socket")
303
    self._connected = True
304

    
305
    # Check if we receive a correct greeting message from the server
306
    # (As per the QEMU Protocol Specification 0.1 - section 2.2)
307
    greeting = self._Recv()
308
    if not greeting[self._FIRST_MESSAGE_KEY]:
309
      self._connected = False
310
      raise errors.HypervisorError("kvm: qmp communication error (wrong"
311
                                   " server greeting")
312

    
313
    # Let's put the monitor in command mode using the qmp_capabilities
314
    # command, or else no command will be executable.
315
    # (As per the QEMU Protocol Specification 0.1 - section 4)
316
    self.Execute(self._CAPABILITIES_COMMAND)
317

    
318
  def _ParseMessage(self, buf):
319
    """Extract and parse a QMP message from the given buffer.
320

321
    Seeks for a QMP message in the given buf. If found, it parses it and
322
    returns it together with the rest of the characters in the buf.
323
    If no message is found, returns None and the whole buffer.
324

325
    @raise errors.ProgrammerError: when there are data serialization errors
326

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

    
339
    return (message, buf)
340

    
341
  def _Recv(self):
342
    """Receives a message from QMP and decodes the received JSON object.
343

344
    @rtype: QmpMessage
345
    @return: the received message
346
    @raise errors.HypervisorError: when there are communication errors
347
    @raise errors.ProgrammerError: when there are data serialization errors
348

349
    """
350
    self._check_connection()
351

    
352
    # Check if there is already a message in the buffer
353
    (message, self._buf) = self._ParseMessage(self._buf)
354
    if message:
355
      return message
356

    
357
    recv_buffer = StringIO.StringIO(self._buf)
358
    recv_buffer.seek(len(self._buf))
359
    try:
360
      while True:
361
        data = self.sock.recv(4096)
362
        if not data:
363
          break
364
        recv_buffer.write(data)
365

    
366
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
367
        if message:
368
          return message
369

    
370
    except socket.timeout, err:
371
      raise errors.HypervisorError("Timeout while receiving a QMP message: "
372
                                   "%s" % (err))
373
    except socket.error, err:
374
      raise errors.HypervisorError("Unable to receive data from KVM using the"
375
                                   " QMP protocol: %s" % err)
376

    
377
  def _Send(self, message):
378
    """Encodes and sends a message to KVM using QMP.
379

380
    @type message: QmpMessage
381
    @param message: message to send to KVM
382
    @raise errors.HypervisorError: when there are communication errors
383
    @raise errors.ProgrammerError: when there are data serialization errors
384

385
    """
386
    self._check_connection()
387
    try:
388
      message_str = str(message)
389
    except Exception, err:
390
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
391

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

    
401
  def Execute(self, command, arguments=None):
402
    """Executes a QMP command and returns the response of the server.
403

404
    @type command: str
405
    @param command: the command to execute
406
    @type arguments: dict
407
    @param arguments: dictionary of arguments to be passed to the command
408
    @rtype: dict
409
    @return: dictionary representing the received JSON object
410
    @raise errors.HypervisorError: when there are communication errors
411
    @raise errors.ProgrammerError: when there are data serialization errors
412

413
    """
414
    self._check_connection()
415
    message = QmpMessage({self._EXECUTE_KEY: command})
416
    if arguments:
417
      message[self._ARGUMENTS_KEY] = arguments
418
    self._Send(message)
419

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

    
433
      elif not response[self._EVENT_KEY]:
434
        return response
435

    
436

    
437
class KVMHypervisor(hv_base.BaseHypervisor):
438
  """KVM hypervisor interface
439

440
  """
441
  CAN_MIGRATE = True
442

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

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

    
545
  _VIRTIO = "virtio"
546
  _VIRTIO_NET_PCI = "virtio-net-pci"
547

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

    
555
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
556
  _MIGRATION_INFO_RETRY_DELAY = 2
557

    
558
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
559

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

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

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

    
580
  ANCILLARY_FILES = [
581
    _KVM_NETWORK_SCRIPT,
582
    ]
583
  ANCILLARY_FILES_OPT = [
584
    _KVM_NETWORK_SCRIPT,
585
    ]
586

    
587
  # Supported kvm options to get output from
588
  _KVMOPT_HELP = "help"
589
  _KVMOPT_MLIST = "mlist"
590
  _KVMOPT_DEVICELIST = "devicelist"
591

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

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

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

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

    
614
  @classmethod
615
  def _InstanceUidFile(cls, instance_name):
616
    """Returns the instance uidfile.
617

618
    """
619
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
620

    
621
  @classmethod
622
  def _InstancePidInfo(cls, pid):
623
    """Check pid file for instance information.
624

625
    Check that a pid file is associated with an instance, and retrieve
626
    information from its command line.
627

628
    @type pid: string or int
629
    @param pid: process id of the instance to check
630
    @rtype: tuple
631
    @return: (instance_name, memory, vcpus)
632
    @raise errors.HypervisorError: when an instance cannot be found
633

634
    """
635
    alive = utils.IsProcessAlive(pid)
636
    if not alive:
637
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
638

    
639
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
640
    try:
641
      cmdline = utils.ReadFile(cmdline_file)
642
    except EnvironmentError, err:
643
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
644
                                   (pid, err))
645

    
646
    instance = None
647
    memory = 0
648
    vcpus = 0
649

    
650
    arg_list = cmdline.split("\x00")
651
    while arg_list:
652
      arg = arg_list.pop(0)
653
      if arg == "-name":
654
        instance = arg_list.pop(0)
655
      elif arg == "-m":
656
        memory = int(arg_list.pop(0))
657
      elif arg == "-smp":
658
        vcpus = int(arg_list.pop(0).split(",")[0])
659

    
660
    if instance is None:
661
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
662
                                   " instance" % pid)
663

    
664
    return (instance, memory, vcpus)
665

    
666
  def _InstancePidAlive(self, instance_name):
667
    """Returns the instance pidfile, pid, and liveness.
668

669
    @type instance_name: string
670
    @param instance_name: instance name
671
    @rtype: tuple
672
    @return: (pid file name, pid, liveness)
673

674
    """
675
    pidfile = self._InstancePidFile(instance_name)
676
    pid = utils.ReadPidFile(pidfile)
677

    
678
    alive = False
679
    try:
680
      cmd_instance = self._InstancePidInfo(pid)[0]
681
      alive = (cmd_instance == instance_name)
682
    except errors.HypervisorError:
683
      pass
684

    
685
    return (pidfile, pid, alive)
686

    
687
  def _CheckDown(self, instance_name):
688
    """Raises an error unless the given instance is down.
689

690
    """
691
    alive = self._InstancePidAlive(instance_name)[2]
692
    if alive:
693
      raise errors.HypervisorError("Failed to start instance %s: %s" %
694
                                   (instance_name, "already running"))
695

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

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

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

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

    
710
  @classmethod
711
  def _InstanceQmpMonitor(cls, instance_name):
712
    """Returns the instance serial QMP socket name
713

714
    """
715
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
716

    
717
  @staticmethod
718
  def _SocatUnixConsoleParams():
719
    """Returns the correct parameters for socat
720

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

723
    """
724
    if constants.SOCAT_USE_ESCAPE:
725
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
726
    else:
727
      return "echo=0,icanon=0"
728

    
729
  @classmethod
730
  def _InstanceKVMRuntime(cls, instance_name):
731
    """Returns the instance KVM runtime filename
732

733
    """
734
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
735

    
736
  @classmethod
737
  def _InstanceChrootDir(cls, instance_name):
738
    """Returns the name of the KVM chroot dir of the instance
739

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

    
743
  @classmethod
744
  def _InstanceNICDir(cls, instance_name):
745
    """Returns the name of the directory holding the tap device files for a
746
    given instance.
747

748
    """
749
    return utils.PathJoin(cls._NICS_DIR, instance_name)
750

    
751
  @classmethod
752
  def _InstanceNICFile(cls, instance_name, seq):
753
    """Returns the name of the file containing the tap device for a given NIC
754

755
    """
756
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
757

    
758
  @classmethod
759
  def _InstanceKeymapFile(cls, instance_name):
760
    """Returns the name of the file containing the keymap for a given instance
761

762
    """
763
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
764

    
765
  @classmethod
766
  def _TryReadUidFile(cls, uid_file):
767
    """Try to read a uid file
768

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

    
780
  @classmethod
781
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
782
    """Removes an instance's rutime sockets/files/dirs.
783

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

    
820
  @staticmethod
821
  def _ConfigureNIC(instance, seq, nic, tap):
822
    """Run the network configuration script for a specified NIC
823

824
    @param instance: instance we're acting on
825
    @type instance: instance object
826
    @param seq: nic sequence number
827
    @type seq: int
828
    @param nic: nic we're acting on
829
    @type nic: nic object
830
    @param tap: the host's tap interface this NIC corresponds to
831
    @type tap: str
832

833
    """
834
    if instance.tags:
835
      tags = " ".join(instance.tags)
836
    else:
837
      tags = ""
838

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

    
849
    if nic.ip:
850
      env["IP"] = nic.ip
851

    
852
    if nic.nicparams[constants.NIC_LINK]:
853
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
854

    
855
    if nic.network:
856
      n = objects.Network.FromDict(nic.netinfo)
857
      _BuildNetworkEnv(nic.network, n.network, n.gateway,
858
                       n.network6, n.gateway6,
859
                       n.mac_prefix, n.tags, env)
860

    
861
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
862
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
863

    
864
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
865
    if result.failed:
866
      raise errors.HypervisorError("Failed to configure interface %s: %s."
867
                                   " Network configuration script output: %s" %
868
                                   (tap, result.fail_reason, result.output))
869

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

    
876
  @staticmethod
877
  def _BuildAffinityCpuMask(cpu_list):
878
    """Create a CPU mask suitable for sched_setaffinity from a list of
879
    CPUs.
880

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

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

889
    """
890
    if cpu_list == constants.CPU_PINNING_OFF:
891
      return constants.CPU_PINNING_ALL_KVM
892
    else:
893
      return sum(2 ** cpu for cpu in cpu_list)
894

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

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

907
    """
908
    # Convert the string CPU mask to a list of list of int's
909
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
910

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

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

    
934
  def _GetVcpuThreadIds(self, instance_name):
935
    """Get a mapping of vCPU no. to thread IDs for the instance
936

937
    @type instance_name: string
938
    @param instance_name: instance in question
939
    @rtype: dictionary of int:int
940
    @return: a dictionary mapping vCPU numbers to thread IDs
941

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

    
952
    return result
953

    
954
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
955
    """Complete CPU pinning.
956

957
    @type instance_name: string
958
    @param instance_name: name of instance
959
    @type cpu_mask: string
960
    @param cpu_mask: CPU pinning mask as entered by user
961

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

    
970
  def ListInstances(self):
971
    """Get the list of running instances.
972

973
    We can do this by listing our live instances directory and
974
    checking whether the associated kvm process is still alive.
975

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

    
983
  def GetInstanceInfo(self, instance_name):
984
    """Get instance properties.
985

986
    @type instance_name: string
987
    @param instance_name: the instance name
988
    @rtype: tuple of strings
989
    @return: (name, id, memory, vcpus, stat, times)
990

991
    """
992
    _, pid, alive = self._InstancePidAlive(instance_name)
993
    if not alive:
994
      return None
995

    
996
    _, memory, vcpus = self._InstancePidInfo(pid)
997
    istat = "---b-"
998
    times = "0"
999

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

    
1011
    return (instance_name, pid, memory, vcpus, istat, times)
1012

    
1013
  def GetAllInstancesInfo(self):
1014
    """Get properties of all instances.
1015

1016
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1017

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

    
1030
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1031
                          kvmhelp):
1032
    """Generate KVM information to start an instance.
1033

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

1043
    """
1044
    # pylint: disable=R0912,R0914,R0915
1045
    hvp = instance.hvparams
1046

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

    
1054
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1055
    if hvp[constants.HV_CPU_CORES]:
1056
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1057
    if hvp[constants.HV_CPU_THREADS]:
1058
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1059
    if hvp[constants.HV_CPU_SOCKETS]:
1060
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1061

    
1062
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1063

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

    
1073
    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1074
    if not mversion:
1075
      mversion = self._GetDefaultMachineVersion(kvm)
1076
    kvm_cmd.extend(["-M", mversion])
1077

    
1078
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1079
    if kernel_path:
1080
      boot_disk = boot_cdrom = boot_floppy = boot_network = False
1081
    else:
1082
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1083
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1084
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1085
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1086

    
1087
    self.ValidateParameters(hvp)
1088

    
1089
    if startup_paused:
1090
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1091

    
1092
    if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1093
        self._ENABLE_KVM_RE.search(kvmhelp)):
1094
      kvm_cmd.extend(["-enable-kvm"])
1095
    elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1096
          self._DISABLE_KVM_RE.search(kvmhelp)):
1097
      kvm_cmd.extend(["-disable-kvm"])
1098

    
1099
    if boot_network:
1100
      kvm_cmd.extend(["-boot", "n"])
1101

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

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

    
1136
      drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
1137
                                                cache_val)
1138
      kvm_cmd.extend(["-drive", drive_val])
1139

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

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

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

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

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

    
1199
    mem_path = hvp[constants.HV_MEM_PATH]
1200
    if mem_path:
1201
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1202

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

    
1213
    mouse_type = hvp[constants.HV_USB_MOUSE]
1214
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1215
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1216
    spice_ip_version = None
1217

    
1218
    kvm_cmd.extend(["-usb"])
1219

    
1220
    if mouse_type:
1221
      kvm_cmd.extend(["-usbdevice", mouse_type])
1222
    elif vnc_bind_address:
1223
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1224

    
1225
    if vnc_bind_address:
1226
      if netutils.IP4Address.IsValid(vnc_bind_address):
1227
        if instance.network_port > constants.VNC_BASE_PORT:
1228
          display = instance.network_port - constants.VNC_BASE_PORT
1229
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1230
            vnc_arg = ":%d" % (display)
1231
          else:
1232
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1233
        else:
1234
          logging.error("Network port is not a valid VNC display (%d < %d)."
1235
                        " Not starting VNC", instance.network_port,
1236
                        constants.VNC_BASE_PORT)
1237
          vnc_arg = "none"
1238

    
1239
        # Only allow tls and other option when not binding to a file, for now.
1240
        # kvm/qemu gets confused otherwise about the filename to use.
1241
        vnc_append = ""
1242
        if hvp[constants.HV_VNC_TLS]:
1243
          vnc_append = "%s,tls" % vnc_append
1244
          if hvp[constants.HV_VNC_X509_VERIFY]:
1245
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1246
                                               hvp[constants.HV_VNC_X509])
1247
          elif hvp[constants.HV_VNC_X509]:
1248
            vnc_append = "%s,x509=%s" % (vnc_append,
1249
                                         hvp[constants.HV_VNC_X509])
1250
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1251
          vnc_append = "%s,password" % vnc_append
1252

    
1253
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1254

    
1255
      else:
1256
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1257

    
1258
      kvm_cmd.extend(["-vnc", vnc_arg])
1259
    elif spice_bind:
1260
      # FIXME: this is wrong here; the iface ip address differs
1261
      # between systems, so it should be done in _ExecuteKVMRuntime
1262
      if netutils.IsValidInterface(spice_bind):
1263
        # The user specified a network interface, we have to figure out the IP
1264
        # address.
1265
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1266
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1267

    
1268
        # if the user specified an IP version and the interface does not
1269
        # have that kind of IP addresses, throw an exception
1270
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1271
          if not addresses[spice_ip_version]:
1272
            raise errors.HypervisorError("spice: unable to get an IPv%s address"
1273
                                         " for %s" % (spice_ip_version,
1274
                                                      spice_bind))
1275

    
1276
        # the user did not specify an IP version, we have to figure it out
1277
        elif (addresses[constants.IP4_VERSION] and
1278
              addresses[constants.IP6_VERSION]):
1279
          # we have both ipv4 and ipv6, let's use the cluster default IP
1280
          # version
1281
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1282
          spice_ip_version = \
1283
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1284
        elif addresses[constants.IP4_VERSION]:
1285
          spice_ip_version = constants.IP4_VERSION
1286
        elif addresses[constants.IP6_VERSION]:
1287
          spice_ip_version = constants.IP6_VERSION
1288
        else:
1289
          raise errors.HypervisorError("spice: unable to get an IP address"
1290
                                       " for %s" % (spice_bind))
1291

    
1292
        spice_address = addresses[spice_ip_version][0]
1293

    
1294
      else:
1295
        # spice_bind is known to be a valid IP address, because
1296
        # ValidateParameters checked it.
1297
        spice_address = spice_bind
1298

    
1299
      spice_arg = "addr=%s" % spice_address
1300
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1301
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1302
                     (spice_arg, instance.network_port,
1303
                      pathutils.SPICE_CACERT_FILE))
1304
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1305
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1306
                      pathutils.SPICE_CERT_FILE))
1307
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1308
        if tls_ciphers:
1309
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1310
      else:
1311
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1312

    
1313
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1314
        spice_arg = "%s,disable-ticketing" % spice_arg
1315

    
1316
      if spice_ip_version:
1317
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1318

    
1319
      # Image compression options
1320
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1321
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1322
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1323
      if img_lossless:
1324
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1325
      if img_jpeg:
1326
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1327
      if img_zlib_glz:
1328
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1329

    
1330
      # Video stream detection
1331
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1332
      if video_streaming:
1333
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1334

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

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

    
1351
    else:
1352
      kvm_cmd.extend(["-nographic"])
1353

    
1354
    if hvp[constants.HV_USE_LOCALTIME]:
1355
      kvm_cmd.extend(["-localtime"])
1356

    
1357
    if hvp[constants.HV_KVM_USE_CHROOT]:
1358
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1359

    
1360
    # Add qemu-KVM -cpu param
1361
    if hvp[constants.HV_CPU_TYPE]:
1362
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1363

    
1364
    # As requested by music lovers
1365
    if hvp[constants.HV_SOUNDHW]:
1366
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1367

    
1368
    # Pass a -vga option if requested, or if spice is used, for backwards
1369
    # compatibility.
1370
    if hvp[constants.HV_VGA]:
1371
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1372
    elif spice_bind:
1373
      kvm_cmd.extend(["-vga", "qxl"])
1374

    
1375
    # Various types of usb devices, comma separated
1376
    if hvp[constants.HV_USB_DEVICES]:
1377
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1378
        kvm_cmd.extend(["-usbdevice", dev])
1379

    
1380
    if hvp[constants.HV_KVM_EXTRA]:
1381
      kvm_cmd.extend([hvp[constants.HV_KVM_EXTRA]])
1382

    
1383
    # Save the current instance nics, but defer their expansion as parameters,
1384
    # as we'll need to generate executable temp files for them.
1385
    kvm_nics = instance.nics
1386
    hvparams = hvp
1387

    
1388
    return (kvm_cmd, kvm_nics, hvparams)
1389

    
1390
  def _WriteKVMRuntime(self, instance_name, data):
1391
    """Write an instance's KVM runtime
1392

1393
    """
1394
    try:
1395
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1396
                      data=data)
1397
    except EnvironmentError, err:
1398
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1399

    
1400
  def _ReadKVMRuntime(self, instance_name):
1401
    """Read an instance's KVM runtime
1402

1403
    """
1404
    try:
1405
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1406
    except EnvironmentError, err:
1407
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1408
    return file_content
1409

    
1410
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1411
    """Save an instance's KVM runtime
1412

1413
    """
1414
    kvm_cmd, kvm_nics, hvparams = kvm_runtime
1415
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1416
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1417
    self._WriteKVMRuntime(instance.name, serialized_form)
1418

    
1419
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1420
    """Load an instance's KVM runtime
1421

1422
    """
1423
    if not serialized_runtime:
1424
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1425
    loaded_runtime = serializer.Load(serialized_runtime)
1426
    kvm_cmd, serialized_nics, hvparams = loaded_runtime
1427
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1428
    return (kvm_cmd, kvm_nics, hvparams)
1429

    
1430
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1431
    """Run the KVM cmd and check for errors
1432

1433
    @type name: string
1434
    @param name: instance name
1435
    @type kvm_cmd: list of strings
1436
    @param kvm_cmd: runcmd input for kvm
1437
    @type tap_fds: list of int
1438
    @param tap_fds: fds of tap devices opened by Ganeti
1439

1440
    """
1441
    try:
1442
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1443
    finally:
1444
      for fd in tap_fds:
1445
        utils_wrapper.CloseFdNoError(fd)
1446

    
1447
    if result.failed:
1448
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1449
                                   (name, result.fail_reason, result.output))
1450
    if not self._InstancePidAlive(name)[2]:
1451
      raise errors.HypervisorError("Failed to start instance %s" % name)
1452

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

1456
    @type incoming: tuple of strings
1457
    @param incoming: (target_host_ip, port)
1458
    @type kvmhelp: string
1459
    @param kvmhelp: output of kvm --help
1460

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

    
1474
    temp_files = []
1475

    
1476
    kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1477
    # the first element of kvm_cmd is always the path to the kvm binary
1478
    kvm_path = kvm_cmd[0]
1479
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1480

    
1481
    # We know it's safe to run as a different user upon migration, so we'll use
1482
    # the latest conf, from conf_hvp.
1483
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1484
    if security_model == constants.HT_SM_USER:
1485
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1486

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

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

    
1520
        if up_hvp[constants.HV_VHOST_NET]:
1521
          # check for vhost_net support
1522
          if self._VHOST_RE.search(kvmhelp):
1523
            tap_extra = ",vhost=on"
1524
          else:
1525
            raise errors.HypervisorError("vhost_net is configured"
1526
                                         " but it is not available")
1527
      else:
1528
        nic_model = nic_type
1529

    
1530
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1531

    
1532
      for nic_seq, nic in enumerate(kvm_nics):
1533
        tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1534
        tapfds.append(tapfd)
1535
        taps.append(tapname)
1536
        if kvm_supports_netdev:
1537
          nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1538
          tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1539
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1540
        else:
1541
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1542
                                                         nic.mac, nic_model)
1543
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1544
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1545

    
1546
    if incoming:
1547
      target, port = incoming
1548
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1549

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

    
1562
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1563
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1564
                         constants.SECURE_DIR_MODE)])
1565

    
1566
    # Automatically enable QMP if version is >= 0.14
1567
    if self._QMP_RE.search(kvmhelp):
1568
      logging.debug("Enabling QMP")
1569
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1570
                      self._InstanceQmpMonitor(instance.name)])
1571

    
1572
    # Configure the network now for starting instances and bridged interfaces,
1573
    # during FinalizeMigration for incoming instances' routed interfaces
1574
    for nic_seq, nic in enumerate(kvm_nics):
1575
      if (incoming and
1576
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1577
        continue
1578
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1579

    
1580
    # CPU affinity requires kvm to start paused, so we set this flag if the
1581
    # instance is not already paused and if we are not going to accept a
1582
    # migrating instance. In the latter case, pausing is not needed.
1583
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1584
    if start_kvm_paused:
1585
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1586

    
1587
    # Note: CPU pinning is using up_hvp since changes take effect
1588
    # during instance startup anyway, and to avoid problems when soft
1589
    # rebooting the instance.
1590
    cpu_pinning = False
1591
    if up_hvp.get(constants.HV_CPU_MASK, None):
1592
      cpu_pinning = True
1593

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

    
1612
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1613
                     constants.RUN_DIRS_MODE)])
1614
    for nic_seq, tap in enumerate(taps):
1615
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1616
                      data=tap)
1617

    
1618
    if vnc_pwd:
1619
      change_cmd = "change vnc password %s" % vnc_pwd
1620
      self._CallMonitorCommand(instance.name, change_cmd)
1621

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

    
1636
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1637
      qmp.connect()
1638
      arguments = {
1639
          "protocol": "spice",
1640
          "password": spice_pwd,
1641
      }
1642
      qmp.Execute("set_password", arguments)
1643

    
1644
    for filename in temp_files:
1645
      utils.RemoveFile(filename)
1646

    
1647
    # If requested, set CPU affinity and resume instance execution
1648
    if cpu_pinning:
1649
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1650

    
1651
    start_memory = self._InstanceStartupMemory(instance)
1652
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1653
      self.BalloonInstanceMemory(instance, start_memory)
1654

    
1655
    if start_kvm_paused:
1656
      # To control CPU pinning, ballooning, and vnc/spice passwords
1657
      # the VM was started in a frozen state. If freezing was not
1658
      # explicitly requested resume the vm status.
1659
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1660

    
1661
  def StartInstance(self, instance, block_devices, startup_paused):
1662
    """Start an instance.
1663

1664
    """
1665
    self._CheckDown(instance.name)
1666
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1667
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1668
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1669
                                           startup_paused, kvmhelp)
1670
    self._SaveKVMRuntime(instance, kvm_runtime)
1671
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1672

    
1673
  def _CallMonitorCommand(self, instance_name, command):
1674
    """Invoke a command on the instance monitor.
1675

1676
    """
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."
1684
             " output: %s, error: %s, fail_reason: %s" %
1685
             (command, instance_name,
1686
              result.stdout, result.stderr, result.fail_reason))
1687
      raise errors.HypervisorError(msg)
1688

    
1689
    return result
1690

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1840
    Stop the incoming mode KVM.
1841

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1951
          return migration_status
1952

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

    
1955
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1956

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

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

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

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

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

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

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

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

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

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

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

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

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

2030
    Check that the required binaries exist.
2031

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

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

    
2045
    return self._FormatVerifyResults(msgs)
2046

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

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

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

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

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

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

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

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

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

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

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

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

2128
    """
2129
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2130

    
2131
    kvm_path = hvparams[constants.HV_KVM_PATH]
2132

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

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

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

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

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

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

2175
    """
2176
    cls.LinuxPowercycle()