Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 7e8f03e3

History | View | Annotate | Download (78.3 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
  _NEW_VIRTIO_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
552
  # match  -drive.*boot=on|off on different lines, but in between accept only
553
  # dashes not preceeded by a new line (which would mean another option
554
  # different than -drive is starting)
555
  _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
556

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
641
    return (instance, memory, vcpus)
642

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

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

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

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

    
662
    return (pidfile, pid, alive)
663

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
927
    return result
928

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1062
    self.ValidateParameters(hvp)
1063

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1267
        spice_address = addresses[spice_ip_version][0]
1268

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

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

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

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

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

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

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

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

    
1326
    else:
1327
      kvm_cmd.extend(["-nographic"])
1328

    
1329
    if hvp[constants.HV_USE_LOCALTIME]:
1330
      kvm_cmd.extend(["-localtime"])
1331

    
1332
    if hvp[constants.HV_KVM_USE_CHROOT]:
1333
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1334

    
1335
    # Add qemu-KVM -cpu param
1336
    if hvp[constants.HV_CPU_TYPE]:
1337
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1338

    
1339
    # As requested by music lovers
1340
    if hvp[constants.HV_SOUNDHW]:
1341
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1342

    
1343
    # Pass a -vga option if requested, or if spice is used, for backwards
1344
    # compatibility.
1345
    if hvp[constants.HV_VGA]:
1346
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1347
    elif spice_bind:
1348
      kvm_cmd.extend(["-vga", "qxl"])
1349

    
1350
    # Various types of usb devices, comma separated
1351
    if hvp[constants.HV_USB_DEVICES]:
1352
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1353
        kvm_cmd.extend(["-usbdevice", dev])
1354

    
1355
    if hvp[constants.HV_KVM_EXTRA]:
1356
      kvm_cmd.extend([hvp[constants.HV_KVM_EXTRA]])
1357

    
1358
    # Save the current instance nics, but defer their expansion as parameters,
1359
    # as we'll need to generate executable temp files for them.
1360
    kvm_nics = instance.nics
1361
    hvparams = hvp
1362

    
1363
    return (kvm_cmd, kvm_nics, hvparams)
1364

    
1365
  def _WriteKVMRuntime(self, instance_name, data):
1366
    """Write an instance's KVM runtime
1367

1368
    """
1369
    try:
1370
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1371
                      data=data)
1372
    except EnvironmentError, err:
1373
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1374

    
1375
  def _ReadKVMRuntime(self, instance_name):
1376
    """Read an instance's KVM runtime
1377

1378
    """
1379
    try:
1380
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1381
    except EnvironmentError, err:
1382
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1383
    return file_content
1384

    
1385
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1386
    """Save an instance's KVM runtime
1387

1388
    """
1389
    kvm_cmd, kvm_nics, hvparams = kvm_runtime
1390
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1391
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1392
    self._WriteKVMRuntime(instance.name, serialized_form)
1393

    
1394
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1395
    """Load an instance's KVM runtime
1396

1397
    """
1398
    if not serialized_runtime:
1399
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1400
    loaded_runtime = serializer.Load(serialized_runtime)
1401
    kvm_cmd, serialized_nics, hvparams = loaded_runtime
1402
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1403
    return (kvm_cmd, kvm_nics, hvparams)
1404

    
1405
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1406
    """Run the KVM cmd and check for errors
1407

1408
    @type name: string
1409
    @param name: instance name
1410
    @type kvm_cmd: list of strings
1411
    @param kvm_cmd: runcmd input for kvm
1412
    @type tap_fds: list of int
1413
    @param tap_fds: fds of tap devices opened by Ganeti
1414

1415
    """
1416
    try:
1417
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1418
    finally:
1419
      for fd in tap_fds:
1420
        utils_wrapper.CloseFdNoError(fd)
1421

    
1422
    if result.failed:
1423
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1424
                                   (name, result.fail_reason, result.output))
1425
    if not self._InstancePidAlive(name)[2]:
1426
      raise errors.HypervisorError("Failed to start instance %s" % name)
1427

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

1431
    @type incoming: tuple of strings
1432
    @param incoming: (target_host_ip, port)
1433
    @type kvmhelp: string
1434
    @param kvmhelp: output of kvm --help
1435

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

    
1449
    temp_files = []
1450

    
1451
    kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1452
    # the first element of kvm_cmd is always the path to the kvm binary
1453
    kvm_path = kvm_cmd[0]
1454
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1455

    
1456
    # We know it's safe to run as a different user upon migration, so we'll use
1457
    # the latest conf, from conf_hvp.
1458
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1459
    if security_model == constants.HT_SM_USER:
1460
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1461

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

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

    
1495
        if up_hvp[constants.HV_VHOST_NET]:
1496
          # check for vhost_net support
1497
          if self._VHOST_RE.search(kvmhelp):
1498
            tap_extra = ",vhost=on"
1499
          else:
1500
            raise errors.HypervisorError("vhost_net is configured"
1501
                                         " but it is not available")
1502
      else:
1503
        nic_model = nic_type
1504

    
1505
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1506

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

    
1521
    if incoming:
1522
      target, port = incoming
1523
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1524

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

    
1537
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1538
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1539
                         constants.SECURE_DIR_MODE)])
1540

    
1541
    # Automatically enable QMP if version is >= 0.14
1542
    if self._QMP_RE.search(kvmhelp):
1543
      logging.debug("Enabling QMP")
1544
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1545
                      self._InstanceQmpMonitor(instance.name)])
1546

    
1547
    # Configure the network now for starting instances and bridged interfaces,
1548
    # during FinalizeMigration for incoming instances' routed interfaces
1549
    for nic_seq, nic in enumerate(kvm_nics):
1550
      if (incoming and
1551
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1552
        continue
1553
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1554

    
1555
    # CPU affinity requires kvm to start paused, so we set this flag if the
1556
    # instance is not already paused and if we are not going to accept a
1557
    # migrating instance. In the latter case, pausing is not needed.
1558
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1559
    if start_kvm_paused:
1560
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1561

    
1562
    # Note: CPU pinning is using up_hvp since changes take effect
1563
    # during instance startup anyway, and to avoid problems when soft
1564
    # rebooting the instance.
1565
    cpu_pinning = False
1566
    if up_hvp.get(constants.HV_CPU_MASK, None):
1567
      cpu_pinning = True
1568

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

    
1587
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1588
                     constants.RUN_DIRS_MODE)])
1589
    for nic_seq, tap in enumerate(taps):
1590
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1591
                      data=tap)
1592

    
1593
    if vnc_pwd:
1594
      change_cmd = "change vnc password %s" % vnc_pwd
1595
      self._CallMonitorCommand(instance.name, change_cmd)
1596

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

    
1611
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1612
      qmp.connect()
1613
      arguments = {
1614
          "protocol": "spice",
1615
          "password": spice_pwd,
1616
      }
1617
      qmp.Execute("set_password", arguments)
1618

    
1619
    for filename in temp_files:
1620
      utils.RemoveFile(filename)
1621

    
1622
    # If requested, set CPU affinity and resume instance execution
1623
    if cpu_pinning:
1624
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1625

    
1626
    start_memory = self._InstanceStartupMemory(instance)
1627
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1628
      self.BalloonInstanceMemory(instance, start_memory)
1629

    
1630
    if start_kvm_paused:
1631
      # To control CPU pinning, ballooning, and vnc/spice passwords
1632
      # the VM was started in a frozen state. If freezing was not
1633
      # explicitly requested resume the vm status.
1634
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1635

    
1636
  def StartInstance(self, instance, block_devices, startup_paused):
1637
    """Start an instance.
1638

1639
    """
1640
    self._CheckDown(instance.name)
1641
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1642
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1643
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1644
                                           startup_paused, kvmhelp)
1645
    self._SaveKVMRuntime(instance, kvm_runtime)
1646
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1647

    
1648
  def _CallMonitorCommand(self, instance_name, command):
1649
    """Invoke a command on the instance monitor.
1650

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

    
1664
    return result
1665

    
1666
  @classmethod
1667
  def _ParseKVMVersion(cls, text):
1668
    """Parse the KVM version from the --help output.
1669

1670
    @type text: string
1671
    @param text: output of kvm --help
1672
    @return: (version, v_maj, v_min, v_rev)
1673
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1674

1675
    """
1676
    match = cls._VERSION_RE.search(text.splitlines()[0])
1677
    if not match:
1678
      raise errors.HypervisorError("Unable to get KVM version")
1679

    
1680
    v_all = match.group(0)
1681
    v_maj = int(match.group(1))
1682
    v_min = int(match.group(2))
1683
    if match.group(4):
1684
      v_rev = int(match.group(4))
1685
    else:
1686
      v_rev = 0
1687
    return (v_all, v_maj, v_min, v_rev)
1688

    
1689
  @classmethod
1690
  def _GetKVMOutput(cls, kvm_path, option):
1691
    """Return the output of a kvm invocation
1692

1693
    @type kvm_path: string
1694
    @param kvm_path: path to the kvm executable
1695
    @type option: a key of _KVMOPTS_CMDS
1696
    @param option: kvm option to fetch the output from
1697
    @return: output a supported kvm invocation
1698
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1699

1700
    """
1701
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
1702

    
1703
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
1704

    
1705
    result = utils.RunCmd([kvm_path] + optlist)
1706
    if result.failed and not can_fail:
1707
      raise errors.HypervisorError("Unable to get KVM %s output" %
1708
                                    " ".join(cls._KVMOPTS_CMDS[option]))
1709
    return result.output
1710

    
1711
  @classmethod
1712
  def _GetKVMVersion(cls, kvm_path):
1713
    """Return the installed KVM version.
1714

1715
    @return: (version, v_maj, v_min, v_rev)
1716
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1717

1718
    """
1719
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
1720

    
1721
  @classmethod
1722
  def _GetDefaultMachineVersion(cls, kvm_path):
1723
    """Return the default hardware revision (e.g. pc-1.1)
1724

1725
    """
1726
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
1727
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
1728
    if match:
1729
      return match.group(1)
1730
    else:
1731
      return "pc"
1732

    
1733
  def StopInstance(self, instance, force=False, retry=False, name=None):
1734
    """Stop an instance.
1735

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

    
1751
  def CleanupInstance(self, instance_name):
1752
    """Cleanup after a stopped instance
1753

1754
    """
1755
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
1756
    if pid > 0 and alive:
1757
      raise errors.HypervisorError("Cannot cleanup a live instance")
1758
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1759

    
1760
  def RebootInstance(self, instance):
1761
    """Reboot an instance.
1762

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

    
1783
  def MigrationInfo(self, instance):
1784
    """Get instance information to perform a migration.
1785

1786
    @type instance: L{objects.Instance}
1787
    @param instance: instance to be migrated
1788
    @rtype: string
1789
    @return: content of the KVM runtime file
1790

1791
    """
1792
    return self._ReadKVMRuntime(instance.name)
1793

    
1794
  def AcceptInstance(self, instance, info, target):
1795
    """Prepare to accept an instance.
1796

1797
    @type instance: L{objects.Instance}
1798
    @param instance: instance to be accepted
1799
    @type info: string
1800
    @param info: content of the KVM runtime file on the source node
1801
    @type target: string
1802
    @param target: target host (usually ip), on this node
1803

1804
    """
1805
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1806
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1807
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1808
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1809
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
1810
                            incoming=incoming_address)
1811

    
1812
  def FinalizeMigrationDst(self, instance, info, success):
1813
    """Finalize the instance migration on the target node.
1814

1815
    Stop the incoming mode KVM.
1816

1817
    @type instance: L{objects.Instance}
1818
    @param instance: instance whose migration is being finalized
1819

1820
    """
1821
    if success:
1822
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1823
      kvm_nics = kvm_runtime[1]
1824

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

    
1840
      self._WriteKVMRuntime(instance.name, info)
1841
    else:
1842
      self.StopInstance(instance, force=True)
1843

    
1844
  def MigrateInstance(self, instance, target, live):
1845
    """Migrate an instance to a target node.
1846

1847
    The migration will not be attempted if the instance is not
1848
    currently running.
1849

1850
    @type instance: L{objects.Instance}
1851
    @param instance: the instance to be migrated
1852
    @type target: string
1853
    @param target: ip address of the target node
1854
    @type live: boolean
1855
    @param live: perform a live migration
1856

1857
    """
1858
    instance_name = instance.name
1859
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
1860
    _, _, alive = self._InstancePidAlive(instance_name)
1861
    if not alive:
1862
      raise errors.HypervisorError("Instance not running, cannot migrate")
1863

    
1864
    if not live:
1865
      self._CallMonitorCommand(instance_name, "stop")
1866

    
1867
    migrate_command = ("migrate_set_speed %dm" %
1868
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1869
    self._CallMonitorCommand(instance_name, migrate_command)
1870

    
1871
    migrate_command = ("migrate_set_downtime %dms" %
1872
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1873
    self._CallMonitorCommand(instance_name, migrate_command)
1874

    
1875
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1876
    self._CallMonitorCommand(instance_name, migrate_command)
1877

    
1878
  def FinalizeMigrationSource(self, instance, success, live):
1879
    """Finalize the instance migration on the source node.
1880

1881
    @type instance: L{objects.Instance}
1882
    @param instance: the instance that was migrated
1883
    @type success: bool
1884
    @param success: whether the migration succeeded or not
1885
    @type live: bool
1886
    @param live: whether the user requested a live migration or not
1887

1888
    """
1889
    if success:
1890
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
1891
      utils.KillProcess(pid)
1892
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1893
    elif live:
1894
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1895

    
1896
  def GetMigrationStatus(self, instance):
1897
    """Get the migration status
1898

1899
    @type instance: L{objects.Instance}
1900
    @param instance: the instance that is being migrated
1901
    @rtype: L{objects.MigrationStatus}
1902
    @return: the status of the current migration (one of
1903
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1904
             progress info that can be retrieved from the hypervisor
1905

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

    
1926
          return migration_status
1927

    
1928
        logging.warning("KVM: unknown migration status '%s'", status)
1929

    
1930
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1931

    
1932
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
1933

    
1934
  def BalloonInstanceMemory(self, instance, mem):
1935
    """Balloon an instance memory to a certain value.
1936

1937
    @type instance: L{objects.Instance}
1938
    @param instance: instance to be accepted
1939
    @type mem: int
1940
    @param mem: actual memory size to use for instance runtime
1941

1942
    """
1943
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
1944

    
1945
  def GetNodeInfo(self):
1946
    """Return information about the node.
1947

1948
    @return: a dict with the following keys (values in MiB):
1949
          - memory_total: the total memory size on the node
1950
          - memory_free: the available memory on the node for instances
1951
          - memory_dom0: the memory used by the node itself, if available
1952
          - hv_version: the hypervisor version in the form (major, minor,
1953
                        revision)
1954

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

    
1964
  @classmethod
1965
  def GetInstanceConsole(cls, instance, hvparams, beparams):
1966
    """Return a command for connecting to the console of an instance.
1967

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

    
1981
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1982
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1983
      display = instance.network_port - constants.VNC_BASE_PORT
1984
      return objects.InstanceConsole(instance=instance.name,
1985
                                     kind=constants.CONS_VNC,
1986
                                     host=vnc_bind_address,
1987
                                     port=instance.network_port,
1988
                                     display=display)
1989

    
1990
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1991
    if spice_bind:
1992
      return objects.InstanceConsole(instance=instance.name,
1993
                                     kind=constants.CONS_SPICE,
1994
                                     host=spice_bind,
1995
                                     port=instance.network_port)
1996

    
1997
    return objects.InstanceConsole(instance=instance.name,
1998
                                   kind=constants.CONS_MESSAGE,
1999
                                   message=("No serial shell for instance %s" %
2000
                                            instance.name))
2001

    
2002
  def Verify(self):
2003
    """Verify the hypervisor.
2004

2005
    Check that the required binaries exist.
2006

2007
    @return: Problem description if something is wrong, C{None} otherwise
2008

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

    
2020
    return self._FormatVerifyResults(msgs)
2021

    
2022
  @classmethod
2023
  def CheckParameterSyntax(cls, hvparams):
2024
    """Check the given parameters for validity.
2025

2026
    @type hvparams:  dict
2027
    @param hvparams: dictionary with parameter names/value
2028
    @raise errors.HypervisorError: when a parameter is not valid
2029

2030
    """
2031
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2032

    
2033
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2034
    if kernel_path:
2035
      if not hvparams[constants.HV_ROOT_PATH]:
2036
        raise errors.HypervisorError("Need a root partition for the instance,"
2037
                                     " if a kernel is defined")
2038

    
2039
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2040
        not hvparams[constants.HV_VNC_X509]):
2041
      raise errors.HypervisorError("%s must be defined, if %s is" %
2042
                                   (constants.HV_VNC_X509,
2043
                                    constants.HV_VNC_X509_VERIFY))
2044

    
2045
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2046
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2047
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2048
      if not serial_speed or serial_speed not in valid_speeds:
2049
        raise errors.HypervisorError("Invalid serial console speed, must be"
2050
                                     " one of: %s" %
2051
                                     utils.CommaJoin(valid_speeds))
2052

    
2053
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2054
    if (boot_order == constants.HT_BO_CDROM and
2055
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2056
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2057
                                   " ISO path")
2058

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

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

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

    
2095
  @classmethod
2096
  def ValidateParameters(cls, hvparams):
2097
    """Check the given parameters for validity.
2098

2099
    @type hvparams:  dict
2100
    @param hvparams: dictionary with parameter names/value
2101
    @raise errors.HypervisorError: when a parameter is not valid
2102

2103
    """
2104
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2105

    
2106
    kvm_path = hvparams[constants.HV_KVM_PATH]
2107

    
2108
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2109
    if security_model == constants.HT_SM_USER:
2110
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2111
      try:
2112
        pwd.getpwnam(username)
2113
      except KeyError:
2114
        raise errors.HypervisorError("Unknown security domain user %s"
2115
                                     % username)
2116

    
2117
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2118
    if spice_bind:
2119
      # only one of VNC and SPICE can be used currently.
2120
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2121
        raise errors.HypervisorError("both SPICE and VNC are configured, but"
2122
                                     " only one of them can be used at a"
2123
                                     " given time.")
2124

    
2125
      # check that KVM supports SPICE
2126
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2127
      if not cls._SPICE_RE.search(kvmhelp):
2128
        raise errors.HypervisorError("spice is configured, but it is not"
2129
                                     " supported according to kvm --help")
2130

    
2131
      # if spice_bind is not an IP address, it must be a valid interface
2132
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind)
2133
                       or netutils.IP6Address.IsValid(spice_bind))
2134
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2135
        raise errors.HypervisorError("spice: the %s parameter must be either"
2136
                                     " a valid IP address or interface name" %
2137
                                     constants.HV_KVM_SPICE_BIND)
2138

    
2139
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2140
    if machine_version:
2141
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2142
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2143
        raise errors.HypervisorError("Unsupported machine version: %s" %
2144
                                     machine_version)
2145

    
2146
  @classmethod
2147
  def PowercycleNode(cls):
2148
    """KVM powercycle, just a wrapper over Linux powercycle.
2149

2150
    """
2151
    cls.LinuxPowercycle()