Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 065d194b

History | View | Annotate | Download (97.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
from bitarray import bitarray
41
try:
42
  import affinity   # pylint: disable=F0401
43
except ImportError:
44
  affinity = None
45
try:
46
  import fdsend   # pylint: disable=F0401
47
except ImportError:
48
  fdsend = None
49

    
50
from ganeti import utils
51
from ganeti import constants
52
from ganeti import errors
53
from ganeti import serializer
54
from ganeti import objects
55
from ganeti import uidpool
56
from ganeti import ssconf
57
from ganeti import netutils
58
from ganeti import pathutils
59
from ganeti.hypervisor import hv_base
60
from ganeti.utils import wrapper as utils_wrapper
61

    
62

    
63
_KVM_NETWORK_SCRIPT = pathutils.CONF_DIR + "/kvm-vif-bridge"
64
_KVM_START_PAUSED_FLAG = "-S"
65

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

    
76
#: SPICE parameters which depend on L{constants.HV_KVM_SPICE_BIND}
77
_SPICE_ADDITIONAL_PARAMS = frozenset([
78
  constants.HV_KVM_SPICE_IP_VERSION,
79
  constants.HV_KVM_SPICE_PASSWORD_FILE,
80
  constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR,
81
  constants.HV_KVM_SPICE_JPEG_IMG_COMPR,
82
  constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR,
83
  constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION,
84
  constants.HV_KVM_SPICE_USE_TLS,
85
  ])
86

    
87
# Constant bitarray that reflects to a free pci slot
88
# Use it with bitarray.search()
89
_AVAILABLE_PCI_SLOT = bitarray("0")
90

    
91
# below constants show the format of runtime file
92
# the nics are in second possition, while the disks in 4th (last)
93
# moreover disk entries are stored as a list of in tuples
94
# (L{objects.Disk}, link_name)
95
_KVM_NICS_RUNTIME_INDEX = 1
96
_KVM_DISKS_RUNTIME_INDEX = 3
97
_DEVICE_RUNTIME_INDEX = {
98
  constants.HOTPLUG_TARGET_DISK: _KVM_DISKS_RUNTIME_INDEX,
99
  constants.HOTPLUG_TARGET_NIC: _KVM_NICS_RUNTIME_INDEX
100
  }
101
_FIND_RUNTIME_ENTRY = {
102
  constants.HOTPLUG_TARGET_NIC:
103
    lambda nic, kvm_nics: [n for n in kvm_nics if n.uuid == nic.uuid],
104
  constants.HOTPLUG_TARGET_DISK:
105
    lambda disk, kvm_disks: [(d, l) for (d, l) in kvm_disks
106
                             if d.uuid == disk.uuid]
107
  }
108
_RUNTIME_DEVICE = {
109
  constants.HOTPLUG_TARGET_NIC: lambda d: d,
110
  constants.HOTPLUG_TARGET_DISK: lambda (d, e): d
111
  }
112
_RUNTIME_ENTRY = {
113
  constants.HOTPLUG_TARGET_NIC: lambda d, e: d,
114
  constants.HOTPLUG_TARGET_DISK: lambda d, e: (d, e)
115
  }
116

    
117

    
118
def _GenerateDeviceKVMId(dev_type, dev, idx=None):
119
  """Helper function to generate a unique device name used by KVM
120

121
  QEMU monitor commands use names to identify devices. Here we use their pci
122
  slot and a part of their UUID to name them. dev.pci might be None for old
123
  devices in the cluster.
124

125
  @type dev_type: sting
126
  @param dev_type: device type of param dev
127
  @type dev: L{objects.Disk} or L{objects.NIC}
128
  @param dev: the device object for which we generate a kvm name
129
  @raise errors.HotplugError: in case a device has no pci slot (old devices)
130

131
  """
132

    
133
  # proper device id - available in latest Ganeti versions
134
  if dev.pci and dev.uuid:
135
    return "%s-%s-pci-%d" % (dev_type.lower(), dev.uuid.split("-")[0], dev.pci)
136

    
137
  # dummy device id - returned only to _GenerateKVMBlockDevicesOptions
138
  # This enables -device option for paravirtual disk_type
139
  if idx is not None:
140
    return "%s-%d" % (dev_type.lower(), idx)
141

    
142
  raise errors.HotplugError("Hotplug is not supported for devices"
143
                            " without UUID or PCI info")
144

    
145

    
146
def _UpdatePCISlots(dev, pci_reservations):
147
  """Update pci configuration for a stopped instance
148

149
  If dev has a pci slot then reserve it, else find first available
150
  in pci_reservations bitarray. It acts on the same objects passed
151
  as params so there is no need to return anything.
152

153
  @type dev: L{objects.Disk} or L{objects.NIC}
154
  @param dev: the device object for which we update its pci slot
155
  @type pci_reservations: bitarray
156
  @param pci_reservations: existing pci reservations for an instance
157
  @raise errors.HotplugError: in case an instance has all its slot occupied
158

159
  """
160
  if dev.pci:
161
    free = dev.pci
162
  else: # pylint: disable=E1103
163
    [free] = pci_reservations.search(_AVAILABLE_PCI_SLOT, 1)
164
    if not free:
165
      raise errors.HypervisorError("All PCI slots occupied")
166
    dev.pci = int(free)
167

    
168
  pci_reservations[free] = True
169

    
170

    
171
def _GetExistingDeviceInfo(dev_type, device, runtime):
172
  """Helper function to get an existing device inside the runtime file
173

174
  Used when an instance is running. Load kvm runtime file and search
175
  for a device based on its type and uuid.
176

177
  @type dev_type: sting
178
  @param dev_type: device type of param dev
179
  @type device: L{objects.Disk} or L{objects.NIC}
180
  @param device: the device object for which we generate a kvm name
181
  @type runtime: tuple (cmd, nics, hvparams, disks)
182
  @param runtime: the runtime data to search for the device
183
  @raise errors.HotplugError: in case the requested device does not
184
    exist (e.g. device has been added without --hotplug option) or
185
    device info has not pci slot (e.g. old devices in the cluster)
186

187
  """
188
  index = _DEVICE_RUNTIME_INDEX[dev_type]
189
  found = _FIND_RUNTIME_ENTRY[dev_type](device, runtime[index])
190
  if not found:
191
    raise errors.HotplugError("Cannot find runtime info for %s with UUID %s" %
192
                              (dev_type, device.uuid))
193

    
194
  return found[0]
195

    
196

    
197
def _UpgradeSerializedRuntime(serialized_runtime):
198
  """Upgrade runtime data
199

200
  Remove any deprecated fields or change the format of the data.
201
  The runtime files are not upgraded when Ganeti is upgraded, so the required
202
  modification have to be performed here.
203

204
  @type serialized_runtime: string
205
  @param serialized_runtime: raw text data read from actual runtime file
206
  @return: (cmd, nic dicts, hvparams, bdev dicts)
207
  @rtype: tuple
208

209
  """
210
  loaded_runtime = serializer.Load(serialized_runtime)
211
  kvm_cmd, serialized_nics, hvparams = loaded_runtime[:3]
212
  if len(loaded_runtime) >= 4:
213
    serialized_disks = loaded_runtime[3]
214
  else:
215
    serialized_disks = []
216

    
217
  for nic in serialized_nics:
218
    # Add a dummy uuid slot if an pre-2.8 NIC is found
219
    if "uuid" not in nic:
220
      nic["uuid"] = utils.NewUUID()
221

    
222
  return kvm_cmd, serialized_nics, hvparams, serialized_disks
223

    
224

    
225
def _AnalyzeSerializedRuntime(serialized_runtime):
226
  """Return runtime entries for a serialized runtime file
227

228
  @type serialized_runtime: string
229
  @param serialized_runtime: raw text data read from actual runtime file
230
  @return: (cmd, nics, hvparams, bdevs)
231
  @rtype: tuple
232

233
  """
234
  kvm_cmd, serialized_nics, hvparams, serialized_disks = \
235
    _UpgradeSerializedRuntime(serialized_runtime)
236
  kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
237
  kvm_disks = [(objects.Disk.FromDict(sdisk), link)
238
               for sdisk, link in serialized_disks]
239

    
240
  return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
241

    
242

    
243
def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
244
  """Retrieves supported TUN features from file descriptor.
245

246
  @see: L{_ProbeTapVnetHdr}
247

248
  """
249
  req = struct.pack("I", 0)
250
  try:
251
    buf = _ioctl(fd, TUNGETFEATURES, req)
252
  except EnvironmentError, err:
253
    logging.warning("ioctl(TUNGETFEATURES) failed: %s", err)
254
    return None
255
  else:
256
    (flags, ) = struct.unpack("I", buf)
257
    return flags
258

    
259

    
260
def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
261
  """Check whether to enable the IFF_VNET_HDR flag.
262

263
  To do this, _all_ of the following conditions must be met:
264
   1. TUNGETFEATURES ioctl() *must* be implemented
265
   2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
266
   3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
267
      drivers/net/tun.c there is no way to test this until after the tap device
268
      has been created using TUNSETIFF, and there is no way to change the
269
      IFF_VNET_HDR flag after creating the interface, catch-22! However both
270
      TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
271
      thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
272

273
   @type fd: int
274
   @param fd: the file descriptor of /dev/net/tun
275

276
  """
277
  flags = _features_fn(fd)
278

    
279
  if flags is None:
280
    # Not supported
281
    return False
282

    
283
  result = bool(flags & IFF_VNET_HDR)
284

    
285
  if not result:
286
    logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
287

    
288
  return result
289

    
290

    
291
def _OpenTap(vnet_hdr=True):
292
  """Open a new tap device and return its file descriptor.
293

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

297
  @type vnet_hdr: boolean
298
  @param vnet_hdr: Enable the VNET Header
299
  @return: (ifname, tapfd)
300
  @rtype: tuple
301

302
  """
303
  try:
304
    tapfd = os.open("/dev/net/tun", os.O_RDWR)
305
  except EnvironmentError:
306
    raise errors.HypervisorError("Failed to open /dev/net/tun")
307

    
308
  flags = IFF_TAP | IFF_NO_PI
309

    
310
  if vnet_hdr and _ProbeTapVnetHdr(tapfd):
311
    flags |= IFF_VNET_HDR
312

    
313
  # The struct ifreq ioctl request (see netdevice(7))
314
  ifr = struct.pack("16sh", "", flags)
315

    
316
  try:
317
    res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
318
  except EnvironmentError, err:
319
    raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
320
                                 err)
321

    
322
  # Get the interface name from the ioctl
323
  ifname = struct.unpack("16sh", res)[0].strip("\x00")
324
  return (ifname, tapfd)
325

    
326

    
327
class QmpMessage:
328
  """QEMU Messaging Protocol (QMP) message.
329

330
  """
331
  def __init__(self, data):
332
    """Creates a new QMP message based on the passed data.
333

334
    """
335
    if not isinstance(data, dict):
336
      raise TypeError("QmpMessage must be initialized with a dict")
337

    
338
    self.data = data
339

    
340
  def __getitem__(self, field_name):
341
    """Get the value of the required field if present, or None.
342

343
    Overrides the [] operator to provide access to the message data,
344
    returning None if the required item is not in the message
345
    @return: the value of the field_name field, or None if field_name
346
             is not contained in the message
347

348
    """
349
    return self.data.get(field_name, None)
350

    
351
  def __setitem__(self, field_name, field_value):
352
    """Set the value of the required field_name to field_value.
353

354
    """
355
    self.data[field_name] = field_value
356

    
357
  @staticmethod
358
  def BuildFromJsonString(json_string):
359
    """Build a QmpMessage from a JSON encoded string.
360

361
    @type json_string: str
362
    @param json_string: JSON string representing the message
363
    @rtype: L{QmpMessage}
364
    @return: a L{QmpMessage} built from json_string
365

366
    """
367
    # Parse the string
368
    data = serializer.LoadJson(json_string)
369
    return QmpMessage(data)
370

    
371
  def __str__(self):
372
    # The protocol expects the JSON object to be sent as a single line.
373
    return serializer.DumpJson(self.data)
374

    
375
  def __eq__(self, other):
376
    # When comparing two QmpMessages, we are interested in comparing
377
    # their internal representation of the message data
378
    return self.data == other.data
379

    
380

    
381
class MonitorSocket(object):
382
  _SOCKET_TIMEOUT = 5
383

    
384
  def __init__(self, monitor_filename):
385
    """Instantiates the MonitorSocket object.
386

387
    @type monitor_filename: string
388
    @param monitor_filename: the filename of the UNIX raw socket on which the
389
                             monitor (QMP or simple one) is listening
390

391
    """
392
    self.monitor_filename = monitor_filename
393
    self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
394
    # We want to fail if the server doesn't send a complete message
395
    # in a reasonable amount of time
396
    self.sock.settimeout(self._SOCKET_TIMEOUT)
397
    self._connected = False
398

    
399
  def _check_socket(self):
400
    sock_stat = None
401
    try:
402
      sock_stat = os.stat(self.monitor_filename)
403
    except EnvironmentError, err:
404
      if err.errno == errno.ENOENT:
405
        raise errors.HypervisorError("No monitor socket found")
406
      else:
407
        raise errors.HypervisorError("Error checking monitor socket: %s",
408
                                     utils.ErrnoOrStr(err))
409
    if not stat.S_ISSOCK(sock_stat.st_mode):
410
      raise errors.HypervisorError("Monitor socket is not a socket")
411

    
412
  def _check_connection(self):
413
    """Make sure that the connection is established.
414

415
    """
416
    if not self._connected:
417
      raise errors.ProgrammerError("To use a MonitorSocket you need to first"
418
                                   " invoke connect() on it")
419

    
420
  def connect(self):
421
    """Connects to the monitor.
422

423
    Connects to the UNIX socket
424

425
    @raise errors.HypervisorError: when there are communication errors
426

427
    """
428
    if self._connected:
429
      raise errors.ProgrammerError("Cannot connect twice")
430

    
431
    self._check_socket()
432

    
433
    # Check file existance/stuff
434
    try:
435
      self.sock.connect(self.monitor_filename)
436
    except EnvironmentError:
437
      raise errors.HypervisorError("Can't connect to qmp socket")
438
    self._connected = True
439

    
440
  def close(self):
441
    """Closes the socket
442

443
    It cannot be used after this call.
444

445
    """
446
    self.sock.close()
447

    
448

    
449
class QmpConnection(MonitorSocket):
450
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
451

452
  """
453
  _FIRST_MESSAGE_KEY = "QMP"
454
  _EVENT_KEY = "event"
455
  _ERROR_KEY = "error"
456
  _RETURN_KEY = RETURN_KEY = "return"
457
  _ACTUAL_KEY = ACTUAL_KEY = "actual"
458
  _ERROR_CLASS_KEY = "class"
459
  _ERROR_DESC_KEY = "desc"
460
  _EXECUTE_KEY = "execute"
461
  _ARGUMENTS_KEY = "arguments"
462
  _CAPABILITIES_COMMAND = "qmp_capabilities"
463
  _MESSAGE_END_TOKEN = "\r\n"
464

    
465
  def __init__(self, monitor_filename):
466
    super(QmpConnection, self).__init__(monitor_filename)
467
    self._buf = ""
468

    
469
  def connect(self):
470
    """Connects to the QMP monitor.
471

472
    Connects to the UNIX socket and makes sure that we can actually send and
473
    receive data to the kvm instance via QMP.
474

475
    @raise errors.HypervisorError: when there are communication errors
476
    @raise errors.ProgrammerError: when there are data serialization errors
477

478
    """
479
    super(QmpConnection, self).connect()
480
    # Check if we receive a correct greeting message from the server
481
    # (As per the QEMU Protocol Specification 0.1 - section 2.2)
482
    greeting = self._Recv()
483
    if not greeting[self._FIRST_MESSAGE_KEY]:
484
      self._connected = False
485
      raise errors.HypervisorError("kvm: QMP communication error (wrong"
486
                                   " server greeting")
487

    
488
    # Let's put the monitor in command mode using the qmp_capabilities
489
    # command, or else no command will be executable.
490
    # (As per the QEMU Protocol Specification 0.1 - section 4)
491
    self.Execute(self._CAPABILITIES_COMMAND)
492

    
493
  def _ParseMessage(self, buf):
494
    """Extract and parse a QMP message from the given buffer.
495

496
    Seeks for a QMP message in the given buf. If found, it parses it and
497
    returns it together with the rest of the characters in the buf.
498
    If no message is found, returns None and the whole buffer.
499

500
    @raise errors.ProgrammerError: when there are data serialization errors
501

502
    """
503
    message = None
504
    # Check if we got the message end token (CRLF, as per the QEMU Protocol
505
    # Specification 0.1 - Section 2.1.1)
506
    pos = buf.find(self._MESSAGE_END_TOKEN)
507
    if pos >= 0:
508
      try:
509
        message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
510
      except Exception, err:
511
        raise errors.ProgrammerError("QMP data serialization error: %s" % err)
512
      buf = buf[pos + 1:]
513

    
514
    return (message, buf)
515

    
516
  def _Recv(self):
517
    """Receives a message from QMP and decodes the received JSON object.
518

519
    @rtype: QmpMessage
520
    @return: the received message
521
    @raise errors.HypervisorError: when there are communication errors
522
    @raise errors.ProgrammerError: when there are data serialization errors
523

524
    """
525
    self._check_connection()
526

    
527
    # Check if there is already a message in the buffer
528
    (message, self._buf) = self._ParseMessage(self._buf)
529
    if message:
530
      return message
531

    
532
    recv_buffer = StringIO.StringIO(self._buf)
533
    recv_buffer.seek(len(self._buf))
534
    try:
535
      while True:
536
        data = self.sock.recv(4096)
537
        if not data:
538
          break
539
        recv_buffer.write(data)
540

    
541
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
542
        if message:
543
          return message
544

    
545
    except socket.timeout, err:
546
      raise errors.HypervisorError("Timeout while receiving a QMP message: "
547
                                   "%s" % (err))
548
    except socket.error, err:
549
      raise errors.HypervisorError("Unable to receive data from KVM using the"
550
                                   " QMP protocol: %s" % err)
551

    
552
  def _Send(self, message):
553
    """Encodes and sends a message to KVM using QMP.
554

555
    @type message: QmpMessage
556
    @param message: message to send to KVM
557
    @raise errors.HypervisorError: when there are communication errors
558
    @raise errors.ProgrammerError: when there are data serialization errors
559

560
    """
561
    self._check_connection()
562
    try:
563
      message_str = str(message)
564
    except Exception, err:
565
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
566

    
567
    try:
568
      self.sock.sendall(message_str)
569
    except socket.timeout, err:
570
      raise errors.HypervisorError("Timeout while sending a QMP message: "
571
                                   "%s (%s)" % (err.string, err.errno))
572
    except socket.error, err:
573
      raise errors.HypervisorError("Unable to send data from KVM using the"
574
                                   " QMP protocol: %s" % err)
575

    
576
  def Execute(self, command, arguments=None):
577
    """Executes a QMP command and returns the response of the server.
578

579
    @type command: str
580
    @param command: the command to execute
581
    @type arguments: dict
582
    @param arguments: dictionary of arguments to be passed to the command
583
    @rtype: dict
584
    @return: dictionary representing the received JSON object
585
    @raise errors.HypervisorError: when there are communication errors
586
    @raise errors.ProgrammerError: when there are data serialization errors
587

588
    """
589
    self._check_connection()
590
    message = QmpMessage({self._EXECUTE_KEY: command})
591
    if arguments:
592
      message[self._ARGUMENTS_KEY] = arguments
593
    self._Send(message)
594

    
595
    # Events can occur between the sending of the command and the reception
596
    # of the response, so we need to filter out messages with the event key.
597
    while True:
598
      response = self._Recv()
599
      err = response[self._ERROR_KEY]
600
      if err:
601
        raise errors.HypervisorError("kvm: error executing the %s"
602
                                     " command: %s (%s):" %
603
                                     (command,
604
                                      err[self._ERROR_DESC_KEY],
605
                                      err[self._ERROR_CLASS_KEY]))
606

    
607
      elif not response[self._EVENT_KEY]:
608
        return response
609

    
610

    
611
class KVMHypervisor(hv_base.BaseHypervisor):
612
  """KVM hypervisor interface
613

614
  """
615
  CAN_MIGRATE = True
616

    
617
  _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
618
  _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
619
  _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
620
  _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
621
  _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
622
  _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
623
  _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
624
  # KVM instances with chroot enabled are started in empty chroot directories.
625
  _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
626
  # After an instance is stopped, its chroot directory is removed.
627
  # If the chroot directory is not empty, it can't be removed.
628
  # A non-empty chroot directory indicates a possible security incident.
629
  # To support forensics, the non-empty chroot directory is quarantined in
630
  # a separate directory, called 'chroot-quarantine'.
631
  _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
632
  _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
633
           _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
634

    
635
  PARAMETERS = {
636
    constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
637
    constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
638
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
639
    constants.HV_ROOT_PATH: hv_base.NO_CHECK,
640
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
641
    constants.HV_ACPI: hv_base.NO_CHECK,
642
    constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
643
    constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
644
    constants.HV_VNC_BIND_ADDRESS:
645
      (False, lambda x: (netutils.IP4Address.IsValid(x) or
646
                         utils.IsNormAbsPath(x)),
647
       "The VNC bind address must be either a valid IP address or an absolute"
648
       " pathname", None, None),
649
    constants.HV_VNC_TLS: hv_base.NO_CHECK,
650
    constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
651
    constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
652
    constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
653
    constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
654
    constants.HV_KVM_SPICE_IP_VERSION:
655
      (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
656
                         x in constants.VALID_IP_VERSIONS),
657
       "The SPICE IP version should be 4 or 6",
658
       None, None),
659
    constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
660
    constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
661
      hv_base.ParamInSet(
662
        False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
663
    constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
664
      hv_base.ParamInSet(
665
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
666
    constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
667
      hv_base.ParamInSet(
668
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
669
    constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
670
      hv_base.ParamInSet(
671
        False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
672
    constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
673
    constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
674
    constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
675
    constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
676
    constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
677
    constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
678
    constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
679
    constants.HV_BOOT_ORDER:
680
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
681
    constants.HV_NIC_TYPE:
682
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
683
    constants.HV_DISK_TYPE:
684
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
685
    constants.HV_KVM_CDROM_DISK_TYPE:
686
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
687
    constants.HV_USB_MOUSE:
688
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
689
    constants.HV_KEYMAP: hv_base.NO_CHECK,
690
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
691
    constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
692
    constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
693
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
694
    constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
695
    constants.HV_DISK_CACHE:
696
      hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
697
    constants.HV_SECURITY_MODEL:
698
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
699
    constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
700
    constants.HV_KVM_FLAG:
701
      hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
702
    constants.HV_VHOST_NET: hv_base.NO_CHECK,
703
    constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
704
    constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
705
    constants.HV_REBOOT_BEHAVIOR:
706
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
707
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
708
    constants.HV_CPU_TYPE: hv_base.NO_CHECK,
709
    constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
710
    constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
711
    constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
712
    constants.HV_SOUNDHW: hv_base.NO_CHECK,
713
    constants.HV_USB_DEVICES: hv_base.NO_CHECK,
714
    constants.HV_VGA: hv_base.NO_CHECK,
715
    constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
716
    constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
717
    constants.HV_VNET_HDR: hv_base.NO_CHECK,
718
    }
719

    
720
  _VIRTIO = "virtio"
721
  _VIRTIO_NET_PCI = "virtio-net-pci"
722
  _VIRTIO_BLK_PCI = "virtio-blk-pci"
723

    
724
  _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
725
                                    re.M | re.I)
726
  _MIGRATION_PROGRESS_RE = \
727
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
728
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
729
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
730

    
731
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
732
  _MIGRATION_INFO_RETRY_DELAY = 2
733

    
734
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
735

    
736
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
737
  _CPU_INFO_CMD = "info cpus"
738
  _CONT_CMD = "cont"
739

    
740
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
741
  _CHECK_MACHINE_VERSION_RE = \
742
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
743

    
744
  _QMP_RE = re.compile(r"^-qmp\s", re.M)
745
  _SPICE_RE = re.compile(r"^-spice\s", re.M)
746
  _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
747
  _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
748
  _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
749
  _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
750
  _DISPLAY_RE = re.compile(r"^-display\s", re.M)
751
  _MACHINE_RE = re.compile(r"^-machine\s", re.M)
752
  _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
753
  _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M)
754
  # match  -drive.*boot=on|off on different lines, but in between accept only
755
  # dashes not preceeded by a new line (which would mean another option
756
  # different than -drive is starting)
757
  _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
758

    
759
  _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
760
  _INFO_PCI_CMD = "info pci"
761
  _FIND_PCI_DEVICE_RE = \
762
    staticmethod(lambda pci, devid:
763
      re.compile(r'Bus.*device[ ]*%d,(.*\n){5,6}.*id "%s"' % (pci, devid),
764
                 re.M))
765

    
766
  _INFO_VERSION_RE = \
767
    re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
768
  _INFO_VERSION_CMD = "info version"
769

    
770
  _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
771

    
772
  ANCILLARY_FILES = [
773
    _KVM_NETWORK_SCRIPT,
774
    ]
775
  ANCILLARY_FILES_OPT = [
776
    _KVM_NETWORK_SCRIPT,
777
    ]
778

    
779
  # Supported kvm options to get output from
780
  _KVMOPT_HELP = "help"
781
  _KVMOPT_MLIST = "mlist"
782
  _KVMOPT_DEVICELIST = "devicelist"
783

    
784
  # Command to execute to get the output from kvm, and whether to
785
  # accept the output even on failure.
786
  _KVMOPTS_CMDS = {
787
    _KVMOPT_HELP: (["--help"], False),
788
    _KVMOPT_MLIST: (["-M", "?"], False),
789
    _KVMOPT_DEVICELIST: (["-device", "?"], True),
790
  }
791

    
792
  def __init__(self):
793
    hv_base.BaseHypervisor.__init__(self)
794
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
795
    # in a tmpfs filesystem or has been otherwise wiped out.
796
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
797
    utils.EnsureDirs(dirs)
798

    
799
  @classmethod
800
  def _InstancePidFile(cls, instance_name):
801
    """Returns the instance pidfile.
802

803
    """
804
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
805

    
806
  @classmethod
807
  def _InstanceUidFile(cls, instance_name):
808
    """Returns the instance uidfile.
809

810
    """
811
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
812

    
813
  @classmethod
814
  def _InstancePidInfo(cls, pid):
815
    """Check pid file for instance information.
816

817
    Check that a pid file is associated with an instance, and retrieve
818
    information from its command line.
819

820
    @type pid: string or int
821
    @param pid: process id of the instance to check
822
    @rtype: tuple
823
    @return: (instance_name, memory, vcpus)
824
    @raise errors.HypervisorError: when an instance cannot be found
825

826
    """
827
    alive = utils.IsProcessAlive(pid)
828
    if not alive:
829
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
830

    
831
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
832
    try:
833
      cmdline = utils.ReadFile(cmdline_file)
834
    except EnvironmentError, err:
835
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
836
                                   (pid, err))
837

    
838
    instance = None
839
    memory = 0
840
    vcpus = 0
841

    
842
    arg_list = cmdline.split("\x00")
843
    while arg_list:
844
      arg = arg_list.pop(0)
845
      if arg == "-name":
846
        instance = arg_list.pop(0)
847
      elif arg == "-m":
848
        memory = int(arg_list.pop(0))
849
      elif arg == "-smp":
850
        vcpus = int(arg_list.pop(0).split(",")[0])
851

    
852
    if instance is None:
853
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
854
                                   " instance" % pid)
855

    
856
    return (instance, memory, vcpus)
857

    
858
  def _InstancePidAlive(self, instance_name):
859
    """Returns the instance pidfile, pid, and liveness.
860

861
    @type instance_name: string
862
    @param instance_name: instance name
863
    @rtype: tuple
864
    @return: (pid file name, pid, liveness)
865

866
    """
867
    pidfile = self._InstancePidFile(instance_name)
868
    pid = utils.ReadPidFile(pidfile)
869

    
870
    alive = False
871
    try:
872
      cmd_instance = self._InstancePidInfo(pid)[0]
873
      alive = (cmd_instance == instance_name)
874
    except errors.HypervisorError:
875
      pass
876

    
877
    return (pidfile, pid, alive)
878

    
879
  def _CheckDown(self, instance_name):
880
    """Raises an error unless the given instance is down.
881

882
    """
883
    alive = self._InstancePidAlive(instance_name)[2]
884
    if alive:
885
      raise errors.HypervisorError("Failed to start instance %s: %s" %
886
                                   (instance_name, "already running"))
887

    
888
  @classmethod
889
  def _InstanceMonitor(cls, instance_name):
890
    """Returns the instance monitor socket name
891

892
    """
893
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
894

    
895
  @classmethod
896
  def _InstanceSerial(cls, instance_name):
897
    """Returns the instance serial socket name
898

899
    """
900
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
901

    
902
  @classmethod
903
  def _InstanceQmpMonitor(cls, instance_name):
904
    """Returns the instance serial QMP socket name
905

906
    """
907
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
908

    
909
  @staticmethod
910
  def _SocatUnixConsoleParams():
911
    """Returns the correct parameters for socat
912

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

915
    """
916
    if constants.SOCAT_USE_ESCAPE:
917
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
918
    else:
919
      return "echo=0,icanon=0"
920

    
921
  @classmethod
922
  def _InstanceKVMRuntime(cls, instance_name):
923
    """Returns the instance KVM runtime filename
924

925
    """
926
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
927

    
928
  @classmethod
929
  def _InstanceChrootDir(cls, instance_name):
930
    """Returns the name of the KVM chroot dir of the instance
931

932
    """
933
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
934

    
935
  @classmethod
936
  def _InstanceNICDir(cls, instance_name):
937
    """Returns the name of the directory holding the tap device files for a
938
    given instance.
939

940
    """
941
    return utils.PathJoin(cls._NICS_DIR, instance_name)
942

    
943
  @classmethod
944
  def _InstanceNICFile(cls, instance_name, seq):
945
    """Returns the name of the file containing the tap device for a given NIC
946

947
    """
948
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
949

    
950
  @classmethod
951
  def _InstanceKeymapFile(cls, instance_name):
952
    """Returns the name of the file containing the keymap for a given instance
953

954
    """
955
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
956

    
957
  @classmethod
958
  def _TryReadUidFile(cls, uid_file):
959
    """Try to read a uid file
960

961
    """
962
    if os.path.exists(uid_file):
963
      try:
964
        uid = int(utils.ReadOneLineFile(uid_file))
965
        return uid
966
      except EnvironmentError:
967
        logging.warning("Can't read uid file", exc_info=True)
968
      except (TypeError, ValueError):
969
        logging.warning("Can't parse uid file contents", exc_info=True)
970
    return None
971

    
972
  @classmethod
973
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
974
    """Removes an instance's rutime sockets/files/dirs.
975

976
    """
977
    utils.RemoveFile(pidfile)
978
    utils.RemoveFile(cls._InstanceMonitor(instance_name))
979
    utils.RemoveFile(cls._InstanceSerial(instance_name))
980
    utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
981
    utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
982
    utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
983
    uid_file = cls._InstanceUidFile(instance_name)
984
    uid = cls._TryReadUidFile(uid_file)
985
    utils.RemoveFile(uid_file)
986
    if uid is not None:
987
      uidpool.ReleaseUid(uid)
988
    try:
989
      shutil.rmtree(cls._InstanceNICDir(instance_name))
990
    except OSError, err:
991
      if err.errno != errno.ENOENT:
992
        raise
993
    try:
994
      chroot_dir = cls._InstanceChrootDir(instance_name)
995
      utils.RemoveDir(chroot_dir)
996
    except OSError, err:
997
      if err.errno == errno.ENOTEMPTY:
998
        # The chroot directory is expected to be empty, but it isn't.
999
        new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
1000
                                          prefix="%s-%s-" %
1001
                                          (instance_name,
1002
                                           utils.TimestampForFilename()))
1003
        logging.warning("The chroot directory of instance %s can not be"
1004
                        " removed as it is not empty. Moving it to the"
1005
                        " quarantine instead. Please investigate the"
1006
                        " contents (%s) and clean up manually",
1007
                        instance_name, new_chroot_dir)
1008
        utils.RenameFile(chroot_dir, new_chroot_dir)
1009
      else:
1010
        raise
1011

    
1012
  @staticmethod
1013
  def _ConfigureNIC(instance, seq, nic, tap):
1014
    """Run the network configuration script for a specified NIC
1015

1016
    @param instance: instance we're acting on
1017
    @type instance: instance object
1018
    @param seq: nic sequence number
1019
    @type seq: int
1020
    @param nic: nic we're acting on
1021
    @type nic: nic object
1022
    @param tap: the host's tap interface this NIC corresponds to
1023
    @type tap: str
1024

1025
    """
1026
    env = {
1027
      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
1028
      "INSTANCE": instance.name,
1029
      "MAC": nic.mac,
1030
      "MODE": nic.nicparams[constants.NIC_MODE],
1031
      "INTERFACE": tap,
1032
      "INTERFACE_INDEX": str(seq),
1033
      "INTERFACE_UUID": nic.uuid,
1034
      "TAGS": " ".join(instance.GetTags()),
1035
    }
1036

    
1037
    if nic.ip:
1038
      env["IP"] = nic.ip
1039

    
1040
    if nic.name:
1041
      env["INTERFACE_NAME"] = nic.name
1042

    
1043
    if nic.nicparams[constants.NIC_LINK]:
1044
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
1045

    
1046
    if nic.network:
1047
      n = objects.Network.FromDict(nic.netinfo)
1048
      env.update(n.HooksDict())
1049

    
1050
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1051
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
1052

    
1053
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
1054
    if result.failed:
1055
      raise errors.HypervisorError("Failed to configure interface %s: %s;"
1056
                                   " network configuration script output: %s" %
1057
                                   (tap, result.fail_reason, result.output))
1058

    
1059
  @staticmethod
1060
  def _VerifyAffinityPackage():
1061
    if affinity is None:
1062
      raise errors.HypervisorError("affinity Python package not"
1063
                                   " found; cannot use CPU pinning under KVM")
1064

    
1065
  @staticmethod
1066
  def _BuildAffinityCpuMask(cpu_list):
1067
    """Create a CPU mask suitable for sched_setaffinity from a list of
1068
    CPUs.
1069

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

1073
    @type cpu_list: list of int
1074
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
1075
    @rtype: int
1076
    @return: a bit mask of CPU affinities
1077

1078
    """
1079
    if cpu_list == constants.CPU_PINNING_OFF:
1080
      return constants.CPU_PINNING_ALL_KVM
1081
    else:
1082
      return sum(2 ** cpu for cpu in cpu_list)
1083

    
1084
  @classmethod
1085
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
1086
    """Change CPU affinity for running VM according to given CPU mask.
1087

1088
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
1089
    @type cpu_mask: string
1090
    @param process_id: process ID of KVM process. Used to pin entire VM
1091
                       to physical CPUs.
1092
    @type process_id: int
1093
    @param thread_dict: map of virtual CPUs to KVM thread IDs
1094
    @type thread_dict: dict int:int
1095

1096
    """
1097
    # Convert the string CPU mask to a list of list of int's
1098
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
1099

    
1100
    if len(cpu_list) == 1:
1101
      all_cpu_mapping = cpu_list[0]
1102
      if all_cpu_mapping == constants.CPU_PINNING_OFF:
1103
        # If CPU pinning has 1 entry that's "all", then do nothing
1104
        pass
1105
      else:
1106
        # If CPU pinning has one non-all entry, map the entire VM to
1107
        # one set of physical CPUs
1108
        cls._VerifyAffinityPackage()
1109
        affinity.set_process_affinity_mask(
1110
          process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
1111
    else:
1112
      # The number of vCPUs mapped should match the number of vCPUs
1113
      # reported by KVM. This was already verified earlier, so
1114
      # here only as a sanity check.
1115
      assert len(thread_dict) == len(cpu_list)
1116
      cls._VerifyAffinityPackage()
1117

    
1118
      # For each vCPU, map it to the proper list of physical CPUs
1119
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1120
        affinity.set_process_affinity_mask(thread_dict[i],
1121
                                           cls._BuildAffinityCpuMask(vcpu))
1122

    
1123
  def _GetVcpuThreadIds(self, instance_name):
1124
    """Get a mapping of vCPU no. to thread IDs for the instance
1125

1126
    @type instance_name: string
1127
    @param instance_name: instance in question
1128
    @rtype: dictionary of int:int
1129
    @return: a dictionary mapping vCPU numbers to thread IDs
1130

1131
    """
1132
    result = {}
1133
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1134
    for line in output.stdout.splitlines():
1135
      match = self._CPU_INFO_RE.search(line)
1136
      if not match:
1137
        continue
1138
      grp = map(int, match.groups())
1139
      result[grp[0]] = grp[1]
1140

    
1141
    return result
1142

    
1143
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1144
    """Complete CPU pinning.
1145

1146
    @type instance_name: string
1147
    @param instance_name: name of instance
1148
    @type cpu_mask: string
1149
    @param cpu_mask: CPU pinning mask as entered by user
1150

1151
    """
1152
    # Get KVM process ID, to be used if need to pin entire VM
1153
    _, pid, _ = self._InstancePidAlive(instance_name)
1154
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1155
    thread_dict = self._GetVcpuThreadIds(instance_name)
1156
    # Run CPU pinning, based on configured mask
1157
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1158

    
1159
  def ListInstances(self):
1160
    """Get the list of running instances.
1161

1162
    We can do this by listing our live instances directory and
1163
    checking whether the associated kvm process is still alive.
1164

1165
    """
1166
    result = []
1167
    for name in os.listdir(self._PIDS_DIR):
1168
      if self._InstancePidAlive(name)[2]:
1169
        result.append(name)
1170
    return result
1171

    
1172
  def GetInstanceInfo(self, instance_name):
1173
    """Get instance properties.
1174

1175
    @type instance_name: string
1176
    @param instance_name: the instance name
1177
    @rtype: tuple of strings
1178
    @return: (name, id, memory, vcpus, stat, times)
1179

1180
    """
1181
    _, pid, alive = self._InstancePidAlive(instance_name)
1182
    if not alive:
1183
      return None
1184

    
1185
    _, memory, vcpus = self._InstancePidInfo(pid)
1186
    istat = "---b-"
1187
    times = "0"
1188

    
1189
    try:
1190
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1191
      qmp.connect()
1192
      vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1193
      # Will fail if ballooning is not enabled, but we can then just resort to
1194
      # the value above.
1195
      mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1196
      memory = mem_bytes / 1048576
1197
    except errors.HypervisorError:
1198
      pass
1199

    
1200
    return (instance_name, pid, memory, vcpus, istat, times)
1201

    
1202
  def GetAllInstancesInfo(self):
1203
    """Get properties of all instances.
1204

1205
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1206

1207
    """
1208
    data = []
1209
    for name in os.listdir(self._PIDS_DIR):
1210
      try:
1211
        info = self.GetInstanceInfo(name)
1212
      except errors.HypervisorError:
1213
        # Ignore exceptions due to instances being shut down
1214
        continue
1215
      if info:
1216
        data.append(info)
1217
    return data
1218

    
1219
  def _GenerateKVMBlockDevicesOptions(self, instance, kvm_disks,
1220
                                      kvmhelp, devlist):
1221
    """Generate KVM options regarding instance's block devices.
1222

1223
    @type instance: L{objects.Instance}
1224
    @param instance: the instance object
1225
    @type kvm_disks: list of tuples
1226
    @param kvm_disks: list of tuples [(disk, link_name)..]
1227
    @type kvmhelp: string
1228
    @param kvmhelp: output of kvm --help
1229
    @type devlist: string
1230
    @param devlist: output of kvm -device ?
1231
    @rtype: list
1232
    @return: list of command line options eventually used by kvm executable
1233

1234
    """
1235
    hvp = instance.hvparams
1236
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1237
    if kernel_path:
1238
      boot_disk = False
1239
    else:
1240
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1241

    
1242
    # whether this is an older KVM version that uses the boot=on flag
1243
    # on devices
1244
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1245

    
1246
    dev_opts = []
1247
    device_driver = None
1248
    disk_type = hvp[constants.HV_DISK_TYPE]
1249
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
1250
      if_val = ",if=%s" % self._VIRTIO
1251
      try:
1252
        if self._VIRTIO_BLK_RE.search(devlist):
1253
          if_val = ",if=none"
1254
          # will be passed in -device option as driver
1255
          device_driver = self._VIRTIO_BLK_PCI
1256
      except errors.HypervisorError, _:
1257
        pass
1258
    else:
1259
      if_val = ",if=%s" % disk_type
1260
    # Cache mode
1261
    disk_cache = hvp[constants.HV_DISK_CACHE]
1262
    if instance.disk_template in constants.DTS_EXT_MIRROR:
1263
      if disk_cache != "none":
1264
        # TODO: make this a hard error, instead of a silent overwrite
1265
        logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1266
                        " to prevent shared storage corruption on migration",
1267
                        disk_cache)
1268
      cache_val = ",cache=none"
1269
    elif disk_cache != constants.HT_CACHE_DEFAULT:
1270
      cache_val = ",cache=%s" % disk_cache
1271
    else:
1272
      cache_val = ""
1273
    for idx, (cfdev, link_name) in enumerate(kvm_disks):
1274
      if cfdev.mode != constants.DISK_RDWR:
1275
        raise errors.HypervisorError("Instance has read-only disks which"
1276
                                     " are not supported by KVM")
1277
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
1278
      boot_val = ""
1279
      if boot_disk:
1280
        dev_opts.extend(["-boot", "c"])
1281
        boot_disk = False
1282
        if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1283
          boot_val = ",boot=on"
1284

    
1285
      # For ext we allow overriding disk_cache hypervisor params per disk
1286
      disk_cache = cfdev.params.get("cache", None)
1287
      if disk_cache:
1288
        cache_val = ",cache=%s" % disk_cache
1289
      drive_val = "file=%s,format=raw%s%s%s" % \
1290
                  (link_name, if_val, boot_val, cache_val)
1291

    
1292
      if device_driver:
1293
        # kvm_disks are the 4th entry of runtime file that did not exist in
1294
        # the past. That means that cfdev should always have pci slot and
1295
        # _GenerateDeviceKVMId() will not raise a exception.
1296
        kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_DISK,
1297
                                         cfdev, idx)
1298
        drive_val += (",id=%s" % kvm_devid)
1299
        if cfdev.pci:
1300
          drive_val += (",bus=0,unit=%d" % cfdev.pci)
1301
        dev_val = ("%s,drive=%s,id=%s" %
1302
                   (device_driver, kvm_devid, kvm_devid))
1303
        if cfdev.pci:
1304
          dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci)
1305
        dev_opts.extend(["-device", dev_val])
1306

    
1307
      # TODO: export disk geometry in IDISK_PARAMS
1308
      heads = cfdev.params.get('heads', None)
1309
      secs = cfdev.params.get('secs', None)
1310
      if heads and secs:
1311
        nr_sectors = cfdev.size * 1024 * 1024 / 512
1312
        cyls = nr_sectors / (int(heads) * int(secs))
1313
        if cyls > 16383:
1314
          cyls = 16383
1315
        elif cyls < 2:
1316
          cyls = 2
1317
        if cyls and heads and secs:
1318
          drive_val += (",cyls=%d,heads=%d,secs=%d" %
1319
                        (cyls, int(heads), int(secs)))
1320

    
1321
      dev_opts.extend(["-drive", drive_val])
1322

    
1323
    return dev_opts
1324

    
1325
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1326
                          kvmhelp):
1327
    """Generate KVM information to start an instance.
1328

1329
    @type kvmhelp: string
1330
    @param kvmhelp: output of kvm --help
1331
    @attention: this function must not have any side-effects; for
1332
        example, it must not write to the filesystem, or read values
1333
        from the current system the are expected to differ between
1334
        nodes, since it is only run once at instance startup;
1335
        actions/kvm arguments that can vary between systems should be
1336
        done in L{_ExecuteKVMRuntime}
1337

1338
    """
1339
    # pylint: disable=R0912,R0914,R0915
1340
    hvp = instance.hvparams
1341
    self.ValidateParameters(hvp)
1342

    
1343
    pidfile = self._InstancePidFile(instance.name)
1344
    kvm = hvp[constants.HV_KVM_PATH]
1345
    kvm_cmd = [kvm]
1346
    # used just by the vnc server, if enabled
1347
    kvm_cmd.extend(["-name", instance.name])
1348
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1349

    
1350
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1351
    if hvp[constants.HV_CPU_CORES]:
1352
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1353
    if hvp[constants.HV_CPU_THREADS]:
1354
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1355
    if hvp[constants.HV_CPU_SOCKETS]:
1356
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1357

    
1358
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1359

    
1360
    kvm_cmd.extend(["-pidfile", pidfile])
1361
    kvm_cmd.extend(["-balloon", "virtio"])
1362
    kvm_cmd.extend(["-daemonize"])
1363
    if not instance.hvparams[constants.HV_ACPI]:
1364
      kvm_cmd.extend(["-no-acpi"])
1365
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1366
        constants.INSTANCE_REBOOT_EXIT:
1367
      kvm_cmd.extend(["-no-reboot"])
1368

    
1369
    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1370
    if not mversion:
1371
      mversion = self._GetDefaultMachineVersion(kvm)
1372
    if self._MACHINE_RE.search(kvmhelp):
1373
      # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1374
      # extra hypervisor parameters. We should also investigate whether and how
1375
      # shadow_mem should be considered for the resource model.
1376
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1377
        specprop = ",accel=kvm"
1378
      else:
1379
        specprop = ""
1380
      machinespec = "%s%s" % (mversion, specprop)
1381
      kvm_cmd.extend(["-machine", machinespec])
1382
    else:
1383
      kvm_cmd.extend(["-M", mversion])
1384
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1385
          self._ENABLE_KVM_RE.search(kvmhelp)):
1386
        kvm_cmd.extend(["-enable-kvm"])
1387
      elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1388
            self._DISABLE_KVM_RE.search(kvmhelp)):
1389
        kvm_cmd.extend(["-disable-kvm"])
1390

    
1391
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1392
    if kernel_path:
1393
      boot_cdrom = boot_floppy = boot_network = False
1394
    else:
1395
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1396
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1397
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1398

    
1399
    if startup_paused:
1400
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1401

    
1402
    if boot_network:
1403
      kvm_cmd.extend(["-boot", "n"])
1404

    
1405
    # whether this is an older KVM version that uses the boot=on flag
1406
    # on devices
1407
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1408

    
1409
    disk_type = hvp[constants.HV_DISK_TYPE]
1410

    
1411
    #Now we can specify a different device type for CDROM devices.
1412
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1413
    if not cdrom_disk_type:
1414
      cdrom_disk_type = disk_type
1415

    
1416
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1417
    if iso_image:
1418
      options = ",format=raw,media=cdrom"
1419
      # set cdrom 'if' type
1420
      if boot_cdrom:
1421
        actual_cdrom_type = constants.HT_DISK_IDE
1422
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1423
        actual_cdrom_type = "virtio"
1424
      else:
1425
        actual_cdrom_type = cdrom_disk_type
1426
      if_val = ",if=%s" % actual_cdrom_type
1427
      # set boot flag, if needed
1428
      boot_val = ""
1429
      if boot_cdrom:
1430
        kvm_cmd.extend(["-boot", "d"])
1431
        if needs_boot_flag:
1432
          boot_val = ",boot=on"
1433
      # and finally build the entire '-drive' value
1434
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1435
      kvm_cmd.extend(["-drive", drive_val])
1436

    
1437
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1438
    if iso_image2:
1439
      options = ",format=raw,media=cdrom"
1440
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1441
        if_val = ",if=virtio"
1442
      else:
1443
        if_val = ",if=%s" % cdrom_disk_type
1444
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1445
      kvm_cmd.extend(["-drive", drive_val])
1446

    
1447
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1448
    if floppy_image:
1449
      options = ",format=raw,media=disk"
1450
      if boot_floppy:
1451
        kvm_cmd.extend(["-boot", "a"])
1452
        options = "%s,boot=on" % options
1453
      if_val = ",if=floppy"
1454
      options = "%s%s" % (options, if_val)
1455
      drive_val = "file=%s%s" % (floppy_image, options)
1456
      kvm_cmd.extend(["-drive", drive_val])
1457

    
1458
    if kernel_path:
1459
      kvm_cmd.extend(["-kernel", kernel_path])
1460
      initrd_path = hvp[constants.HV_INITRD_PATH]
1461
      if initrd_path:
1462
        kvm_cmd.extend(["-initrd", initrd_path])
1463
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1464
                     hvp[constants.HV_KERNEL_ARGS]]
1465
      if hvp[constants.HV_SERIAL_CONSOLE]:
1466
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1467
        root_append.append("console=ttyS0,%s" % serial_speed)
1468
      kvm_cmd.extend(["-append", " ".join(root_append)])
1469

    
1470
    mem_path = hvp[constants.HV_MEM_PATH]
1471
    if mem_path:
1472
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1473

    
1474
    monitor_dev = ("unix:%s,server,nowait" %
1475
                   self._InstanceMonitor(instance.name))
1476
    kvm_cmd.extend(["-monitor", monitor_dev])
1477
    if hvp[constants.HV_SERIAL_CONSOLE]:
1478
      serial_dev = ("unix:%s,server,nowait" %
1479
                    self._InstanceSerial(instance.name))
1480
      kvm_cmd.extend(["-serial", serial_dev])
1481
    else:
1482
      kvm_cmd.extend(["-serial", "none"])
1483

    
1484
    mouse_type = hvp[constants.HV_USB_MOUSE]
1485
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1486
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1487
    spice_ip_version = None
1488

    
1489
    kvm_cmd.extend(["-usb"])
1490

    
1491
    if mouse_type:
1492
      kvm_cmd.extend(["-usbdevice", mouse_type])
1493
    elif vnc_bind_address:
1494
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1495

    
1496
    if vnc_bind_address:
1497
      if netutils.IP4Address.IsValid(vnc_bind_address):
1498
        if instance.network_port > constants.VNC_BASE_PORT:
1499
          display = instance.network_port - constants.VNC_BASE_PORT
1500
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1501
            vnc_arg = ":%d" % (display)
1502
          else:
1503
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1504
        else:
1505
          logging.error("Network port is not a valid VNC display (%d < %d),"
1506
                        " not starting VNC",
1507
                        instance.network_port, constants.VNC_BASE_PORT)
1508
          vnc_arg = "none"
1509

    
1510
        # Only allow tls and other option when not binding to a file, for now.
1511
        # kvm/qemu gets confused otherwise about the filename to use.
1512
        vnc_append = ""
1513
        if hvp[constants.HV_VNC_TLS]:
1514
          vnc_append = "%s,tls" % vnc_append
1515
          if hvp[constants.HV_VNC_X509_VERIFY]:
1516
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1517
                                               hvp[constants.HV_VNC_X509])
1518
          elif hvp[constants.HV_VNC_X509]:
1519
            vnc_append = "%s,x509=%s" % (vnc_append,
1520
                                         hvp[constants.HV_VNC_X509])
1521
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1522
          vnc_append = "%s,password" % vnc_append
1523

    
1524
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1525

    
1526
      else:
1527
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1528

    
1529
      kvm_cmd.extend(["-vnc", vnc_arg])
1530
    elif spice_bind:
1531
      # FIXME: this is wrong here; the iface ip address differs
1532
      # between systems, so it should be done in _ExecuteKVMRuntime
1533
      if netutils.IsValidInterface(spice_bind):
1534
        # The user specified a network interface, we have to figure out the IP
1535
        # address.
1536
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1537
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1538

    
1539
        # if the user specified an IP version and the interface does not
1540
        # have that kind of IP addresses, throw an exception
1541
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1542
          if not addresses[spice_ip_version]:
1543
            raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1544
                                         " for %s" % (spice_ip_version,
1545
                                                      spice_bind))
1546

    
1547
        # the user did not specify an IP version, we have to figure it out
1548
        elif (addresses[constants.IP4_VERSION] and
1549
              addresses[constants.IP6_VERSION]):
1550
          # we have both ipv4 and ipv6, let's use the cluster default IP
1551
          # version
1552
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1553
          spice_ip_version = \
1554
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1555
        elif addresses[constants.IP4_VERSION]:
1556
          spice_ip_version = constants.IP4_VERSION
1557
        elif addresses[constants.IP6_VERSION]:
1558
          spice_ip_version = constants.IP6_VERSION
1559
        else:
1560
          raise errors.HypervisorError("SPICE: Unable to get an IP address"
1561
                                       " for %s" % (spice_bind))
1562

    
1563
        spice_address = addresses[spice_ip_version][0]
1564

    
1565
      else:
1566
        # spice_bind is known to be a valid IP address, because
1567
        # ValidateParameters checked it.
1568
        spice_address = spice_bind
1569

    
1570
      spice_arg = "addr=%s" % spice_address
1571
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1572
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1573
                     (spice_arg, instance.network_port,
1574
                      pathutils.SPICE_CACERT_FILE))
1575
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1576
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1577
                      pathutils.SPICE_CERT_FILE))
1578
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1579
        if tls_ciphers:
1580
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1581
      else:
1582
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1583

    
1584
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1585
        spice_arg = "%s,disable-ticketing" % spice_arg
1586

    
1587
      if spice_ip_version:
1588
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1589

    
1590
      # Image compression options
1591
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1592
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1593
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1594
      if img_lossless:
1595
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1596
      if img_jpeg:
1597
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1598
      if img_zlib_glz:
1599
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1600

    
1601
      # Video stream detection
1602
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1603
      if video_streaming:
1604
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1605

    
1606
      # Audio compression, by default in qemu-kvm it is on
1607
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1608
        spice_arg = "%s,playback-compression=off" % spice_arg
1609
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1610
        spice_arg = "%s,agent-mouse=off" % spice_arg
1611
      else:
1612
        # Enable the spice agent communication channel between the host and the
1613
        # agent.
1614
        kvm_cmd.extend(["-device", "virtio-serial-pci"])
1615
        kvm_cmd.extend([
1616
          "-device",
1617
          "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1618
          ])
1619
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1620

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

    
1624
    else:
1625
      # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1626
      # also works in earlier versions though (tested with 1.1 and 1.3)
1627
      if self._DISPLAY_RE.search(kvmhelp):
1628
        kvm_cmd.extend(["-display", "none"])
1629
      else:
1630
        kvm_cmd.extend(["-nographic"])
1631

    
1632
    if hvp[constants.HV_USE_LOCALTIME]:
1633
      kvm_cmd.extend(["-localtime"])
1634

    
1635
    if hvp[constants.HV_KVM_USE_CHROOT]:
1636
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1637

    
1638
    # Add qemu-KVM -cpu param
1639
    if hvp[constants.HV_CPU_TYPE]:
1640
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1641

    
1642
    # As requested by music lovers
1643
    if hvp[constants.HV_SOUNDHW]:
1644
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1645

    
1646
    # Pass a -vga option if requested, or if spice is used, for backwards
1647
    # compatibility.
1648
    if hvp[constants.HV_VGA]:
1649
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1650
    elif spice_bind:
1651
      kvm_cmd.extend(["-vga", "qxl"])
1652

    
1653
    # Various types of usb devices, comma separated
1654
    if hvp[constants.HV_USB_DEVICES]:
1655
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1656
        kvm_cmd.extend(["-usbdevice", dev])
1657

    
1658
    if hvp[constants.HV_KVM_EXTRA]:
1659
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1660

    
1661
    pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1662
    kvm_disks = []
1663
    for disk, link_name in block_devices:
1664
      _UpdatePCISlots(disk, pci_reservations)
1665
      kvm_disks.append((disk, link_name))
1666

    
1667
    kvm_nics = []
1668
    for nic in instance.nics:
1669
      _UpdatePCISlots(nic, pci_reservations)
1670
      kvm_nics.append(nic)
1671

    
1672
    hvparams = hvp
1673

    
1674
    return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1675

    
1676
  def _WriteKVMRuntime(self, instance_name, data):
1677
    """Write an instance's KVM runtime
1678

1679
    """
1680
    try:
1681
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1682
                      data=data)
1683
    except EnvironmentError, err:
1684
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1685

    
1686
  def _ReadKVMRuntime(self, instance_name):
1687
    """Read an instance's KVM runtime
1688

1689
    """
1690
    try:
1691
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1692
    except EnvironmentError, err:
1693
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1694
    return file_content
1695

    
1696
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1697
    """Save an instance's KVM runtime
1698

1699
    """
1700
    kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1701

    
1702
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1703
    serialized_disks = [(blk.ToDict(), link)
1704
                            for blk, link in kvm_disks]
1705
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1706
                                      serialized_disks))
1707

    
1708
    self._WriteKVMRuntime(instance.name, serialized_form)
1709

    
1710
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1711
    """Load an instance's KVM runtime
1712

1713
    """
1714
    if not serialized_runtime:
1715
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1716

    
1717
    return _AnalyzeSerializedRuntime(serialized_runtime)
1718

    
1719
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1720
    """Run the KVM cmd and check for errors
1721

1722
    @type name: string
1723
    @param name: instance name
1724
    @type kvm_cmd: list of strings
1725
    @param kvm_cmd: runcmd input for kvm
1726
    @type tap_fds: list of int
1727
    @param tap_fds: fds of tap devices opened by Ganeti
1728

1729
    """
1730
    try:
1731
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1732
    finally:
1733
      for fd in tap_fds:
1734
        utils_wrapper.CloseFdNoError(fd)
1735

    
1736
    if result.failed:
1737
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1738
                                   (name, result.fail_reason, result.output))
1739
    if not self._InstancePidAlive(name)[2]:
1740
      raise errors.HypervisorError("Failed to start instance %s" % name)
1741

    
1742
  # too many local variables
1743
  # pylint: disable=R0914
1744
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1745
    """Execute a KVM cmd, after completing it with some last minute data.
1746

1747
    @type incoming: tuple of strings
1748
    @param incoming: (target_host_ip, port)
1749
    @type kvmhelp: string
1750
    @param kvmhelp: output of kvm --help
1751

1752
    """
1753
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1754
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1755
    #    have changed since the instance started; only use them if the change
1756
    #    won't affect the inside of the instance (which hasn't been rebooted).
1757
    #  - up_hvp contains the parameters as they were when the instance was
1758
    #    started, plus any new parameter which has been added between ganeti
1759
    #    versions: it is paramount that those default to a value which won't
1760
    #    affect the inside of the instance as well.
1761
    conf_hvp = instance.hvparams
1762
    name = instance.name
1763
    self._CheckDown(name)
1764

    
1765
    temp_files = []
1766

    
1767
    kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1768
    # the first element of kvm_cmd is always the path to the kvm binary
1769
    kvm_path = kvm_cmd[0]
1770
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1771

    
1772
    # We know it's safe to run as a different user upon migration, so we'll use
1773
    # the latest conf, from conf_hvp.
1774
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1775
    if security_model == constants.HT_SM_USER:
1776
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1777

    
1778
    keymap = conf_hvp[constants.HV_KEYMAP]
1779
    if keymap:
1780
      keymap_path = self._InstanceKeymapFile(name)
1781
      # If a keymap file is specified, KVM won't use its internal defaults. By
1782
      # first including the "en-us" layout, an error on loading the actual
1783
      # layout (e.g. because it can't be found) won't lead to a non-functional
1784
      # keyboard. A keyboard with incorrect keys is still better than none.
1785
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1786
      kvm_cmd.extend(["-k", keymap_path])
1787

    
1788
    # We have reasons to believe changing something like the nic driver/type
1789
    # upon migration won't exactly fly with the instance kernel, so for nic
1790
    # related parameters we'll use up_hvp
1791
    tapfds = []
1792
    taps = []
1793
    devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1794

    
1795
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1796
                                                     kvm_disks,
1797
                                                     kvmhelp,
1798
                                                     devlist)
1799
    kvm_cmd.extend(bdev_opts)
1800

    
1801
    if not kvm_nics:
1802
      kvm_cmd.extend(["-net", "none"])
1803
    else:
1804
      vnet_hdr = False
1805
      tap_extra = ""
1806
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1807
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1808
        nic_model = self._VIRTIO
1809
        try:
1810
          if self._VIRTIO_NET_RE.search(devlist):
1811
            nic_model = self._VIRTIO_NET_PCI
1812
            vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1813
        except errors.HypervisorError, _:
1814
          # Older versions of kvm don't support DEVICE_LIST, but they don't
1815
          # have new virtio syntax either.
1816
          pass
1817

    
1818
        if up_hvp[constants.HV_VHOST_NET]:
1819
          # check for vhost_net support
1820
          if self._VHOST_RE.search(kvmhelp):
1821
            tap_extra = ",vhost=on"
1822
          else:
1823
            raise errors.HypervisorError("vhost_net is configured"
1824
                                         " but it is not available")
1825
      else:
1826
        nic_model = nic_type
1827

    
1828
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1829

    
1830
      for nic_seq, nic in enumerate(kvm_nics):
1831
        tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1832
        tapfds.append(tapfd)
1833
        taps.append(tapname)
1834
        if kvm_supports_netdev:
1835
          nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1836
          try:
1837
            # kvm_nics already exist in old runtime files and thus there might
1838
            # be some entries without pci slot (therefore try: except:)
1839
            kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1840
            netdev = kvm_devid
1841
            nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1842
          except errors.HotplugError:
1843
            netdev = "netdev%d" % nic_seq
1844
          nic_val += (",netdev=%s" % netdev)
1845
          tap_val = ("type=tap,id=%s,fd=%d%s" %
1846
                     (netdev, tapfd, tap_extra))
1847
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1848
        else:
1849
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1850
                                                         nic.mac, nic_model)
1851
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1852
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1853

    
1854
    if incoming:
1855
      target, port = incoming
1856
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1857

    
1858
    # Changing the vnc password doesn't bother the guest that much. At most it
1859
    # will surprise people who connect to it. Whether positively or negatively
1860
    # it's debatable.
1861
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1862
    vnc_pwd = None
1863
    if vnc_pwd_file:
1864
      try:
1865
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1866
      except EnvironmentError, err:
1867
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1868
                                     % (vnc_pwd_file, err))
1869

    
1870
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1871
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1872
                         constants.SECURE_DIR_MODE)])
1873

    
1874
    # Automatically enable QMP if version is >= 0.14
1875
    if self._QMP_RE.search(kvmhelp):
1876
      logging.debug("Enabling QMP")
1877
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1878
                      self._InstanceQmpMonitor(instance.name)])
1879

    
1880
    # Configure the network now for starting instances and bridged interfaces,
1881
    # during FinalizeMigration for incoming instances' routed interfaces
1882
    for nic_seq, nic in enumerate(kvm_nics):
1883
      if (incoming and
1884
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1885
        continue
1886
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1887

    
1888
    # CPU affinity requires kvm to start paused, so we set this flag if the
1889
    # instance is not already paused and if we are not going to accept a
1890
    # migrating instance. In the latter case, pausing is not needed.
1891
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1892
    if start_kvm_paused:
1893
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1894

    
1895
    # Note: CPU pinning is using up_hvp since changes take effect
1896
    # during instance startup anyway, and to avoid problems when soft
1897
    # rebooting the instance.
1898
    cpu_pinning = False
1899
    if up_hvp.get(constants.HV_CPU_MASK, None):
1900
      cpu_pinning = True
1901

    
1902
    if security_model == constants.HT_SM_POOL:
1903
      ss = ssconf.SimpleStore()
1904
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1905
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1906
      uid = uidpool.RequestUnusedUid(all_uids)
1907
      try:
1908
        username = pwd.getpwuid(uid.GetUid()).pw_name
1909
        kvm_cmd.extend(["-runas", username])
1910
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1911
      except:
1912
        uidpool.ReleaseUid(uid)
1913
        raise
1914
      else:
1915
        uid.Unlock()
1916
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1917
    else:
1918
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1919

    
1920
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1921
                     constants.RUN_DIRS_MODE)])
1922
    for nic_seq, tap in enumerate(taps):
1923
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1924
                      data=tap)
1925

    
1926
    if vnc_pwd:
1927
      change_cmd = "change vnc password %s" % vnc_pwd
1928
      self._CallMonitorCommand(instance.name, change_cmd)
1929

    
1930
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1931
    # connection attempts because SPICE by default does not allow connections
1932
    # if neither a password nor the "disable_ticketing" options are specified.
1933
    # As soon as we send the password via QMP, that password is a valid ticket
1934
    # for connection.
1935
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1936
    if spice_password_file:
1937
      spice_pwd = ""
1938
      try:
1939
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1940
      except EnvironmentError, err:
1941
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1942
                                     % (spice_password_file, err))
1943

    
1944
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1945
      qmp.connect()
1946
      arguments = {
1947
          "protocol": "spice",
1948
          "password": spice_pwd,
1949
      }
1950
      qmp.Execute("set_password", arguments)
1951

    
1952
    for filename in temp_files:
1953
      utils.RemoveFile(filename)
1954

    
1955
    # If requested, set CPU affinity and resume instance execution
1956
    if cpu_pinning:
1957
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1958

    
1959
    start_memory = self._InstanceStartupMemory(instance)
1960
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1961
      self.BalloonInstanceMemory(instance, start_memory)
1962

    
1963
    if start_kvm_paused:
1964
      # To control CPU pinning, ballooning, and vnc/spice passwords
1965
      # the VM was started in a frozen state. If freezing was not
1966
      # explicitly requested resume the vm status.
1967
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1968

    
1969
  def StartInstance(self, instance, block_devices, startup_paused):
1970
    """Start an instance.
1971

1972
    """
1973
    self._CheckDown(instance.name)
1974
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1975
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1976
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1977
                                           startup_paused, kvmhelp)
1978
    self._SaveKVMRuntime(instance, kvm_runtime)
1979
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1980

    
1981
  def _CallMonitorCommand(self, instance_name, command):
1982
    """Invoke a command on the instance monitor.
1983

1984
    """
1985
    # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1986
    # version. The monitor protocol is designed for human consumption, whereas
1987
    # QMP is made for programmatic usage. In the worst case QMP can also
1988
    # execute monitor commands. As it is, all calls to socat take at least
1989
    # 500ms and likely more: socat can't detect the end of the reply and waits
1990
    # for 500ms of no data received before exiting (500 ms is the default for
1991
    # the "-t" parameter).
1992
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1993
             (utils.ShellQuote(command),
1994
              constants.SOCAT_PATH,
1995
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1996
    result = utils.RunCmd(socat)
1997
    if result.failed:
1998
      msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1999
             " output: %s" %
2000
             (command, instance_name, result.fail_reason, result.output))
2001
      raise errors.HypervisorError(msg)
2002

    
2003
    return result
2004

    
2005
  def _GetFreePCISlot(self, instance, dev):
2006
    """Get the first available pci slot of a runnung instance.
2007

2008
    """
2009
    slots = bitarray(32)
2010
    slots.setall(False) # pylint: disable=E1101
2011
    output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
2012
    for line in output.stdout.splitlines():
2013
      match = self._INFO_PCI_RE.search(line)
2014
      if match:
2015
        slot = int(match.group(1))
2016
        slots[slot] = True
2017

    
2018
    [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
2019
    if not free:
2020
      raise errors.HypervisorError("All PCI slots occupied")
2021

    
2022
    dev.pci = int(free)
2023

    
2024
  def VerifyHotplugSupport(self, instance, action, dev_type):
2025
    """Verifies that hotplug is supported.
2026

2027
    Hotplug is *not* supported in case of:
2028
     - security models and chroot (disk hotplug)
2029
     - fdsend module is missing (nic hot-add)
2030

2031
    @raise errors.HypervisorError: in one of the previous cases
2032

2033
    """
2034
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2035
      hvp = instance.hvparams
2036
      security_model = hvp[constants.HV_SECURITY_MODEL]
2037
      use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
2038
      if use_chroot:
2039
        raise errors.HotplugError("Disk hotplug is not supported"
2040
                                  " in case of chroot.")
2041
      if security_model != constants.HT_SM_NONE:
2042
        raise errors.HotplugError("Disk Hotplug is not supported in case"
2043
                                  " security models are used.")
2044

    
2045
    if (dev_type == constants.HOTPLUG_TARGET_NIC and
2046
        action == constants.HOTPLUG_ACTION_ADD and not fdsend):
2047
      raise errors.HotplugError("Cannot hot-add NIC."
2048
                                " fdsend python module is missing.")
2049

    
2050
  def HotplugSupported(self, instance):
2051
    """Checks if hotplug is generally supported.
2052

2053
    Hotplug is *not* supported in case of:
2054
     - qemu versions < 1.0
2055
     - for stopped instances
2056

2057
    @raise errors.HypervisorError: in one of the previous cases
2058

2059
    """
2060
    try:
2061
      output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2062
    except errors.HypervisorError:
2063
      raise errors.HotplugError("Instance is probably down")
2064

    
2065
    # TODO: search for netdev_add, drive_add, device_add.....
2066
    match = self._INFO_VERSION_RE.search(output.stdout)
2067
    if not match:
2068
      raise errors.HotplugError("Cannot parse qemu version via monitor")
2069

    
2070
    v_major, v_min, _, _ = match.groups()
2071
    if (int(v_major), int(v_min)) < (1, 0):
2072
      raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2073

    
2074
  def _CallHotplugCommands(self, name, cmds):
2075
    for c in cmds:
2076
      self._CallMonitorCommand(name, c)
2077
      time.sleep(1)
2078

    
2079
  def _VerifyHotplugCommand(self, instance_name, device, dev_type,
2080
                            should_exist):
2081
    """Checks if a previous hotplug command has succeeded.
2082

2083
    It issues info pci monitor command and checks depending on should_exist
2084
    value if an entry with PCI slot and device ID is found or not.
2085

2086
    @raise errors.HypervisorError: if result is not the expected one
2087

2088
    """
2089
    output = self._CallMonitorCommand(instance_name, self._INFO_PCI_CMD)
2090
    kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2091
    match = \
2092
      self._FIND_PCI_DEVICE_RE(device.pci, kvm_devid).search(output.stdout)
2093
    if match and not should_exist:
2094
      msg = "Device %s should have been removed but is still there" % kvm_devid
2095
      raise errors.HypervisorError(msg)
2096

    
2097
    if not match and should_exist:
2098
      msg = "Device %s should have been added but is missing" % kvm_devid
2099
      raise errors.HypervisorError(msg)
2100

    
2101
    logging.info("Device %s has been correctly hot-plugged", kvm_devid)
2102

    
2103
  def HotAddDevice(self, instance, dev_type, device, extra, seq):
2104
    """ Helper method to hot-add a new device
2105

2106
    It gets free pci slot generates the device name and invokes the
2107
    device specific method.
2108

2109
    """
2110
    # in case of hot-mod this is given
2111
    if device.pci is None:
2112
      self._GetFreePCISlot(instance, device)
2113
    kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2114
    runtime = self._LoadKVMRuntime(instance)
2115
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2116
      cmds = ["drive_add dummy file=%s,if=none,id=%s,format=raw" %
2117
                (extra, kvm_devid)]
2118
      cmds += ["device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
2119
                (hex(device.pci), kvm_devid, kvm_devid)]
2120
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
2121
      (tap, fd) = _OpenTap()
2122
      self._ConfigureNIC(instance, seq, device, tap)
2123
      self._PassTapFd(instance, fd, device)
2124
      cmds = ["netdev_add tap,id=%s,fd=%s" % (kvm_devid, kvm_devid)]
2125
      args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
2126
               (hex(device.pci), device.mac, kvm_devid, kvm_devid)
2127
      cmds += ["device_add %s" % args]
2128
      utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
2129

    
2130
    self._CallHotplugCommands(instance.name, cmds)
2131
    self._VerifyHotplugCommand(instance.name, device, dev_type, True)
2132
    # update relevant entries in runtime file
2133
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2134
    entry = _RUNTIME_ENTRY[dev_type](device, extra)
2135
    runtime[index].append(entry)
2136
    self._SaveKVMRuntime(instance, runtime)
2137

    
2138
  def HotDelDevice(self, instance, dev_type, device, _, seq):
2139
    """ Helper method for hot-del device
2140

2141
    It gets device info from runtime file, generates the device name and
2142
    invokes the device specific method.
2143

2144
    """
2145
    runtime = self._LoadKVMRuntime(instance)
2146
    entry = _GetExistingDeviceInfo(dev_type, device, runtime)
2147
    kvm_device = _RUNTIME_DEVICE[dev_type](entry)
2148
    kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
2149
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2150
      cmds = ["device_del %s" % kvm_devid]
2151
      cmds += ["drive_del %s" % kvm_devid]
2152
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
2153
      cmds = ["device_del %s" % kvm_devid]
2154
      cmds += ["netdev_del %s" % kvm_devid]
2155
      utils.RemoveFile(self._InstanceNICFile(instance.name, seq))
2156
    self._CallHotplugCommands(instance.name, cmds)
2157
    self._VerifyHotplugCommand(instance.name, kvm_device, dev_type, False)
2158
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2159
    runtime[index].remove(entry)
2160
    self._SaveKVMRuntime(instance, runtime)
2161

    
2162
    return kvm_device.pci
2163

    
2164
  def HotModDevice(self, instance, dev_type, device, _, seq):
2165
    """ Helper method for hot-mod device
2166

2167
    It gets device info from runtime file, generates the device name and
2168
    invokes the device specific method. Currently only NICs support hot-mod
2169

2170
    """
2171
    if dev_type == constants.HOTPLUG_TARGET_NIC:
2172
      # putting it back in the same pci slot
2173
      device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2174
      # TODO: remove sleep when socat gets removed
2175
      self.HotAddDevice(instance, dev_type, device, _, seq)
2176

    
2177
  def _PassTapFd(self, instance, fd, nic):
2178
    """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2179

2180
    """
2181
    # TODO: factor out code related to unix sockets.
2182
    #       squash common parts between monitor and qmp
2183
    kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2184
    command = "getfd %s\n" % kvm_devid
2185
    fds = [fd]
2186
    logging.info("%s", fds)
2187
    try:
2188
      monsock = MonitorSocket(self._InstanceMonitor(instance.name))
2189
      monsock.connect()
2190
      fdsend.sendfds(monsock.sock, command, fds=fds)
2191
    finally:
2192
      monsock.close()
2193

    
2194
  @classmethod
2195
  def _ParseKVMVersion(cls, text):
2196
    """Parse the KVM version from the --help output.
2197

2198
    @type text: string
2199
    @param text: output of kvm --help
2200
    @return: (version, v_maj, v_min, v_rev)
2201
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2202

2203
    """
2204
    match = cls._VERSION_RE.search(text.splitlines()[0])
2205
    if not match:
2206
      raise errors.HypervisorError("Unable to get KVM version")
2207

    
2208
    v_all = match.group(0)
2209
    v_maj = int(match.group(1))
2210
    v_min = int(match.group(2))
2211
    if match.group(4):
2212
      v_rev = int(match.group(4))
2213
    else:
2214
      v_rev = 0
2215
    return (v_all, v_maj, v_min, v_rev)
2216

    
2217
  @classmethod
2218
  def _GetKVMOutput(cls, kvm_path, option):
2219
    """Return the output of a kvm invocation
2220

2221
    @type kvm_path: string
2222
    @param kvm_path: path to the kvm executable
2223
    @type option: a key of _KVMOPTS_CMDS
2224
    @param option: kvm option to fetch the output from
2225
    @return: output a supported kvm invocation
2226
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2227

2228
    """
2229
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2230

    
2231
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
2232

    
2233
    result = utils.RunCmd([kvm_path] + optlist)
2234
    if result.failed and not can_fail:
2235
      raise errors.HypervisorError("Unable to get KVM %s output" %
2236
                                    " ".join(optlist))
2237
    return result.output
2238

    
2239
  @classmethod
2240
  def _GetKVMVersion(cls, kvm_path):
2241
    """Return the installed KVM version.
2242

2243
    @return: (version, v_maj, v_min, v_rev)
2244
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2245

2246
    """
2247
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2248

    
2249
  @classmethod
2250
  def _GetDefaultMachineVersion(cls, kvm_path):
2251
    """Return the default hardware revision (e.g. pc-1.1)
2252

2253
    """
2254
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2255
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2256
    if match:
2257
      return match.group(1)
2258
    else:
2259
      return "pc"
2260

    
2261
  def StopInstance(self, instance, force=False, retry=False, name=None):
2262
    """Stop an instance.
2263

2264
    """
2265
    if name is not None and not force:
2266
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2267
    if name is None:
2268
      name = instance.name
2269
      acpi = instance.hvparams[constants.HV_ACPI]
2270
    else:
2271
      acpi = False
2272
    _, pid, alive = self._InstancePidAlive(name)
2273
    if pid > 0 and alive:
2274
      if force or not acpi:
2275
        utils.KillProcess(pid)
2276
      else:
2277
        self._CallMonitorCommand(name, "system_powerdown")
2278

    
2279
  def CleanupInstance(self, instance_name):
2280
    """Cleanup after a stopped instance
2281

2282
    """
2283
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
2284
    if pid > 0 and alive:
2285
      raise errors.HypervisorError("Cannot cleanup a live instance")
2286
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2287

    
2288
  def RebootInstance(self, instance):
2289
    """Reboot an instance.
2290

2291
    """
2292
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2293
    # socket the instance will stop, but now power up again. So we'll resort
2294
    # to shutdown and restart.
2295
    _, _, alive = self._InstancePidAlive(instance.name)
2296
    if not alive:
2297
      raise errors.HypervisorError("Failed to reboot instance %s:"
2298
                                   " not running" % instance.name)
2299
    # StopInstance will delete the saved KVM runtime so:
2300
    # ...first load it...
2301
    kvm_runtime = self._LoadKVMRuntime(instance)
2302
    # ...now we can safely call StopInstance...
2303
    if not self.StopInstance(instance):
2304
      self.StopInstance(instance, force=True)
2305
    # ...and finally we can save it again, and execute it...
2306
    self._SaveKVMRuntime(instance, kvm_runtime)
2307
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2308
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2309
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2310

    
2311
  def MigrationInfo(self, instance):
2312
    """Get instance information to perform a migration.
2313

2314
    @type instance: L{objects.Instance}
2315
    @param instance: instance to be migrated
2316
    @rtype: string
2317
    @return: content of the KVM runtime file
2318

2319
    """
2320
    return self._ReadKVMRuntime(instance.name)
2321

    
2322
  def AcceptInstance(self, instance, info, target):
2323
    """Prepare to accept an instance.
2324

2325
    @type instance: L{objects.Instance}
2326
    @param instance: instance to be accepted
2327
    @type info: string
2328
    @param info: content of the KVM runtime file on the source node
2329
    @type target: string
2330
    @param target: target host (usually ip), on this node
2331

2332
    """
2333
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2334
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2335
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2336
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2337
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2338
                            incoming=incoming_address)
2339

    
2340
  def FinalizeMigrationDst(self, instance, info, success):
2341
    """Finalize the instance migration on the target node.
2342

2343
    Stop the incoming mode KVM.
2344

2345
    @type instance: L{objects.Instance}
2346
    @param instance: instance whose migration is being finalized
2347

2348
    """
2349
    if success:
2350
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2351
      kvm_nics = kvm_runtime[1]
2352

    
2353
      for nic_seq, nic in enumerate(kvm_nics):
2354
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2355
          # Bridged interfaces have already been configured
2356
          continue
2357
        try:
2358
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2359
        except EnvironmentError, err:
2360
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
2361
                          instance.name, nic_seq, str(err))
2362
          continue
2363
        try:
2364
          self._ConfigureNIC(instance, nic_seq, nic, tap)
2365
        except errors.HypervisorError, err:
2366
          logging.warning(str(err))
2367

    
2368
      self._WriteKVMRuntime(instance.name, info)
2369
    else:
2370
      self.StopInstance(instance, force=True)
2371

    
2372
  def MigrateInstance(self, instance, target, live):
2373
    """Migrate an instance to a target node.
2374

2375
    The migration will not be attempted if the instance is not
2376
    currently running.
2377

2378
    @type instance: L{objects.Instance}
2379
    @param instance: the instance to be migrated
2380
    @type target: string
2381
    @param target: ip address of the target node
2382
    @type live: boolean
2383
    @param live: perform a live migration
2384

2385
    """
2386
    instance_name = instance.name
2387
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
2388
    _, _, alive = self._InstancePidAlive(instance_name)
2389
    if not alive:
2390
      raise errors.HypervisorError("Instance not running, cannot migrate")
2391

    
2392
    if not live:
2393
      self._CallMonitorCommand(instance_name, "stop")
2394

    
2395
    migrate_command = ("migrate_set_speed %dm" %
2396
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2397
    self._CallMonitorCommand(instance_name, migrate_command)
2398

    
2399
    migrate_command = ("migrate_set_downtime %dms" %
2400
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2401
    self._CallMonitorCommand(instance_name, migrate_command)
2402

    
2403
    # These commands are supported in latest qemu versions.
2404
    # Since _CallMonitorCommand does not catch monitor errors
2405
    # this does not raise an exception in case command is not supported
2406
    # TODO: either parse output of command or see if the command supported
2407
    # via info help (see hotplug)
2408
    migrate_command = ("migrate_set_capability xbzrle on")
2409
    self._CallMonitorCommand(instance_name, migrate_command)
2410

    
2411
    migrate_command = ("migrate_set_capability auto-converge on")
2412
    self._CallMonitorCommand(instance_name, migrate_command)
2413

    
2414
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2415
    self._CallMonitorCommand(instance_name, migrate_command)
2416

    
2417
  def FinalizeMigrationSource(self, instance, success, live):
2418
    """Finalize the instance migration on the source node.
2419

2420
    @type instance: L{objects.Instance}
2421
    @param instance: the instance that was migrated
2422
    @type success: bool
2423
    @param success: whether the migration succeeded or not
2424
    @type live: bool
2425
    @param live: whether the user requested a live migration or not
2426

2427
    """
2428
    if success:
2429
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2430
      utils.KillProcess(pid)
2431
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2432
    elif live:
2433
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2434

    
2435
  def GetMigrationStatus(self, instance):
2436
    """Get the migration status
2437

2438
    @type instance: L{objects.Instance}
2439
    @param instance: the instance that is being migrated
2440
    @rtype: L{objects.MigrationStatus}
2441
    @return: the status of the current migration (one of
2442
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2443
             progress info that can be retrieved from the hypervisor
2444

2445
    """
2446
    info_command = "info migrate"
2447
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2448
      result = self._CallMonitorCommand(instance.name, info_command)
2449
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
2450
      if not match:
2451
        if not result.stdout:
2452
          logging.info("KVM: empty 'info migrate' result")
2453
        else:
2454
          logging.warning("KVM: unknown 'info migrate' result: %s",
2455
                          result.stdout)
2456
      else:
2457
        status = match.group(1)
2458
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2459
          migration_status = objects.MigrationStatus(status=status)
2460
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2461
          if match:
2462
            migration_status.transferred_ram = match.group("transferred")
2463
            migration_status.total_ram = match.group("total")
2464

    
2465
          return migration_status
2466

    
2467
        logging.warning("KVM: unknown migration status '%s'", status)
2468

    
2469
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2470

    
2471
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2472

    
2473
  def BalloonInstanceMemory(self, instance, mem):
2474
    """Balloon an instance memory to a certain value.
2475

2476
    @type instance: L{objects.Instance}
2477
    @param instance: instance to be accepted
2478
    @type mem: int
2479
    @param mem: actual memory size to use for instance runtime
2480

2481
    """
2482
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2483

    
2484
  def GetNodeInfo(self):
2485
    """Return information about the node.
2486

2487
    @return: a dict with the following keys (values in MiB):
2488
          - memory_total: the total memory size on the node
2489
          - memory_free: the available memory on the node for instances
2490
          - memory_dom0: the memory used by the node itself, if available
2491
          - hv_version: the hypervisor version in the form (major, minor,
2492
                        revision)
2493

2494
    """
2495
    result = self.GetLinuxNodeInfo()
2496
    # FIXME: this is the global kvm version, but the actual version can be
2497
    # customized as an hv parameter. we should use the nodegroup's default kvm
2498
    # path parameter here.
2499
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2500
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2501
    return result
2502

    
2503
  @classmethod
2504
  def GetInstanceConsole(cls, instance, hvparams, beparams):
2505
    """Return a command for connecting to the console of an instance.
2506

2507
    """
2508
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2509
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2510
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2511
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2512
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2513
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2514
      return objects.InstanceConsole(instance=instance.name,
2515
                                     kind=constants.CONS_SSH,
2516
                                     host=instance.primary_node,
2517
                                     user=constants.SSH_CONSOLE_USER,
2518
                                     command=cmd)
2519

    
2520
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2521
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2522
      display = instance.network_port - constants.VNC_BASE_PORT
2523
      return objects.InstanceConsole(instance=instance.name,
2524
                                     kind=constants.CONS_VNC,
2525
                                     host=vnc_bind_address,
2526
                                     port=instance.network_port,
2527
                                     display=display)
2528

    
2529
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2530
    if spice_bind:
2531
      return objects.InstanceConsole(instance=instance.name,
2532
                                     kind=constants.CONS_SPICE,
2533
                                     host=spice_bind,
2534
                                     port=instance.network_port)
2535

    
2536
    return objects.InstanceConsole(instance=instance.name,
2537
                                   kind=constants.CONS_MESSAGE,
2538
                                   message=("No serial shell for instance %s" %
2539
                                            instance.name))
2540

    
2541
  def Verify(self):
2542
    """Verify the hypervisor.
2543

2544
    Check that the required binaries exist.
2545

2546
    @return: Problem description if something is wrong, C{None} otherwise
2547

2548
    """
2549
    msgs = []
2550
    # FIXME: this is the global kvm binary, but the actual path can be
2551
    # customized as an hv parameter; we should use the nodegroup's
2552
    # default kvm path parameter here.
2553
    if not os.path.exists(constants.KVM_PATH):
2554
      msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2555
    if not os.path.exists(constants.SOCAT_PATH):
2556
      msgs.append("The socat binary ('%s') does not exist" %
2557
                  constants.SOCAT_PATH)
2558

    
2559
    return self._FormatVerifyResults(msgs)
2560

    
2561
  @classmethod
2562
  def CheckParameterSyntax(cls, hvparams):
2563
    """Check the given parameters for validity.
2564

2565
    @type hvparams:  dict
2566
    @param hvparams: dictionary with parameter names/value
2567
    @raise errors.HypervisorError: when a parameter is not valid
2568

2569
    """
2570
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2571

    
2572
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2573
    if kernel_path:
2574
      if not hvparams[constants.HV_ROOT_PATH]:
2575
        raise errors.HypervisorError("Need a root partition for the instance,"
2576
                                     " if a kernel is defined")
2577

    
2578
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2579
        not hvparams[constants.HV_VNC_X509]):
2580
      raise errors.HypervisorError("%s must be defined, if %s is" %
2581
                                   (constants.HV_VNC_X509,
2582
                                    constants.HV_VNC_X509_VERIFY))
2583

    
2584
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2585
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2586
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2587
      if not serial_speed or serial_speed not in valid_speeds:
2588
        raise errors.HypervisorError("Invalid serial console speed, must be"
2589
                                     " one of: %s" %
2590
                                     utils.CommaJoin(valid_speeds))
2591

    
2592
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2593
    if (boot_order == constants.HT_BO_CDROM and
2594
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2595
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2596
                                   " ISO path")
2597

    
2598
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2599
    if security_model == constants.HT_SM_USER:
2600
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2601
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2602
                                     " must be specified")
2603
    elif (security_model == constants.HT_SM_NONE or
2604
          security_model == constants.HT_SM_POOL):
2605
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2606
        raise errors.HypervisorError("Cannot have a security domain when the"
2607
                                     " security model is 'none' or 'pool'")
2608

    
2609
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2610
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2611
    if spice_bind:
2612
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2613
        # if an IP version is specified, the spice_bind parameter must be an
2614
        # IP of that family
2615
        if (netutils.IP4Address.IsValid(spice_bind) and
2616
            spice_ip_version != constants.IP4_VERSION):
2617
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2618
                                       " the specified IP version is %s" %
2619
                                       (spice_bind, spice_ip_version))
2620

    
2621
        if (netutils.IP6Address.IsValid(spice_bind) and
2622
            spice_ip_version != constants.IP6_VERSION):
2623
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2624
                                       " the specified IP version is %s" %
2625
                                       (spice_bind, spice_ip_version))
2626
    else:
2627
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2628
      # error if any of them is set without it.
2629
      for param in _SPICE_ADDITIONAL_PARAMS:
2630
        if hvparams[param]:
2631
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2632
                                       (param, constants.HV_KVM_SPICE_BIND))
2633

    
2634
  @classmethod
2635
  def ValidateParameters(cls, hvparams):
2636
    """Check the given parameters for validity.
2637

2638
    @type hvparams:  dict
2639
    @param hvparams: dictionary with parameter names/value
2640
    @raise errors.HypervisorError: when a parameter is not valid
2641

2642
    """
2643
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2644

    
2645
    kvm_path = hvparams[constants.HV_KVM_PATH]
2646

    
2647
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2648
    if security_model == constants.HT_SM_USER:
2649
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2650
      try:
2651
        pwd.getpwnam(username)
2652
      except KeyError:
2653
        raise errors.HypervisorError("Unknown security domain user %s"
2654
                                     % username)
2655

    
2656
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2657
    if spice_bind:
2658
      # only one of VNC and SPICE can be used currently.
2659
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2660
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2661
                                     " only one of them can be used at a"
2662
                                     " given time")
2663

    
2664
      # check that KVM supports SPICE
2665
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2666
      if not cls._SPICE_RE.search(kvmhelp):
2667
        raise errors.HypervisorError("SPICE is configured, but it is not"
2668
                                     " supported according to 'kvm --help'")
2669

    
2670
      # if spice_bind is not an IP address, it must be a valid interface
2671
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2672
                       netutils.IP6Address.IsValid(spice_bind))
2673
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2674
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2675
                                     " a valid IP address or interface name" %
2676
                                     constants.HV_KVM_SPICE_BIND)
2677

    
2678
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2679
    if machine_version:
2680
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2681
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2682
        raise errors.HypervisorError("Unsupported machine version: %s" %
2683
                                     machine_version)
2684

    
2685
  @classmethod
2686
  def PowercycleNode(cls):
2687
    """KVM powercycle, just a wrapper over Linux powercycle.
2688

2689
    """
2690
    cls.LinuxPowercycle()