Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ f0db563d

History | View | Annotate | Download (78.4 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
  _KVMOPTS_CMDS = {
593
    _KVMOPT_HELP: ["--help"],
594
    _KVMOPT_MLIST: ["-M", "?"],
595
    _KVMOPT_DEVICELIST: ["-device", "?"],
596
  }
597

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

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

609
    """
610
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
611

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

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

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

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

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

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

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

    
644
    instance = None
645
    memory = 0
646
    vcpus = 0
647

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

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

    
662
    return (instance, memory, vcpus)
663

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

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

672
    """
673
    pidfile = self._InstancePidFile(instance_name)
674
    pid = utils.ReadPidFile(pidfile)
675

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

    
683
    return (pidfile, pid, alive)
684

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

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

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

698
    """
699
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
700

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

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

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

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

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

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

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

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

731
    """
732
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
733

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

738
    """
739
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
740

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

746
    """
747
    return utils.PathJoin(cls._NICS_DIR, instance_name)
748

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

753
    """
754
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
755

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

760
    """
761
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
762

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

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

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

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

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

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

831
    """
832
    if instance.tags:
833
      tags = " ".join(instance.tags)
834
    else:
835
      tags = ""
836

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

    
847
    if nic.ip:
848
      env["IP"] = nic.ip
849

    
850
    if nic.nicparams[constants.NIC_LINK]:
851
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
852

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
950
    return result
951

    
952
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
953
    """Complete CPU pinning.
954

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

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

    
968
  def ListInstances(self):
969
    """Get the list of running instances.
970

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

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

    
981
  def GetInstanceInfo(self, instance_name):
982
    """Get instance properties.
983

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

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

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

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

    
1009
    return (instance_name, pid, memory, vcpus, istat, times)
1010

    
1011
  def GetAllInstancesInfo(self):
1012
    """Get properties of all instances.
1013

1014
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1015

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

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

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

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

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

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

    
1060
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1061

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

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

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

    
1085
    self.ValidateParameters(hvp)
1086

    
1087
    if startup_paused:
1088
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1089

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1216
    kvm_cmd.extend(["-usb"])
1217

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

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

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

    
1251
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1252

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

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

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

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

    
1290
        spice_address = addresses[spice_ip_version][0]
1291

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

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

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

    
1314
      if spice_ip_version:
1315
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1316

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

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

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

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

    
1349
    else:
1350
      kvm_cmd.extend(["-nographic"])
1351

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

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

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

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

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

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

    
1378
    if hvp[constants.HV_KVM_EXTRA]:
1379
      kvm_cmd.extend([hvp[constants.HV_KVM_EXTRA]])
1380

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

    
1386
    return (kvm_cmd, kvm_nics, hvparams)
1387

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1472
    temp_files = []
1473

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

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

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

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

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

    
1528
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1529

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1642
    for filename in temp_files:
1643
      utils.RemoveFile(filename)
1644

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

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

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

    
1659
  def StartInstance(self, instance, block_devices, startup_paused):
1660
    """Start an instance.
1661

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

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

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

    
1687
    return result
1688

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

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

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

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

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

1716
    @return: output a supported kvm invocation
1717
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1718

1719
    """
1720
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
1721

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1832
    Stop the incoming mode KVM.
1833

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1943
          return migration_status
1944

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

    
1947
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1948

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

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

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

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

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

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

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

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

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

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

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

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

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

2022
    Check that the binary exists.
2023

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

    
2033
  @classmethod
2034
  def CheckParameterSyntax(cls, hvparams):
2035
    """Check the given parameters for validity.
2036

2037
    @type hvparams:  dict
2038
    @param hvparams: dictionary with parameter names/value
2039
    @raise errors.HypervisorError: when a parameter is not valid
2040

2041
    """
2042
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2043

    
2044
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2045
    if kernel_path:
2046
      if not hvparams[constants.HV_ROOT_PATH]:
2047
        raise errors.HypervisorError("Need a root partition for the instance,"
2048
                                     " if a kernel is defined")
2049

    
2050
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2051
        not hvparams[constants.HV_VNC_X509]):
2052
      raise errors.HypervisorError("%s must be defined, if %s is" %
2053
                                   (constants.HV_VNC_X509,
2054
                                    constants.HV_VNC_X509_VERIFY))
2055

    
2056
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2057
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2058
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2059
      if not serial_speed or serial_speed not in valid_speeds:
2060
        raise errors.HypervisorError("Invalid serial console speed, must be"
2061
                                     " one of: %s" %
2062
                                     utils.CommaJoin(valid_speeds))
2063

    
2064
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2065
    if (boot_order == constants.HT_BO_CDROM and
2066
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2067
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2068
                                   " ISO path")
2069

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

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

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

    
2106
  @classmethod
2107
  def ValidateParameters(cls, hvparams):
2108
    """Check the given parameters for validity.
2109

2110
    @type hvparams:  dict
2111
    @param hvparams: dictionary with parameter names/value
2112
    @raise errors.HypervisorError: when a parameter is not valid
2113

2114
    """
2115
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2116

    
2117
    kvm_path = hvparams[constants.HV_KVM_PATH]
2118

    
2119
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2120
    if security_model == constants.HT_SM_USER:
2121
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2122
      try:
2123
        pwd.getpwnam(username)
2124
      except KeyError:
2125
        raise errors.HypervisorError("Unknown security domain user %s"
2126
                                     % username)
2127

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

    
2136
      # check that KVM supports SPICE
2137
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2138
      if not cls._SPICE_RE.search(kvmhelp):
2139
        raise errors.HypervisorError("spice is configured, but it is not"
2140
                                     " supported according to kvm --help")
2141

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

    
2150
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2151
    if machine_version:
2152
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2153
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2154
        raise errors.HypervisorError("Unsupported machine version: %s" %
2155
                                     machine_version)
2156

    
2157
  @classmethod
2158
  def PowercycleNode(cls):
2159
    """KVM powercycle, just a wrapper over Linux powercycle.
2160

2161
    """
2162
    cls.LinuxPowercycle()