Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 5063d1d5

History | View | Annotate | Download (97.9 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
    # This is needed because QMP can return more than one greetings
489
    # see https://groups.google.com/d/msg/ganeti-devel/gZYcvHKDooU/SnukC8dgS5AJ
490
    self._buf = ""
491

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

    
497
  def _ParseMessage(self, buf):
498
    """Extract and parse a QMP message from the given buffer.
499

500
    Seeks for a QMP message in the given buf. If found, it parses it and
501
    returns it together with the rest of the characters in the buf.
502
    If no message is found, returns None and the whole buffer.
503

504
    @raise errors.ProgrammerError: when there are data serialization errors
505

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

    
518
    return (message, buf)
519

    
520
  def _Recv(self):
521
    """Receives a message from QMP and decodes the received JSON object.
522

523
    @rtype: QmpMessage
524
    @return: the received message
525
    @raise errors.HypervisorError: when there are communication errors
526
    @raise errors.ProgrammerError: when there are data serialization errors
527

528
    """
529
    self._check_connection()
530

    
531
    # Check if there is already a message in the buffer
532
    (message, self._buf) = self._ParseMessage(self._buf)
533
    if message:
534
      return message
535

    
536
    recv_buffer = StringIO.StringIO(self._buf)
537
    recv_buffer.seek(len(self._buf))
538
    try:
539
      while True:
540
        data = self.sock.recv(4096)
541
        if not data:
542
          break
543
        recv_buffer.write(data)
544

    
545
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
546
        if message:
547
          return message
548

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

    
556
  def _Send(self, message):
557
    """Encodes and sends a message to KVM using QMP.
558

559
    @type message: QmpMessage
560
    @param message: message to send to KVM
561
    @raise errors.HypervisorError: when there are communication errors
562
    @raise errors.ProgrammerError: when there are data serialization errors
563

564
    """
565
    self._check_connection()
566
    try:
567
      message_str = str(message)
568
    except Exception, err:
569
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
570

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

    
580
  def Execute(self, command, arguments=None):
581
    """Executes a QMP command and returns the response of the server.
582

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

592
    """
593
    self._check_connection()
594
    message = QmpMessage({self._EXECUTE_KEY: command})
595
    if arguments:
596
      message[self._ARGUMENTS_KEY] = arguments
597
    self._Send(message)
598

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

    
611
      elif not response[self._EVENT_KEY]:
612
        return response
613

    
614

    
615
class KVMHypervisor(hv_base.BaseHypervisor):
616
  """KVM hypervisor interface
617

618
  """
619
  CAN_MIGRATE = True
620

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

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

    
724
  _VIRTIO = "virtio"
725
  _VIRTIO_NET_PCI = "virtio-net-pci"
726
  _VIRTIO_BLK_PCI = "virtio-blk-pci"
727

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

    
735
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
736
  _MIGRATION_INFO_RETRY_DELAY = 2
737

    
738
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
739

    
740
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
741
  _CPU_INFO_CMD = "info cpus"
742
  _CONT_CMD = "cont"
743

    
744
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
745
  _CHECK_MACHINE_VERSION_RE = \
746
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
747

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

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

    
770
  _INFO_VERSION_RE = \
771
    re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
772
  _INFO_VERSION_CMD = "info version"
773

    
774
  _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
775

    
776
  ANCILLARY_FILES = [
777
    _KVM_NETWORK_SCRIPT,
778
    ]
779
  ANCILLARY_FILES_OPT = [
780
    _KVM_NETWORK_SCRIPT,
781
    ]
782

    
783
  # Supported kvm options to get output from
784
  _KVMOPT_HELP = "help"
785
  _KVMOPT_MLIST = "mlist"
786
  _KVMOPT_DEVICELIST = "devicelist"
787

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

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

    
803
  @classmethod
804
  def _InstancePidFile(cls, instance_name):
805
    """Returns the instance pidfile.
806

807
    """
808
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
809

    
810
  @classmethod
811
  def _InstanceUidFile(cls, instance_name):
812
    """Returns the instance uidfile.
813

814
    """
815
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
816

    
817
  @classmethod
818
  def _InstancePidInfo(cls, pid):
819
    """Check pid file for instance information.
820

821
    Check that a pid file is associated with an instance, and retrieve
822
    information from its command line.
823

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

830
    """
831
    alive = utils.IsProcessAlive(pid)
832
    if not alive:
833
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
834

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

    
842
    instance = None
843
    memory = 0
844
    vcpus = 0
845

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

    
856
    if instance is None:
857
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
858
                                   " instance" % pid)
859

    
860
    return (instance, memory, vcpus)
861

    
862
  def _InstancePidAlive(self, instance_name):
863
    """Returns the instance pidfile, pid, and liveness.
864

865
    @type instance_name: string
866
    @param instance_name: instance name
867
    @rtype: tuple
868
    @return: (pid file name, pid, liveness)
869

870
    """
871
    pidfile = self._InstancePidFile(instance_name)
872
    pid = utils.ReadPidFile(pidfile)
873

    
874
    alive = False
875
    try:
876
      cmd_instance = self._InstancePidInfo(pid)[0]
877
      alive = (cmd_instance == instance_name)
878
    except errors.HypervisorError:
879
      pass
880

    
881
    return (pidfile, pid, alive)
882

    
883
  def _CheckDown(self, instance_name):
884
    """Raises an error unless the given instance is down.
885

886
    """
887
    alive = self._InstancePidAlive(instance_name)[2]
888
    if alive:
889
      raise errors.HypervisorError("Failed to start instance %s: %s" %
890
                                   (instance_name, "already running"))
891

    
892
  @classmethod
893
  def _InstanceMonitor(cls, instance_name):
894
    """Returns the instance monitor socket name
895

896
    """
897
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
898

    
899
  @classmethod
900
  def _InstanceSerial(cls, instance_name):
901
    """Returns the instance serial socket name
902

903
    """
904
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
905

    
906
  @classmethod
907
  def _InstanceQmpMonitor(cls, instance_name):
908
    """Returns the instance serial QMP socket name
909

910
    """
911
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
912

    
913
  @staticmethod
914
  def _SocatUnixConsoleParams():
915
    """Returns the correct parameters for socat
916

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

919
    """
920
    if constants.SOCAT_USE_ESCAPE:
921
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
922
    else:
923
      return "echo=0,icanon=0"
924

    
925
  @classmethod
926
  def _InstanceKVMRuntime(cls, instance_name):
927
    """Returns the instance KVM runtime filename
928

929
    """
930
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
931

    
932
  @classmethod
933
  def _InstanceChrootDir(cls, instance_name):
934
    """Returns the name of the KVM chroot dir of the instance
935

936
    """
937
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
938

    
939
  @classmethod
940
  def _InstanceNICDir(cls, instance_name):
941
    """Returns the name of the directory holding the tap device files for a
942
    given instance.
943

944
    """
945
    return utils.PathJoin(cls._NICS_DIR, instance_name)
946

    
947
  @classmethod
948
  def _InstanceNICFile(cls, instance_name, seq):
949
    """Returns the name of the file containing the tap device for a given NIC
950

951
    """
952
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
953

    
954
  @classmethod
955
  def _InstanceKeymapFile(cls, instance_name):
956
    """Returns the name of the file containing the keymap for a given instance
957

958
    """
959
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
960

    
961
  @classmethod
962
  def _TryReadUidFile(cls, uid_file):
963
    """Try to read a uid file
964

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

    
976
  @classmethod
977
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
978
    """Removes an instance's rutime sockets/files/dirs.
979

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

    
1016
  @staticmethod
1017
  def _ConfigureNIC(instance, seq, nic, tap):
1018
    """Run the network configuration script for a specified NIC
1019

1020
    @param instance: instance we're acting on
1021
    @type instance: instance object
1022
    @param seq: nic sequence number
1023
    @type seq: int
1024
    @param nic: nic we're acting on
1025
    @type nic: nic object
1026
    @param tap: the host's tap interface this NIC corresponds to
1027
    @type tap: str
1028

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

    
1041
    if nic.ip:
1042
      env["IP"] = nic.ip
1043

    
1044
    if nic.name:
1045
      env["INTERFACE_NAME"] = nic.name
1046

    
1047
    if nic.nicparams[constants.NIC_LINK]:
1048
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
1049

    
1050
    if nic.network:
1051
      n = objects.Network.FromDict(nic.netinfo)
1052
      env.update(n.HooksDict())
1053

    
1054
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1055
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
1056

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

    
1063
  @staticmethod
1064
  def _VerifyAffinityPackage():
1065
    if affinity is None:
1066
      raise errors.HypervisorError("affinity Python package not"
1067
                                   " found; cannot use CPU pinning under KVM")
1068

    
1069
  @staticmethod
1070
  def _BuildAffinityCpuMask(cpu_list):
1071
    """Create a CPU mask suitable for sched_setaffinity from a list of
1072
    CPUs.
1073

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

1077
    @type cpu_list: list of int
1078
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
1079
    @rtype: int
1080
    @return: a bit mask of CPU affinities
1081

1082
    """
1083
    if cpu_list == constants.CPU_PINNING_OFF:
1084
      return constants.CPU_PINNING_ALL_KVM
1085
    else:
1086
      return sum(2 ** cpu for cpu in cpu_list)
1087

    
1088
  @classmethod
1089
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
1090
    """Change CPU affinity for running VM according to given CPU mask.
1091

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

1100
    """
1101
    # Convert the string CPU mask to a list of list of int's
1102
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
1103

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

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

    
1127
  def _GetVcpuThreadIds(self, instance_name):
1128
    """Get a mapping of vCPU no. to thread IDs for the instance
1129

1130
    @type instance_name: string
1131
    @param instance_name: instance in question
1132
    @rtype: dictionary of int:int
1133
    @return: a dictionary mapping vCPU numbers to thread IDs
1134

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

    
1145
    return result
1146

    
1147
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1148
    """Complete CPU pinning.
1149

1150
    @type instance_name: string
1151
    @param instance_name: name of instance
1152
    @type cpu_mask: string
1153
    @param cpu_mask: CPU pinning mask as entered by user
1154

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

    
1163
  def ListInstances(self):
1164
    """Get the list of running instances.
1165

1166
    We can do this by listing our live instances directory and
1167
    checking whether the associated kvm process is still alive.
1168

1169
    """
1170
    result = []
1171
    for name in os.listdir(self._PIDS_DIR):
1172
      if self._InstancePidAlive(name)[2]:
1173
        result.append(name)
1174
    return result
1175

    
1176
  def GetInstanceInfo(self, instance_name):
1177
    """Get instance properties.
1178

1179
    @type instance_name: string
1180
    @param instance_name: the instance name
1181
    @rtype: tuple of strings
1182
    @return: (name, id, memory, vcpus, stat, times)
1183

1184
    """
1185
    _, pid, alive = self._InstancePidAlive(instance_name)
1186
    if not alive:
1187
      return None
1188

    
1189
    _, memory, vcpus = self._InstancePidInfo(pid)
1190
    istat = "---b-"
1191
    times = "0"
1192

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

    
1204
    return (instance_name, pid, memory, vcpus, istat, times)
1205

    
1206
  def GetAllInstancesInfo(self):
1207
    """Get properties of all instances.
1208

1209
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1210

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

    
1223
  def _GenerateKVMBlockDevicesOptions(self, instance, kvm_disks,
1224
                                      kvmhelp, devlist):
1225
    """Generate KVM options regarding instance's block devices.
1226

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

1238
    """
1239
    hvp = instance.hvparams
1240
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1241
    if kernel_path:
1242
      boot_disk = False
1243
    else:
1244
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1245

    
1246
    # whether this is an older KVM version that uses the boot=on flag
1247
    # on devices
1248
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1249

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

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

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

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

    
1325
      dev_opts.extend(["-drive", drive_val])
1326

    
1327
    return dev_opts
1328

    
1329
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1330
                          kvmhelp):
1331
    """Generate KVM information to start an instance.
1332

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

1342
    """
1343
    # pylint: disable=R0912,R0914,R0915
1344
    hvp = instance.hvparams
1345
    self.ValidateParameters(hvp)
1346

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

    
1354
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1355
    if hvp[constants.HV_CPU_CORES]:
1356
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1357
    if hvp[constants.HV_CPU_THREADS]:
1358
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1359
    if hvp[constants.HV_CPU_SOCKETS]:
1360
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1361

    
1362
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1363

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

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

    
1395
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1396
    if kernel_path:
1397
      boot_cdrom = boot_floppy = boot_network = False
1398
    else:
1399
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1400
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1401
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1402

    
1403
    if startup_paused:
1404
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1405

    
1406
    if boot_network:
1407
      kvm_cmd.extend(["-boot", "n"])
1408

    
1409
    # whether this is an older KVM version that uses the boot=on flag
1410
    # on devices
1411
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1412

    
1413
    disk_type = hvp[constants.HV_DISK_TYPE]
1414

    
1415
    #Now we can specify a different device type for CDROM devices.
1416
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1417
    if not cdrom_disk_type:
1418
      cdrom_disk_type = disk_type
1419

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

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

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

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

    
1474
    mem_path = hvp[constants.HV_MEM_PATH]
1475
    if mem_path:
1476
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1477

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

    
1488
    mouse_type = hvp[constants.HV_USB_MOUSE]
1489
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1490
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1491
    spice_ip_version = None
1492

    
1493
    kvm_cmd.extend(["-usb"])
1494

    
1495
    if mouse_type:
1496
      kvm_cmd.extend(["-usbdevice", mouse_type])
1497
    elif vnc_bind_address:
1498
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1499

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

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

    
1528
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1529

    
1530
      else:
1531
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1532

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

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

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

    
1567
        spice_address = addresses[spice_ip_version][0]
1568

    
1569
      else:
1570
        # spice_bind is known to be a valid IP address, because
1571
        # ValidateParameters checked it.
1572
        spice_address = spice_bind
1573

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

    
1588
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1589
        spice_arg = "%s,disable-ticketing" % spice_arg
1590

    
1591
      if spice_ip_version:
1592
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1593

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

    
1605
      # Video stream detection
1606
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1607
      if video_streaming:
1608
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1609

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

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

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

    
1636
    if hvp[constants.HV_USE_LOCALTIME]:
1637
      kvm_cmd.extend(["-localtime"])
1638

    
1639
    if hvp[constants.HV_KVM_USE_CHROOT]:
1640
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1641

    
1642
    # Add qemu-KVM -cpu param
1643
    if hvp[constants.HV_CPU_TYPE]:
1644
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1645

    
1646
    # As requested by music lovers
1647
    if hvp[constants.HV_SOUNDHW]:
1648
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1649

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

    
1657
    # Various types of usb devices, comma separated
1658
    if hvp[constants.HV_USB_DEVICES]:
1659
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1660
        kvm_cmd.extend(["-usbdevice", dev])
1661

    
1662
    if hvp[constants.HV_KVM_EXTRA]:
1663
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1664

    
1665
    pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1666
    kvm_disks = []
1667
    for disk, link_name in block_devices:
1668
      _UpdatePCISlots(disk, pci_reservations)
1669
      kvm_disks.append((disk, link_name))
1670

    
1671
    kvm_nics = []
1672
    for nic in instance.nics:
1673
      _UpdatePCISlots(nic, pci_reservations)
1674
      kvm_nics.append(nic)
1675

    
1676
    hvparams = hvp
1677

    
1678
    return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1679

    
1680
  def _WriteKVMRuntime(self, instance_name, data):
1681
    """Write an instance's KVM runtime
1682

1683
    """
1684
    try:
1685
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1686
                      data=data)
1687
    except EnvironmentError, err:
1688
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1689

    
1690
  def _ReadKVMRuntime(self, instance_name):
1691
    """Read an instance's KVM runtime
1692

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

    
1700
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1701
    """Save an instance's KVM runtime
1702

1703
    """
1704
    kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1705

    
1706
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1707
    serialized_disks = [(blk.ToDict(), link)
1708
                            for blk, link in kvm_disks]
1709
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1710
                                      serialized_disks))
1711

    
1712
    self._WriteKVMRuntime(instance.name, serialized_form)
1713

    
1714
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1715
    """Load an instance's KVM runtime
1716

1717
    """
1718
    if not serialized_runtime:
1719
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1720

    
1721
    return _AnalyzeSerializedRuntime(serialized_runtime)
1722

    
1723
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1724
    """Run the KVM cmd and check for errors
1725

1726
    @type name: string
1727
    @param name: instance name
1728
    @type kvm_cmd: list of strings
1729
    @param kvm_cmd: runcmd input for kvm
1730
    @type tap_fds: list of int
1731
    @param tap_fds: fds of tap devices opened by Ganeti
1732

1733
    """
1734
    try:
1735
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1736
    finally:
1737
      for fd in tap_fds:
1738
        utils_wrapper.CloseFdNoError(fd)
1739

    
1740
    if result.failed:
1741
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1742
                                   (name, result.fail_reason, result.output))
1743
    if not self._InstancePidAlive(name)[2]:
1744
      raise errors.HypervisorError("Failed to start instance %s" % name)
1745

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

1751
    @type incoming: tuple of strings
1752
    @param incoming: (target_host_ip, port)
1753
    @type kvmhelp: string
1754
    @param kvmhelp: output of kvm --help
1755

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

    
1769
    temp_files = []
1770

    
1771
    kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1772
    # the first element of kvm_cmd is always the path to the kvm binary
1773
    kvm_path = kvm_cmd[0]
1774
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1775

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

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

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

    
1799
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1800
                                                     kvm_disks,
1801
                                                     kvmhelp,
1802
                                                     devlist)
1803
    kvm_cmd.extend(bdev_opts)
1804

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

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

    
1832
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1833

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

    
1858
    if incoming:
1859
      target, port = incoming
1860
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1861

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

    
1874
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1875
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1876
                         constants.SECURE_DIR_MODE)])
1877

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

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

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

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

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

    
1924
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1925
                     constants.RUN_DIRS_MODE)])
1926
    for nic_seq, tap in enumerate(taps):
1927
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1928
                      data=tap)
1929

    
1930
    if vnc_pwd:
1931
      change_cmd = "change vnc password %s" % vnc_pwd
1932
      self._CallMonitorCommand(instance.name, change_cmd)
1933

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

    
1948
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1949
      qmp.connect()
1950
      arguments = {
1951
          "protocol": "spice",
1952
          "password": spice_pwd,
1953
      }
1954
      qmp.Execute("set_password", arguments)
1955

    
1956
    for filename in temp_files:
1957
      utils.RemoveFile(filename)
1958

    
1959
    # If requested, set CPU affinity and resume instance execution
1960
    if cpu_pinning:
1961
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1962

    
1963
    start_memory = self._InstanceStartupMemory(instance)
1964
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1965
      self.BalloonInstanceMemory(instance, start_memory)
1966

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

    
1973
  def StartInstance(self, instance, block_devices, startup_paused):
1974
    """Start an instance.
1975

1976
    """
1977
    self._CheckDown(instance.name)
1978
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1979
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1980
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1981
                                           startup_paused, kvmhelp)
1982
    self._SaveKVMRuntime(instance, kvm_runtime)
1983
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1984

    
1985
  def _CallMonitorCommand(self, instance_name, command):
1986
    """Invoke a command on the instance monitor.
1987

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

    
2007
    return result
2008

    
2009
  def _GetFreePCISlot(self, instance, dev):
2010
    """Get the first available pci slot of a runnung instance.
2011

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

    
2022
    [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
2023
    if not free:
2024
      raise errors.HypervisorError("All PCI slots occupied")
2025

    
2026
    dev.pci = int(free)
2027

    
2028
  def VerifyHotplugSupport(self, instance, action, dev_type):
2029
    """Verifies that hotplug is supported.
2030

2031
    Hotplug is *not* supported in case of:
2032
     - security models and chroot (disk hotplug)
2033
     - fdsend module is missing (nic hot-add)
2034

2035
    @raise errors.HypervisorError: in one of the previous cases
2036

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

    
2049
    if (dev_type == constants.HOTPLUG_TARGET_NIC and
2050
        action == constants.HOTPLUG_ACTION_ADD and not fdsend):
2051
      raise errors.HotplugError("Cannot hot-add NIC."
2052
                                " fdsend python module is missing.")
2053

    
2054
  def HotplugSupported(self, instance):
2055
    """Checks if hotplug is generally supported.
2056

2057
    Hotplug is *not* supported in case of:
2058
     - qemu versions < 1.0
2059
     - for stopped instances
2060

2061
    @raise errors.HypervisorError: in one of the previous cases
2062

2063
    """
2064
    try:
2065
      output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2066
    except errors.HypervisorError:
2067
      raise errors.HotplugError("Instance is probably down")
2068

    
2069
    # TODO: search for netdev_add, drive_add, device_add.....
2070
    match = self._INFO_VERSION_RE.search(output.stdout)
2071
    if not match:
2072
      raise errors.HotplugError("Cannot parse qemu version via monitor")
2073

    
2074
    v_major, v_min, _, _ = match.groups()
2075
    if (int(v_major), int(v_min)) < (1, 0):
2076
      raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2077

    
2078
  def _CallHotplugCommands(self, name, cmds):
2079
    for c in cmds:
2080
      self._CallMonitorCommand(name, c)
2081
      time.sleep(1)
2082

    
2083
  def _VerifyHotplugCommand(self, instance_name, device, dev_type,
2084
                            should_exist):
2085
    """Checks if a previous hotplug command has succeeded.
2086

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

2090
    @raise errors.HypervisorError: if result is not the expected one
2091

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

    
2101
    if not match and should_exist:
2102
      msg = "Device %s should have been added but is missing" % kvm_devid
2103
      raise errors.HypervisorError(msg)
2104

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

    
2107
  def HotAddDevice(self, instance, dev_type, device, extra, seq):
2108
    """ Helper method to hot-add a new device
2109

2110
    It gets free pci slot generates the device name and invokes the
2111
    device specific method.
2112

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

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

    
2142
  def HotDelDevice(self, instance, dev_type, device, _, seq):
2143
    """ Helper method for hot-del device
2144

2145
    It gets device info from runtime file, generates the device name and
2146
    invokes the device specific method.
2147

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

    
2166
    return kvm_device.pci
2167

    
2168
  def HotModDevice(self, instance, dev_type, device, _, seq):
2169
    """ Helper method for hot-mod device
2170

2171
    It gets device info from runtime file, generates the device name and
2172
    invokes the device specific method. Currently only NICs support hot-mod
2173

2174
    """
2175
    if dev_type == constants.HOTPLUG_TARGET_NIC:
2176
      # putting it back in the same pci slot
2177
      try:
2178
        device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2179
      except errors.HotplugError:
2180
        logging.info("Device not found in runtime file. Assuming it was"
2181
                     " previously added without --hotplug option.")
2182
      # TODO: remove sleep when socat gets removed
2183
      self.HotAddDevice(instance, dev_type, device, _, seq)
2184

    
2185
  def _PassTapFd(self, instance, fd, nic):
2186
    """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2187

2188
    """
2189
    # TODO: factor out code related to unix sockets.
2190
    #       squash common parts between monitor and qmp
2191
    kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2192
    command = "getfd %s\n" % kvm_devid
2193
    fds = [fd]
2194
    logging.info("%s", fds)
2195
    try:
2196
      monsock = MonitorSocket(self._InstanceMonitor(instance.name))
2197
      monsock.connect()
2198
      fdsend.sendfds(monsock.sock, command, fds=fds)
2199
    finally:
2200
      monsock.close()
2201

    
2202
  @classmethod
2203
  def _ParseKVMVersion(cls, text):
2204
    """Parse the KVM version from the --help output.
2205

2206
    @type text: string
2207
    @param text: output of kvm --help
2208
    @return: (version, v_maj, v_min, v_rev)
2209
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2210

2211
    """
2212
    match = cls._VERSION_RE.search(text.splitlines()[0])
2213
    if not match:
2214
      raise errors.HypervisorError("Unable to get KVM version")
2215

    
2216
    v_all = match.group(0)
2217
    v_maj = int(match.group(1))
2218
    v_min = int(match.group(2))
2219
    if match.group(4):
2220
      v_rev = int(match.group(4))
2221
    else:
2222
      v_rev = 0
2223
    return (v_all, v_maj, v_min, v_rev)
2224

    
2225
  @classmethod
2226
  def _GetKVMOutput(cls, kvm_path, option):
2227
    """Return the output of a kvm invocation
2228

2229
    @type kvm_path: string
2230
    @param kvm_path: path to the kvm executable
2231
    @type option: a key of _KVMOPTS_CMDS
2232
    @param option: kvm option to fetch the output from
2233
    @return: output a supported kvm invocation
2234
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2235

2236
    """
2237
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2238

    
2239
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
2240

    
2241
    result = utils.RunCmd([kvm_path] + optlist)
2242
    if result.failed and not can_fail:
2243
      raise errors.HypervisorError("Unable to get KVM %s output" %
2244
                                    " ".join(optlist))
2245
    return result.output
2246

    
2247
  @classmethod
2248
  def _GetKVMVersion(cls, kvm_path):
2249
    """Return the installed KVM version.
2250

2251
    @return: (version, v_maj, v_min, v_rev)
2252
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2253

2254
    """
2255
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2256

    
2257
  @classmethod
2258
  def _GetDefaultMachineVersion(cls, kvm_path):
2259
    """Return the default hardware revision (e.g. pc-1.1)
2260

2261
    """
2262
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2263
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2264
    if match:
2265
      return match.group(1)
2266
    else:
2267
      return "pc"
2268

    
2269
  def StopInstance(self, instance, force=False, retry=False, name=None):
2270
    """Stop an instance.
2271

2272
    """
2273
    if name is not None and not force:
2274
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2275
    if name is None:
2276
      name = instance.name
2277
      acpi = instance.hvparams[constants.HV_ACPI]
2278
    else:
2279
      acpi = False
2280
    _, pid, alive = self._InstancePidAlive(name)
2281
    if pid > 0 and alive:
2282
      if force or not acpi:
2283
        utils.KillProcess(pid)
2284
      else:
2285
        self._CallMonitorCommand(name, "system_powerdown")
2286

    
2287
  def CleanupInstance(self, instance_name):
2288
    """Cleanup after a stopped instance
2289

2290
    """
2291
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
2292
    if pid > 0 and alive:
2293
      raise errors.HypervisorError("Cannot cleanup a live instance")
2294
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2295

    
2296
  def RebootInstance(self, instance):
2297
    """Reboot an instance.
2298

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

    
2319
  def MigrationInfo(self, instance):
2320
    """Get instance information to perform a migration.
2321

2322
    @type instance: L{objects.Instance}
2323
    @param instance: instance to be migrated
2324
    @rtype: string
2325
    @return: content of the KVM runtime file
2326

2327
    """
2328
    return self._ReadKVMRuntime(instance.name)
2329

    
2330
  def AcceptInstance(self, instance, info, target):
2331
    """Prepare to accept an instance.
2332

2333
    @type instance: L{objects.Instance}
2334
    @param instance: instance to be accepted
2335
    @type info: string
2336
    @param info: content of the KVM runtime file on the source node
2337
    @type target: string
2338
    @param target: target host (usually ip), on this node
2339

2340
    """
2341
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2342
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2343
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2344
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2345
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2346
                            incoming=incoming_address)
2347

    
2348
  def FinalizeMigrationDst(self, instance, info, success):
2349
    """Finalize the instance migration on the target node.
2350

2351
    Stop the incoming mode KVM.
2352

2353
    @type instance: L{objects.Instance}
2354
    @param instance: instance whose migration is being finalized
2355

2356
    """
2357
    if success:
2358
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2359
      kvm_nics = kvm_runtime[1]
2360

    
2361
      for nic_seq, nic in enumerate(kvm_nics):
2362
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2363
          # Bridged interfaces have already been configured
2364
          continue
2365
        try:
2366
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2367
        except EnvironmentError, err:
2368
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
2369
                          instance.name, nic_seq, str(err))
2370
          continue
2371
        try:
2372
          self._ConfigureNIC(instance, nic_seq, nic, tap)
2373
        except errors.HypervisorError, err:
2374
          logging.warning(str(err))
2375

    
2376
      self._WriteKVMRuntime(instance.name, info)
2377
    else:
2378
      self.StopInstance(instance, force=True)
2379

    
2380
  def MigrateInstance(self, instance, target, live):
2381
    """Migrate an instance to a target node.
2382

2383
    The migration will not be attempted if the instance is not
2384
    currently running.
2385

2386
    @type instance: L{objects.Instance}
2387
    @param instance: the instance to be migrated
2388
    @type target: string
2389
    @param target: ip address of the target node
2390
    @type live: boolean
2391
    @param live: perform a live migration
2392

2393
    """
2394
    instance_name = instance.name
2395
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
2396
    _, _, alive = self._InstancePidAlive(instance_name)
2397
    if not alive:
2398
      raise errors.HypervisorError("Instance not running, cannot migrate")
2399

    
2400
    if not live:
2401
      self._CallMonitorCommand(instance_name, "stop")
2402

    
2403
    migrate_command = ("migrate_set_speed %dm" %
2404
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2405
    self._CallMonitorCommand(instance_name, migrate_command)
2406

    
2407
    migrate_command = ("migrate_set_downtime %dms" %
2408
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2409
    self._CallMonitorCommand(instance_name, migrate_command)
2410

    
2411
    # These commands are supported in latest qemu versions.
2412
    # Since _CallMonitorCommand does not catch monitor errors
2413
    # this does not raise an exception in case command is not supported
2414
    # TODO: either parse output of command or see if the command supported
2415
    # via info help (see hotplug)
2416
    migrate_command = ("migrate_set_capability xbzrle on")
2417
    self._CallMonitorCommand(instance_name, migrate_command)
2418

    
2419
    migrate_command = ("migrate_set_capability auto-converge on")
2420
    self._CallMonitorCommand(instance_name, migrate_command)
2421

    
2422
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2423
    self._CallMonitorCommand(instance_name, migrate_command)
2424

    
2425
  def FinalizeMigrationSource(self, instance, success, live):
2426
    """Finalize the instance migration on the source node.
2427

2428
    @type instance: L{objects.Instance}
2429
    @param instance: the instance that was migrated
2430
    @type success: bool
2431
    @param success: whether the migration succeeded or not
2432
    @type live: bool
2433
    @param live: whether the user requested a live migration or not
2434

2435
    """
2436
    if success:
2437
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2438
      utils.KillProcess(pid)
2439
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2440
    elif live:
2441
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2442

    
2443
  def GetMigrationStatus(self, instance):
2444
    """Get the migration status
2445

2446
    @type instance: L{objects.Instance}
2447
    @param instance: the instance that is being migrated
2448
    @rtype: L{objects.MigrationStatus}
2449
    @return: the status of the current migration (one of
2450
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2451
             progress info that can be retrieved from the hypervisor
2452

2453
    """
2454
    info_command = "info migrate"
2455
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2456
      result = self._CallMonitorCommand(instance.name, info_command)
2457
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
2458
      if not match:
2459
        if not result.stdout:
2460
          logging.info("KVM: empty 'info migrate' result")
2461
        else:
2462
          logging.warning("KVM: unknown 'info migrate' result: %s",
2463
                          result.stdout)
2464
      else:
2465
        status = match.group(1)
2466
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2467
          migration_status = objects.MigrationStatus(status=status)
2468
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2469
          if match:
2470
            migration_status.transferred_ram = match.group("transferred")
2471
            migration_status.total_ram = match.group("total")
2472

    
2473
          return migration_status
2474

    
2475
        logging.warning("KVM: unknown migration status '%s'", status)
2476

    
2477
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2478

    
2479
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2480

    
2481
  def BalloonInstanceMemory(self, instance, mem):
2482
    """Balloon an instance memory to a certain value.
2483

2484
    @type instance: L{objects.Instance}
2485
    @param instance: instance to be accepted
2486
    @type mem: int
2487
    @param mem: actual memory size to use for instance runtime
2488

2489
    """
2490
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2491

    
2492
  def GetNodeInfo(self):
2493
    """Return information about the node.
2494

2495
    @return: a dict with the following keys (values in MiB):
2496
          - memory_total: the total memory size on the node
2497
          - memory_free: the available memory on the node for instances
2498
          - memory_dom0: the memory used by the node itself, if available
2499
          - hv_version: the hypervisor version in the form (major, minor,
2500
                        revision)
2501

2502
    """
2503
    result = self.GetLinuxNodeInfo()
2504
    # FIXME: this is the global kvm version, but the actual version can be
2505
    # customized as an hv parameter. we should use the nodegroup's default kvm
2506
    # path parameter here.
2507
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2508
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2509
    return result
2510

    
2511
  @classmethod
2512
  def GetInstanceConsole(cls, instance, hvparams, beparams):
2513
    """Return a command for connecting to the console of an instance.
2514

2515
    """
2516
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2517
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2518
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2519
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2520
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2521
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2522
      return objects.InstanceConsole(instance=instance.name,
2523
                                     kind=constants.CONS_SSH,
2524
                                     host=instance.primary_node,
2525
                                     user=constants.SSH_CONSOLE_USER,
2526
                                     command=cmd)
2527

    
2528
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2529
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2530
      display = instance.network_port - constants.VNC_BASE_PORT
2531
      return objects.InstanceConsole(instance=instance.name,
2532
                                     kind=constants.CONS_VNC,
2533
                                     host=vnc_bind_address,
2534
                                     port=instance.network_port,
2535
                                     display=display)
2536

    
2537
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2538
    if spice_bind:
2539
      return objects.InstanceConsole(instance=instance.name,
2540
                                     kind=constants.CONS_SPICE,
2541
                                     host=spice_bind,
2542
                                     port=instance.network_port)
2543

    
2544
    return objects.InstanceConsole(instance=instance.name,
2545
                                   kind=constants.CONS_MESSAGE,
2546
                                   message=("No serial shell for instance %s" %
2547
                                            instance.name))
2548

    
2549
  def Verify(self):
2550
    """Verify the hypervisor.
2551

2552
    Check that the required binaries exist.
2553

2554
    @return: Problem description if something is wrong, C{None} otherwise
2555

2556
    """
2557
    msgs = []
2558
    # FIXME: this is the global kvm binary, but the actual path can be
2559
    # customized as an hv parameter; we should use the nodegroup's
2560
    # default kvm path parameter here.
2561
    if not os.path.exists(constants.KVM_PATH):
2562
      msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2563
    if not os.path.exists(constants.SOCAT_PATH):
2564
      msgs.append("The socat binary ('%s') does not exist" %
2565
                  constants.SOCAT_PATH)
2566

    
2567
    return self._FormatVerifyResults(msgs)
2568

    
2569
  @classmethod
2570
  def CheckParameterSyntax(cls, hvparams):
2571
    """Check the given parameters for validity.
2572

2573
    @type hvparams:  dict
2574
    @param hvparams: dictionary with parameter names/value
2575
    @raise errors.HypervisorError: when a parameter is not valid
2576

2577
    """
2578
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2579

    
2580
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2581
    if kernel_path:
2582
      if not hvparams[constants.HV_ROOT_PATH]:
2583
        raise errors.HypervisorError("Need a root partition for the instance,"
2584
                                     " if a kernel is defined")
2585

    
2586
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2587
        not hvparams[constants.HV_VNC_X509]):
2588
      raise errors.HypervisorError("%s must be defined, if %s is" %
2589
                                   (constants.HV_VNC_X509,
2590
                                    constants.HV_VNC_X509_VERIFY))
2591

    
2592
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2593
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2594
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2595
      if not serial_speed or serial_speed not in valid_speeds:
2596
        raise errors.HypervisorError("Invalid serial console speed, must be"
2597
                                     " one of: %s" %
2598
                                     utils.CommaJoin(valid_speeds))
2599

    
2600
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2601
    if (boot_order == constants.HT_BO_CDROM and
2602
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2603
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2604
                                   " ISO path")
2605

    
2606
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2607
    if security_model == constants.HT_SM_USER:
2608
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2609
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2610
                                     " must be specified")
2611
    elif (security_model == constants.HT_SM_NONE or
2612
          security_model == constants.HT_SM_POOL):
2613
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2614
        raise errors.HypervisorError("Cannot have a security domain when the"
2615
                                     " security model is 'none' or 'pool'")
2616

    
2617
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2618
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2619
    if spice_bind:
2620
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2621
        # if an IP version is specified, the spice_bind parameter must be an
2622
        # IP of that family
2623
        if (netutils.IP4Address.IsValid(spice_bind) and
2624
            spice_ip_version != constants.IP4_VERSION):
2625
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2626
                                       " the specified IP version is %s" %
2627
                                       (spice_bind, spice_ip_version))
2628

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

    
2642
  @classmethod
2643
  def ValidateParameters(cls, hvparams):
2644
    """Check the given parameters for validity.
2645

2646
    @type hvparams:  dict
2647
    @param hvparams: dictionary with parameter names/value
2648
    @raise errors.HypervisorError: when a parameter is not valid
2649

2650
    """
2651
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2652

    
2653
    kvm_path = hvparams[constants.HV_KVM_PATH]
2654

    
2655
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2656
    if security_model == constants.HT_SM_USER:
2657
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2658
      try:
2659
        pwd.getpwnam(username)
2660
      except KeyError:
2661
        raise errors.HypervisorError("Unknown security domain user %s"
2662
                                     % username)
2663

    
2664
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2665
    if spice_bind:
2666
      # only one of VNC and SPICE can be used currently.
2667
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2668
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2669
                                     " only one of them can be used at a"
2670
                                     " given time")
2671

    
2672
      # check that KVM supports SPICE
2673
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2674
      if not cls._SPICE_RE.search(kvmhelp):
2675
        raise errors.HypervisorError("SPICE is configured, but it is not"
2676
                                     " supported according to 'kvm --help'")
2677

    
2678
      # if spice_bind is not an IP address, it must be a valid interface
2679
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2680
                       netutils.IP6Address.IsValid(spice_bind))
2681
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2682
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2683
                                     " a valid IP address or interface name" %
2684
                                     constants.HV_KVM_SPICE_BIND)
2685

    
2686
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2687
    if machine_version:
2688
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2689
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2690
        raise errors.HypervisorError("Unsupported machine version: %s" %
2691
                                     machine_version)
2692

    
2693
  @classmethod
2694
  def PowercycleNode(cls):
2695
    """KVM powercycle, just a wrapper over Linux powercycle.
2696

2697
    """
2698
    cls.LinuxPowercycle()