Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ bc0fed4b

History | View | Annotate | Download (78.9 kB)

1
#
2
#
3

    
4
# Copyright (C) 2008, 2009, 2010, 2011, 2012 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:
143
    raise errors.HypervisorError("Failed to allocate a new TAP device")
144

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

    
149

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

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

    
172
  return env
173

    
174

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

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

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

    
186
    self.data = data
187

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

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

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

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

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

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

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

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

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

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

    
228

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

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

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

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

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

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

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

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

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

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

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

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

    
297
    self._check_socket()
298

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

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

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

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

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

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

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

    
340
    return (message, buf)
341

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

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

350
    """
351
    self._check_connection()
352

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

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

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

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

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

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

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

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

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

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

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

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

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

    
437

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

441
  """
442
  CAN_MIGRATE = True
443

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

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

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

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

    
556
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
557
  _MIGRATION_INFO_RETRY_DELAY = 2
558

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
665
    return (instance, memory, vcpus)
666

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

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

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

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

    
686
    return (pidfile, pid, alive)
687

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
953
    return result
954

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1088
    self.ValidateParameters(hvp)
1089

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1293
        spice_address = addresses[spice_ip_version][0]
1294

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1389
    return (kvm_cmd, kvm_nics, hvparams)
1390

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1475
    temp_files = []
1476

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1677
    """
1678
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1679
             (utils.ShellQuote(command),
1680
              constants.SOCAT_PATH,
1681
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1682
    result = utils.RunCmd(socat)
1683
    if result.failed:
1684
      msg = ("Failed to send command '%s' to instance %s."
1685
             " output: %s, error: %s, fail_reason: %s" %
1686
             (command, instance_name,
1687
              result.stdout, result.stderr, result.fail_reason))
1688
      raise errors.HypervisorError(msg)
1689

    
1690
    return result
1691

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1841
    Stop the incoming mode KVM.
1842

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1952
          return migration_status
1953

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

    
1956
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1957

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

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

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

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

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

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

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

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

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

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

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

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

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

2031
    Check that the required binaries exist.
2032

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2126
    """
2127
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2128

    
2129
    kvm_path = hvparams[constants.HV_KVM_PATH]
2130

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

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

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

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

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

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

2173
    """
2174
    cls.LinuxPowercycle()