Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 5f045eb8

History | View | Annotate | Download (102 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-ifup-custom"
64
_KVM_START_PAUSED_FLAG = "-S"
65

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

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

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

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

    
117
_MIGRATION_CAPS_DELIM = ":"
118

    
119

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

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

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

133
  """
134

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

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

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

    
147

    
148
def _GetFreeSlot(slots, slot=None, reserve=False):
149
  """Helper method to get first available slot in a bitarray
150

151
  @type slots: bitarray
152
  @param slots: the bitarray to operate on
153
  @type slot: integer
154
  @param slot: if given we check whether the slot is free
155
  @type reserve: boolean
156
  @param reserve: whether to reserve the first available slot or not
157
  @return: the idx of the (first) available slot
158
  @raise errors.HotplugError: If all slots in a bitarray are occupied
159
    or the given slot is not free.
160

161
  """
162
  if slot is not None:
163
    assert slot < len(slots)
164
    if slots[slot]:
165
      raise errors.HypervisorError("Slots %d occupied" % slot)
166

    
167
  else:
168
    avail = slots.search(_AVAILABLE_PCI_SLOT, 1)
169
    if not avail:
170
      raise errors.HypervisorError("All slots occupied")
171

    
172
    slot = int(avail[0])
173

    
174
  if reserve:
175
    slots[slot] = True
176

    
177
  return slot
178

    
179

    
180
def _GetExistingDeviceInfo(dev_type, device, runtime):
181
  """Helper function to get an existing device inside the runtime file
182

183
  Used when an instance is running. Load kvm runtime file and search
184
  for a device based on its type and uuid.
185

186
  @type dev_type: sting
187
  @param dev_type: device type of param dev
188
  @type device: L{objects.Disk} or L{objects.NIC}
189
  @param device: the device object for which we generate a kvm name
190
  @type runtime: tuple (cmd, nics, hvparams, disks)
191
  @param runtime: the runtime data to search for the device
192
  @raise errors.HotplugError: in case the requested device does not
193
    exist (e.g. device has been added without --hotplug option) or
194
    device info has not pci slot (e.g. old devices in the cluster)
195

196
  """
197
  index = _DEVICE_RUNTIME_INDEX[dev_type]
198
  found = _FIND_RUNTIME_ENTRY[dev_type](device, runtime[index])
199
  if not found:
200
    raise errors.HotplugError("Cannot find runtime info for %s with UUID %s" %
201
                              (dev_type, device.uuid))
202

    
203
  return found[0]
204

    
205

    
206
def _UpgradeSerializedRuntime(serialized_runtime):
207
  """Upgrade runtime data
208

209
  Remove any deprecated fields or change the format of the data.
210
  The runtime files are not upgraded when Ganeti is upgraded, so the required
211
  modification have to be performed here.
212

213
  @type serialized_runtime: string
214
  @param serialized_runtime: raw text data read from actual runtime file
215
  @return: (cmd, nic dicts, hvparams, bdev dicts)
216
  @rtype: tuple
217

218
  """
219
  loaded_runtime = serializer.Load(serialized_runtime)
220
  kvm_cmd, serialized_nics, hvparams = loaded_runtime[:3]
221
  if len(loaded_runtime) >= 4:
222
    serialized_disks = loaded_runtime[3]
223
  else:
224
    serialized_disks = []
225

    
226
  for nic in serialized_nics:
227
    # Add a dummy uuid slot if an pre-2.8 NIC is found
228
    if "uuid" not in nic:
229
      nic["uuid"] = utils.NewUUID()
230

    
231
  return kvm_cmd, serialized_nics, hvparams, serialized_disks
232

    
233

    
234
def _AnalyzeSerializedRuntime(serialized_runtime):
235
  """Return runtime entries for a serialized runtime file
236

237
  @type serialized_runtime: string
238
  @param serialized_runtime: raw text data read from actual runtime file
239
  @return: (cmd, nics, hvparams, bdevs)
240
  @rtype: tuple
241

242
  """
243
  kvm_cmd, serialized_nics, hvparams, serialized_disks = \
244
    _UpgradeSerializedRuntime(serialized_runtime)
245
  kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
246
  kvm_disks = [(objects.Disk.FromDict(sdisk), link)
247
               for sdisk, link in serialized_disks]
248

    
249
  return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
250

    
251

    
252
def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
253
  """Retrieves supported TUN features from file descriptor.
254

255
  @see: L{_ProbeTapVnetHdr}
256

257
  """
258
  req = struct.pack("I", 0)
259
  try:
260
    buf = _ioctl(fd, TUNGETFEATURES, req)
261
  except EnvironmentError, err:
262
    logging.warning("ioctl(TUNGETFEATURES) failed: %s", err)
263
    return None
264
  else:
265
    (flags, ) = struct.unpack("I", buf)
266
    return flags
267

    
268

    
269
def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
270
  """Check whether to enable the IFF_VNET_HDR flag.
271

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

282
   @type fd: int
283
   @param fd: the file descriptor of /dev/net/tun
284

285
  """
286
  flags = _features_fn(fd)
287

    
288
  if flags is None:
289
    # Not supported
290
    return False
291

    
292
  result = bool(flags & IFF_VNET_HDR)
293

    
294
  if not result:
295
    logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
296

    
297
  return result
298

    
299

    
300
def _OpenTap(vnet_hdr=True):
301
  """Open a new tap device and return its file descriptor.
302

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

306
  @type vnet_hdr: boolean
307
  @param vnet_hdr: Enable the VNET Header
308
  @return: (ifname, tapfd)
309
  @rtype: tuple
310

311
  """
312
  try:
313
    tapfd = os.open("/dev/net/tun", os.O_RDWR)
314
  except EnvironmentError:
315
    raise errors.HypervisorError("Failed to open /dev/net/tun")
316

    
317
  flags = IFF_TAP | IFF_NO_PI
318

    
319
  if vnet_hdr and _ProbeTapVnetHdr(tapfd):
320
    flags |= IFF_VNET_HDR
321

    
322
  # The struct ifreq ioctl request (see netdevice(7))
323
  ifr = struct.pack("16sh", "", flags)
324

    
325
  try:
326
    res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
327
  except EnvironmentError, err:
328
    raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
329
                                 err)
330

    
331
  # Get the interface name from the ioctl
332
  ifname = struct.unpack("16sh", res)[0].strip("\x00")
333
  return (ifname, tapfd)
334

    
335

    
336
class QmpMessage:
337
  """QEMU Messaging Protocol (QMP) message.
338

339
  """
340
  def __init__(self, data):
341
    """Creates a new QMP message based on the passed data.
342

343
    """
344
    if not isinstance(data, dict):
345
      raise TypeError("QmpMessage must be initialized with a dict")
346

    
347
    self.data = data
348

    
349
  def __getitem__(self, field_name):
350
    """Get the value of the required field if present, or None.
351

352
    Overrides the [] operator to provide access to the message data,
353
    returning None if the required item is not in the message
354
    @return: the value of the field_name field, or None if field_name
355
             is not contained in the message
356

357
    """
358
    return self.data.get(field_name, None)
359

    
360
  def __setitem__(self, field_name, field_value):
361
    """Set the value of the required field_name to field_value.
362

363
    """
364
    self.data[field_name] = field_value
365

    
366
  @staticmethod
367
  def BuildFromJsonString(json_string):
368
    """Build a QmpMessage from a JSON encoded string.
369

370
    @type json_string: str
371
    @param json_string: JSON string representing the message
372
    @rtype: L{QmpMessage}
373
    @return: a L{QmpMessage} built from json_string
374

375
    """
376
    # Parse the string
377
    data = serializer.LoadJson(json_string)
378
    return QmpMessage(data)
379

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

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

    
389

    
390
class MonitorSocket(object):
391
  _SOCKET_TIMEOUT = 5
392

    
393
  def __init__(self, monitor_filename):
394
    """Instantiates the MonitorSocket object.
395

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

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

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

    
421
  def _check_connection(self):
422
    """Make sure that the connection is established.
423

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

    
429
  def connect(self):
430
    """Connects to the monitor.
431

432
    Connects to the UNIX socket
433

434
    @raise errors.HypervisorError: when there are communication errors
435

436
    """
437
    if self._connected:
438
      raise errors.ProgrammerError("Cannot connect twice")
439

    
440
    self._check_socket()
441

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

    
449
  def close(self):
450
    """Closes the socket
451

452
    It cannot be used after this call.
453

454
    """
455
    self.sock.close()
456

    
457

    
458
class QmpConnection(MonitorSocket):
459
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
460

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

    
474
  def __init__(self, monitor_filename):
475
    super(QmpConnection, self).__init__(monitor_filename)
476
    self._buf = ""
477

    
478
  def connect(self):
479
    """Connects to the QMP monitor.
480

481
    Connects to the UNIX socket and makes sure that we can actually send and
482
    receive data to the kvm instance via QMP.
483

484
    @raise errors.HypervisorError: when there are communication errors
485
    @raise errors.ProgrammerError: when there are data serialization errors
486

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

    
497
    # This is needed because QMP can return more than one greetings
498
    # see https://groups.google.com/d/msg/ganeti-devel/gZYcvHKDooU/SnukC8dgS5AJ
499
    self._buf = ""
500

    
501
    # Let's put the monitor in command mode using the qmp_capabilities
502
    # command, or else no command will be executable.
503
    # (As per the QEMU Protocol Specification 0.1 - section 4)
504
    self.Execute(self._CAPABILITIES_COMMAND)
505

    
506
  def _ParseMessage(self, buf):
507
    """Extract and parse a QMP message from the given buffer.
508

509
    Seeks for a QMP message in the given buf. If found, it parses it and
510
    returns it together with the rest of the characters in the buf.
511
    If no message is found, returns None and the whole buffer.
512

513
    @raise errors.ProgrammerError: when there are data serialization errors
514

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

    
527
    return (message, buf)
528

    
529
  def _Recv(self):
530
    """Receives a message from QMP and decodes the received JSON object.
531

532
    @rtype: QmpMessage
533
    @return: the received message
534
    @raise errors.HypervisorError: when there are communication errors
535
    @raise errors.ProgrammerError: when there are data serialization errors
536

537
    """
538
    self._check_connection()
539

    
540
    # Check if there is already a message in the buffer
541
    (message, self._buf) = self._ParseMessage(self._buf)
542
    if message:
543
      return message
544

    
545
    recv_buffer = StringIO.StringIO(self._buf)
546
    recv_buffer.seek(len(self._buf))
547
    try:
548
      while True:
549
        data = self.sock.recv(4096)
550
        if not data:
551
          break
552
        recv_buffer.write(data)
553

    
554
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
555
        if message:
556
          return message
557

    
558
    except socket.timeout, err:
559
      raise errors.HypervisorError("Timeout while receiving a QMP message: "
560
                                   "%s" % (err))
561
    except socket.error, err:
562
      raise errors.HypervisorError("Unable to receive data from KVM using the"
563
                                   " QMP protocol: %s" % err)
564

    
565
  def _Send(self, message):
566
    """Encodes and sends a message to KVM using QMP.
567

568
    @type message: QmpMessage
569
    @param message: message to send to KVM
570
    @raise errors.HypervisorError: when there are communication errors
571
    @raise errors.ProgrammerError: when there are data serialization errors
572

573
    """
574
    self._check_connection()
575
    try:
576
      message_str = str(message)
577
    except Exception, err:
578
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
579

    
580
    try:
581
      self.sock.sendall(message_str)
582
    except socket.timeout, err:
583
      raise errors.HypervisorError("Timeout while sending a QMP message: "
584
                                   "%s (%s)" % (err.string, err.errno))
585
    except socket.error, err:
586
      raise errors.HypervisorError("Unable to send data from KVM using the"
587
                                   " QMP protocol: %s" % err)
588

    
589
  def Execute(self, command, arguments=None):
590
    """Executes a QMP command and returns the response of the server.
591

592
    @type command: str
593
    @param command: the command to execute
594
    @type arguments: dict
595
    @param arguments: dictionary of arguments to be passed to the command
596
    @rtype: dict
597
    @return: dictionary representing the received JSON object
598
    @raise errors.HypervisorError: when there are communication errors
599
    @raise errors.ProgrammerError: when there are data serialization errors
600

601
    """
602
    self._check_connection()
603
    message = QmpMessage({self._EXECUTE_KEY: command})
604
    if arguments:
605
      message[self._ARGUMENTS_KEY] = arguments
606
    self._Send(message)
607

    
608
    # Events can occur between the sending of the command and the reception
609
    # of the response, so we need to filter out messages with the event key.
610
    while True:
611
      response = self._Recv()
612
      err = response[self._ERROR_KEY]
613
      if err:
614
        raise errors.HypervisorError("kvm: error executing the %s"
615
                                     " command: %s (%s):" %
616
                                     (command,
617
                                      err[self._ERROR_DESC_KEY],
618
                                      err[self._ERROR_CLASS_KEY]))
619

    
620
      elif not response[self._EVENT_KEY]:
621
        return response
622

    
623

    
624
class KVMHypervisor(hv_base.BaseHypervisor):
625
  """KVM hypervisor interface
626

627
  """
628
  CAN_MIGRATE = True
629

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

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

    
734
  _VIRTIO = "virtio"
735
  _VIRTIO_NET_PCI = "virtio-net-pci"
736
  _VIRTIO_BLK_PCI = "virtio-blk-pci"
737

    
738
  _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
739
                                    re.M | re.I)
740
  _MIGRATION_PROGRESS_RE = \
741
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
742
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
743
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
744

    
745
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
746
  _MIGRATION_INFO_RETRY_DELAY = 2
747

    
748
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
749

    
750
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
751
  _CPU_INFO_CMD = "info cpus"
752
  _CONT_CMD = "cont"
753

    
754
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
755
  _CHECK_MACHINE_VERSION_RE = \
756
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
757

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

    
773
  _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
774
  _INFO_PCI_CMD = "info pci"
775
  _FIND_PCI_DEVICE_RE = \
776
    staticmethod(lambda pci, devid:
777
      re.compile(r'Bus.*device[ ]*%d,(.*\n){5,6}.*id "%s"' % (pci, devid),
778
                 re.M))
779

    
780
  _INFO_VERSION_RE = \
781
    re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
782
  _INFO_VERSION_CMD = "info version"
783

    
784
  # Slot 0 for Host bridge, Slot 1 for ISA bridge, Slot 2 for VGA controller
785
  _DEFAULT_PCI_RESERVATIONS = "11100000000000000000000000000000"
786
  _SOUNDHW_WITH_PCI_SLOT = ["ac97", "es1370", "hda"]
787

    
788
  ANCILLARY_FILES = [
789
    _KVM_NETWORK_SCRIPT,
790
    ]
791
  ANCILLARY_FILES_OPT = [
792
    _KVM_NETWORK_SCRIPT,
793
    ]
794

    
795
  # Supported kvm options to get output from
796
  _KVMOPT_HELP = "help"
797
  _KVMOPT_MLIST = "mlist"
798
  _KVMOPT_DEVICELIST = "devicelist"
799

    
800
  # Command to execute to get the output from kvm, and whether to
801
  # accept the output even on failure.
802
  _KVMOPTS_CMDS = {
803
    _KVMOPT_HELP: (["--help"], False),
804
    _KVMOPT_MLIST: (["-M", "?"], False),
805
    _KVMOPT_DEVICELIST: (["-device", "?"], True),
806
  }
807

    
808
  def __init__(self):
809
    hv_base.BaseHypervisor.__init__(self)
810
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
811
    # in a tmpfs filesystem or has been otherwise wiped out.
812
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
813
    utils.EnsureDirs(dirs)
814

    
815
  @classmethod
816
  def _InstancePidFile(cls, instance_name):
817
    """Returns the instance pidfile.
818

819
    """
820
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
821

    
822
  @classmethod
823
  def _InstanceUidFile(cls, instance_name):
824
    """Returns the instance uidfile.
825

826
    """
827
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
828

    
829
  @classmethod
830
  def _InstancePidInfo(cls, pid):
831
    """Check pid file for instance information.
832

833
    Check that a pid file is associated with an instance, and retrieve
834
    information from its command line.
835

836
    @type pid: string or int
837
    @param pid: process id of the instance to check
838
    @rtype: tuple
839
    @return: (instance_name, memory, vcpus)
840
    @raise errors.HypervisorError: when an instance cannot be found
841

842
    """
843
    alive = utils.IsProcessAlive(pid)
844
    if not alive:
845
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
846

    
847
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
848
    try:
849
      cmdline = utils.ReadFile(cmdline_file)
850
    except EnvironmentError, err:
851
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
852
                                   (pid, err))
853

    
854
    instance = None
855
    memory = 0
856
    vcpus = 0
857

    
858
    arg_list = cmdline.split("\x00")
859
    while arg_list:
860
      arg = arg_list.pop(0)
861
      if arg == "-name":
862
        instance = arg_list.pop(0)
863
      elif arg == "-m":
864
        memory = int(arg_list.pop(0))
865
      elif arg == "-smp":
866
        vcpus = int(arg_list.pop(0).split(",")[0])
867

    
868
    if instance is None:
869
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
870
                                   " instance" % pid)
871

    
872
    return (instance, memory, vcpus)
873

    
874
  def _InstancePidAlive(self, instance_name):
875
    """Returns the instance pidfile, pid, and liveness.
876

877
    @type instance_name: string
878
    @param instance_name: instance name
879
    @rtype: tuple
880
    @return: (pid file name, pid, liveness)
881

882
    """
883
    pidfile = self._InstancePidFile(instance_name)
884
    pid = utils.ReadPidFile(pidfile)
885

    
886
    alive = False
887
    try:
888
      cmd_instance = self._InstancePidInfo(pid)[0]
889
      alive = (cmd_instance == instance_name)
890
    except errors.HypervisorError:
891
      pass
892

    
893
    return (pidfile, pid, alive)
894

    
895
  def _CheckDown(self, instance_name):
896
    """Raises an error unless the given instance is down.
897

898
    """
899
    alive = self._InstancePidAlive(instance_name)[2]
900
    if alive:
901
      raise errors.HypervisorError("Failed to start instance %s: %s" %
902
                                   (instance_name, "already running"))
903

    
904
  @classmethod
905
  def _InstanceMonitor(cls, instance_name):
906
    """Returns the instance monitor socket name
907

908
    """
909
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
910

    
911
  @classmethod
912
  def _InstanceSerial(cls, instance_name):
913
    """Returns the instance serial socket name
914

915
    """
916
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
917

    
918
  @classmethod
919
  def _InstanceQmpMonitor(cls, instance_name):
920
    """Returns the instance serial QMP socket name
921

922
    """
923
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
924

    
925
  @staticmethod
926
  def _SocatUnixConsoleParams():
927
    """Returns the correct parameters for socat
928

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

931
    """
932
    if constants.SOCAT_USE_ESCAPE:
933
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
934
    else:
935
      return "echo=0,icanon=0"
936

    
937
  @classmethod
938
  def _InstanceKVMRuntime(cls, instance_name):
939
    """Returns the instance KVM runtime filename
940

941
    """
942
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
943

    
944
  @classmethod
945
  def _InstanceChrootDir(cls, instance_name):
946
    """Returns the name of the KVM chroot dir of the instance
947

948
    """
949
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
950

    
951
  @classmethod
952
  def _InstanceNICDir(cls, instance_name):
953
    """Returns the name of the directory holding the tap device files for a
954
    given instance.
955

956
    """
957
    return utils.PathJoin(cls._NICS_DIR, instance_name)
958

    
959
  @classmethod
960
  def _InstanceNICFile(cls, instance_name, seq_or_uuid):
961
    """Returns the name of the file containing the tap device for a given NIC
962

963
    """
964
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq_or_uuid))
965

    
966
  @classmethod
967
  def _GetInstanceNICTap(cls, instance_name, nic):
968
    """Returns the tap for the corresponding nic
969

970
    Search for tap file named after NIC's uuid.
971
    For old instances without uuid indexed tap files returns nothing.
972

973
    """
974
    try:
975
      return utils.ReadFile(cls._InstanceNICFile(instance_name, nic.uuid))
976
    except EnvironmentError:
977
      pass
978

    
979
  @classmethod
980
  def _WriteInstanceNICFiles(cls, instance_name, seq, nic, tap):
981
    """Write tap name to both instance NIC files
982

983
    """
984
    for ident in [seq, nic.uuid]:
985
      utils.WriteFile(cls._InstanceNICFile(instance_name, ident), data=tap)
986

    
987
  @classmethod
988
  def _RemoveInstanceNICFiles(cls, instance_name, seq, nic):
989
    """Write tap name to both instance NIC files
990

991
    """
992
    for ident in [seq, nic.uuid]:
993
      utils.RemoveFile(cls._InstanceNICFile(instance_name, ident))
994

    
995
  @classmethod
996
  def _InstanceKeymapFile(cls, instance_name):
997
    """Returns the name of the file containing the keymap for a given instance
998

999
    """
1000
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
1001

    
1002
  @classmethod
1003
  def _TryReadUidFile(cls, uid_file):
1004
    """Try to read a uid file
1005

1006
    """
1007
    if os.path.exists(uid_file):
1008
      try:
1009
        uid = int(utils.ReadOneLineFile(uid_file))
1010
        return uid
1011
      except EnvironmentError:
1012
        logging.warning("Can't read uid file", exc_info=True)
1013
      except (TypeError, ValueError):
1014
        logging.warning("Can't parse uid file contents", exc_info=True)
1015
    return None
1016

    
1017
  @classmethod
1018
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
1019
    """Removes an instance's rutime sockets/files/dirs.
1020

1021
    """
1022
    # This takes info from NICDir and RuntimeFile
1023
    cls._UnconfigureInstanceNICs(instance_name)
1024
    utils.RemoveFile(pidfile)
1025
    utils.RemoveFile(cls._InstanceMonitor(instance_name))
1026
    utils.RemoveFile(cls._InstanceSerial(instance_name))
1027
    utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
1028
    utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
1029
    utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
1030
    uid_file = cls._InstanceUidFile(instance_name)
1031
    uid = cls._TryReadUidFile(uid_file)
1032
    utils.RemoveFile(uid_file)
1033
    if uid is not None:
1034
      uidpool.ReleaseUid(uid)
1035
    try:
1036
      shutil.rmtree(cls._InstanceNICDir(instance_name))
1037
    except OSError, err:
1038
      if err.errno != errno.ENOENT:
1039
        raise
1040
    try:
1041
      chroot_dir = cls._InstanceChrootDir(instance_name)
1042
      utils.RemoveDir(chroot_dir)
1043
    except OSError, err:
1044
      if err.errno == errno.ENOTEMPTY:
1045
        # The chroot directory is expected to be empty, but it isn't.
1046
        new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
1047
                                          prefix="%s-%s-" %
1048
                                          (instance_name,
1049
                                           utils.TimestampForFilename()))
1050
        logging.warning("The chroot directory of instance %s can not be"
1051
                        " removed as it is not empty. Moving it to the"
1052
                        " quarantine instead. Please investigate the"
1053
                        " contents (%s) and clean up manually",
1054
                        instance_name, new_chroot_dir)
1055
        utils.RenameFile(chroot_dir, new_chroot_dir)
1056
      else:
1057
        raise
1058

    
1059
  @staticmethod
1060
  def _CreateNICEnv(instance_name, nic, tap, seq=None, instance_tags=None):
1061
    """Create environment variables for a specific NIC
1062

1063
    This is needed during NIC ifup/ifdown scripts.
1064
    Since instance tags may change during NIC creation and removal
1065
    and because during cleanup instance object is not available we
1066
    pass them only upon NIC creation (instance startup/NIC hot-plugging).
1067

1068
    """
1069
    env = {
1070
      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
1071
      "INSTANCE": instance_name,
1072
      "MAC": nic.mac,
1073
      "MODE": nic.nicparams[constants.NIC_MODE],
1074
      "INTERFACE_UUID": nic.uuid,
1075
    }
1076

    
1077
    if instance_tags:
1078
      env["TAGS"] = " ".join(instance_tags)
1079

    
1080
    # This should always be available except for old instances in the
1081
    # cluster without uuid indexed tap files.
1082
    if tap:
1083
      env["INTERFACE"] = tap
1084

    
1085
    if seq:
1086
      env["INTERFACE_INDEX"] = str(seq)
1087

    
1088
    if nic.ip:
1089
      env["IP"] = nic.ip
1090

    
1091
    if nic.name:
1092
      env["INTERFACE_NAME"] = nic.name
1093

    
1094
    if nic.nicparams[constants.NIC_LINK]:
1095
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
1096

    
1097
    if nic.network:
1098
      n = objects.Network.FromDict(nic.netinfo)
1099
      env.update(n.HooksDict())
1100

    
1101
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1102
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
1103

    
1104
    return env
1105

    
1106
  @classmethod
1107
  def _ConfigureNIC(cls, instance, seq, nic, tap):
1108
    """Run the network configuration script for a specified NIC
1109

1110
    @param instance: instance we're acting on
1111
    @type instance: instance object
1112
    @param seq: nic sequence number
1113
    @type seq: int
1114
    @param nic: nic we're acting on
1115
    @type nic: nic object
1116
    @param tap: the host's tap interface this NIC corresponds to
1117
    @type tap: str
1118

1119
    """
1120
    env = cls._CreateNICEnv(instance.name, nic, tap, seq, instance.GetTags())
1121
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
1122
    if result.failed:
1123
      raise errors.HypervisorError("Failed to configure interface %s: %s;"
1124
                                   " network configuration script output: %s" %
1125
                                   (tap, result.fail_reason, result.output))
1126

    
1127
  @classmethod
1128
  def _UnconfigureNic(cls, instance_name, nic, only_local=True):
1129
    """Run ifdown script for a specific NIC
1130

1131
    This is executed during instance cleanup and NIC hot-unplug
1132

1133
    @param instance: instance we're acting on
1134
    @type instance: instance object
1135
    @param nic: nic we're acting on
1136
    @type nic: nic object
1137
    @param localy: whether ifdown script should reset global conf (dns) or not
1138
    @type localy: boolean
1139

1140
    """
1141
    tap = cls._GetInstanceNICTap(instance_name, nic)
1142
    env = cls._CreateNICEnv(instance_name, nic, tap)
1143
    arg2 = str(only_local).lower()
1144
    result = utils.RunCmd([pathutils.KVM_IFDOWN, tap, arg2], env=env)
1145
    if result.failed:
1146
      raise errors.HypervisorError("Failed to unconfigure interface %s: %s;"
1147
                                   " network configuration script output: %s" %
1148
                                   (tap, result.fail_reason, result.output))
1149

    
1150
  @staticmethod
1151
  def _VerifyAffinityPackage():
1152
    if affinity is None:
1153
      raise errors.HypervisorError("affinity Python package not"
1154
                                   " found; cannot use CPU pinning under KVM")
1155

    
1156
  @staticmethod
1157
  def _BuildAffinityCpuMask(cpu_list):
1158
    """Create a CPU mask suitable for sched_setaffinity from a list of
1159
    CPUs.
1160

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

1164
    @type cpu_list: list of int
1165
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
1166
    @rtype: int
1167
    @return: a bit mask of CPU affinities
1168

1169
    """
1170
    if cpu_list == constants.CPU_PINNING_OFF:
1171
      return constants.CPU_PINNING_ALL_KVM
1172
    else:
1173
      return sum(2 ** cpu for cpu in cpu_list)
1174

    
1175
  @classmethod
1176
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
1177
    """Change CPU affinity for running VM according to given CPU mask.
1178

1179
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
1180
    @type cpu_mask: string
1181
    @param process_id: process ID of KVM process. Used to pin entire VM
1182
                       to physical CPUs.
1183
    @type process_id: int
1184
    @param thread_dict: map of virtual CPUs to KVM thread IDs
1185
    @type thread_dict: dict int:int
1186

1187
    """
1188
    # Convert the string CPU mask to a list of list of int's
1189
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
1190

    
1191
    if len(cpu_list) == 1:
1192
      all_cpu_mapping = cpu_list[0]
1193
      if all_cpu_mapping == constants.CPU_PINNING_OFF:
1194
        # If CPU pinning has 1 entry that's "all", then do nothing
1195
        pass
1196
      else:
1197
        # If CPU pinning has one non-all entry, map the entire VM to
1198
        # one set of physical CPUs
1199
        cls._VerifyAffinityPackage()
1200
        affinity.set_process_affinity_mask(
1201
          process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
1202
    else:
1203
      # The number of vCPUs mapped should match the number of vCPUs
1204
      # reported by KVM. This was already verified earlier, so
1205
      # here only as a sanity check.
1206
      assert len(thread_dict) == len(cpu_list)
1207
      cls._VerifyAffinityPackage()
1208

    
1209
      # For each vCPU, map it to the proper list of physical CPUs
1210
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1211
        affinity.set_process_affinity_mask(thread_dict[i],
1212
                                           cls._BuildAffinityCpuMask(vcpu))
1213

    
1214
  def _GetVcpuThreadIds(self, instance_name):
1215
    """Get a mapping of vCPU no. to thread IDs for the instance
1216

1217
    @type instance_name: string
1218
    @param instance_name: instance in question
1219
    @rtype: dictionary of int:int
1220
    @return: a dictionary mapping vCPU numbers to thread IDs
1221

1222
    """
1223
    result = {}
1224
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1225
    for line in output.stdout.splitlines():
1226
      match = self._CPU_INFO_RE.search(line)
1227
      if not match:
1228
        continue
1229
      grp = map(int, match.groups())
1230
      result[grp[0]] = grp[1]
1231

    
1232
    return result
1233

    
1234
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1235
    """Complete CPU pinning.
1236

1237
    @type instance_name: string
1238
    @param instance_name: name of instance
1239
    @type cpu_mask: string
1240
    @param cpu_mask: CPU pinning mask as entered by user
1241

1242
    """
1243
    # Get KVM process ID, to be used if need to pin entire VM
1244
    _, pid, _ = self._InstancePidAlive(instance_name)
1245
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1246
    thread_dict = self._GetVcpuThreadIds(instance_name)
1247
    # Run CPU pinning, based on configured mask
1248
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1249

    
1250
  def ListInstances(self):
1251
    """Get the list of running instances.
1252

1253
    We can do this by listing our live instances directory and
1254
    checking whether the associated kvm process is still alive.
1255

1256
    """
1257
    result = []
1258
    for name in os.listdir(self._PIDS_DIR):
1259
      if self._InstancePidAlive(name)[2]:
1260
        result.append(name)
1261
    return result
1262

    
1263
  def GetInstanceInfo(self, instance_name):
1264
    """Get instance properties.
1265

1266
    @type instance_name: string
1267
    @param instance_name: the instance name
1268
    @rtype: tuple of strings
1269
    @return: (name, id, memory, vcpus, stat, times)
1270

1271
    """
1272
    _, pid, alive = self._InstancePidAlive(instance_name)
1273
    if not alive:
1274
      return None
1275

    
1276
    _, memory, vcpus = self._InstancePidInfo(pid)
1277
    istat = "---b-"
1278
    times = "0"
1279

    
1280
    try:
1281
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1282
      qmp.connect()
1283
      vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1284
      # Will fail if ballooning is not enabled, but we can then just resort to
1285
      # the value above.
1286
      mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1287
      memory = mem_bytes / 1048576
1288
    except errors.HypervisorError:
1289
      pass
1290

    
1291
    return (instance_name, pid, memory, vcpus, istat, times)
1292

    
1293
  def GetAllInstancesInfo(self):
1294
    """Get properties of all instances.
1295

1296
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1297

1298
    """
1299
    data = []
1300
    for name in os.listdir(self._PIDS_DIR):
1301
      try:
1302
        info = self.GetInstanceInfo(name)
1303
      except errors.HypervisorError:
1304
        # Ignore exceptions due to instances being shut down
1305
        continue
1306
      if info:
1307
        data.append(info)
1308
    return data
1309

    
1310
  def _GenerateKVMBlockDevicesOptions(self, instance, up_hvp, kvm_disks,
1311
                                      kvmhelp, devlist):
1312
    """Generate KVM options regarding instance's block devices.
1313

1314
    @type instance: L{objects.Instance}
1315
    @param instance: the instance object
1316
    @type up_hvp: dict
1317
    @param up_hvp: the instance's runtime hypervisor parameters
1318
    @type kvm_disks: list of tuples
1319
    @param kvm_disks: list of tuples [(disk, link_name)..]
1320
    @type kvmhelp: string
1321
    @param kvmhelp: output of kvm --help
1322
    @type devlist: string
1323
    @param devlist: output of kvm -device ?
1324
    @rtype: list
1325
    @return: list of command line options eventually used by kvm executable
1326

1327
    """
1328
    kernel_path = up_hvp[constants.HV_KERNEL_PATH]
1329
    if kernel_path:
1330
      boot_disk = False
1331
    else:
1332
      boot_disk = up_hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1333

    
1334
    # whether this is an older KVM version that uses the boot=on flag
1335
    # on devices
1336
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1337

    
1338
    dev_opts = []
1339
    device_driver = None
1340
    disk_type = up_hvp[constants.HV_DISK_TYPE]
1341
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
1342
      if_val = ",if=%s" % self._VIRTIO
1343
      try:
1344
        if self._VIRTIO_BLK_RE.search(devlist):
1345
          if_val = ",if=none"
1346
          # will be passed in -device option as driver
1347
          device_driver = self._VIRTIO_BLK_PCI
1348
      except errors.HypervisorError, _:
1349
        pass
1350
    else:
1351
      if_val = ",if=%s" % disk_type
1352
    # Cache mode
1353
    disk_cache = up_hvp[constants.HV_DISK_CACHE]
1354
    if instance.disk_template in constants.DTS_EXT_MIRROR:
1355
      if disk_cache != "none":
1356
        # TODO: make this a hard error, instead of a silent overwrite
1357
        logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1358
                        " to prevent shared storage corruption on migration",
1359
                        disk_cache)
1360
      cache_val = ",cache=none"
1361
    elif disk_cache != constants.HT_CACHE_DEFAULT:
1362
      cache_val = ",cache=%s" % disk_cache
1363
    else:
1364
      cache_val = ""
1365
    for idx, (cfdev, link_name) in enumerate(kvm_disks):
1366
      if cfdev.mode != constants.DISK_RDWR:
1367
        raise errors.HypervisorError("Instance has read-only disks which"
1368
                                     " are not supported by KVM")
1369
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
1370
      boot_val = ""
1371
      if boot_disk:
1372
        dev_opts.extend(["-boot", "c"])
1373
        boot_disk = False
1374
        if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1375
          boot_val = ",boot=on"
1376

    
1377
      # For ext we allow overriding disk_cache hypervisor params per disk
1378
      disk_cache = cfdev.params.get("cache", None)
1379
      if disk_cache:
1380
        cache_val = ",cache=%s" % disk_cache
1381
      drive_val = "file=%s,format=raw%s%s%s" % \
1382
                  (link_name, if_val, boot_val, cache_val)
1383

    
1384
      if device_driver:
1385
        # kvm_disks are the 4th entry of runtime file that did not exist in
1386
        # the past. That means that cfdev should always have pci slot and
1387
        # _GenerateDeviceKVMId() will not raise a exception.
1388
        kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_DISK,
1389
                                         cfdev, idx)
1390
        drive_val += (",id=%s" % kvm_devid)
1391
        if cfdev.pci:
1392
          drive_val += (",bus=0,unit=%d" % cfdev.pci)
1393
        dev_val = ("%s,drive=%s,id=%s" %
1394
                   (device_driver, kvm_devid, kvm_devid))
1395
        if cfdev.pci:
1396
          dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci)
1397
        dev_opts.extend(["-device", dev_val])
1398

    
1399
      # TODO: export disk geometry in IDISK_PARAMS
1400
      heads = cfdev.params.get('heads', None)
1401
      secs = cfdev.params.get('secs', None)
1402
      if heads and secs:
1403
        nr_sectors = cfdev.size * 1024 * 1024 / 512
1404
        cyls = nr_sectors / (int(heads) * int(secs))
1405
        if cyls > 16383:
1406
          cyls = 16383
1407
        elif cyls < 2:
1408
          cyls = 2
1409
        if cyls and heads and secs:
1410
          drive_val += (",cyls=%d,heads=%d,secs=%d" %
1411
                        (cyls, int(heads), int(secs)))
1412

    
1413
      dev_opts.extend(["-drive", drive_val])
1414

    
1415
    return dev_opts
1416

    
1417
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1418
                          kvmhelp):
1419
    """Generate KVM information to start an instance.
1420

1421
    @type kvmhelp: string
1422
    @param kvmhelp: output of kvm --help
1423
    @attention: this function must not have any side-effects; for
1424
        example, it must not write to the filesystem, or read values
1425
        from the current system the are expected to differ between
1426
        nodes, since it is only run once at instance startup;
1427
        actions/kvm arguments that can vary between systems should be
1428
        done in L{_ExecuteKVMRuntime}
1429

1430
    """
1431
    # pylint: disable=R0912,R0914,R0915
1432
    hvp = instance.hvparams
1433
    self.ValidateParameters(hvp)
1434

    
1435
    pidfile = self._InstancePidFile(instance.name)
1436
    kvm = hvp[constants.HV_KVM_PATH]
1437
    kvm_cmd = [kvm]
1438
    # used just by the vnc server, if enabled
1439
    kvm_cmd.extend(["-name", instance.name])
1440
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1441

    
1442
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1443
    if hvp[constants.HV_CPU_CORES]:
1444
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1445
    if hvp[constants.HV_CPU_THREADS]:
1446
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1447
    if hvp[constants.HV_CPU_SOCKETS]:
1448
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1449

    
1450
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1451

    
1452
    kvm_cmd.extend(["-pidfile", pidfile])
1453

    
1454
    pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1455

    
1456
    # As requested by music lovers
1457
    if hvp[constants.HV_SOUNDHW]:
1458
      soundhw = hvp[constants.HV_SOUNDHW]
1459
      # For some reason only few sound devices require a PCI slot
1460
      # while the Audio controller *must* be in slot 3.
1461
      # That's why we bridge this option early in command line
1462
      if soundhw in self._SOUNDHW_WITH_PCI_SLOT:
1463
        _ = _GetFreeSlot(pci_reservations, reserve=True)
1464
      kvm_cmd.extend(["-soundhw", soundhw])
1465

    
1466
    if hvp[constants.HV_DISK_TYPE] == constants.HT_DISK_SCSI:
1467
      # The SCSI controller requires another PCI slot.
1468
      _ = _GetFreeSlot(pci_reservations, reserve=True)
1469

    
1470
    # Add id to ballon and place to the first available slot (3 or 4)
1471
    addr = _GetFreeSlot(pci_reservations, reserve=True)
1472
    pci_info = ",bus=pci.0,addr=%s" % hex(addr)
1473
    kvm_cmd.extend(["-balloon", "virtio,id=balloon%s" % pci_info])
1474
    kvm_cmd.extend(["-daemonize"])
1475
    if not instance.hvparams[constants.HV_ACPI]:
1476
      kvm_cmd.extend(["-no-acpi"])
1477
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1478
        constants.INSTANCE_REBOOT_EXIT:
1479
      kvm_cmd.extend(["-no-reboot"])
1480

    
1481
    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1482
    if not mversion:
1483
      mversion = self._GetDefaultMachineVersion(kvm)
1484
    if self._MACHINE_RE.search(kvmhelp):
1485
      # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1486
      # extra hypervisor parameters. We should also investigate whether and how
1487
      # shadow_mem should be considered for the resource model.
1488
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1489
        specprop = ",accel=kvm"
1490
      else:
1491
        specprop = ""
1492
      machinespec = "%s%s" % (mversion, specprop)
1493
      kvm_cmd.extend(["-machine", machinespec])
1494
    else:
1495
      kvm_cmd.extend(["-M", mversion])
1496
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1497
          self._ENABLE_KVM_RE.search(kvmhelp)):
1498
        kvm_cmd.extend(["-enable-kvm"])
1499
      elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1500
            self._DISABLE_KVM_RE.search(kvmhelp)):
1501
        kvm_cmd.extend(["-disable-kvm"])
1502

    
1503
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1504
    if kernel_path:
1505
      boot_cdrom = boot_floppy = boot_network = False
1506
    else:
1507
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1508
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1509
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1510

    
1511
    if startup_paused:
1512
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1513

    
1514
    if boot_network:
1515
      kvm_cmd.extend(["-boot", "n"])
1516

    
1517
    # whether this is an older KVM version that uses the boot=on flag
1518
    # on devices
1519
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1520

    
1521
    disk_type = hvp[constants.HV_DISK_TYPE]
1522

    
1523
    #Now we can specify a different device type for CDROM devices.
1524
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1525
    if not cdrom_disk_type:
1526
      cdrom_disk_type = disk_type
1527

    
1528
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1529
    if iso_image:
1530
      options = ",format=raw,media=cdrom"
1531
      # set cdrom 'if' type
1532
      if boot_cdrom:
1533
        actual_cdrom_type = constants.HT_DISK_IDE
1534
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1535
        actual_cdrom_type = "virtio"
1536
      else:
1537
        actual_cdrom_type = cdrom_disk_type
1538
      if_val = ",if=%s" % actual_cdrom_type
1539
      # set boot flag, if needed
1540
      boot_val = ""
1541
      if boot_cdrom:
1542
        kvm_cmd.extend(["-boot", "d"])
1543
        if needs_boot_flag:
1544
          boot_val = ",boot=on"
1545
      # and finally build the entire '-drive' value
1546
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1547
      kvm_cmd.extend(["-drive", drive_val])
1548

    
1549
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1550
    if iso_image2:
1551
      options = ",format=raw,media=cdrom"
1552
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1553
        if_val = ",if=virtio"
1554
      else:
1555
        if_val = ",if=%s" % cdrom_disk_type
1556
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1557
      kvm_cmd.extend(["-drive", drive_val])
1558

    
1559
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1560
    if floppy_image:
1561
      options = ",format=raw,media=disk"
1562
      if boot_floppy:
1563
        kvm_cmd.extend(["-boot", "a"])
1564
        options = "%s,boot=on" % options
1565
      if_val = ",if=floppy"
1566
      options = "%s%s" % (options, if_val)
1567
      drive_val = "file=%s%s" % (floppy_image, options)
1568
      kvm_cmd.extend(["-drive", drive_val])
1569

    
1570
    if kernel_path:
1571
      kvm_cmd.extend(["-kernel", kernel_path])
1572
      initrd_path = hvp[constants.HV_INITRD_PATH]
1573
      if initrd_path:
1574
        kvm_cmd.extend(["-initrd", initrd_path])
1575
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1576
                     hvp[constants.HV_KERNEL_ARGS]]
1577
      if hvp[constants.HV_SERIAL_CONSOLE]:
1578
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1579
        root_append.append("console=ttyS0,%s" % serial_speed)
1580
      kvm_cmd.extend(["-append", " ".join(root_append)])
1581

    
1582
    mem_path = hvp[constants.HV_MEM_PATH]
1583
    if mem_path:
1584
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1585

    
1586
    monitor_dev = ("unix:%s,server,nowait" %
1587
                   self._InstanceMonitor(instance.name))
1588
    kvm_cmd.extend(["-monitor", monitor_dev])
1589
    if hvp[constants.HV_SERIAL_CONSOLE]:
1590
      serial_dev = ("unix:%s,server,nowait" %
1591
                    self._InstanceSerial(instance.name))
1592
      kvm_cmd.extend(["-serial", serial_dev])
1593
    else:
1594
      kvm_cmd.extend(["-serial", "none"])
1595

    
1596
    mouse_type = hvp[constants.HV_USB_MOUSE]
1597
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1598
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1599
    spice_ip_version = None
1600

    
1601
    kvm_cmd.extend(["-usb"])
1602

    
1603
    if mouse_type:
1604
      kvm_cmd.extend(["-usbdevice", mouse_type])
1605
    elif vnc_bind_address:
1606
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1607

    
1608
    if vnc_bind_address:
1609
      if netutils.IP4Address.IsValid(vnc_bind_address):
1610
        if instance.network_port > constants.VNC_BASE_PORT:
1611
          display = instance.network_port - constants.VNC_BASE_PORT
1612
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1613
            vnc_arg = ":%d" % (display)
1614
          else:
1615
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1616
        else:
1617
          logging.error("Network port is not a valid VNC display (%d < %d),"
1618
                        " not starting VNC",
1619
                        instance.network_port, constants.VNC_BASE_PORT)
1620
          vnc_arg = "none"
1621

    
1622
        # Only allow tls and other option when not binding to a file, for now.
1623
        # kvm/qemu gets confused otherwise about the filename to use.
1624
        vnc_append = ""
1625
        if hvp[constants.HV_VNC_TLS]:
1626
          vnc_append = "%s,tls" % vnc_append
1627
          if hvp[constants.HV_VNC_X509_VERIFY]:
1628
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1629
                                               hvp[constants.HV_VNC_X509])
1630
          elif hvp[constants.HV_VNC_X509]:
1631
            vnc_append = "%s,x509=%s" % (vnc_append,
1632
                                         hvp[constants.HV_VNC_X509])
1633
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1634
          vnc_append = "%s,password" % vnc_append
1635

    
1636
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1637

    
1638
      else:
1639
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1640

    
1641
      kvm_cmd.extend(["-vnc", vnc_arg])
1642
    elif spice_bind:
1643
      # FIXME: this is wrong here; the iface ip address differs
1644
      # between systems, so it should be done in _ExecuteKVMRuntime
1645
      if netutils.IsValidInterface(spice_bind):
1646
        # The user specified a network interface, we have to figure out the IP
1647
        # address.
1648
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1649
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1650

    
1651
        # if the user specified an IP version and the interface does not
1652
        # have that kind of IP addresses, throw an exception
1653
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1654
          if not addresses[spice_ip_version]:
1655
            raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1656
                                         " for %s" % (spice_ip_version,
1657
                                                      spice_bind))
1658

    
1659
        # the user did not specify an IP version, we have to figure it out
1660
        elif (addresses[constants.IP4_VERSION] and
1661
              addresses[constants.IP6_VERSION]):
1662
          # we have both ipv4 and ipv6, let's use the cluster default IP
1663
          # version
1664
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1665
          spice_ip_version = \
1666
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1667
        elif addresses[constants.IP4_VERSION]:
1668
          spice_ip_version = constants.IP4_VERSION
1669
        elif addresses[constants.IP6_VERSION]:
1670
          spice_ip_version = constants.IP6_VERSION
1671
        else:
1672
          raise errors.HypervisorError("SPICE: Unable to get an IP address"
1673
                                       " for %s" % (spice_bind))
1674

    
1675
        spice_address = addresses[spice_ip_version][0]
1676

    
1677
      else:
1678
        # spice_bind is known to be a valid IP address, because
1679
        # ValidateParameters checked it.
1680
        spice_address = spice_bind
1681

    
1682
      spice_arg = "addr=%s" % spice_address
1683
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1684
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1685
                     (spice_arg, instance.network_port,
1686
                      pathutils.SPICE_CACERT_FILE))
1687
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1688
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1689
                      pathutils.SPICE_CERT_FILE))
1690
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1691
        if tls_ciphers:
1692
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1693
      else:
1694
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1695

    
1696
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1697
        spice_arg = "%s,disable-ticketing" % spice_arg
1698

    
1699
      if spice_ip_version:
1700
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1701

    
1702
      # Image compression options
1703
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1704
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1705
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1706
      if img_lossless:
1707
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1708
      if img_jpeg:
1709
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1710
      if img_zlib_glz:
1711
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1712

    
1713
      # Video stream detection
1714
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1715
      if video_streaming:
1716
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1717

    
1718
      # Audio compression, by default in qemu-kvm it is on
1719
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1720
        spice_arg = "%s,playback-compression=off" % spice_arg
1721
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1722
        spice_arg = "%s,agent-mouse=off" % spice_arg
1723
      else:
1724
        # Enable the spice agent communication channel between the host and the
1725
        # agent.
1726
        addr = _GetFreeSlot(pci_reservations, reserve=True)
1727
        pci_info = ",bus=pci.0,addr=%s" % hex(addr)
1728
        kvm_cmd.extend(["-device", "virtio-serial-pci,id=spice%s" % pci_info])
1729
        kvm_cmd.extend([
1730
          "-device",
1731
          "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1732
          ])
1733
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1734

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

    
1738
    else:
1739
      # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1740
      # also works in earlier versions though (tested with 1.1 and 1.3)
1741
      if self._DISPLAY_RE.search(kvmhelp):
1742
        kvm_cmd.extend(["-display", "none"])
1743
      else:
1744
        kvm_cmd.extend(["-nographic"])
1745

    
1746
    if hvp[constants.HV_USE_LOCALTIME]:
1747
      kvm_cmd.extend(["-localtime"])
1748

    
1749
    if hvp[constants.HV_KVM_USE_CHROOT]:
1750
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1751

    
1752
    # Add qemu-KVM -cpu param
1753
    if hvp[constants.HV_CPU_TYPE]:
1754
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1755

    
1756
    # Pass a -vga option if requested, or if spice is used, for backwards
1757
    # compatibility.
1758
    if hvp[constants.HV_VGA]:
1759
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1760
    elif spice_bind:
1761
      kvm_cmd.extend(["-vga", "qxl"])
1762

    
1763
    # Various types of usb devices, comma separated
1764
    if hvp[constants.HV_USB_DEVICES]:
1765
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1766
        kvm_cmd.extend(["-usbdevice", dev])
1767

    
1768
    if hvp[constants.HV_KVM_EXTRA]:
1769
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1770

    
1771
    kvm_disks = []
1772
    for disk, link_name in block_devices:
1773
      disk.pci = _GetFreeSlot(pci_reservations, disk.pci, True)
1774
      kvm_disks.append((disk, link_name))
1775

    
1776
    kvm_nics = []
1777
    for nic in instance.nics:
1778
      nic.pci = _GetFreeSlot(pci_reservations, nic.pci, True)
1779
      kvm_nics.append(nic)
1780

    
1781
    hvparams = hvp
1782

    
1783
    return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1784

    
1785
  def _WriteKVMRuntime(self, instance_name, data):
1786
    """Write an instance's KVM runtime
1787

1788
    """
1789
    try:
1790
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1791
                      data=data)
1792
    except EnvironmentError, err:
1793
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1794

    
1795
  @classmethod
1796
  def _ReadKVMRuntime(cls, instance_name):
1797
    """Read an instance's KVM runtime
1798

1799
    """
1800
    try:
1801
      file_content = utils.ReadFile(cls._InstanceKVMRuntime(instance_name))
1802
    except EnvironmentError, err:
1803
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1804
    return file_content
1805

    
1806
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1807
    """Save an instance's KVM runtime
1808

1809
    """
1810
    kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1811

    
1812
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1813
    serialized_disks = [(blk.ToDict(), link)
1814
                            for blk, link in kvm_disks]
1815
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1816
                                      serialized_disks))
1817

    
1818
    self._WriteKVMRuntime(instance.name, serialized_form)
1819

    
1820
  @classmethod
1821
  def _LoadKVMRuntime(cls, instance_name, serialized_runtime=None):
1822
    """Load an instance's KVM runtime
1823

1824
    """
1825
    if not serialized_runtime:
1826
      serialized_runtime = cls._ReadKVMRuntime(instance_name)
1827

    
1828
    return _AnalyzeSerializedRuntime(serialized_runtime)
1829

    
1830
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1831
    """Run the KVM cmd and check for errors
1832

1833
    @type name: string
1834
    @param name: instance name
1835
    @type kvm_cmd: list of strings
1836
    @param kvm_cmd: runcmd input for kvm
1837
    @type tap_fds: list of int
1838
    @param tap_fds: fds of tap devices opened by Ganeti
1839

1840
    """
1841
    try:
1842
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1843
    finally:
1844
      for fd in tap_fds:
1845
        utils_wrapper.CloseFdNoError(fd)
1846

    
1847
    if result.failed:
1848
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1849
                                   (name, result.fail_reason, result.output))
1850
    if not self._InstancePidAlive(name)[2]:
1851
      raise errors.HypervisorError("Failed to start instance %s" % name)
1852

    
1853
  # too many local variables
1854
  # pylint: disable=R0914
1855
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1856
    """Execute a KVM cmd, after completing it with some last minute data.
1857

1858
    @type incoming: tuple of strings
1859
    @param incoming: (target_host_ip, port)
1860
    @type kvmhelp: string
1861
    @param kvmhelp: output of kvm --help
1862

1863
    """
1864
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1865
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1866
    #    have changed since the instance started; only use them if the change
1867
    #    won't affect the inside of the instance (which hasn't been rebooted).
1868
    #  - up_hvp contains the parameters as they were when the instance was
1869
    #    started, plus any new parameter which has been added between ganeti
1870
    #    versions: it is paramount that those default to a value which won't
1871
    #    affect the inside of the instance as well.
1872
    conf_hvp = instance.hvparams
1873
    name = instance.name
1874
    self._CheckDown(name)
1875

    
1876
    temp_files = []
1877

    
1878
    kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1879
    # the first element of kvm_cmd is always the path to the kvm binary
1880
    kvm_path = kvm_cmd[0]
1881
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1882

    
1883
    # We know it's safe to run as a different user upon migration, so we'll use
1884
    # the latest conf, from conf_hvp.
1885
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1886
    if security_model == constants.HT_SM_USER:
1887
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1888

    
1889
    keymap = conf_hvp[constants.HV_KEYMAP]
1890
    if keymap:
1891
      keymap_path = self._InstanceKeymapFile(name)
1892
      # If a keymap file is specified, KVM won't use its internal defaults. By
1893
      # first including the "en-us" layout, an error on loading the actual
1894
      # layout (e.g. because it can't be found) won't lead to a non-functional
1895
      # keyboard. A keyboard with incorrect keys is still better than none.
1896
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1897
      kvm_cmd.extend(["-k", keymap_path])
1898

    
1899
    # We have reasons to believe changing something like the nic driver/type
1900
    # upon migration won't exactly fly with the instance kernel, so for nic
1901
    # related parameters we'll use up_hvp
1902
    tapfds = []
1903
    taps = []
1904
    devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1905

    
1906
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1907
                                                     up_hvp,
1908
                                                     kvm_disks,
1909
                                                     kvmhelp,
1910
                                                     devlist)
1911
    kvm_cmd.extend(bdev_opts)
1912

    
1913
    if not kvm_nics:
1914
      kvm_cmd.extend(["-net", "none"])
1915
    else:
1916
      vnet_hdr = False
1917
      tap_extra = ""
1918
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1919
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1920
        nic_model = self._VIRTIO
1921
        try:
1922
          if self._VIRTIO_NET_RE.search(devlist):
1923
            nic_model = self._VIRTIO_NET_PCI
1924
            vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1925
        except errors.HypervisorError, _:
1926
          # Older versions of kvm don't support DEVICE_LIST, but they don't
1927
          # have new virtio syntax either.
1928
          pass
1929

    
1930
        if up_hvp[constants.HV_VHOST_NET]:
1931
          # check for vhost_net support
1932
          if self._VHOST_RE.search(kvmhelp):
1933
            tap_extra = ",vhost=on"
1934
          else:
1935
            raise errors.HypervisorError("vhost_net is configured"
1936
                                         " but it is not available")
1937
      else:
1938
        nic_model = nic_type
1939

    
1940
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1941

    
1942
      for nic_seq, nic in enumerate(kvm_nics):
1943
        tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1944
        tapfds.append(tapfd)
1945
        taps.append(tapname)
1946
        if kvm_supports_netdev:
1947
          nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1948
          try:
1949
            # kvm_nics already exist in old runtime files and thus there might
1950
            # be some entries without pci slot (therefore try: except:)
1951
            kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1952
            netdev = kvm_devid
1953
            nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1954
          except errors.HotplugError:
1955
            netdev = "netdev%d" % nic_seq
1956
          nic_val += (",netdev=%s" % netdev)
1957
          tap_val = ("type=tap,id=%s,fd=%d%s" %
1958
                     (netdev, tapfd, tap_extra))
1959
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1960
        else:
1961
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1962
                                                         nic.mac, nic_model)
1963
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1964
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1965

    
1966
    if incoming:
1967
      target, port = incoming
1968
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1969

    
1970
    # Changing the vnc password doesn't bother the guest that much. At most it
1971
    # will surprise people who connect to it. Whether positively or negatively
1972
    # it's debatable.
1973
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1974
    vnc_pwd = None
1975
    if vnc_pwd_file:
1976
      try:
1977
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1978
      except EnvironmentError, err:
1979
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1980
                                     % (vnc_pwd_file, err))
1981

    
1982
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1983
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1984
                         constants.SECURE_DIR_MODE)])
1985

    
1986
    # Automatically enable QMP if version is >= 0.14
1987
    if self._QMP_RE.search(kvmhelp):
1988
      logging.debug("Enabling QMP")
1989
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1990
                      self._InstanceQmpMonitor(instance.name)])
1991

    
1992
    # Configure the network now for starting instances and bridged interfaces,
1993
    # during FinalizeMigration for incoming instances' routed interfaces
1994
    for nic_seq, nic in enumerate(kvm_nics):
1995
      if (incoming and
1996
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1997
        continue
1998
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1999

    
2000
    # CPU affinity requires kvm to start paused, so we set this flag if the
2001
    # instance is not already paused and if we are not going to accept a
2002
    # migrating instance. In the latter case, pausing is not needed.
2003
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
2004
    if start_kvm_paused:
2005
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
2006

    
2007
    # Note: CPU pinning is using up_hvp since changes take effect
2008
    # during instance startup anyway, and to avoid problems when soft
2009
    # rebooting the instance.
2010
    cpu_pinning = False
2011
    if up_hvp.get(constants.HV_CPU_MASK, None):
2012
      cpu_pinning = True
2013

    
2014
    if security_model == constants.HT_SM_POOL:
2015
      ss = ssconf.SimpleStore()
2016
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
2017
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
2018
      uid = uidpool.RequestUnusedUid(all_uids)
2019
      try:
2020
        username = pwd.getpwuid(uid.GetUid()).pw_name
2021
        kvm_cmd.extend(["-runas", username])
2022
        self._RunKVMCmd(name, kvm_cmd, tapfds)
2023
      except:
2024
        uidpool.ReleaseUid(uid)
2025
        raise
2026
      else:
2027
        uid.Unlock()
2028
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
2029
    else:
2030
      self._RunKVMCmd(name, kvm_cmd, tapfds)
2031

    
2032
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
2033
                     constants.RUN_DIRS_MODE)])
2034
    for nic_seq, tap in enumerate(taps):
2035
      nic = kvm_nics[nic_seq]
2036
      self._WriteInstanceNICFiles(instance.name, nic_seq, nic, tap)
2037

    
2038
    if vnc_pwd:
2039
      change_cmd = "change vnc password %s" % vnc_pwd
2040
      self._CallMonitorCommand(instance.name, change_cmd)
2041

    
2042
    # Setting SPICE password. We are not vulnerable to malicious passwordless
2043
    # connection attempts because SPICE by default does not allow connections
2044
    # if neither a password nor the "disable_ticketing" options are specified.
2045
    # As soon as we send the password via QMP, that password is a valid ticket
2046
    # for connection.
2047
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
2048
    if spice_password_file:
2049
      spice_pwd = ""
2050
      try:
2051
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
2052
      except EnvironmentError, err:
2053
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
2054
                                     % (spice_password_file, err))
2055

    
2056
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
2057
      qmp.connect()
2058
      arguments = {
2059
          "protocol": "spice",
2060
          "password": spice_pwd,
2061
      }
2062
      qmp.Execute("set_password", arguments)
2063

    
2064
    for filename in temp_files:
2065
      utils.RemoveFile(filename)
2066

    
2067
    # If requested, set CPU affinity and resume instance execution
2068
    if cpu_pinning:
2069
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
2070

    
2071
    start_memory = self._InstanceStartupMemory(instance)
2072
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
2073
      self.BalloonInstanceMemory(instance, start_memory)
2074

    
2075
    if start_kvm_paused:
2076
      # To control CPU pinning, ballooning, and vnc/spice passwords
2077
      # the VM was started in a frozen state. If freezing was not
2078
      # explicitly requested resume the vm status.
2079
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2080

    
2081
  def StartInstance(self, instance, block_devices, startup_paused):
2082
    """Start an instance.
2083

2084
    """
2085
    self._CheckDown(instance.name)
2086
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2087
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2088
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
2089
                                           startup_paused, kvmhelp)
2090
    self._SaveKVMRuntime(instance, kvm_runtime)
2091
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2092

    
2093
  def _CallMonitorCommand(self, instance_name, command, timeout=None):
2094
    """Invoke a command on the instance monitor.
2095

2096
    """
2097
    if timeout is not None:
2098
      timeout_cmd = "timeout %s" % (timeout, )
2099
    else:
2100
      timeout_cmd = ""
2101

    
2102
    # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
2103
    # version. The monitor protocol is designed for human consumption, whereas
2104
    # QMP is made for programmatic usage. In the worst case QMP can also
2105
    # execute monitor commands. As it is, all calls to socat take at least
2106
    # 500ms and likely more: socat can't detect the end of the reply and waits
2107
    # for 500ms of no data received before exiting (500 ms is the default for
2108
    # the "-t" parameter).
2109
    socat = ("echo %s | %s %s STDIO UNIX-CONNECT:%s" %
2110
             (utils.ShellQuote(command),
2111
              timeout_cmd,
2112
              constants.SOCAT_PATH,
2113
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
2114

    
2115
    result = utils.RunCmd(socat)
2116
    if result.failed:
2117
      msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
2118
             " output: %s" %
2119
             (command, instance_name, result.fail_reason, result.output))
2120
      raise errors.HypervisorError(msg)
2121

    
2122
    return result
2123

    
2124
  def _GetFreePCISlot(self, instance, dev):
2125
    """Get the first available pci slot of a runnung instance.
2126

2127
    """
2128
    slots = bitarray(32)
2129
    slots.setall(False) # pylint: disable=E1101
2130
    output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
2131
    for line in output.stdout.splitlines():
2132
      match = self._INFO_PCI_RE.search(line)
2133
      if match:
2134
        slot = int(match.group(1))
2135
        slots[slot] = True
2136

    
2137
    dev.pci = _GetFreeSlot(slots)
2138

    
2139
  def VerifyHotplugSupport(self, instance, action, dev_type):
2140
    """Verifies that hotplug is supported.
2141

2142
    Hotplug is *not* supported in case of:
2143
     - security models and chroot (disk hotplug)
2144
     - fdsend module is missing (nic hot-add)
2145

2146
    @raise errors.HypervisorError: in one of the previous cases
2147

2148
    """
2149
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2150
      hvp = instance.hvparams
2151
      security_model = hvp[constants.HV_SECURITY_MODEL]
2152
      use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
2153
      if use_chroot:
2154
        raise errors.HotplugError("Disk hotplug is not supported"
2155
                                  " in case of chroot.")
2156
      if security_model != constants.HT_SM_NONE:
2157
        raise errors.HotplugError("Disk Hotplug is not supported in case"
2158
                                  " security models are used.")
2159

    
2160
    if (dev_type == constants.HOTPLUG_TARGET_NIC and
2161
        action == constants.HOTPLUG_ACTION_ADD and not fdsend):
2162
      raise errors.HotplugError("Cannot hot-add NIC."
2163
                                " fdsend python module is missing.")
2164

    
2165
  def HotplugSupported(self, instance):
2166
    """Checks if hotplug is generally supported.
2167

2168
    Hotplug is *not* supported in case of:
2169
     - qemu versions < 1.0
2170
     - for stopped instances
2171

2172
    @raise errors.HypervisorError: in one of the previous cases
2173

2174
    """
2175
    try:
2176
      output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2177
    except errors.HypervisorError:
2178
      raise errors.HotplugError("Instance is probably down")
2179

    
2180
    # TODO: search for netdev_add, drive_add, device_add.....
2181
    match = self._INFO_VERSION_RE.search(output.stdout)
2182
    if not match:
2183
      raise errors.HotplugError("Cannot parse qemu version via monitor")
2184

    
2185
    v_major, v_min, _, _ = match.groups()
2186
    if (int(v_major), int(v_min)) < (1, 0):
2187
      raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2188

    
2189
  def _CallHotplugCommands(self, name, cmds):
2190
    for c in cmds:
2191
      self._CallMonitorCommand(name, c)
2192
      time.sleep(1)
2193

    
2194
  def _VerifyHotplugCommand(self, instance_name, device, dev_type,
2195
                            should_exist):
2196
    """Checks if a previous hotplug command has succeeded.
2197

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

2201
    @raise errors.HypervisorError: if result is not the expected one
2202

2203
    """
2204
    output = self._CallMonitorCommand(instance_name, self._INFO_PCI_CMD)
2205
    kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2206
    match = \
2207
      self._FIND_PCI_DEVICE_RE(device.pci, kvm_devid).search(output.stdout)
2208
    if match and not should_exist:
2209
      msg = "Device %s should have been removed but is still there" % kvm_devid
2210
      raise errors.HypervisorError(msg)
2211

    
2212
    if not match and should_exist:
2213
      msg = "Device %s should have been added but is missing" % kvm_devid
2214
      raise errors.HypervisorError(msg)
2215

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

    
2218
  def HotAddDevice(self, instance, dev_type, device, extra, seq):
2219
    """ Helper method to hot-add a new device
2220

2221
    It gets free pci slot generates the device name and invokes the
2222
    device specific method.
2223

2224
    """
2225
    # in case of hot-mod this is given
2226
    if device.pci is None:
2227
      self._GetFreePCISlot(instance, device)
2228
    kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2229
    runtime = self._LoadKVMRuntime(instance.name)
2230
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2231
      cmds = ["drive_add dummy file=%s,if=none,id=%s,format=raw" %
2232
                (extra, kvm_devid)]
2233
      cmds += ["device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
2234
                (hex(device.pci), kvm_devid, kvm_devid)]
2235
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
2236
      (tap, fd) = _OpenTap()
2237
      self._ConfigureNIC(instance, seq, device, tap)
2238
      self._PassTapFd(instance, fd, device)
2239
      cmds = ["netdev_add tap,id=%s,fd=%s" % (kvm_devid, kvm_devid)]
2240
      args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
2241
               (hex(device.pci), device.mac, kvm_devid, kvm_devid)
2242
      cmds += ["device_add %s" % args]
2243
      self._WriteInstanceNICFiles(instance.name, seq, device, tap)
2244

    
2245
    self._CallHotplugCommands(instance.name, cmds)
2246
    self._VerifyHotplugCommand(instance.name, device, dev_type, True)
2247
    # update relevant entries in runtime file
2248
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2249
    entry = _RUNTIME_ENTRY[dev_type](device, extra)
2250
    runtime[index].append(entry)
2251
    self._SaveKVMRuntime(instance, runtime)
2252

    
2253
  def HotDelDevice(self, instance, dev_type, device, _, seq):
2254
    """ Helper method for hot-del device
2255

2256
    It gets device info from runtime file, generates the device name and
2257
    invokes the device specific method.
2258

2259
    """
2260
    runtime = self._LoadKVMRuntime(instance.name)
2261
    entry = _GetExistingDeviceInfo(dev_type, device, runtime)
2262
    kvm_device = _RUNTIME_DEVICE[dev_type](entry)
2263
    kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
2264
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2265
      cmds = ["device_del %s" % kvm_devid]
2266
      cmds += ["drive_del %s" % kvm_devid]
2267
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
2268
      cmds = ["device_del %s" % kvm_devid]
2269
      cmds += ["netdev_del %s" % kvm_devid]
2270
      self._UnconfigureNic(instance.name, kvm_device, False)
2271
      self._RemoveInstanceNICFiles(instance.name, seq, device)
2272
    self._CallHotplugCommands(instance.name, cmds)
2273
    self._VerifyHotplugCommand(instance.name, kvm_device, dev_type, False)
2274
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2275
    runtime[index].remove(entry)
2276
    self._SaveKVMRuntime(instance, runtime)
2277

    
2278
    return kvm_device.pci
2279

    
2280
  def HotModDevice(self, instance, dev_type, device, _, seq):
2281
    """ Helper method for hot-mod device
2282

2283
    It gets device info from runtime file, generates the device name and
2284
    invokes the device specific method. Currently only NICs support hot-mod
2285

2286
    """
2287
    if dev_type == constants.HOTPLUG_TARGET_NIC:
2288
      # putting it back in the same pci slot
2289
      device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2290
      # TODO: remove sleep when socat gets removed
2291
      self.HotAddDevice(instance, dev_type, device, _, seq)
2292

    
2293
  def _PassTapFd(self, instance, fd, nic):
2294
    """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2295

2296
    """
2297
    # TODO: factor out code related to unix sockets.
2298
    #       squash common parts between monitor and qmp
2299
    kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2300
    command = "getfd %s\n" % kvm_devid
2301
    fds = [fd]
2302
    logging.info("%s", fds)
2303
    try:
2304
      monsock = MonitorSocket(self._InstanceMonitor(instance.name))
2305
      monsock.connect()
2306
      fdsend.sendfds(monsock.sock, command, fds=fds)
2307
    finally:
2308
      monsock.close()
2309

    
2310
  @classmethod
2311
  def _ParseKVMVersion(cls, text):
2312
    """Parse the KVM version from the --help output.
2313

2314
    @type text: string
2315
    @param text: output of kvm --help
2316
    @return: (version, v_maj, v_min, v_rev)
2317
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2318

2319
    """
2320
    match = cls._VERSION_RE.search(text.splitlines()[0])
2321
    if not match:
2322
      raise errors.HypervisorError("Unable to get KVM version")
2323

    
2324
    v_all = match.group(0)
2325
    v_maj = int(match.group(1))
2326
    v_min = int(match.group(2))
2327
    if match.group(4):
2328
      v_rev = int(match.group(4))
2329
    else:
2330
      v_rev = 0
2331
    return (v_all, v_maj, v_min, v_rev)
2332

    
2333
  @classmethod
2334
  def _GetKVMOutput(cls, kvm_path, option):
2335
    """Return the output of a kvm invocation
2336

2337
    @type kvm_path: string
2338
    @param kvm_path: path to the kvm executable
2339
    @type option: a key of _KVMOPTS_CMDS
2340
    @param option: kvm option to fetch the output from
2341
    @return: output a supported kvm invocation
2342
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2343

2344
    """
2345
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2346

    
2347
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
2348

    
2349
    result = utils.RunCmd([kvm_path] + optlist)
2350
    if result.failed and not can_fail:
2351
      raise errors.HypervisorError("Unable to get KVM %s output" %
2352
                                    " ".join(optlist))
2353
    return result.output
2354

    
2355
  @classmethod
2356
  def _GetKVMVersion(cls, kvm_path):
2357
    """Return the installed KVM version.
2358

2359
    @return: (version, v_maj, v_min, v_rev)
2360
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2361

2362
    """
2363
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2364

    
2365
  @classmethod
2366
  def _GetDefaultMachineVersion(cls, kvm_path):
2367
    """Return the default hardware revision (e.g. pc-1.1)
2368

2369
    """
2370
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2371
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2372
    if match:
2373
      return match.group(1)
2374
    else:
2375
      return "pc"
2376

    
2377
  def StopInstance(self, instance, force=False, retry=False, name=None,
2378
                   timeout=None):
2379
    """Stop an instance.
2380

2381
    """
2382
    assert(timeout is None or force is not None)
2383

    
2384
    if name is not None and not force:
2385
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2386
    if name is None:
2387
      name = instance.name
2388
      acpi = instance.hvparams[constants.HV_ACPI]
2389
    else:
2390
      acpi = False
2391
    _, pid, alive = self._InstancePidAlive(name)
2392
    if pid > 0 and alive:
2393
      if force or not acpi:
2394
        utils.KillProcess(pid)
2395
      else:
2396
        self._CallMonitorCommand(name, "system_powerdown", timeout)
2397

    
2398
  @classmethod
2399
  def _UnconfigureInstanceNICs(cls, instance_name, info=None):
2400
    """Get runtime NICs of an instance and unconfigure them
2401

2402
    """
2403
    _, kvm_nics, __, ___ = cls._LoadKVMRuntime(instance_name, info)
2404
    for nic in kvm_nics:
2405
      cls._UnconfigureNic(instance_name, nic)
2406

    
2407
  def CleanupInstance(self, instance_name):
2408
    """Cleanup after a stopped instance
2409

2410
    """
2411
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
2412
    if pid > 0 and alive:
2413
      raise errors.HypervisorError("Cannot cleanup a live instance")
2414
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2415

    
2416
  def RebootInstance(self, instance):
2417
    """Reboot an instance.
2418

2419
    """
2420
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2421
    # socket the instance will stop, but now power up again. So we'll resort
2422
    # to shutdown and restart.
2423
    _, _, alive = self._InstancePidAlive(instance.name)
2424
    if not alive:
2425
      raise errors.HypervisorError("Failed to reboot instance %s:"
2426
                                   " not running" % instance.name)
2427
    # StopInstance will delete the saved KVM runtime so:
2428
    # ...first load it...
2429
    kvm_runtime = self._LoadKVMRuntime(instance.name)
2430
    # ...now we can safely call StopInstance...
2431
    if not self.StopInstance(instance):
2432
      self.StopInstance(instance, force=True)
2433
    # ...and finally we can save it again, and execute it...
2434
    self._SaveKVMRuntime(instance, kvm_runtime)
2435
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2436
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2437
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2438

    
2439
  def MigrationInfo(self, instance):
2440
    """Get instance information to perform a migration.
2441

2442
    @type instance: L{objects.Instance}
2443
    @param instance: instance to be migrated
2444
    @rtype: string
2445
    @return: content of the KVM runtime file
2446

2447
    """
2448
    return self._ReadKVMRuntime(instance.name)
2449

    
2450
  def AcceptInstance(self, instance, info, target):
2451
    """Prepare to accept an instance.
2452

2453
    @type instance: L{objects.Instance}
2454
    @param instance: instance to be accepted
2455
    @type info: string
2456
    @param info: content of the KVM runtime file on the source node
2457
    @type target: string
2458
    @param target: target host (usually ip), on this node
2459

2460
    """
2461
    kvm_runtime = self._LoadKVMRuntime(instance.name, serialized_runtime=info)
2462
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2463
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2464
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2465
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2466
                            incoming=incoming_address)
2467

    
2468
  def FinalizeMigrationDst(self, instance, info, success):
2469
    """Finalize the instance migration on the target node.
2470

2471
    Stop the incoming mode KVM.
2472

2473
    @type instance: L{objects.Instance}
2474
    @param instance: instance whose migration is being finalized
2475

2476
    """
2477
    if success:
2478
      kvm_runtime = self._LoadKVMRuntime(instance.name, serialized_runtime=info)
2479
      kvm_nics = kvm_runtime[1]
2480

    
2481
      for nic_seq, nic in enumerate(kvm_nics):
2482
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2483
          # Bridged interfaces have already been configured
2484
          continue
2485
        try:
2486
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2487
        except EnvironmentError, err:
2488
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
2489
                          instance.name, nic_seq, str(err))
2490
          continue
2491
        try:
2492
          self._ConfigureNIC(instance, nic_seq, nic, tap)
2493
        except errors.HypervisorError, err:
2494
          logging.warning(str(err))
2495

    
2496
      self._WriteKVMRuntime(instance.name, info)
2497
    else:
2498
      self._UnconfigureInstanceNICs(instance.name, info)
2499
      self.StopInstance(instance, force=True)
2500

    
2501
  def MigrateInstance(self, instance, target, live):
2502
    """Migrate an instance to a target node.
2503

2504
    The migration will not be attempted if the instance is not
2505
    currently running.
2506

2507
    @type instance: L{objects.Instance}
2508
    @param instance: the instance to be migrated
2509
    @type target: string
2510
    @param target: ip address of the target node
2511
    @type live: boolean
2512
    @param live: perform a live migration
2513

2514
    """
2515
    instance_name = instance.name
2516
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
2517
    _, _, alive = self._InstancePidAlive(instance_name)
2518
    if not alive:
2519
      raise errors.HypervisorError("Instance not running, cannot migrate")
2520

    
2521
    if not live:
2522
      self._CallMonitorCommand(instance_name, "stop")
2523

    
2524
    migrate_command = ("migrate_set_speed %dm" %
2525
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2526
    self._CallMonitorCommand(instance_name, migrate_command)
2527

    
2528
    migrate_command = ("migrate_set_downtime %dms" %
2529
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2530
    self._CallMonitorCommand(instance_name, migrate_command)
2531

    
2532
    # These commands are supported in latest qemu versions.
2533
    # Since _CallMonitorCommand does not catch monitor errors
2534
    # this does not raise an exception in case command is not supported
2535
    # TODO: either parse output of command or see if the command supported
2536
    # via info help (see hotplug)
2537
    migration_caps = instance.hvparams[constants.HV_KVM_MIGRATION_CAPS]
2538
    if migration_caps:
2539
      for c in migration_caps.split(_MIGRATION_CAPS_DELIM):
2540
        migrate_command = ("migrate_set_capability %s on" % c)
2541
        self._CallMonitorCommand(instance_name, migrate_command)
2542

    
2543
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2544
    self._CallMonitorCommand(instance_name, migrate_command)
2545

    
2546
  def FinalizeMigrationSource(self, instance, success, live):
2547
    """Finalize the instance migration on the source node.
2548

2549
    @type instance: L{objects.Instance}
2550
    @param instance: the instance that was migrated
2551
    @type success: bool
2552
    @param success: whether the migration succeeded or not
2553
    @type live: bool
2554
    @param live: whether the user requested a live migration or not
2555

2556
    """
2557
    if success:
2558
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2559
      utils.KillProcess(pid)
2560
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2561
    elif live:
2562
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2563

    
2564
  def GetMigrationStatus(self, instance):
2565
    """Get the migration status
2566

2567
    @type instance: L{objects.Instance}
2568
    @param instance: the instance that is being migrated
2569
    @rtype: L{objects.MigrationStatus}
2570
    @return: the status of the current migration (one of
2571
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2572
             progress info that can be retrieved from the hypervisor
2573

2574
    """
2575
    info_command = "info migrate"
2576
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2577
      result = self._CallMonitorCommand(instance.name, info_command)
2578
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
2579
      if not match:
2580
        if not result.stdout:
2581
          logging.info("KVM: empty 'info migrate' result")
2582
        else:
2583
          logging.warning("KVM: unknown 'info migrate' result: %s",
2584
                          result.stdout)
2585
      else:
2586
        status = match.group(1)
2587
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2588
          migration_status = objects.MigrationStatus(status=status)
2589
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2590
          if match:
2591
            migration_status.transferred_ram = match.group("transferred")
2592
            migration_status.total_ram = match.group("total")
2593

    
2594
          return migration_status
2595

    
2596
        logging.warning("KVM: unknown migration status '%s'", status)
2597

    
2598
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2599

    
2600
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2601

    
2602
  def BalloonInstanceMemory(self, instance, mem):
2603
    """Balloon an instance memory to a certain value.
2604

2605
    @type instance: L{objects.Instance}
2606
    @param instance: instance to be accepted
2607
    @type mem: int
2608
    @param mem: actual memory size to use for instance runtime
2609

2610
    """
2611
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2612

    
2613
  def GetNodeInfo(self):
2614
    """Return information about the node.
2615

2616
    @return: a dict with the following keys (values in MiB):
2617
          - memory_total: the total memory size on the node
2618
          - memory_free: the available memory on the node for instances
2619
          - memory_dom0: the memory used by the node itself, if available
2620
          - hv_version: the hypervisor version in the form (major, minor,
2621
                        revision)
2622

2623
    """
2624
    result = self.GetLinuxNodeInfo()
2625
    # FIXME: this is the global kvm version, but the actual version can be
2626
    # customized as an hv parameter. we should use the nodegroup's default kvm
2627
    # path parameter here.
2628
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2629
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2630
    return result
2631

    
2632
  @classmethod
2633
  def GetInstanceConsole(cls, instance, hvparams, beparams):
2634
    """Return a command for connecting to the console of an instance.
2635

2636
    """
2637
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2638
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2639
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2640
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2641
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2642
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2643
      return objects.InstanceConsole(instance=instance.name,
2644
                                     kind=constants.CONS_SSH,
2645
                                     host=instance.primary_node,
2646
                                     user=constants.SSH_CONSOLE_USER,
2647
                                     command=cmd)
2648

    
2649
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2650
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2651
      display = instance.network_port - constants.VNC_BASE_PORT
2652
      return objects.InstanceConsole(instance=instance.name,
2653
                                     kind=constants.CONS_VNC,
2654
                                     host=vnc_bind_address,
2655
                                     port=instance.network_port,
2656
                                     display=display)
2657

    
2658
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2659
    if spice_bind:
2660
      return objects.InstanceConsole(instance=instance.name,
2661
                                     kind=constants.CONS_SPICE,
2662
                                     host=spice_bind,
2663
                                     port=instance.network_port)
2664

    
2665
    return objects.InstanceConsole(instance=instance.name,
2666
                                   kind=constants.CONS_MESSAGE,
2667
                                   message=("No serial shell for instance %s" %
2668
                                            instance.name))
2669

    
2670
  def Verify(self):
2671
    """Verify the hypervisor.
2672

2673
    Check that the required binaries exist.
2674

2675
    @return: Problem description if something is wrong, C{None} otherwise
2676

2677
    """
2678
    msgs = []
2679
    # FIXME: this is the global kvm binary, but the actual path can be
2680
    # customized as an hv parameter; we should use the nodegroup's
2681
    # default kvm path parameter here.
2682
    if not os.path.exists(constants.KVM_PATH):
2683
      msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2684
    if not os.path.exists(constants.SOCAT_PATH):
2685
      msgs.append("The socat binary ('%s') does not exist" %
2686
                  constants.SOCAT_PATH)
2687

    
2688
    return self._FormatVerifyResults(msgs)
2689

    
2690
  @classmethod
2691
  def CheckParameterSyntax(cls, hvparams):
2692
    """Check the given parameters for validity.
2693

2694
    @type hvparams:  dict
2695
    @param hvparams: dictionary with parameter names/value
2696
    @raise errors.HypervisorError: when a parameter is not valid
2697

2698
    """
2699
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2700

    
2701
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2702
    if kernel_path:
2703
      if not hvparams[constants.HV_ROOT_PATH]:
2704
        raise errors.HypervisorError("Need a root partition for the instance,"
2705
                                     " if a kernel is defined")
2706

    
2707
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2708
        not hvparams[constants.HV_VNC_X509]):
2709
      raise errors.HypervisorError("%s must be defined, if %s is" %
2710
                                   (constants.HV_VNC_X509,
2711
                                    constants.HV_VNC_X509_VERIFY))
2712

    
2713
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2714
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2715
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2716
      if not serial_speed or serial_speed not in valid_speeds:
2717
        raise errors.HypervisorError("Invalid serial console speed, must be"
2718
                                     " one of: %s" %
2719
                                     utils.CommaJoin(valid_speeds))
2720

    
2721
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2722
    if (boot_order == constants.HT_BO_CDROM and
2723
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2724
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2725
                                   " ISO path")
2726

    
2727
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2728
    if security_model == constants.HT_SM_USER:
2729
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2730
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2731
                                     " must be specified")
2732
    elif (security_model == constants.HT_SM_NONE or
2733
          security_model == constants.HT_SM_POOL):
2734
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2735
        raise errors.HypervisorError("Cannot have a security domain when the"
2736
                                     " security model is 'none' or 'pool'")
2737

    
2738
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2739
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2740
    if spice_bind:
2741
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2742
        # if an IP version is specified, the spice_bind parameter must be an
2743
        # IP of that family
2744
        if (netutils.IP4Address.IsValid(spice_bind) and
2745
            spice_ip_version != constants.IP4_VERSION):
2746
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2747
                                       " the specified IP version is %s" %
2748
                                       (spice_bind, spice_ip_version))
2749

    
2750
        if (netutils.IP6Address.IsValid(spice_bind) and
2751
            spice_ip_version != constants.IP6_VERSION):
2752
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2753
                                       " the specified IP version is %s" %
2754
                                       (spice_bind, spice_ip_version))
2755
    else:
2756
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2757
      # error if any of them is set without it.
2758
      for param in _SPICE_ADDITIONAL_PARAMS:
2759
        if hvparams[param]:
2760
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2761
                                       (param, constants.HV_KVM_SPICE_BIND))
2762

    
2763
  @classmethod
2764
  def ValidateParameters(cls, hvparams):
2765
    """Check the given parameters for validity.
2766

2767
    @type hvparams:  dict
2768
    @param hvparams: dictionary with parameter names/value
2769
    @raise errors.HypervisorError: when a parameter is not valid
2770

2771
    """
2772
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2773

    
2774
    kvm_path = hvparams[constants.HV_KVM_PATH]
2775

    
2776
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2777
    if security_model == constants.HT_SM_USER:
2778
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2779
      try:
2780
        pwd.getpwnam(username)
2781
      except KeyError:
2782
        raise errors.HypervisorError("Unknown security domain user %s"
2783
                                     % username)
2784

    
2785
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2786
    if spice_bind:
2787
      # only one of VNC and SPICE can be used currently.
2788
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2789
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2790
                                     " only one of them can be used at a"
2791
                                     " given time")
2792

    
2793
      # check that KVM supports SPICE
2794
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2795
      if not cls._SPICE_RE.search(kvmhelp):
2796
        raise errors.HypervisorError("SPICE is configured, but it is not"
2797
                                     " supported according to 'kvm --help'")
2798

    
2799
      # if spice_bind is not an IP address, it must be a valid interface
2800
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2801
                       netutils.IP6Address.IsValid(spice_bind))
2802
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2803
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2804
                                     " a valid IP address or interface name" %
2805
                                     constants.HV_KVM_SPICE_BIND)
2806

    
2807
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2808
    if machine_version:
2809
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2810
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2811
        raise errors.HypervisorError("Unsupported machine version: %s" %
2812
                                     machine_version)
2813

    
2814
  @classmethod
2815
  def PowercycleNode(cls):
2816
    """KVM powercycle, just a wrapper over Linux powercycle.
2817

2818
    """
2819
    cls.LinuxPowercycle()