Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 360e6c08

History | View | Annotate | Download (79.1 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
class QmpMessage:
152
  """QEMU Messaging Protocol (QMP) message.
153

154
  """
155
  def __init__(self, data):
156
    """Creates a new QMP message based on the passed data.
157

158
    """
159
    if not isinstance(data, dict):
160
      raise TypeError("QmpMessage must be initialized with a dict")
161

    
162
    self.data = data
163

    
164
  def __getitem__(self, field_name):
165
    """Get the value of the required field if present, or None.
166

167
    Overrides the [] operator to provide access to the message data,
168
    returning None if the required item is not in the message
169
    @return: the value of the field_name field, or None if field_name
170
             is not contained in the message
171

172
    """
173
    return self.data.get(field_name, None)
174

    
175
  def __setitem__(self, field_name, field_value):
176
    """Set the value of the required field_name to field_value.
177

178
    """
179
    self.data[field_name] = field_value
180

    
181
  @staticmethod
182
  def BuildFromJsonString(json_string):
183
    """Build a QmpMessage from a JSON encoded string.
184

185
    @type json_string: str
186
    @param json_string: JSON string representing the message
187
    @rtype: L{QmpMessage}
188
    @return: a L{QmpMessage} built from json_string
189

190
    """
191
    # Parse the string
192
    data = serializer.LoadJson(json_string)
193
    return QmpMessage(data)
194

    
195
  def __str__(self):
196
    # The protocol expects the JSON object to be sent as a single line.
197
    return serializer.DumpJson(self.data)
198

    
199
  def __eq__(self, other):
200
    # When comparing two QmpMessages, we are interested in comparing
201
    # their internal representation of the message data
202
    return self.data == other.data
203

    
204

    
205
class QmpConnection:
206
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
207

208
  """
209
  _FIRST_MESSAGE_KEY = "QMP"
210
  _EVENT_KEY = "event"
211
  _ERROR_KEY = "error"
212
  _RETURN_KEY = RETURN_KEY = "return"
213
  _ACTUAL_KEY = ACTUAL_KEY = "actual"
214
  _ERROR_CLASS_KEY = "class"
215
  _ERROR_DATA_KEY = "data"
216
  _ERROR_DESC_KEY = "desc"
217
  _EXECUTE_KEY = "execute"
218
  _ARGUMENTS_KEY = "arguments"
219
  _CAPABILITIES_COMMAND = "qmp_capabilities"
220
  _MESSAGE_END_TOKEN = "\r\n"
221
  _SOCKET_TIMEOUT = 5
222

    
223
  def __init__(self, monitor_filename):
224
    """Instantiates the QmpConnection object.
225

226
    @type monitor_filename: string
227
    @param monitor_filename: the filename of the UNIX raw socket on which the
228
                             QMP monitor is listening
229

230
    """
231
    self.monitor_filename = monitor_filename
232
    self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
233
    # We want to fail if the server doesn't send a complete message
234
    # in a reasonable amount of time
235
    self.sock.settimeout(self._SOCKET_TIMEOUT)
236
    self._connected = False
237
    self._buf = ""
238

    
239
  def _check_socket(self):
240
    sock_stat = None
241
    try:
242
      sock_stat = os.stat(self.monitor_filename)
243
    except EnvironmentError, err:
244
      if err.errno == errno.ENOENT:
245
        raise errors.HypervisorError("No qmp socket found")
246
      else:
247
        raise errors.HypervisorError("Error checking qmp socket: %s",
248
                                     utils.ErrnoOrStr(err))
249
    if not stat.S_ISSOCK(sock_stat.st_mode):
250
      raise errors.HypervisorError("Qmp socket is not a socket")
251

    
252
  def _check_connection(self):
253
    """Make sure that the connection is established.
254

255
    """
256
    if not self._connected:
257
      raise errors.ProgrammerError("To use a QmpConnection you need to first"
258
                                   " invoke connect() on it")
259

    
260
  def connect(self):
261
    """Connects to the QMP monitor.
262

263
    Connects to the UNIX socket and makes sure that we can actually send and
264
    receive data to the kvm instance via QMP.
265

266
    @raise errors.HypervisorError: when there are communication errors
267
    @raise errors.ProgrammerError: when there are data serialization errors
268

269
    """
270
    if self._connected:
271
      raise errors.ProgrammerError("Cannot connect twice")
272

    
273
    self._check_socket()
274

    
275
    # Check file existance/stuff
276
    try:
277
      self.sock.connect(self.monitor_filename)
278
    except EnvironmentError:
279
      raise errors.HypervisorError("Can't connect to qmp socket")
280
    self._connected = True
281

    
282
    # Check if we receive a correct greeting message from the server
283
    # (As per the QEMU Protocol Specification 0.1 - section 2.2)
284
    greeting = self._Recv()
285
    if not greeting[self._FIRST_MESSAGE_KEY]:
286
      self._connected = False
287
      raise errors.HypervisorError("kvm: qmp communication error (wrong"
288
                                   " server greeting")
289

    
290
    # Let's put the monitor in command mode using the qmp_capabilities
291
    # command, or else no command will be executable.
292
    # (As per the QEMU Protocol Specification 0.1 - section 4)
293
    self.Execute(self._CAPABILITIES_COMMAND)
294

    
295
  def _ParseMessage(self, buf):
296
    """Extract and parse a QMP message from the given buffer.
297

298
    Seeks for a QMP message in the given buf. If found, it parses it and
299
    returns it together with the rest of the characters in the buf.
300
    If no message is found, returns None and the whole buffer.
301

302
    @raise errors.ProgrammerError: when there are data serialization errors
303

304
    """
305
    message = None
306
    # Check if we got the message end token (CRLF, as per the QEMU Protocol
307
    # Specification 0.1 - Section 2.1.1)
308
    pos = buf.find(self._MESSAGE_END_TOKEN)
309
    if pos >= 0:
310
      try:
311
        message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
312
      except Exception, err:
313
        raise errors.ProgrammerError("QMP data serialization error: %s" % err)
314
      buf = buf[pos + 1:]
315

    
316
    return (message, buf)
317

    
318
  def _Recv(self):
319
    """Receives a message from QMP and decodes the received JSON object.
320

321
    @rtype: QmpMessage
322
    @return: the received message
323
    @raise errors.HypervisorError: when there are communication errors
324
    @raise errors.ProgrammerError: when there are data serialization errors
325

326
    """
327
    self._check_connection()
328

    
329
    # Check if there is already a message in the buffer
330
    (message, self._buf) = self._ParseMessage(self._buf)
331
    if message:
332
      return message
333

    
334
    recv_buffer = StringIO.StringIO(self._buf)
335
    recv_buffer.seek(len(self._buf))
336
    try:
337
      while True:
338
        data = self.sock.recv(4096)
339
        if not data:
340
          break
341
        recv_buffer.write(data)
342

    
343
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
344
        if message:
345
          return message
346

    
347
    except socket.timeout, err:
348
      raise errors.HypervisorError("Timeout while receiving a QMP message: "
349
                                   "%s" % (err))
350
    except socket.error, err:
351
      raise errors.HypervisorError("Unable to receive data from KVM using the"
352
                                   " QMP protocol: %s" % err)
353

    
354
  def _Send(self, message):
355
    """Encodes and sends a message to KVM using QMP.
356

357
    @type message: QmpMessage
358
    @param message: message to send to KVM
359
    @raise errors.HypervisorError: when there are communication errors
360
    @raise errors.ProgrammerError: when there are data serialization errors
361

362
    """
363
    self._check_connection()
364
    try:
365
      message_str = str(message)
366
    except Exception, err:
367
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
368

    
369
    try:
370
      self.sock.sendall(message_str)
371
    except socket.timeout, err:
372
      raise errors.HypervisorError("Timeout while sending a QMP message: "
373
                                   "%s (%s)" % (err.string, err.errno))
374
    except socket.error, err:
375
      raise errors.HypervisorError("Unable to send data from KVM using the"
376
                                   " QMP protocol: %s" % err)
377

    
378
  def Execute(self, command, arguments=None):
379
    """Executes a QMP command and returns the response of the server.
380

381
    @type command: str
382
    @param command: the command to execute
383
    @type arguments: dict
384
    @param arguments: dictionary of arguments to be passed to the command
385
    @rtype: dict
386
    @return: dictionary representing the received JSON object
387
    @raise errors.HypervisorError: when there are communication errors
388
    @raise errors.ProgrammerError: when there are data serialization errors
389

390
    """
391
    self._check_connection()
392
    message = QmpMessage({self._EXECUTE_KEY: command})
393
    if arguments:
394
      message[self._ARGUMENTS_KEY] = arguments
395
    self._Send(message)
396

    
397
    # Events can occur between the sending of the command and the reception
398
    # of the response, so we need to filter out messages with the event key.
399
    while True:
400
      response = self._Recv()
401
      err = response[self._ERROR_KEY]
402
      if err:
403
        raise errors.HypervisorError("kvm: error executing the %s"
404
                                     " command: %s (%s, %s):" %
405
                                     (command,
406
                                      err[self._ERROR_DESC_KEY],
407
                                      err[self._ERROR_CLASS_KEY],
408
                                      err[self._ERROR_DATA_KEY]))
409

    
410
      elif not response[self._EVENT_KEY]:
411
        return response
412

    
413

    
414
class KVMHypervisor(hv_base.BaseHypervisor):
415
  """KVM hypervisor interface
416

417
  """
418
  CAN_MIGRATE = True
419

    
420
  _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
421
  _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
422
  _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
423
  _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
424
  _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
425
  _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
426
  _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
427
  # KVM instances with chroot enabled are started in empty chroot directories.
428
  _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
429
  # After an instance is stopped, its chroot directory is removed.
430
  # If the chroot directory is not empty, it can't be removed.
431
  # A non-empty chroot directory indicates a possible security incident.
432
  # To support forensics, the non-empty chroot directory is quarantined in
433
  # a separate directory, called 'chroot-quarantine'.
434
  _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
435
  _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
436
           _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
437

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

    
522
  _VIRTIO = "virtio"
523
  _VIRTIO_NET_PCI = "virtio-net-pci"
524

    
525
  _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
526
                                    re.M | re.I)
527
  _MIGRATION_PROGRESS_RE = \
528
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
529
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
530
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
531

    
532
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
533
  _MIGRATION_INFO_RETRY_DELAY = 2
534

    
535
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
536

    
537
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
538
  _CPU_INFO_CMD = "info cpus"
539
  _CONT_CMD = "cont"
540

    
541
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
542
  _CHECK_MACHINE_VERSION_RE = \
543
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
544

    
545
  _QMP_RE = re.compile(r"^-qmp\s", re.M)
546
  _SPICE_RE = re.compile(r"^-spice\s", re.M)
547
  _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
548
  _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
549
  _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
550
  _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
551
  _DISPLAY_RE = re.compile(r"^-display\s", re.M)
552
  _MACHINE_RE = re.compile(r"^-machine\s", re.M)
553
  _NEW_VIRTIO_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
554
  # match  -drive.*boot=on|off on different lines, but in between accept only
555
  # dashes not preceeded by a new line (which would mean another option
556
  # different than -drive is starting)
557
  _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
558

    
559
  ANCILLARY_FILES = [
560
    _KVM_NETWORK_SCRIPT,
561
    ]
562
  ANCILLARY_FILES_OPT = [
563
    _KVM_NETWORK_SCRIPT,
564
    ]
565

    
566
  # Supported kvm options to get output from
567
  _KVMOPT_HELP = "help"
568
  _KVMOPT_MLIST = "mlist"
569
  _KVMOPT_DEVICELIST = "devicelist"
570

    
571
  # Command to execute to get the output from kvm, and whether to
572
  # accept the output even on failure.
573
  _KVMOPTS_CMDS = {
574
    _KVMOPT_HELP: (["--help"], False),
575
    _KVMOPT_MLIST: (["-M", "?"], False),
576
    _KVMOPT_DEVICELIST: (["-device", "?"], True),
577
  }
578

    
579
  def __init__(self):
580
    hv_base.BaseHypervisor.__init__(self)
581
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
582
    # in a tmpfs filesystem or has been otherwise wiped out.
583
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
584
    utils.EnsureDirs(dirs)
585

    
586
  @classmethod
587
  def _InstancePidFile(cls, instance_name):
588
    """Returns the instance pidfile.
589

590
    """
591
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
592

    
593
  @classmethod
594
  def _InstanceUidFile(cls, instance_name):
595
    """Returns the instance uidfile.
596

597
    """
598
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
599

    
600
  @classmethod
601
  def _InstancePidInfo(cls, pid):
602
    """Check pid file for instance information.
603

604
    Check that a pid file is associated with an instance, and retrieve
605
    information from its command line.
606

607
    @type pid: string or int
608
    @param pid: process id of the instance to check
609
    @rtype: tuple
610
    @return: (instance_name, memory, vcpus)
611
    @raise errors.HypervisorError: when an instance cannot be found
612

613
    """
614
    alive = utils.IsProcessAlive(pid)
615
    if not alive:
616
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
617

    
618
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
619
    try:
620
      cmdline = utils.ReadFile(cmdline_file)
621
    except EnvironmentError, err:
622
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
623
                                   (pid, err))
624

    
625
    instance = None
626
    memory = 0
627
    vcpus = 0
628

    
629
    arg_list = cmdline.split("\x00")
630
    while arg_list:
631
      arg = arg_list.pop(0)
632
      if arg == "-name":
633
        instance = arg_list.pop(0)
634
      elif arg == "-m":
635
        memory = int(arg_list.pop(0))
636
      elif arg == "-smp":
637
        vcpus = int(arg_list.pop(0).split(",")[0])
638

    
639
    if instance is None:
640
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
641
                                   " instance" % pid)
642

    
643
    return (instance, memory, vcpus)
644

    
645
  def _InstancePidAlive(self, instance_name):
646
    """Returns the instance pidfile, pid, and liveness.
647

648
    @type instance_name: string
649
    @param instance_name: instance name
650
    @rtype: tuple
651
    @return: (pid file name, pid, liveness)
652

653
    """
654
    pidfile = self._InstancePidFile(instance_name)
655
    pid = utils.ReadPidFile(pidfile)
656

    
657
    alive = False
658
    try:
659
      cmd_instance = self._InstancePidInfo(pid)[0]
660
      alive = (cmd_instance == instance_name)
661
    except errors.HypervisorError:
662
      pass
663

    
664
    return (pidfile, pid, alive)
665

    
666
  def _CheckDown(self, instance_name):
667
    """Raises an error unless the given instance is down.
668

669
    """
670
    alive = self._InstancePidAlive(instance_name)[2]
671
    if alive:
672
      raise errors.HypervisorError("Failed to start instance %s: %s" %
673
                                   (instance_name, "already running"))
674

    
675
  @classmethod
676
  def _InstanceMonitor(cls, instance_name):
677
    """Returns the instance monitor socket name
678

679
    """
680
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
681

    
682
  @classmethod
683
  def _InstanceSerial(cls, instance_name):
684
    """Returns the instance serial socket name
685

686
    """
687
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
688

    
689
  @classmethod
690
  def _InstanceQmpMonitor(cls, instance_name):
691
    """Returns the instance serial QMP socket name
692

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

    
696
  @staticmethod
697
  def _SocatUnixConsoleParams():
698
    """Returns the correct parameters for socat
699

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

702
    """
703
    if constants.SOCAT_USE_ESCAPE:
704
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
705
    else:
706
      return "echo=0,icanon=0"
707

    
708
  @classmethod
709
  def _InstanceKVMRuntime(cls, instance_name):
710
    """Returns the instance KVM runtime filename
711

712
    """
713
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
714

    
715
  @classmethod
716
  def _InstanceChrootDir(cls, instance_name):
717
    """Returns the name of the KVM chroot dir of the instance
718

719
    """
720
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
721

    
722
  @classmethod
723
  def _InstanceNICDir(cls, instance_name):
724
    """Returns the name of the directory holding the tap device files for a
725
    given instance.
726

727
    """
728
    return utils.PathJoin(cls._NICS_DIR, instance_name)
729

    
730
  @classmethod
731
  def _InstanceNICFile(cls, instance_name, seq):
732
    """Returns the name of the file containing the tap device for a given NIC
733

734
    """
735
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
736

    
737
  @classmethod
738
  def _InstanceKeymapFile(cls, instance_name):
739
    """Returns the name of the file containing the keymap for a given instance
740

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

    
744
  @classmethod
745
  def _TryReadUidFile(cls, uid_file):
746
    """Try to read a uid file
747

748
    """
749
    if os.path.exists(uid_file):
750
      try:
751
        uid = int(utils.ReadOneLineFile(uid_file))
752
        return uid
753
      except EnvironmentError:
754
        logging.warning("Can't read uid file", exc_info=True)
755
      except (TypeError, ValueError):
756
        logging.warning("Can't parse uid file contents", exc_info=True)
757
    return None
758

    
759
  @classmethod
760
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
761
    """Removes an instance's rutime sockets/files/dirs.
762

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

    
799
  @staticmethod
800
  def _ConfigureNIC(instance, seq, nic, tap):
801
    """Run the network configuration script for a specified NIC
802

803
    @param instance: instance we're acting on
804
    @type instance: instance object
805
    @param seq: nic sequence number
806
    @type seq: int
807
    @param nic: nic we're acting on
808
    @type nic: nic object
809
    @param tap: the host's tap interface this NIC corresponds to
810
    @type tap: str
811

812
    """
813
    if instance.tags:
814
      tags = " ".join(instance.tags)
815
    else:
816
      tags = ""
817

    
818
    env = {
819
      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
820
      "INSTANCE": instance.name,
821
      "MAC": nic.mac,
822
      "MODE": nic.nicparams[constants.NIC_MODE],
823
      "INTERFACE": tap,
824
      "INTERFACE_INDEX": str(seq),
825
      "TAGS": tags,
826
    }
827

    
828
    if nic.ip:
829
      env["IP"] = nic.ip
830

    
831
    if nic.nicparams[constants.NIC_LINK]:
832
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
833

    
834
    if nic.network:
835
      n = objects.Network.FromDict(nic.netinfo)
836
      env.update(n.HooksDict())
837

    
838
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
839
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
840

    
841
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
842
    if result.failed:
843
      raise errors.HypervisorError("Failed to configure interface %s: %s."
844
                                   " Network configuration script output: %s" %
845
                                   (tap, result.fail_reason, result.output))
846

    
847
  @staticmethod
848
  def _VerifyAffinityPackage():
849
    if affinity is None:
850
      raise errors.HypervisorError("affinity Python package not"
851
                                   " found; cannot use CPU pinning under KVM")
852

    
853
  @staticmethod
854
  def _BuildAffinityCpuMask(cpu_list):
855
    """Create a CPU mask suitable for sched_setaffinity from a list of
856
    CPUs.
857

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

861
    @type cpu_list: list of int
862
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
863
    @rtype: int
864
    @return: a bit mask of CPU affinities
865

866
    """
867
    if cpu_list == constants.CPU_PINNING_OFF:
868
      return constants.CPU_PINNING_ALL_KVM
869
    else:
870
      return sum(2 ** cpu for cpu in cpu_list)
871

    
872
  @classmethod
873
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
874
    """Change CPU affinity for running VM according to given CPU mask.
875

876
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
877
    @type cpu_mask: string
878
    @param process_id: process ID of KVM process. Used to pin entire VM
879
                       to physical CPUs.
880
    @type process_id: int
881
    @param thread_dict: map of virtual CPUs to KVM thread IDs
882
    @type thread_dict: dict int:int
883

884
    """
885
    # Convert the string CPU mask to a list of list of int's
886
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
887

    
888
    if len(cpu_list) == 1:
889
      all_cpu_mapping = cpu_list[0]
890
      if all_cpu_mapping == constants.CPU_PINNING_OFF:
891
        # If CPU pinning has 1 entry that's "all", then do nothing
892
        pass
893
      else:
894
        # If CPU pinning has one non-all entry, map the entire VM to
895
        # one set of physical CPUs
896
        cls._VerifyAffinityPackage()
897
        affinity.set_process_affinity_mask(
898
          process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
899
    else:
900
      # The number of vCPUs mapped should match the number of vCPUs
901
      # reported by KVM. This was already verified earlier, so
902
      # here only as a sanity check.
903
      assert len(thread_dict) == len(cpu_list)
904
      cls._VerifyAffinityPackage()
905

    
906
      # For each vCPU, map it to the proper list of physical CPUs
907
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
908
        affinity.set_process_affinity_mask(thread_dict[i],
909
                                           cls._BuildAffinityCpuMask(vcpu))
910

    
911
  def _GetVcpuThreadIds(self, instance_name):
912
    """Get a mapping of vCPU no. to thread IDs for the instance
913

914
    @type instance_name: string
915
    @param instance_name: instance in question
916
    @rtype: dictionary of int:int
917
    @return: a dictionary mapping vCPU numbers to thread IDs
918

919
    """
920
    result = {}
921
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
922
    for line in output.stdout.splitlines():
923
      match = self._CPU_INFO_RE.search(line)
924
      if not match:
925
        continue
926
      grp = map(int, match.groups())
927
      result[grp[0]] = grp[1]
928

    
929
    return result
930

    
931
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
932
    """Complete CPU pinning.
933

934
    @type instance_name: string
935
    @param instance_name: name of instance
936
    @type cpu_mask: string
937
    @param cpu_mask: CPU pinning mask as entered by user
938

939
    """
940
    # Get KVM process ID, to be used if need to pin entire VM
941
    _, pid, _ = self._InstancePidAlive(instance_name)
942
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
943
    thread_dict = self._GetVcpuThreadIds(instance_name)
944
    # Run CPU pinning, based on configured mask
945
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
946

    
947
  def ListInstances(self):
948
    """Get the list of running instances.
949

950
    We can do this by listing our live instances directory and
951
    checking whether the associated kvm process is still alive.
952

953
    """
954
    result = []
955
    for name in os.listdir(self._PIDS_DIR):
956
      if self._InstancePidAlive(name)[2]:
957
        result.append(name)
958
    return result
959

    
960
  def GetInstanceInfo(self, instance_name):
961
    """Get instance properties.
962

963
    @type instance_name: string
964
    @param instance_name: the instance name
965
    @rtype: tuple of strings
966
    @return: (name, id, memory, vcpus, stat, times)
967

968
    """
969
    _, pid, alive = self._InstancePidAlive(instance_name)
970
    if not alive:
971
      return None
972

    
973
    _, memory, vcpus = self._InstancePidInfo(pid)
974
    istat = "---b-"
975
    times = "0"
976

    
977
    try:
978
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
979
      qmp.connect()
980
      vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
981
      # Will fail if ballooning is not enabled, but we can then just resort to
982
      # the value above.
983
      mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
984
      memory = mem_bytes / 1048576
985
    except errors.HypervisorError:
986
      pass
987

    
988
    return (instance_name, pid, memory, vcpus, istat, times)
989

    
990
  def GetAllInstancesInfo(self):
991
    """Get properties of all instances.
992

993
    @return: list of tuples (name, id, memory, vcpus, stat, times)
994

995
    """
996
    data = []
997
    for name in os.listdir(self._PIDS_DIR):
998
      try:
999
        info = self.GetInstanceInfo(name)
1000
      except errors.HypervisorError:
1001
        # Ignore exceptions due to instances being shut down
1002
        continue
1003
      if info:
1004
        data.append(info)
1005
    return data
1006

    
1007
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1008
                          kvmhelp):
1009
    """Generate KVM information to start an instance.
1010

1011
    @type kvmhelp: string
1012
    @param kvmhelp: output of kvm --help
1013
    @attention: this function must not have any side-effects; for
1014
        example, it must not write to the filesystem, or read values
1015
        from the current system the are expected to differ between
1016
        nodes, since it is only run once at instance startup;
1017
        actions/kvm arguments that can vary between systems should be
1018
        done in L{_ExecuteKVMRuntime}
1019

1020
    """
1021
    # pylint: disable=R0912,R0914,R0915
1022
    hvp = instance.hvparams
1023
    self.ValidateParameters(hvp)
1024

    
1025
    pidfile = self._InstancePidFile(instance.name)
1026
    kvm = hvp[constants.HV_KVM_PATH]
1027
    kvm_cmd = [kvm]
1028
    # used just by the vnc server, if enabled
1029
    kvm_cmd.extend(["-name", instance.name])
1030
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1031

    
1032
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1033
    if hvp[constants.HV_CPU_CORES]:
1034
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1035
    if hvp[constants.HV_CPU_THREADS]:
1036
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1037
    if hvp[constants.HV_CPU_SOCKETS]:
1038
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1039

    
1040
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1041

    
1042
    kvm_cmd.extend(["-pidfile", pidfile])
1043
    kvm_cmd.extend(["-balloon", "virtio"])
1044
    kvm_cmd.extend(["-daemonize"])
1045
    if not instance.hvparams[constants.HV_ACPI]:
1046
      kvm_cmd.extend(["-no-acpi"])
1047
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1048
        constants.INSTANCE_REBOOT_EXIT:
1049
      kvm_cmd.extend(["-no-reboot"])
1050

    
1051
    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1052
    if not mversion:
1053
      mversion = self._GetDefaultMachineVersion(kvm)
1054
    if self._MACHINE_RE.search(kvmhelp):
1055
      # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1056
      # extra hypervisor parameters. We should also investigate whether and how
1057
      # shadow_mem should be considered for the resource model.
1058
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1059
        specprop = ",accel=kvm"
1060
      else:
1061
        specprop = ""
1062
      machinespec = "%s%s" % (mversion, specprop)
1063
      kvm_cmd.extend(["-machine", machinespec])
1064
    else:
1065
      kvm_cmd.extend(["-M", mversion])
1066
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1067
          self._ENABLE_KVM_RE.search(kvmhelp)):
1068
        kvm_cmd.extend(["-enable-kvm"])
1069
      elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1070
            self._DISABLE_KVM_RE.search(kvmhelp)):
1071
        kvm_cmd.extend(["-disable-kvm"])
1072

    
1073
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1074
    if kernel_path:
1075
      boot_disk = boot_cdrom = boot_floppy = boot_network = False
1076
    else:
1077
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1078
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1079
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1080
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1081

    
1082
    if startup_paused:
1083
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1084

    
1085
    if boot_network:
1086
      kvm_cmd.extend(["-boot", "n"])
1087

    
1088
    # whether this is an older KVM version that uses the boot=on flag
1089
    # on devices
1090
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1091

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

    
1122
      drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
1123
                                                cache_val)
1124
      kvm_cmd.extend(["-drive", drive_val])
1125

    
1126
    #Now we can specify a different device type for CDROM devices.
1127
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1128
    if not cdrom_disk_type:
1129
      cdrom_disk_type = disk_type
1130

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

    
1152
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1153
    if iso_image2:
1154
      options = ",format=raw,media=cdrom"
1155
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1156
        if_val = ",if=virtio"
1157
      else:
1158
        if_val = ",if=%s" % cdrom_disk_type
1159
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1160
      kvm_cmd.extend(["-drive", drive_val])
1161

    
1162
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1163
    if floppy_image:
1164
      options = ",format=raw,media=disk"
1165
      if boot_floppy:
1166
        kvm_cmd.extend(["-boot", "a"])
1167
        options = "%s,boot=on" % options
1168
      if_val = ",if=floppy"
1169
      options = "%s%s" % (options, if_val)
1170
      drive_val = "file=%s%s" % (floppy_image, options)
1171
      kvm_cmd.extend(["-drive", drive_val])
1172

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

    
1185
    mem_path = hvp[constants.HV_MEM_PATH]
1186
    if mem_path:
1187
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1188

    
1189
    monitor_dev = ("unix:%s,server,nowait" %
1190
                   self._InstanceMonitor(instance.name))
1191
    kvm_cmd.extend(["-monitor", monitor_dev])
1192
    if hvp[constants.HV_SERIAL_CONSOLE]:
1193
      serial_dev = ("unix:%s,server,nowait" %
1194
                    self._InstanceSerial(instance.name))
1195
      kvm_cmd.extend(["-serial", serial_dev])
1196
    else:
1197
      kvm_cmd.extend(["-serial", "none"])
1198

    
1199
    mouse_type = hvp[constants.HV_USB_MOUSE]
1200
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1201
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1202
    spice_ip_version = None
1203

    
1204
    kvm_cmd.extend(["-usb"])
1205

    
1206
    if mouse_type:
1207
      kvm_cmd.extend(["-usbdevice", mouse_type])
1208
    elif vnc_bind_address:
1209
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1210

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

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

    
1239
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1240

    
1241
      else:
1242
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1243

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

    
1254
        # if the user specified an IP version and the interface does not
1255
        # have that kind of IP addresses, throw an exception
1256
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1257
          if not addresses[spice_ip_version]:
1258
            raise errors.HypervisorError("spice: unable to get an IPv%s address"
1259
                                         " for %s" % (spice_ip_version,
1260
                                                      spice_bind))
1261

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

    
1278
        spice_address = addresses[spice_ip_version][0]
1279

    
1280
      else:
1281
        # spice_bind is known to be a valid IP address, because
1282
        # ValidateParameters checked it.
1283
        spice_address = spice_bind
1284

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

    
1299
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1300
        spice_arg = "%s,disable-ticketing" % spice_arg
1301

    
1302
      if spice_ip_version:
1303
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1304

    
1305
      # Image compression options
1306
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1307
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1308
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1309
      if img_lossless:
1310
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1311
      if img_jpeg:
1312
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1313
      if img_zlib_glz:
1314
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1315

    
1316
      # Video stream detection
1317
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1318
      if video_streaming:
1319
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1320

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

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

    
1337
    else:
1338
      # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1339
      # also works in earlier versions though (tested with 1.1 and 1.3)
1340
      if self._DISPLAY_RE.search(kvmhelp):
1341
        kvm_cmd.extend(["-display", "none"])
1342
      else:
1343
        kvm_cmd.extend(["-nographic"])
1344

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

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

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

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

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

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

    
1371
    if hvp[constants.HV_KVM_EXTRA]:
1372
      kvm_cmd.extend([hvp[constants.HV_KVM_EXTRA].split(" ")])
1373

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

    
1379
    return (kvm_cmd, kvm_nics, hvparams)
1380

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1465
    temp_files = []
1466

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

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

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

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

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

    
1521
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1522

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1635
    for filename in temp_files:
1636
      utils.RemoveFile(filename)
1637

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

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

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

    
1652
  def StartInstance(self, instance, block_devices, startup_paused):
1653
    """Start an instance.
1654

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

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

1667
    """
1668
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1669
             (utils.ShellQuote(command),
1670
              constants.SOCAT_PATH,
1671
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1672
    result = utils.RunCmd(socat)
1673
    if result.failed:
1674
      msg = ("Failed to send command '%s' to instance %s."
1675
             " output: %s, error: %s, fail_reason: %s" %
1676
             (command, instance_name,
1677
              result.stdout, result.stderr, result.fail_reason))
1678
      raise errors.HypervisorError(msg)
1679

    
1680
    return result
1681

    
1682
  @classmethod
1683
  def _ParseKVMVersion(cls, text):
1684
    """Parse the KVM version from the --help output.
1685

1686
    @type text: string
1687
    @param text: output of kvm --help
1688
    @return: (version, v_maj, v_min, v_rev)
1689
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1690

1691
    """
1692
    match = cls._VERSION_RE.search(text.splitlines()[0])
1693
    if not match:
1694
      raise errors.HypervisorError("Unable to get KVM version")
1695

    
1696
    v_all = match.group(0)
1697
    v_maj = int(match.group(1))
1698
    v_min = int(match.group(2))
1699
    if match.group(4):
1700
      v_rev = int(match.group(4))
1701
    else:
1702
      v_rev = 0
1703
    return (v_all, v_maj, v_min, v_rev)
1704

    
1705
  @classmethod
1706
  def _GetKVMOutput(cls, kvm_path, option):
1707
    """Return the output of a kvm invocation
1708

1709
    @type kvm_path: string
1710
    @param kvm_path: path to the kvm executable
1711
    @type option: a key of _KVMOPTS_CMDS
1712
    @param option: kvm option to fetch the output from
1713
    @return: output a supported kvm invocation
1714
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1715

1716
    """
1717
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
1718

    
1719
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
1720

    
1721
    result = utils.RunCmd([kvm_path] + optlist)
1722
    if result.failed and not can_fail:
1723
      raise errors.HypervisorError("Unable to get KVM %s output" %
1724
                                    " ".join(cls._KVMOPTS_CMDS[option]))
1725
    return result.output
1726

    
1727
  @classmethod
1728
  def _GetKVMVersion(cls, kvm_path):
1729
    """Return the installed KVM version.
1730

1731
    @return: (version, v_maj, v_min, v_rev)
1732
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1733

1734
    """
1735
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
1736

    
1737
  @classmethod
1738
  def _GetDefaultMachineVersion(cls, kvm_path):
1739
    """Return the default hardware revision (e.g. pc-1.1)
1740

1741
    """
1742
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
1743
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
1744
    if match:
1745
      return match.group(1)
1746
    else:
1747
      return "pc"
1748

    
1749
  def StopInstance(self, instance, force=False, retry=False, name=None):
1750
    """Stop an instance.
1751

1752
    """
1753
    if name is not None and not force:
1754
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1755
    if name is None:
1756
      name = instance.name
1757
      acpi = instance.hvparams[constants.HV_ACPI]
1758
    else:
1759
      acpi = False
1760
    _, pid, alive = self._InstancePidAlive(name)
1761
    if pid > 0 and alive:
1762
      if force or not acpi:
1763
        utils.KillProcess(pid)
1764
      else:
1765
        self._CallMonitorCommand(name, "system_powerdown")
1766

    
1767
  def CleanupInstance(self, instance_name):
1768
    """Cleanup after a stopped instance
1769

1770
    """
1771
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
1772
    if pid > 0 and alive:
1773
      raise errors.HypervisorError("Cannot cleanup a live instance")
1774
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1775

    
1776
  def RebootInstance(self, instance):
1777
    """Reboot an instance.
1778

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

    
1799
  def MigrationInfo(self, instance):
1800
    """Get instance information to perform a migration.
1801

1802
    @type instance: L{objects.Instance}
1803
    @param instance: instance to be migrated
1804
    @rtype: string
1805
    @return: content of the KVM runtime file
1806

1807
    """
1808
    return self._ReadKVMRuntime(instance.name)
1809

    
1810
  def AcceptInstance(self, instance, info, target):
1811
    """Prepare to accept an instance.
1812

1813
    @type instance: L{objects.Instance}
1814
    @param instance: instance to be accepted
1815
    @type info: string
1816
    @param info: content of the KVM runtime file on the source node
1817
    @type target: string
1818
    @param target: target host (usually ip), on this node
1819

1820
    """
1821
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1822
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1823
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1824
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1825
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
1826
                            incoming=incoming_address)
1827

    
1828
  def FinalizeMigrationDst(self, instance, info, success):
1829
    """Finalize the instance migration on the target node.
1830

1831
    Stop the incoming mode KVM.
1832

1833
    @type instance: L{objects.Instance}
1834
    @param instance: instance whose migration is being finalized
1835

1836
    """
1837
    if success:
1838
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1839
      kvm_nics = kvm_runtime[1]
1840

    
1841
      for nic_seq, nic in enumerate(kvm_nics):
1842
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1843
          # Bridged interfaces have already been configured
1844
          continue
1845
        try:
1846
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1847
        except EnvironmentError, err:
1848
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
1849
                          instance.name, nic_seq, str(err))
1850
          continue
1851
        try:
1852
          self._ConfigureNIC(instance, nic_seq, nic, tap)
1853
        except errors.HypervisorError, err:
1854
          logging.warning(str(err))
1855

    
1856
      self._WriteKVMRuntime(instance.name, info)
1857
    else:
1858
      self.StopInstance(instance, force=True)
1859

    
1860
  def MigrateInstance(self, instance, target, live):
1861
    """Migrate an instance to a target node.
1862

1863
    The migration will not be attempted if the instance is not
1864
    currently running.
1865

1866
    @type instance: L{objects.Instance}
1867
    @param instance: the instance to be migrated
1868
    @type target: string
1869
    @param target: ip address of the target node
1870
    @type live: boolean
1871
    @param live: perform a live migration
1872

1873
    """
1874
    instance_name = instance.name
1875
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
1876
    _, _, alive = self._InstancePidAlive(instance_name)
1877
    if not alive:
1878
      raise errors.HypervisorError("Instance not running, cannot migrate")
1879

    
1880
    if not live:
1881
      self._CallMonitorCommand(instance_name, "stop")
1882

    
1883
    migrate_command = ("migrate_set_speed %dm" %
1884
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1885
    self._CallMonitorCommand(instance_name, migrate_command)
1886

    
1887
    migrate_command = ("migrate_set_downtime %dms" %
1888
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1889
    self._CallMonitorCommand(instance_name, migrate_command)
1890

    
1891
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1892
    self._CallMonitorCommand(instance_name, migrate_command)
1893

    
1894
  def FinalizeMigrationSource(self, instance, success, live):
1895
    """Finalize the instance migration on the source node.
1896

1897
    @type instance: L{objects.Instance}
1898
    @param instance: the instance that was migrated
1899
    @type success: bool
1900
    @param success: whether the migration succeeded or not
1901
    @type live: bool
1902
    @param live: whether the user requested a live migration or not
1903

1904
    """
1905
    if success:
1906
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
1907
      utils.KillProcess(pid)
1908
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1909
    elif live:
1910
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1911

    
1912
  def GetMigrationStatus(self, instance):
1913
    """Get the migration status
1914

1915
    @type instance: L{objects.Instance}
1916
    @param instance: the instance that is being migrated
1917
    @rtype: L{objects.MigrationStatus}
1918
    @return: the status of the current migration (one of
1919
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1920
             progress info that can be retrieved from the hypervisor
1921

1922
    """
1923
    info_command = "info migrate"
1924
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
1925
      result = self._CallMonitorCommand(instance.name, info_command)
1926
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
1927
      if not match:
1928
        if not result.stdout:
1929
          logging.info("KVM: empty 'info migrate' result")
1930
        else:
1931
          logging.warning("KVM: unknown 'info migrate' result: %s",
1932
                          result.stdout)
1933
      else:
1934
        status = match.group(1)
1935
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
1936
          migration_status = objects.MigrationStatus(status=status)
1937
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
1938
          if match:
1939
            migration_status.transferred_ram = match.group("transferred")
1940
            migration_status.total_ram = match.group("total")
1941

    
1942
          return migration_status
1943

    
1944
        logging.warning("KVM: unknown migration status '%s'", status)
1945

    
1946
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1947

    
1948
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
1949

    
1950
  def BalloonInstanceMemory(self, instance, mem):
1951
    """Balloon an instance memory to a certain value.
1952

1953
    @type instance: L{objects.Instance}
1954
    @param instance: instance to be accepted
1955
    @type mem: int
1956
    @param mem: actual memory size to use for instance runtime
1957

1958
    """
1959
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
1960

    
1961
  def GetNodeInfo(self):
1962
    """Return information about the node.
1963

1964
    @return: a dict with the following keys (values in MiB):
1965
          - memory_total: the total memory size on the node
1966
          - memory_free: the available memory on the node for instances
1967
          - memory_dom0: the memory used by the node itself, if available
1968
          - hv_version: the hypervisor version in the form (major, minor,
1969
                        revision)
1970

1971
    """
1972
    result = self.GetLinuxNodeInfo()
1973
    # FIXME: this is the global kvm version, but the actual version can be
1974
    # customized as an hv parameter. we should use the nodegroup's default kvm
1975
    # path parameter here.
1976
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
1977
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
1978
    return result
1979

    
1980
  @classmethod
1981
  def GetInstanceConsole(cls, instance, hvparams, beparams):
1982
    """Return a command for connecting to the console of an instance.
1983

1984
    """
1985
    if hvparams[constants.HV_SERIAL_CONSOLE]:
1986
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
1987
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1988
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1989
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
1990
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1991
      return objects.InstanceConsole(instance=instance.name,
1992
                                     kind=constants.CONS_SSH,
1993
                                     host=instance.primary_node,
1994
                                     user=constants.SSH_CONSOLE_USER,
1995
                                     command=cmd)
1996

    
1997
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1998
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1999
      display = instance.network_port - constants.VNC_BASE_PORT
2000
      return objects.InstanceConsole(instance=instance.name,
2001
                                     kind=constants.CONS_VNC,
2002
                                     host=vnc_bind_address,
2003
                                     port=instance.network_port,
2004
                                     display=display)
2005

    
2006
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2007
    if spice_bind:
2008
      return objects.InstanceConsole(instance=instance.name,
2009
                                     kind=constants.CONS_SPICE,
2010
                                     host=spice_bind,
2011
                                     port=instance.network_port)
2012

    
2013
    return objects.InstanceConsole(instance=instance.name,
2014
                                   kind=constants.CONS_MESSAGE,
2015
                                   message=("No serial shell for instance %s" %
2016
                                            instance.name))
2017

    
2018
  def Verify(self):
2019
    """Verify the hypervisor.
2020

2021
    Check that the required binaries exist.
2022

2023
    @return: Problem description if something is wrong, C{None} otherwise
2024

2025
    """
2026
    msgs = []
2027
    # FIXME: this is the global kvm binary, but the actual path can be
2028
    # customized as an hv parameter; we should use the nodegroup's
2029
    # default kvm path parameter here.
2030
    if not os.path.exists(constants.KVM_PATH):
2031
      msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2032
    if not os.path.exists(constants.SOCAT_PATH):
2033
      msgs.append("The socat binary ('%s') does not exist" %
2034
                  constants.SOCAT_PATH)
2035

    
2036
    return self._FormatVerifyResults(msgs)
2037

    
2038
  @classmethod
2039
  def CheckParameterSyntax(cls, hvparams):
2040
    """Check the given parameters for validity.
2041

2042
    @type hvparams:  dict
2043
    @param hvparams: dictionary with parameter names/value
2044
    @raise errors.HypervisorError: when a parameter is not valid
2045

2046
    """
2047
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2048

    
2049
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2050
    if kernel_path:
2051
      if not hvparams[constants.HV_ROOT_PATH]:
2052
        raise errors.HypervisorError("Need a root partition for the instance,"
2053
                                     " if a kernel is defined")
2054

    
2055
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2056
        not hvparams[constants.HV_VNC_X509]):
2057
      raise errors.HypervisorError("%s must be defined, if %s is" %
2058
                                   (constants.HV_VNC_X509,
2059
                                    constants.HV_VNC_X509_VERIFY))
2060

    
2061
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2062
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2063
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2064
      if not serial_speed or serial_speed not in valid_speeds:
2065
        raise errors.HypervisorError("Invalid serial console speed, must be"
2066
                                     " one of: %s" %
2067
                                     utils.CommaJoin(valid_speeds))
2068

    
2069
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2070
    if (boot_order == constants.HT_BO_CDROM and
2071
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2072
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2073
                                   " ISO path")
2074

    
2075
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2076
    if security_model == constants.HT_SM_USER:
2077
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2078
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2079
                                     " must be specified")
2080
    elif (security_model == constants.HT_SM_NONE or
2081
          security_model == constants.HT_SM_POOL):
2082
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2083
        raise errors.HypervisorError("Cannot have a security domain when the"
2084
                                     " security model is 'none' or 'pool'")
2085

    
2086
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2087
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2088
    if spice_bind:
2089
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2090
        # if an IP version is specified, the spice_bind parameter must be an
2091
        # IP of that family
2092
        if (netutils.IP4Address.IsValid(spice_bind) and
2093
            spice_ip_version != constants.IP4_VERSION):
2094
          raise errors.HypervisorError("spice: got an IPv4 address (%s), but"
2095
                                       " the specified IP version is %s" %
2096
                                       (spice_bind, spice_ip_version))
2097

    
2098
        if (netutils.IP6Address.IsValid(spice_bind) and
2099
            spice_ip_version != constants.IP6_VERSION):
2100
          raise errors.HypervisorError("spice: got an IPv6 address (%s), but"
2101
                                       " the specified IP version is %s" %
2102
                                       (spice_bind, spice_ip_version))
2103
    else:
2104
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2105
      # error if any of them is set without it.
2106
      for param in _SPICE_ADDITIONAL_PARAMS:
2107
        if hvparams[param]:
2108
          raise errors.HypervisorError("spice: %s requires %s to be set" %
2109
                                       (param, constants.HV_KVM_SPICE_BIND))
2110

    
2111
  @classmethod
2112
  def ValidateParameters(cls, hvparams):
2113
    """Check the given parameters for validity.
2114

2115
    @type hvparams:  dict
2116
    @param hvparams: dictionary with parameter names/value
2117
    @raise errors.HypervisorError: when a parameter is not valid
2118

2119
    """
2120
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2121

    
2122
    kvm_path = hvparams[constants.HV_KVM_PATH]
2123

    
2124
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2125
    if security_model == constants.HT_SM_USER:
2126
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2127
      try:
2128
        pwd.getpwnam(username)
2129
      except KeyError:
2130
        raise errors.HypervisorError("Unknown security domain user %s"
2131
                                     % username)
2132

    
2133
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2134
    if spice_bind:
2135
      # only one of VNC and SPICE can be used currently.
2136
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2137
        raise errors.HypervisorError("both SPICE and VNC are configured, but"
2138
                                     " only one of them can be used at a"
2139
                                     " given time.")
2140

    
2141
      # check that KVM supports SPICE
2142
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2143
      if not cls._SPICE_RE.search(kvmhelp):
2144
        raise errors.HypervisorError("spice is configured, but it is not"
2145
                                     " supported according to kvm --help")
2146

    
2147
      # if spice_bind is not an IP address, it must be a valid interface
2148
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind)
2149
                       or netutils.IP6Address.IsValid(spice_bind))
2150
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2151
        raise errors.HypervisorError("spice: the %s parameter must be either"
2152
                                     " a valid IP address or interface name" %
2153
                                     constants.HV_KVM_SPICE_BIND)
2154

    
2155
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2156
    if machine_version:
2157
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2158
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2159
        raise errors.HypervisorError("Unsupported machine version: %s" %
2160
                                     machine_version)
2161

    
2162
  @classmethod
2163
  def PowercycleNode(cls):
2164
    """KVM powercycle, just a wrapper over Linux powercycle.
2165

2166
    """
2167
    cls.LinuxPowercycle()