Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 99c7cd5b

History | View | Annotate | Download (78.5 kB)

1
#
2
#
3

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

    
21

    
22
"""KVM hypervisor
23

24
"""
25

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

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

    
57

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

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

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

    
82

    
83
def _ProbeTapVnetHdr(fd):
84
  """Check whether to enable the IFF_VNET_HDR flag.
85

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

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

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

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

    
114

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

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

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

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

    
132
  flags = IFF_TAP | IFF_NO_PI
133

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

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

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

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

    
150

    
151
class QmpMessage:
152
  """QEMU Messaging Protocol (QMP) message.
153

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

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

    
162
    self.data = data
163

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

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

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

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

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

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

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

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

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

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

    
204

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

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

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

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

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

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

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

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

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

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

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

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

    
273
    self._check_socket()
274

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

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

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

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

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

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

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

    
316
    return (message, buf)
317

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

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

326
    """
327
    self._check_connection()
328

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

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

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

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

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

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

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

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

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

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

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

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

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

    
413

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

417
  """
418
  CAN_MIGRATE = True
419

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

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

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

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

    
532
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
533
  _MIGRATION_INFO_RETRY_DELAY = 2
534

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
642
    return (instance, memory, vcpus)
643

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

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

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

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

    
663
    return (pidfile, pid, alive)
664

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
928
    return result
929

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1019
    """
1020
    # pylint: disable=R0912,R0914,R0915
1021
    hvp = instance.hvparams
1022

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

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

    
1038
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1039

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

    
1049
    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1050
    if not mversion:
1051
      mversion = self._GetDefaultMachineVersion(kvm)
1052
    kvm_cmd.extend(["-M", mversion])
1053

    
1054
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1055
    if kernel_path:
1056
      boot_disk = boot_cdrom = boot_floppy = boot_network = False
1057
    else:
1058
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1059
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1060
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1061
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1062

    
1063
    self.ValidateParameters(hvp)
1064

    
1065
    if startup_paused:
1066
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1067

    
1068
    if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1069
        self._ENABLE_KVM_RE.search(kvmhelp)):
1070
      kvm_cmd.extend(["-enable-kvm"])
1071
    elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1072
          self._DISABLE_KVM_RE.search(kvmhelp)):
1073
      kvm_cmd.extend(["-disable-kvm"])
1074

    
1075
    if boot_network:
1076
      kvm_cmd.extend(["-boot", "n"])
1077

    
1078
    # whether this is an older KVM version that uses the boot=on flag
1079
    # on devices
1080
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1081

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

    
1112
      drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
1113
                                                cache_val)
1114
      kvm_cmd.extend(["-drive", drive_val])
1115

    
1116
    #Now we can specify a different device type for CDROM devices.
1117
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1118
    if not cdrom_disk_type:
1119
      cdrom_disk_type = disk_type
1120

    
1121
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1122
    if iso_image:
1123
      options = ",format=raw,media=cdrom"
1124
      # set cdrom 'if' type
1125
      if boot_cdrom:
1126
        actual_cdrom_type = constants.HT_DISK_IDE
1127
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1128
        actual_cdrom_type = "virtio"
1129
      else:
1130
        actual_cdrom_type = cdrom_disk_type
1131
      if_val = ",if=%s" % actual_cdrom_type
1132
      # set boot flag, if needed
1133
      boot_val = ""
1134
      if boot_cdrom:
1135
        kvm_cmd.extend(["-boot", "d"])
1136
        if needs_boot_flag:
1137
          boot_val = ",boot=on"
1138
      # and finally build the entire '-drive' value
1139
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1140
      kvm_cmd.extend(["-drive", drive_val])
1141

    
1142
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1143
    if iso_image2:
1144
      options = ",format=raw,media=cdrom"
1145
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1146
        if_val = ",if=virtio"
1147
      else:
1148
        if_val = ",if=%s" % cdrom_disk_type
1149
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1150
      kvm_cmd.extend(["-drive", drive_val])
1151

    
1152
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1153
    if floppy_image:
1154
      options = ",format=raw,media=disk"
1155
      if boot_floppy:
1156
        kvm_cmd.extend(["-boot", "a"])
1157
        options = "%s,boot=on" % options
1158
      if_val = ",if=floppy"
1159
      options = "%s%s" % (options, if_val)
1160
      drive_val = "file=%s%s" % (floppy_image, options)
1161
      kvm_cmd.extend(["-drive", drive_val])
1162

    
1163
    if kernel_path:
1164
      kvm_cmd.extend(["-kernel", kernel_path])
1165
      initrd_path = hvp[constants.HV_INITRD_PATH]
1166
      if initrd_path:
1167
        kvm_cmd.extend(["-initrd", initrd_path])
1168
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1169
                     hvp[constants.HV_KERNEL_ARGS]]
1170
      if hvp[constants.HV_SERIAL_CONSOLE]:
1171
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1172
        root_append.append("console=ttyS0,%s" % serial_speed)
1173
      kvm_cmd.extend(["-append", " ".join(root_append)])
1174

    
1175
    mem_path = hvp[constants.HV_MEM_PATH]
1176
    if mem_path:
1177
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1178

    
1179
    monitor_dev = ("unix:%s,server,nowait" %
1180
                   self._InstanceMonitor(instance.name))
1181
    kvm_cmd.extend(["-monitor", monitor_dev])
1182
    if hvp[constants.HV_SERIAL_CONSOLE]:
1183
      serial_dev = ("unix:%s,server,nowait" %
1184
                    self._InstanceSerial(instance.name))
1185
      kvm_cmd.extend(["-serial", serial_dev])
1186
    else:
1187
      kvm_cmd.extend(["-serial", "none"])
1188

    
1189
    mouse_type = hvp[constants.HV_USB_MOUSE]
1190
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1191
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1192
    spice_ip_version = None
1193

    
1194
    kvm_cmd.extend(["-usb"])
1195

    
1196
    if mouse_type:
1197
      kvm_cmd.extend(["-usbdevice", mouse_type])
1198
    elif vnc_bind_address:
1199
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1200

    
1201
    if vnc_bind_address:
1202
      if netutils.IP4Address.IsValid(vnc_bind_address):
1203
        if instance.network_port > constants.VNC_BASE_PORT:
1204
          display = instance.network_port - constants.VNC_BASE_PORT
1205
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1206
            vnc_arg = ":%d" % (display)
1207
          else:
1208
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1209
        else:
1210
          logging.error("Network port is not a valid VNC display (%d < %d)."
1211
                        " Not starting VNC", instance.network_port,
1212
                        constants.VNC_BASE_PORT)
1213
          vnc_arg = "none"
1214

    
1215
        # Only allow tls and other option when not binding to a file, for now.
1216
        # kvm/qemu gets confused otherwise about the filename to use.
1217
        vnc_append = ""
1218
        if hvp[constants.HV_VNC_TLS]:
1219
          vnc_append = "%s,tls" % vnc_append
1220
          if hvp[constants.HV_VNC_X509_VERIFY]:
1221
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1222
                                               hvp[constants.HV_VNC_X509])
1223
          elif hvp[constants.HV_VNC_X509]:
1224
            vnc_append = "%s,x509=%s" % (vnc_append,
1225
                                         hvp[constants.HV_VNC_X509])
1226
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1227
          vnc_append = "%s,password" % vnc_append
1228

    
1229
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1230

    
1231
      else:
1232
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1233

    
1234
      kvm_cmd.extend(["-vnc", vnc_arg])
1235
    elif spice_bind:
1236
      # FIXME: this is wrong here; the iface ip address differs
1237
      # between systems, so it should be done in _ExecuteKVMRuntime
1238
      if netutils.IsValidInterface(spice_bind):
1239
        # The user specified a network interface, we have to figure out the IP
1240
        # address.
1241
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1242
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1243

    
1244
        # if the user specified an IP version and the interface does not
1245
        # have that kind of IP addresses, throw an exception
1246
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1247
          if not addresses[spice_ip_version]:
1248
            raise errors.HypervisorError("spice: unable to get an IPv%s address"
1249
                                         " for %s" % (spice_ip_version,
1250
                                                      spice_bind))
1251

    
1252
        # the user did not specify an IP version, we have to figure it out
1253
        elif (addresses[constants.IP4_VERSION] and
1254
              addresses[constants.IP6_VERSION]):
1255
          # we have both ipv4 and ipv6, let's use the cluster default IP
1256
          # version
1257
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1258
          spice_ip_version = \
1259
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1260
        elif addresses[constants.IP4_VERSION]:
1261
          spice_ip_version = constants.IP4_VERSION
1262
        elif addresses[constants.IP6_VERSION]:
1263
          spice_ip_version = constants.IP6_VERSION
1264
        else:
1265
          raise errors.HypervisorError("spice: unable to get an IP address"
1266
                                       " for %s" % (spice_bind))
1267

    
1268
        spice_address = addresses[spice_ip_version][0]
1269

    
1270
      else:
1271
        # spice_bind is known to be a valid IP address, because
1272
        # ValidateParameters checked it.
1273
        spice_address = spice_bind
1274

    
1275
      spice_arg = "addr=%s" % spice_address
1276
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1277
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1278
                     (spice_arg, instance.network_port,
1279
                      pathutils.SPICE_CACERT_FILE))
1280
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1281
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1282
                      pathutils.SPICE_CERT_FILE))
1283
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1284
        if tls_ciphers:
1285
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1286
      else:
1287
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1288

    
1289
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1290
        spice_arg = "%s,disable-ticketing" % spice_arg
1291

    
1292
      if spice_ip_version:
1293
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1294

    
1295
      # Image compression options
1296
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1297
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1298
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1299
      if img_lossless:
1300
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1301
      if img_jpeg:
1302
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1303
      if img_zlib_glz:
1304
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1305

    
1306
      # Video stream detection
1307
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1308
      if video_streaming:
1309
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1310

    
1311
      # Audio compression, by default in qemu-kvm it is on
1312
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1313
        spice_arg = "%s,playback-compression=off" % spice_arg
1314
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1315
        spice_arg = "%s,agent-mouse=off" % spice_arg
1316
      else:
1317
        # Enable the spice agent communication channel between the host and the
1318
        # agent.
1319
        kvm_cmd.extend(["-device", "virtio-serial-pci"])
1320
        kvm_cmd.extend(["-device", "virtserialport,chardev=spicechannel0,"
1321
                                                   "name=com.redhat.spice.0"])
1322
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1323

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

    
1327
    else:
1328
      # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1329
      # also works in earlier versions though (tested with 1.1 and 1.3)
1330
      if self._DISPLAY_RE.search(kvmhelp):
1331
        kvm_cmd.extend(["-display", "none"])
1332
      else:
1333
        kvm_cmd.extend(["-nographic"])
1334

    
1335
    if hvp[constants.HV_USE_LOCALTIME]:
1336
      kvm_cmd.extend(["-localtime"])
1337

    
1338
    if hvp[constants.HV_KVM_USE_CHROOT]:
1339
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1340

    
1341
    # Add qemu-KVM -cpu param
1342
    if hvp[constants.HV_CPU_TYPE]:
1343
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1344

    
1345
    # As requested by music lovers
1346
    if hvp[constants.HV_SOUNDHW]:
1347
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1348

    
1349
    # Pass a -vga option if requested, or if spice is used, for backwards
1350
    # compatibility.
1351
    if hvp[constants.HV_VGA]:
1352
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1353
    elif spice_bind:
1354
      kvm_cmd.extend(["-vga", "qxl"])
1355

    
1356
    # Various types of usb devices, comma separated
1357
    if hvp[constants.HV_USB_DEVICES]:
1358
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1359
        kvm_cmd.extend(["-usbdevice", dev])
1360

    
1361
    if hvp[constants.HV_KVM_EXTRA]:
1362
      kvm_cmd.extend([hvp[constants.HV_KVM_EXTRA]])
1363

    
1364
    # Save the current instance nics, but defer their expansion as parameters,
1365
    # as we'll need to generate executable temp files for them.
1366
    kvm_nics = instance.nics
1367
    hvparams = hvp
1368

    
1369
    return (kvm_cmd, kvm_nics, hvparams)
1370

    
1371
  def _WriteKVMRuntime(self, instance_name, data):
1372
    """Write an instance's KVM runtime
1373

1374
    """
1375
    try:
1376
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1377
                      data=data)
1378
    except EnvironmentError, err:
1379
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1380

    
1381
  def _ReadKVMRuntime(self, instance_name):
1382
    """Read an instance's KVM runtime
1383

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

    
1391
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1392
    """Save an instance's KVM runtime
1393

1394
    """
1395
    kvm_cmd, kvm_nics, hvparams = kvm_runtime
1396
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1397
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1398
    self._WriteKVMRuntime(instance.name, serialized_form)
1399

    
1400
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1401
    """Load an instance's KVM runtime
1402

1403
    """
1404
    if not serialized_runtime:
1405
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1406
    loaded_runtime = serializer.Load(serialized_runtime)
1407
    kvm_cmd, serialized_nics, hvparams = loaded_runtime
1408
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1409
    return (kvm_cmd, kvm_nics, hvparams)
1410

    
1411
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1412
    """Run the KVM cmd and check for errors
1413

1414
    @type name: string
1415
    @param name: instance name
1416
    @type kvm_cmd: list of strings
1417
    @param kvm_cmd: runcmd input for kvm
1418
    @type tap_fds: list of int
1419
    @param tap_fds: fds of tap devices opened by Ganeti
1420

1421
    """
1422
    try:
1423
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1424
    finally:
1425
      for fd in tap_fds:
1426
        utils_wrapper.CloseFdNoError(fd)
1427

    
1428
    if result.failed:
1429
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1430
                                   (name, result.fail_reason, result.output))
1431
    if not self._InstancePidAlive(name)[2]:
1432
      raise errors.HypervisorError("Failed to start instance %s" % name)
1433

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

1437
    @type incoming: tuple of strings
1438
    @param incoming: (target_host_ip, port)
1439
    @type kvmhelp: string
1440
    @param kvmhelp: output of kvm --help
1441

1442
    """
1443
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1444
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1445
    #    have changed since the instance started; only use them if the change
1446
    #    won't affect the inside of the instance (which hasn't been rebooted).
1447
    #  - up_hvp contains the parameters as they were when the instance was
1448
    #    started, plus any new parameter which has been added between ganeti
1449
    #    versions: it is paramount that those default to a value which won't
1450
    #    affect the inside of the instance as well.
1451
    conf_hvp = instance.hvparams
1452
    name = instance.name
1453
    self._CheckDown(name)
1454

    
1455
    temp_files = []
1456

    
1457
    kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1458
    # the first element of kvm_cmd is always the path to the kvm binary
1459
    kvm_path = kvm_cmd[0]
1460
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1461

    
1462
    # We know it's safe to run as a different user upon migration, so we'll use
1463
    # the latest conf, from conf_hvp.
1464
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1465
    if security_model == constants.HT_SM_USER:
1466
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1467

    
1468
    keymap = conf_hvp[constants.HV_KEYMAP]
1469
    if keymap:
1470
      keymap_path = self._InstanceKeymapFile(name)
1471
      # If a keymap file is specified, KVM won't use its internal defaults. By
1472
      # first including the "en-us" layout, an error on loading the actual
1473
      # layout (e.g. because it can't be found) won't lead to a non-functional
1474
      # keyboard. A keyboard with incorrect keys is still better than none.
1475
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1476
      kvm_cmd.extend(["-k", keymap_path])
1477

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

    
1501
        if up_hvp[constants.HV_VHOST_NET]:
1502
          # check for vhost_net support
1503
          if self._VHOST_RE.search(kvmhelp):
1504
            tap_extra = ",vhost=on"
1505
          else:
1506
            raise errors.HypervisorError("vhost_net is configured"
1507
                                         " but it is not available")
1508
      else:
1509
        nic_model = nic_type
1510

    
1511
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1512

    
1513
      for nic_seq, nic in enumerate(kvm_nics):
1514
        tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1515
        tapfds.append(tapfd)
1516
        taps.append(tapname)
1517
        if kvm_supports_netdev:
1518
          nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1519
          tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1520
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1521
        else:
1522
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1523
                                                         nic.mac, nic_model)
1524
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1525
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1526

    
1527
    if incoming:
1528
      target, port = incoming
1529
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1530

    
1531
    # Changing the vnc password doesn't bother the guest that much. At most it
1532
    # will surprise people who connect to it. Whether positively or negatively
1533
    # it's debatable.
1534
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1535
    vnc_pwd = None
1536
    if vnc_pwd_file:
1537
      try:
1538
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1539
      except EnvironmentError, err:
1540
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1541
                                     % (vnc_pwd_file, err))
1542

    
1543
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1544
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1545
                         constants.SECURE_DIR_MODE)])
1546

    
1547
    # Automatically enable QMP if version is >= 0.14
1548
    if self._QMP_RE.search(kvmhelp):
1549
      logging.debug("Enabling QMP")
1550
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1551
                      self._InstanceQmpMonitor(instance.name)])
1552

    
1553
    # Configure the network now for starting instances and bridged interfaces,
1554
    # during FinalizeMigration for incoming instances' routed interfaces
1555
    for nic_seq, nic in enumerate(kvm_nics):
1556
      if (incoming and
1557
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1558
        continue
1559
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1560

    
1561
    # CPU affinity requires kvm to start paused, so we set this flag if the
1562
    # instance is not already paused and if we are not going to accept a
1563
    # migrating instance. In the latter case, pausing is not needed.
1564
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1565
    if start_kvm_paused:
1566
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1567

    
1568
    # Note: CPU pinning is using up_hvp since changes take effect
1569
    # during instance startup anyway, and to avoid problems when soft
1570
    # rebooting the instance.
1571
    cpu_pinning = False
1572
    if up_hvp.get(constants.HV_CPU_MASK, None):
1573
      cpu_pinning = True
1574

    
1575
    if security_model == constants.HT_SM_POOL:
1576
      ss = ssconf.SimpleStore()
1577
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1578
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1579
      uid = uidpool.RequestUnusedUid(all_uids)
1580
      try:
1581
        username = pwd.getpwuid(uid.GetUid()).pw_name
1582
        kvm_cmd.extend(["-runas", username])
1583
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1584
      except:
1585
        uidpool.ReleaseUid(uid)
1586
        raise
1587
      else:
1588
        uid.Unlock()
1589
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1590
    else:
1591
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1592

    
1593
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1594
                     constants.RUN_DIRS_MODE)])
1595
    for nic_seq, tap in enumerate(taps):
1596
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1597
                      data=tap)
1598

    
1599
    if vnc_pwd:
1600
      change_cmd = "change vnc password %s" % vnc_pwd
1601
      self._CallMonitorCommand(instance.name, change_cmd)
1602

    
1603
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1604
    # connection attempts because SPICE by default does not allow connections
1605
    # if neither a password nor the "disable_ticketing" options are specified.
1606
    # As soon as we send the password via QMP, that password is a valid ticket
1607
    # for connection.
1608
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1609
    if spice_password_file:
1610
      spice_pwd = ""
1611
      try:
1612
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1613
      except EnvironmentError, err:
1614
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1615
                                     % (spice_password_file, err))
1616

    
1617
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1618
      qmp.connect()
1619
      arguments = {
1620
          "protocol": "spice",
1621
          "password": spice_pwd,
1622
      }
1623
      qmp.Execute("set_password", arguments)
1624

    
1625
    for filename in temp_files:
1626
      utils.RemoveFile(filename)
1627

    
1628
    # If requested, set CPU affinity and resume instance execution
1629
    if cpu_pinning:
1630
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1631

    
1632
    start_memory = self._InstanceStartupMemory(instance)
1633
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1634
      self.BalloonInstanceMemory(instance, start_memory)
1635

    
1636
    if start_kvm_paused:
1637
      # To control CPU pinning, ballooning, and vnc/spice passwords
1638
      # the VM was started in a frozen state. If freezing was not
1639
      # explicitly requested resume the vm status.
1640
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1641

    
1642
  def StartInstance(self, instance, block_devices, startup_paused):
1643
    """Start an instance.
1644

1645
    """
1646
    self._CheckDown(instance.name)
1647
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1648
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1649
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1650
                                           startup_paused, kvmhelp)
1651
    self._SaveKVMRuntime(instance, kvm_runtime)
1652
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1653

    
1654
  def _CallMonitorCommand(self, instance_name, command):
1655
    """Invoke a command on the instance monitor.
1656

1657
    """
1658
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1659
             (utils.ShellQuote(command),
1660
              constants.SOCAT_PATH,
1661
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1662
    result = utils.RunCmd(socat)
1663
    if result.failed:
1664
      msg = ("Failed to send command '%s' to instance %s."
1665
             " output: %s, error: %s, fail_reason: %s" %
1666
             (command, instance_name,
1667
              result.stdout, result.stderr, result.fail_reason))
1668
      raise errors.HypervisorError(msg)
1669

    
1670
    return result
1671

    
1672
  @classmethod
1673
  def _ParseKVMVersion(cls, text):
1674
    """Parse the KVM version from the --help output.
1675

1676
    @type text: string
1677
    @param text: output of kvm --help
1678
    @return: (version, v_maj, v_min, v_rev)
1679
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1680

1681
    """
1682
    match = cls._VERSION_RE.search(text.splitlines()[0])
1683
    if not match:
1684
      raise errors.HypervisorError("Unable to get KVM version")
1685

    
1686
    v_all = match.group(0)
1687
    v_maj = int(match.group(1))
1688
    v_min = int(match.group(2))
1689
    if match.group(4):
1690
      v_rev = int(match.group(4))
1691
    else:
1692
      v_rev = 0
1693
    return (v_all, v_maj, v_min, v_rev)
1694

    
1695
  @classmethod
1696
  def _GetKVMOutput(cls, kvm_path, option):
1697
    """Return the output of a kvm invocation
1698

1699
    @type kvm_path: string
1700
    @param kvm_path: path to the kvm executable
1701
    @type option: a key of _KVMOPTS_CMDS
1702
    @param option: kvm option to fetch the output from
1703
    @return: output a supported kvm invocation
1704
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1705

1706
    """
1707
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
1708

    
1709
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
1710

    
1711
    result = utils.RunCmd([kvm_path] + optlist)
1712
    if result.failed and not can_fail:
1713
      raise errors.HypervisorError("Unable to get KVM %s output" %
1714
                                    " ".join(cls._KVMOPTS_CMDS[option]))
1715
    return result.output
1716

    
1717
  @classmethod
1718
  def _GetKVMVersion(cls, kvm_path):
1719
    """Return the installed KVM version.
1720

1721
    @return: (version, v_maj, v_min, v_rev)
1722
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1723

1724
    """
1725
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
1726

    
1727
  @classmethod
1728
  def _GetDefaultMachineVersion(cls, kvm_path):
1729
    """Return the default hardware revision (e.g. pc-1.1)
1730

1731
    """
1732
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
1733
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
1734
    if match:
1735
      return match.group(1)
1736
    else:
1737
      return "pc"
1738

    
1739
  def StopInstance(self, instance, force=False, retry=False, name=None):
1740
    """Stop an instance.
1741

1742
    """
1743
    if name is not None and not force:
1744
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1745
    if name is None:
1746
      name = instance.name
1747
      acpi = instance.hvparams[constants.HV_ACPI]
1748
    else:
1749
      acpi = False
1750
    _, pid, alive = self._InstancePidAlive(name)
1751
    if pid > 0 and alive:
1752
      if force or not acpi:
1753
        utils.KillProcess(pid)
1754
      else:
1755
        self._CallMonitorCommand(name, "system_powerdown")
1756

    
1757
  def CleanupInstance(self, instance_name):
1758
    """Cleanup after a stopped instance
1759

1760
    """
1761
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
1762
    if pid > 0 and alive:
1763
      raise errors.HypervisorError("Cannot cleanup a live instance")
1764
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1765

    
1766
  def RebootInstance(self, instance):
1767
    """Reboot an instance.
1768

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

    
1789
  def MigrationInfo(self, instance):
1790
    """Get instance information to perform a migration.
1791

1792
    @type instance: L{objects.Instance}
1793
    @param instance: instance to be migrated
1794
    @rtype: string
1795
    @return: content of the KVM runtime file
1796

1797
    """
1798
    return self._ReadKVMRuntime(instance.name)
1799

    
1800
  def AcceptInstance(self, instance, info, target):
1801
    """Prepare to accept an instance.
1802

1803
    @type instance: L{objects.Instance}
1804
    @param instance: instance to be accepted
1805
    @type info: string
1806
    @param info: content of the KVM runtime file on the source node
1807
    @type target: string
1808
    @param target: target host (usually ip), on this node
1809

1810
    """
1811
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1812
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1813
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1814
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1815
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
1816
                            incoming=incoming_address)
1817

    
1818
  def FinalizeMigrationDst(self, instance, info, success):
1819
    """Finalize the instance migration on the target node.
1820

1821
    Stop the incoming mode KVM.
1822

1823
    @type instance: L{objects.Instance}
1824
    @param instance: instance whose migration is being finalized
1825

1826
    """
1827
    if success:
1828
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1829
      kvm_nics = kvm_runtime[1]
1830

    
1831
      for nic_seq, nic in enumerate(kvm_nics):
1832
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1833
          # Bridged interfaces have already been configured
1834
          continue
1835
        try:
1836
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1837
        except EnvironmentError, err:
1838
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
1839
                          instance.name, nic_seq, str(err))
1840
          continue
1841
        try:
1842
          self._ConfigureNIC(instance, nic_seq, nic, tap)
1843
        except errors.HypervisorError, err:
1844
          logging.warning(str(err))
1845

    
1846
      self._WriteKVMRuntime(instance.name, info)
1847
    else:
1848
      self.StopInstance(instance, force=True)
1849

    
1850
  def MigrateInstance(self, instance, target, live):
1851
    """Migrate an instance to a target node.
1852

1853
    The migration will not be attempted if the instance is not
1854
    currently running.
1855

1856
    @type instance: L{objects.Instance}
1857
    @param instance: the instance to be migrated
1858
    @type target: string
1859
    @param target: ip address of the target node
1860
    @type live: boolean
1861
    @param live: perform a live migration
1862

1863
    """
1864
    instance_name = instance.name
1865
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
1866
    _, _, alive = self._InstancePidAlive(instance_name)
1867
    if not alive:
1868
      raise errors.HypervisorError("Instance not running, cannot migrate")
1869

    
1870
    if not live:
1871
      self._CallMonitorCommand(instance_name, "stop")
1872

    
1873
    migrate_command = ("migrate_set_speed %dm" %
1874
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1875
    self._CallMonitorCommand(instance_name, migrate_command)
1876

    
1877
    migrate_command = ("migrate_set_downtime %dms" %
1878
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1879
    self._CallMonitorCommand(instance_name, migrate_command)
1880

    
1881
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1882
    self._CallMonitorCommand(instance_name, migrate_command)
1883

    
1884
  def FinalizeMigrationSource(self, instance, success, live):
1885
    """Finalize the instance migration on the source node.
1886

1887
    @type instance: L{objects.Instance}
1888
    @param instance: the instance that was migrated
1889
    @type success: bool
1890
    @param success: whether the migration succeeded or not
1891
    @type live: bool
1892
    @param live: whether the user requested a live migration or not
1893

1894
    """
1895
    if success:
1896
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
1897
      utils.KillProcess(pid)
1898
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1899
    elif live:
1900
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1901

    
1902
  def GetMigrationStatus(self, instance):
1903
    """Get the migration status
1904

1905
    @type instance: L{objects.Instance}
1906
    @param instance: the instance that is being migrated
1907
    @rtype: L{objects.MigrationStatus}
1908
    @return: the status of the current migration (one of
1909
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1910
             progress info that can be retrieved from the hypervisor
1911

1912
    """
1913
    info_command = "info migrate"
1914
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
1915
      result = self._CallMonitorCommand(instance.name, info_command)
1916
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
1917
      if not match:
1918
        if not result.stdout:
1919
          logging.info("KVM: empty 'info migrate' result")
1920
        else:
1921
          logging.warning("KVM: unknown 'info migrate' result: %s",
1922
                          result.stdout)
1923
      else:
1924
        status = match.group(1)
1925
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
1926
          migration_status = objects.MigrationStatus(status=status)
1927
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
1928
          if match:
1929
            migration_status.transferred_ram = match.group("transferred")
1930
            migration_status.total_ram = match.group("total")
1931

    
1932
          return migration_status
1933

    
1934
        logging.warning("KVM: unknown migration status '%s'", status)
1935

    
1936
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1937

    
1938
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
1939

    
1940
  def BalloonInstanceMemory(self, instance, mem):
1941
    """Balloon an instance memory to a certain value.
1942

1943
    @type instance: L{objects.Instance}
1944
    @param instance: instance to be accepted
1945
    @type mem: int
1946
    @param mem: actual memory size to use for instance runtime
1947

1948
    """
1949
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
1950

    
1951
  def GetNodeInfo(self):
1952
    """Return information about the node.
1953

1954
    @return: a dict with the following keys (values in MiB):
1955
          - memory_total: the total memory size on the node
1956
          - memory_free: the available memory on the node for instances
1957
          - memory_dom0: the memory used by the node itself, if available
1958
          - hv_version: the hypervisor version in the form (major, minor,
1959
                        revision)
1960

1961
    """
1962
    result = self.GetLinuxNodeInfo()
1963
    # FIXME: this is the global kvm version, but the actual version can be
1964
    # customized as an hv parameter. we should use the nodegroup's default kvm
1965
    # path parameter here.
1966
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
1967
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
1968
    return result
1969

    
1970
  @classmethod
1971
  def GetInstanceConsole(cls, instance, hvparams, beparams):
1972
    """Return a command for connecting to the console of an instance.
1973

1974
    """
1975
    if hvparams[constants.HV_SERIAL_CONSOLE]:
1976
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
1977
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1978
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1979
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
1980
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1981
      return objects.InstanceConsole(instance=instance.name,
1982
                                     kind=constants.CONS_SSH,
1983
                                     host=instance.primary_node,
1984
                                     user=constants.SSH_CONSOLE_USER,
1985
                                     command=cmd)
1986

    
1987
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1988
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1989
      display = instance.network_port - constants.VNC_BASE_PORT
1990
      return objects.InstanceConsole(instance=instance.name,
1991
                                     kind=constants.CONS_VNC,
1992
                                     host=vnc_bind_address,
1993
                                     port=instance.network_port,
1994
                                     display=display)
1995

    
1996
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1997
    if spice_bind:
1998
      return objects.InstanceConsole(instance=instance.name,
1999
                                     kind=constants.CONS_SPICE,
2000
                                     host=spice_bind,
2001
                                     port=instance.network_port)
2002

    
2003
    return objects.InstanceConsole(instance=instance.name,
2004
                                   kind=constants.CONS_MESSAGE,
2005
                                   message=("No serial shell for instance %s" %
2006
                                            instance.name))
2007

    
2008
  def Verify(self):
2009
    """Verify the hypervisor.
2010

2011
    Check that the required binaries exist.
2012

2013
    @return: Problem description if something is wrong, C{None} otherwise
2014

2015
    """
2016
    msgs = []
2017
    # FIXME: this is the global kvm binary, but the actual path can be
2018
    # customized as an hv parameter; we should use the nodegroup's
2019
    # default kvm path parameter here.
2020
    if not os.path.exists(constants.KVM_PATH):
2021
      msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2022
    if not os.path.exists(constants.SOCAT_PATH):
2023
      msgs.append("The socat binary ('%s') does not exist" %
2024
                  constants.SOCAT_PATH)
2025

    
2026
    return self._FormatVerifyResults(msgs)
2027

    
2028
  @classmethod
2029
  def CheckParameterSyntax(cls, hvparams):
2030
    """Check the given parameters for validity.
2031

2032
    @type hvparams:  dict
2033
    @param hvparams: dictionary with parameter names/value
2034
    @raise errors.HypervisorError: when a parameter is not valid
2035

2036
    """
2037
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2038

    
2039
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2040
    if kernel_path:
2041
      if not hvparams[constants.HV_ROOT_PATH]:
2042
        raise errors.HypervisorError("Need a root partition for the instance,"
2043
                                     " if a kernel is defined")
2044

    
2045
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2046
        not hvparams[constants.HV_VNC_X509]):
2047
      raise errors.HypervisorError("%s must be defined, if %s is" %
2048
                                   (constants.HV_VNC_X509,
2049
                                    constants.HV_VNC_X509_VERIFY))
2050

    
2051
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2052
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2053
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2054
      if not serial_speed or serial_speed not in valid_speeds:
2055
        raise errors.HypervisorError("Invalid serial console speed, must be"
2056
                                     " one of: %s" %
2057
                                     utils.CommaJoin(valid_speeds))
2058

    
2059
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2060
    if (boot_order == constants.HT_BO_CDROM and
2061
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2062
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2063
                                   " ISO path")
2064

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

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

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

    
2101
  @classmethod
2102
  def ValidateParameters(cls, hvparams):
2103
    """Check the given parameters for validity.
2104

2105
    @type hvparams:  dict
2106
    @param hvparams: dictionary with parameter names/value
2107
    @raise errors.HypervisorError: when a parameter is not valid
2108

2109
    """
2110
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2111

    
2112
    kvm_path = hvparams[constants.HV_KVM_PATH]
2113

    
2114
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2115
    if security_model == constants.HT_SM_USER:
2116
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2117
      try:
2118
        pwd.getpwnam(username)
2119
      except KeyError:
2120
        raise errors.HypervisorError("Unknown security domain user %s"
2121
                                     % username)
2122

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

    
2131
      # check that KVM supports SPICE
2132
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2133
      if not cls._SPICE_RE.search(kvmhelp):
2134
        raise errors.HypervisorError("spice is configured, but it is not"
2135
                                     " supported according to kvm --help")
2136

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

    
2145
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2146
    if machine_version:
2147
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2148
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2149
        raise errors.HypervisorError("Unsupported machine version: %s" %
2150
                                     machine_version)
2151

    
2152
  @classmethod
2153
  def PowercycleNode(cls):
2154
    """KVM powercycle, just a wrapper over Linux powercycle.
2155

2156
    """
2157
    cls.LinuxPowercycle()