Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 066f16b0

History | View | Annotate | Download (97.8 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, uri)
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, u) for (d, l, u) 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, None)
115
  }
116

    
117

    
118
def _GenerateDeviceKVMId(dev_type, dev):
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
  if not dev.pci:
134
    raise errors.HotplugError("Hotplug is not supported for %s with UUID %s" %
135
                              (dev_type, dev.uuid))
136

    
137
  return "%s-%s-pci-%d" % (dev_type.lower(), dev.uuid.split("-")[0], dev.pci)
138

    
139

    
140
def _UpdatePCISlots(dev, pci_reservations):
141
  """Update pci configuration for a stopped instance
142

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

147
  @type dev: L{objects.Disk} or L{objects.NIC}
148
  @param dev: the device object for which we update its pci slot
149
  @type pci_reservations: bitarray
150
  @param pci_reservations: existing pci reservations for an instance
151
  @raise errors.HotplugError: in case an instance has all its slot occupied
152

153
  """
154
  if dev.pci:
155
    free = dev.pci
156
  else: # pylint: disable=E1103
157
    [free] = pci_reservations.search(_AVAILABLE_PCI_SLOT, 1)
158
    if not free:
159
      raise errors.HypervisorError("All PCI slots occupied")
160
    dev.pci = int(free)
161

    
162
  pci_reservations[free] = True
163

    
164

    
165
def _GetExistingDeviceInfo(dev_type, device, runtime):
166
  """Helper function to get an existing device inside the runtime file
167

168
  Used when an instance is running. Load kvm runtime file and search
169
  for a device based on its type and uuid.
170

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

181
  """
182
  index = _DEVICE_RUNTIME_INDEX[dev_type]
183
  found = _FIND_RUNTIME_ENTRY[dev_type](device, runtime[index])
184
  if not found:
185
    raise errors.HotplugError("Cannot find runtime info for %s with UUID %s" %
186
                              (dev_type, device.uuid))
187

    
188
  return found[0]
189

    
190

    
191
def _UpgradeSerializedRuntime(serialized_runtime):
192
  """Upgrade runtime data
193

194
  Remove any deprecated fields or change the format of the data.
195
  The runtime files are not upgraded when Ganeti is upgraded, so the required
196
  modification have to be performed here.
197

198
  @type serialized_runtime: string
199
  @param serialized_runtime: raw text data read from actual runtime file
200
  @return: (cmd, nic dicts, hvparams, bdev dicts)
201
  @rtype: tuple
202

203
  """
204
  loaded_runtime = serializer.Load(serialized_runtime)
205
  kvm_cmd, serialized_nics, hvparams = loaded_runtime[:3]
206
  if len(loaded_runtime) >= 4:
207
    serialized_disks = loaded_runtime[3]
208
  else:
209
    serialized_disks = []
210

    
211
  for nic in serialized_nics:
212
    # Add a dummy uuid slot if an pre-2.8 NIC is found
213
    if "uuid" not in nic:
214
      nic["uuid"] = utils.NewUUID()
215

    
216
  return kvm_cmd, serialized_nics, hvparams, serialized_disks
217

    
218

    
219
def _AnalyzeSerializedRuntime(serialized_runtime):
220
  """Return runtime entries for a serialized runtime file
221

222
  @type serialized_runtime: string
223
  @param serialized_runtime: raw text data read from actual runtime file
224
  @return: (cmd, nics, hvparams, bdevs)
225
  @rtype: tuple
226

227
  """
228
  kvm_cmd, serialized_nics, hvparams, serialized_disks = \
229
    _UpgradeSerializedRuntime(serialized_runtime)
230
  kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
231
  kvm_disks = [(objects.Disk.FromDict(sdisk), link, uri)
232
               for sdisk, link, uri in serialized_disks]
233

    
234
  return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
235

    
236

    
237
def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
238
  """Retrieves supported TUN features from file descriptor.
239

240
  @see: L{_ProbeTapVnetHdr}
241

242
  """
243
  req = struct.pack("I", 0)
244
  try:
245
    buf = _ioctl(fd, TUNGETFEATURES, req)
246
  except EnvironmentError, err:
247
    logging.warning("ioctl(TUNGETFEATURES) failed: %s", err)
248
    return None
249
  else:
250
    (flags, ) = struct.unpack("I", buf)
251
    return flags
252

    
253

    
254
def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
255
  """Check whether to enable the IFF_VNET_HDR flag.
256

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

267
   @type fd: int
268
   @param fd: the file descriptor of /dev/net/tun
269

270
  """
271
  flags = _features_fn(fd)
272

    
273
  if flags is None:
274
    # Not supported
275
    return False
276

    
277
  result = bool(flags & IFF_VNET_HDR)
278

    
279
  if not result:
280
    logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
281

    
282
  return result
283

    
284

    
285
def _OpenTap(vnet_hdr=True):
286
  """Open a new tap device and return its file descriptor.
287

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

291
  @type vnet_hdr: boolean
292
  @param vnet_hdr: Enable the VNET Header
293
  @return: (ifname, tapfd)
294
  @rtype: tuple
295

296
  """
297
  try:
298
    tapfd = os.open("/dev/net/tun", os.O_RDWR)
299
  except EnvironmentError:
300
    raise errors.HypervisorError("Failed to open /dev/net/tun")
301

    
302
  flags = IFF_TAP | IFF_NO_PI
303

    
304
  if vnet_hdr and _ProbeTapVnetHdr(tapfd):
305
    flags |= IFF_VNET_HDR
306

    
307
  # The struct ifreq ioctl request (see netdevice(7))
308
  ifr = struct.pack("16sh", "", flags)
309

    
310
  try:
311
    res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
312
  except EnvironmentError, err:
313
    raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
314
                                 err)
315

    
316
  # Get the interface name from the ioctl
317
  ifname = struct.unpack("16sh", res)[0].strip("\x00")
318
  return (ifname, tapfd)
319

    
320

    
321
class QmpMessage:
322
  """QEMU Messaging Protocol (QMP) message.
323

324
  """
325
  def __init__(self, data):
326
    """Creates a new QMP message based on the passed data.
327

328
    """
329
    if not isinstance(data, dict):
330
      raise TypeError("QmpMessage must be initialized with a dict")
331

    
332
    self.data = data
333

    
334
  def __getitem__(self, field_name):
335
    """Get the value of the required field if present, or None.
336

337
    Overrides the [] operator to provide access to the message data,
338
    returning None if the required item is not in the message
339
    @return: the value of the field_name field, or None if field_name
340
             is not contained in the message
341

342
    """
343
    return self.data.get(field_name, None)
344

    
345
  def __setitem__(self, field_name, field_value):
346
    """Set the value of the required field_name to field_value.
347

348
    """
349
    self.data[field_name] = field_value
350

    
351
  def __len__(self):
352
    """Return the number of fields stored in this QmpMessage.
353

354
    """
355
    return len(self.data)
356

    
357
  def __delitem__(self, key):
358
    """Delete the specified element from the QmpMessage.
359

360
    """
361
    del(self.data[key])
362

    
363
  @staticmethod
364
  def BuildFromJsonString(json_string):
365
    """Build a QmpMessage from a JSON encoded string.
366

367
    @type json_string: str
368
    @param json_string: JSON string representing the message
369
    @rtype: L{QmpMessage}
370
    @return: a L{QmpMessage} built from json_string
371

372
    """
373
    # Parse the string
374
    data = serializer.LoadJson(json_string)
375
    return QmpMessage(data)
376

    
377
  def __str__(self):
378
    # The protocol expects the JSON object to be sent as a single line.
379
    return serializer.DumpJson(self.data)
380

    
381
  def __eq__(self, other):
382
    # When comparing two QmpMessages, we are interested in comparing
383
    # their internal representation of the message data
384
    return self.data == other.data
385

    
386

    
387
class MonitorSocket(object):
388
  _SOCKET_TIMEOUT = 5
389

    
390
  def __init__(self, monitor_filename):
391
    """Instantiates the MonitorSocket object.
392

393
    @type monitor_filename: string
394
    @param monitor_filename: the filename of the UNIX raw socket on which the
395
                             monitor (QMP or simple one) is listening
396

397
    """
398
    self.monitor_filename = monitor_filename
399
    self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
400
    # We want to fail if the server doesn't send a complete message
401
    # in a reasonable amount of time
402
    self.sock.settimeout(self._SOCKET_TIMEOUT)
403
    self._connected = False
404

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

    
418
  def _check_connection(self):
419
    """Make sure that the connection is established.
420

421
    """
422
    if not self._connected:
423
      raise errors.ProgrammerError("To use a MonitorSocket you need to first"
424
                                   " invoke connect() on it")
425

    
426
  def connect(self):
427
    """Connects to the monitor.
428

429
    Connects to the UNIX socket
430

431
    @raise errors.HypervisorError: when there are communication errors
432

433
    """
434
    if self._connected:
435
      raise errors.ProgrammerError("Cannot connect twice")
436

    
437
    self._check_socket()
438

    
439
    # Check file existance/stuff
440
    try:
441
      self.sock.connect(self.monitor_filename)
442
    except EnvironmentError:
443
      raise errors.HypervisorError("Can't connect to qmp socket")
444
    self._connected = True
445

    
446
  def close(self):
447
    """Closes the socket
448

449
    It cannot be used after this call.
450

451
    """
452
    self.sock.close()
453

    
454

    
455
class QmpConnection(MonitorSocket):
456
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
457

458
  """
459
  _FIRST_MESSAGE_KEY = "QMP"
460
  _EVENT_KEY = "event"
461
  _ERROR_KEY = "error"
462
  _RETURN_KEY = RETURN_KEY = "return"
463
  _ACTUAL_KEY = ACTUAL_KEY = "actual"
464
  _ERROR_CLASS_KEY = "class"
465
  _ERROR_DESC_KEY = "desc"
466
  _EXECUTE_KEY = "execute"
467
  _ARGUMENTS_KEY = "arguments"
468
  _CAPABILITIES_COMMAND = "qmp_capabilities"
469
  _MESSAGE_END_TOKEN = "\r\n"
470

    
471
  def __init__(self, monitor_filename):
472
    super(QmpConnection, self).__init__(monitor_filename)
473
    self._buf = ""
474

    
475
  def connect(self):
476
    """Connects to the QMP monitor.
477

478
    Connects to the UNIX socket and makes sure that we can actually send and
479
    receive data to the kvm instance via QMP.
480

481
    @raise errors.HypervisorError: when there are communication errors
482
    @raise errors.ProgrammerError: when there are data serialization errors
483

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

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

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

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

506
    @raise errors.ProgrammerError: when there are data serialization errors
507

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

    
520
    return (message, buf)
521

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

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

530
    """
531
    self._check_connection()
532

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

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

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

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

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

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

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

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

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

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

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

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

    
613
      elif not response[self._EVENT_KEY]:
614
        return response
615

    
616

    
617
class KVMHypervisor(hv_base.BaseHypervisor):
618
  """KVM hypervisor interface
619

620
  """
621
  CAN_MIGRATE = True
622

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

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

    
722
  _VIRTIO = "virtio"
723
  _VIRTIO_NET_PCI = "virtio-net-pci"
724
  _VIRTIO_BLK_PCI = "virtio-blk-pci"
725

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

    
733
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
734
  _MIGRATION_INFO_RETRY_DELAY = 2
735

    
736
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
737

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

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

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

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

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

    
773
  _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
774

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
859
    return (instance, memory, vcpus)
860

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

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

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

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

    
880
    return (pidfile, pid, alive)
881

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1144
    return result
1145

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

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

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

    
1162
  def ListInstances(self, hvparams=None):
1163
    """Get the list of running instances.
1164

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

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

    
1175
  def GetInstanceInfo(self, instance_name, hvparams=None):
1176
    """Get instance properties.
1177

1178
    @type instance_name: string
1179
    @param instance_name: the instance name
1180
    @type hvparams: dict of strings
1181
    @param hvparams: hvparams to be used with this instance
1182
    @rtype: tuple of strings
1183
    @return: (name, id, memory, vcpus, stat, times)
1184

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

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

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

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

    
1207
  def GetAllInstancesInfo(self, hvparams=None):
1208
    """Get properties of all instances.
1209

1210
    @type hvparams: dict of strings
1211
    @param hvparams: hypervisor parameter
1212
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1213

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

    
1226
  def _GenerateKVMBlockDevicesOptions(self, instance, kvm_disks,
1227
                                      kvmhelp, devlist):
1228
    """Generate KVM options regarding instance's block devices.
1229

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

1241
    """
1242
    hvp = instance.hvparams
1243
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1244
    if kernel_path:
1245
      boot_disk = False
1246
    else:
1247
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1248

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

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

    
1292
      access_mode = cfdev.params.get(constants.LDP_ACCESS,
1293
                                     constants.DISK_KERNELSPACE)
1294
      if (uri and access_mode == constants.DISK_USERSPACE):
1295
        drive_uri = uri
1296
      else:
1297
        drive_uri = link_name
1298

    
1299
      drive_val = "file=%s,format=raw%s%s%s" % \
1300
                  (drive_uri, if_val, boot_val, cache_val)
1301

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

    
1314
      dev_opts.extend(["-drive", drive_val])
1315

    
1316
    return dev_opts
1317

    
1318
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1319
                          kvmhelp):
1320
    """Generate KVM information to start an instance.
1321

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

1331
    """
1332
    # pylint: disable=R0912,R0914,R0915
1333
    hvp = instance.hvparams
1334
    self.ValidateParameters(hvp)
1335

    
1336
    pidfile = self._InstancePidFile(instance.name)
1337
    kvm = hvp[constants.HV_KVM_PATH]
1338
    kvm_cmd = [kvm]
1339
    # used just by the vnc server, if enabled
1340
    kvm_cmd.extend(["-name", instance.name])
1341
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1342

    
1343
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1344
    if hvp[constants.HV_CPU_CORES]:
1345
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1346
    if hvp[constants.HV_CPU_THREADS]:
1347
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1348
    if hvp[constants.HV_CPU_SOCKETS]:
1349
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1350

    
1351
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1352

    
1353
    kvm_cmd.extend(["-pidfile", pidfile])
1354
    kvm_cmd.extend(["-balloon", "virtio"])
1355
    kvm_cmd.extend(["-daemonize"])
1356
    if not instance.hvparams[constants.HV_ACPI]:
1357
      kvm_cmd.extend(["-no-acpi"])
1358
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1359
        constants.INSTANCE_REBOOT_EXIT:
1360
      kvm_cmd.extend(["-no-reboot"])
1361

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

    
1384
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1385
    if kernel_path:
1386
      boot_cdrom = boot_floppy = boot_network = False
1387
    else:
1388
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1389
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1390
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1391

    
1392
    if startup_paused:
1393
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1394

    
1395
    if boot_network:
1396
      kvm_cmd.extend(["-boot", "n"])
1397

    
1398
    # whether this is an older KVM version that uses the boot=on flag
1399
    # on devices
1400
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1401

    
1402
    disk_type = hvp[constants.HV_DISK_TYPE]
1403

    
1404
    #Now we can specify a different device type for CDROM devices.
1405
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1406
    if not cdrom_disk_type:
1407
      cdrom_disk_type = disk_type
1408

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

    
1430
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1431
    if iso_image2:
1432
      options = ",format=raw,media=cdrom"
1433
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1434
        if_val = ",if=virtio"
1435
      else:
1436
        if_val = ",if=%s" % cdrom_disk_type
1437
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1438
      kvm_cmd.extend(["-drive", drive_val])
1439

    
1440
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1441
    if floppy_image:
1442
      options = ",format=raw,media=disk"
1443
      if boot_floppy:
1444
        kvm_cmd.extend(["-boot", "a"])
1445
        options = "%s,boot=on" % options
1446
      if_val = ",if=floppy"
1447
      options = "%s%s" % (options, if_val)
1448
      drive_val = "file=%s%s" % (floppy_image, options)
1449
      kvm_cmd.extend(["-drive", drive_val])
1450

    
1451
    if kernel_path:
1452
      kvm_cmd.extend(["-kernel", kernel_path])
1453
      initrd_path = hvp[constants.HV_INITRD_PATH]
1454
      if initrd_path:
1455
        kvm_cmd.extend(["-initrd", initrd_path])
1456
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1457
                     hvp[constants.HV_KERNEL_ARGS]]
1458
      if hvp[constants.HV_SERIAL_CONSOLE]:
1459
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1460
        root_append.append("console=ttyS0,%s" % serial_speed)
1461
      kvm_cmd.extend(["-append", " ".join(root_append)])
1462

    
1463
    mem_path = hvp[constants.HV_MEM_PATH]
1464
    if mem_path:
1465
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1466

    
1467
    monitor_dev = ("unix:%s,server,nowait" %
1468
                   self._InstanceMonitor(instance.name))
1469
    kvm_cmd.extend(["-monitor", monitor_dev])
1470
    if hvp[constants.HV_SERIAL_CONSOLE]:
1471
      serial_dev = ("unix:%s,server,nowait" %
1472
                    self._InstanceSerial(instance.name))
1473
      kvm_cmd.extend(["-serial", serial_dev])
1474
    else:
1475
      kvm_cmd.extend(["-serial", "none"])
1476

    
1477
    mouse_type = hvp[constants.HV_USB_MOUSE]
1478
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1479
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1480
    spice_ip_version = None
1481

    
1482
    kvm_cmd.extend(["-usb"])
1483

    
1484
    if mouse_type:
1485
      kvm_cmd.extend(["-usbdevice", mouse_type])
1486
    elif vnc_bind_address:
1487
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1488

    
1489
    if vnc_bind_address:
1490
      if netutils.IsValidInterface(vnc_bind_address):
1491
        if_addresses = netutils.GetInterfaceIpAddresses(vnc_bind_address)
1492
        if_ip4_addresses = if_addresses[constants.IP4_VERSION]
1493
        if len(if_ip4_addresses) < 1:
1494
          logging.error("Could not determine IPv4 address of interface %s",
1495
                        vnc_bind_address)
1496
        else:
1497
          vnc_bind_address = if_ip4_addresses[0]
1498
      if netutils.IP4Address.IsValid(vnc_bind_address):
1499
        if instance.network_port > constants.VNC_BASE_PORT:
1500
          display = instance.network_port - constants.VNC_BASE_PORT
1501
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1502
            vnc_arg = ":%d" % (display)
1503
          else:
1504
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1505
        else:
1506
          logging.error("Network port is not a valid VNC display (%d < %d),"
1507
                        " not starting VNC",
1508
                        instance.network_port, constants.VNC_BASE_PORT)
1509
          vnc_arg = "none"
1510

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

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

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

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

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

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

    
1564
        spice_address = addresses[spice_ip_version][0]
1565

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1659
    # Set system UUID to instance UUID
1660
    if self._UUID_RE.search(kvmhelp):
1661
      kvm_cmd.extend(["-uuid", instance.uuid])
1662

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

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

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

    
1677
    hvparams = hvp
1678

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

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

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

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

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

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

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

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

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

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

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

    
1722
    return _AnalyzeSerializedRuntime(serialized_runtime)
1723

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

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

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

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

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

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

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

    
1770
    temp_files = []
1771

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

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

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

    
1793
    # We have reasons to believe changing something like the nic driver/type
1794
    # upon migration won't exactly fly with the instance kernel, so for nic
1795
    # related parameters we'll use up_hvp
1796
    tapfds = []
1797
    taps = []
1798
    devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1799
    if not kvm_nics:
1800
      kvm_cmd.extend(["-net", "none"])
1801
    else:
1802
      vnet_hdr = False
1803
      tap_extra = ""
1804
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1805
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1806
        nic_model = self._VIRTIO
1807
        try:
1808
          if self._VIRTIO_NET_RE.search(devlist):
1809
            nic_model = self._VIRTIO_NET_PCI
1810
            vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1811
        except errors.HypervisorError, _:
1812
          # Older versions of kvm don't support DEVICE_LIST, but they don't
1813
          # have new virtio syntax either.
1814
          pass
1815

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

    
1826
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1827

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2006
    return result
2007

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

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

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

    
2025
    dev.pci = int(free)
2026

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2165
    return kvm_device.pci
2166

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

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

2173
    """
2174
    if dev_type == constants.HOTPLUG_TARGET_NIC:
2175
      # putting it back in the same pci slot
2176
      device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2177
      self.HotAddDevice(instance, dev_type, device, _, seq)
2178

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

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

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

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

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

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

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

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

2230
    """
2231
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2232

    
2233
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
2234

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

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

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

2248
    """
2249
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2250

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

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

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

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

    
2281
  def CleanupInstance(self, instance_name):
2282
    """Cleanup after a stopped instance
2283

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

    
2290
  def RebootInstance(self, instance):
2291
    """Reboot an instance.
2292

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

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

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

2321
    """
2322
    return self._ReadKVMRuntime(instance.name)
2323

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

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

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

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

2345
    Stop the incoming mode KVM.
2346

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

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

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

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

    
2374
  def MigrateInstance(self, cluster_name, instance, target, live):
2375
    """Migrate an instance to a target node.
2376

2377
    The migration will not be attempted if the instance is not
2378
    currently running.
2379

2380
    @type cluster_name: string
2381
    @param cluster_name: name of the cluster
2382
    @type instance: L{objects.Instance}
2383
    @param instance: the instance to be migrated
2384
    @type target: string
2385
    @param target: ip address of the target node
2386
    @type live: boolean
2387
    @param live: perform a live migration
2388

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

    
2396
    if not live:
2397
      self._CallMonitorCommand(instance_name, "stop")
2398

    
2399
    migrate_command = ("migrate_set_speed %dm" %
2400
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2401
    self._CallMonitorCommand(instance_name, migrate_command)
2402

    
2403
    migrate_command = ("migrate_set_downtime %dms" %
2404
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2405
    self._CallMonitorCommand(instance_name, migrate_command)
2406

    
2407
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2408
    self._CallMonitorCommand(instance_name, migrate_command)
2409

    
2410
  def FinalizeMigrationSource(self, instance, success, live):
2411
    """Finalize the instance migration on the source node.
2412

2413
    @type instance: L{objects.Instance}
2414
    @param instance: the instance that was migrated
2415
    @type success: bool
2416
    @param success: whether the migration succeeded or not
2417
    @type live: bool
2418
    @param live: whether the user requested a live migration or not
2419

2420
    """
2421
    if success:
2422
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2423
      utils.KillProcess(pid)
2424
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2425
    elif live:
2426
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2427

    
2428
  def GetMigrationStatus(self, instance):
2429
    """Get the migration status
2430

2431
    @type instance: L{objects.Instance}
2432
    @param instance: the instance that is being migrated
2433
    @rtype: L{objects.MigrationStatus}
2434
    @return: the status of the current migration (one of
2435
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2436
             progress info that can be retrieved from the hypervisor
2437

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

    
2458
          return migration_status
2459

    
2460
        logging.warning("KVM: unknown migration status '%s'", status)
2461

    
2462
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2463

    
2464
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2465

    
2466
  def BalloonInstanceMemory(self, instance, mem):
2467
    """Balloon an instance memory to a certain value.
2468

2469
    @type instance: L{objects.Instance}
2470
    @param instance: instance to be accepted
2471
    @type mem: int
2472
    @param mem: actual memory size to use for instance runtime
2473

2474
    """
2475
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2476

    
2477
  def GetNodeInfo(self, hvparams=None):
2478
    """Return information about the node.
2479

2480
    @type hvparams: dict of strings
2481
    @param hvparams: hypervisor parameters, not used in this class
2482

2483
    @return: a dict as returned by L{BaseHypervisor.GetLinuxNodeInfo} plus
2484
        the following keys:
2485
          - hv_version: the hypervisor version in the form (major, minor,
2486
                        revision)
2487

2488
    """
2489
    result = self.GetLinuxNodeInfo()
2490
    kvmpath = constants.KVM_PATH
2491
    if hvparams is not None:
2492
      kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2493
    _, v_major, v_min, v_rev = self._GetKVMVersion(kvmpath)
2494
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2495
    return result
2496

    
2497
  @classmethod
2498
  def GetInstanceConsole(cls, instance, primary_node, hvparams, beparams):
2499
    """Return a command for connecting to the console of an instance.
2500

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

    
2514
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2515
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2516
      display = instance.network_port - constants.VNC_BASE_PORT
2517
      return objects.InstanceConsole(instance=instance.name,
2518
                                     kind=constants.CONS_VNC,
2519
                                     host=vnc_bind_address,
2520
                                     port=instance.network_port,
2521
                                     display=display)
2522

    
2523
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2524
    if spice_bind:
2525
      return objects.InstanceConsole(instance=instance.name,
2526
                                     kind=constants.CONS_SPICE,
2527
                                     host=spice_bind,
2528
                                     port=instance.network_port)
2529

    
2530
    return objects.InstanceConsole(instance=instance.name,
2531
                                   kind=constants.CONS_MESSAGE,
2532
                                   message=("No serial shell for instance %s" %
2533
                                            instance.name))
2534

    
2535
  def Verify(self, hvparams=None):
2536
    """Verify the hypervisor.
2537

2538
    Check that the required binaries exist.
2539

2540
    @type hvparams: dict of strings
2541
    @param hvparams: hypervisor parameters to be verified against, not used here
2542

2543
    @return: Problem description if something is wrong, C{None} otherwise
2544

2545
    """
2546
    msgs = []
2547
    kvmpath = constants.KVM_PATH
2548
    if hvparams is not None:
2549
      kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2550
    if not os.path.exists(kvmpath):
2551
      msgs.append("The KVM binary ('%s') does not exist" % kvmpath)
2552
    if not os.path.exists(constants.SOCAT_PATH):
2553
      msgs.append("The socat binary ('%s') does not exist" %
2554
                  constants.SOCAT_PATH)
2555

    
2556
    return self._FormatVerifyResults(msgs)
2557

    
2558
  @classmethod
2559
  def CheckParameterSyntax(cls, hvparams):
2560
    """Check the given parameters for validity.
2561

2562
    @type hvparams:  dict
2563
    @param hvparams: dictionary with parameter names/value
2564
    @raise errors.HypervisorError: when a parameter is not valid
2565

2566
    """
2567
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2568

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

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

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

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

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

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

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

    
2631
  @classmethod
2632
  def ValidateParameters(cls, hvparams):
2633
    """Check the given parameters for validity.
2634

2635
    @type hvparams:  dict
2636
    @param hvparams: dictionary with parameter names/value
2637
    @raise errors.HypervisorError: when a parameter is not valid
2638

2639
    """
2640
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2641

    
2642
    kvm_path = hvparams[constants.HV_KVM_PATH]
2643

    
2644
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2645
    if security_model == constants.HT_SM_USER:
2646
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2647
      try:
2648
        pwd.getpwnam(username)
2649
      except KeyError:
2650
        raise errors.HypervisorError("Unknown security domain user %s"
2651
                                     % username)
2652
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2653
    if vnc_bind_address:
2654
      bound_to_addr = netutils.IP4Address.IsValid(vnc_bind_address)
2655
      is_interface = netutils.IsValidInterface(vnc_bind_address)
2656
      is_path = utils.IsNormAbsPath(vnc_bind_address)
2657
      if not bound_to_addr and not is_interface and not is_path:
2658
        raise errors.HypervisorError("VNC: The %s parameter must be either"
2659
                                     " a valid IP address, an interface name,"
2660
                                     " or an absolute path" %
2661
                                     constants.HV_KVM_SPICE_BIND)
2662

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

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

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

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

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

2696
    @type hvparams: dict of strings
2697
    @param hvparams: hypervisor params to be used on this node
2698

2699
    """
2700
    cls.LinuxPowercycle()