Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ c6407ff7

History | View | Annotate | Download (101.8 kB)

1
#
2
#
3

    
4
# Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

    
21

    
22
"""KVM hypervisor
23

24
"""
25

    
26
import errno
27
import os
28
import os.path
29
import re
30
import tempfile
31
import time
32
import logging
33
import pwd
34
import struct
35
import fcntl
36
import shutil
37
import socket
38
import stat
39
import StringIO
40
from bitarray import bitarray
41
try:
42
  import affinity   # pylint: disable=F0401
43
except ImportError:
44
  affinity = None
45
try:
46
  import fdsend   # pylint: disable=F0401
47
except ImportError:
48
  fdsend = None
49

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

    
62

    
63
_KVM_NETWORK_SCRIPT = pathutils.CONF_DIR + "/kvm-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, uri)
95
_KVM_NICS_RUNTIME_INDEX = 1
96
_KVM_DISKS_RUNTIME_INDEX = 3
97
_DEVICE_RUNTIME_INDEX = {
98
  constants.HOTPLUG_TARGET_DISK: _KVM_DISKS_RUNTIME_INDEX,
99
  constants.HOTPLUG_TARGET_NIC: _KVM_NICS_RUNTIME_INDEX
100
  }
101
_FIND_RUNTIME_ENTRY = {
102
  constants.HOTPLUG_TARGET_NIC:
103
    lambda nic, kvm_nics: [n for n in kvm_nics if n.uuid == nic.uuid],
104
  constants.HOTPLUG_TARGET_DISK:
105
    lambda disk, kvm_disks: [(d, l, u) for (d, l, u) in kvm_disks
106
                             if d.uuid == disk.uuid]
107
  }
108
_RUNTIME_DEVICE = {
109
  constants.HOTPLUG_TARGET_NIC: lambda d: d,
110
  constants.HOTPLUG_TARGET_DISK: lambda (d, e, _): d
111
  }
112
_RUNTIME_ENTRY = {
113
  constants.HOTPLUG_TARGET_NIC: lambda d, e: d,
114
  constants.HOTPLUG_TARGET_DISK: lambda d, e: (d, e, None)
115
  }
116

    
117
_MIGRATION_CAPS_DELIM = ":"
118

    
119

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

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

    
141

    
142
def _GetFreeSlot(slots, slot=None, reserve=False):
143
  """Helper method to get first available slot in a bitarray
144

145
  @type slots: bitarray
146
  @param slots: the bitarray to operate on
147
  @type slot: integer
148
  @param slot: if given we check whether the slot is free
149
  @type reserve: boolean
150
  @param reserve: whether to reserve the first available slot or not
151
  @return: the idx of the (first) available slot
152
  @raise errors.HotplugError: If all slots in a bitarray are occupied
153
    or the given slot is not free.
154

155
  """
156
  if slot is not None:
157
    assert slot < len(slots)
158
    if slots[slot]:
159
      raise errors.HypervisorError("Slots %d occupied" % slot)
160

    
161
  else:
162
    avail = slots.search(_AVAILABLE_PCI_SLOT, 1)
163
    if not avail:
164
      raise errors.HypervisorError("All slots occupied")
165

    
166
    slot = int(avail[0])
167

    
168
  if reserve:
169
    slots[slot] = True
170

    
171
  return slot
172

    
173

    
174
def _GetExistingDeviceInfo(dev_type, device, runtime):
175
  """Helper function to get an existing device inside the runtime file
176

177
  Used when an instance is running. Load kvm runtime file and search
178
  for a device based on its type and uuid.
179

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

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

    
197
  return found[0]
198

    
199

    
200
def _UpgradeSerializedRuntime(serialized_runtime):
201
  """Upgrade runtime data
202

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

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

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

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

    
225
  return kvm_cmd, serialized_nics, hvparams, serialized_disks
226

    
227

    
228
def _AnalyzeSerializedRuntime(serialized_runtime):
229
  """Return runtime entries for a serialized runtime file
230

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

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

    
243
  return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
244

    
245

    
246
def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
247
  """Retrieves supported TUN features from file descriptor.
248

249
  @see: L{_ProbeTapVnetHdr}
250

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

    
262

    
263
def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
264
  """Check whether to enable the IFF_VNET_HDR flag.
265

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

276
   @type fd: int
277
   @param fd: the file descriptor of /dev/net/tun
278

279
  """
280
  flags = _features_fn(fd)
281

    
282
  if flags is None:
283
    # Not supported
284
    return False
285

    
286
  result = bool(flags & IFF_VNET_HDR)
287

    
288
  if not result:
289
    logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
290

    
291
  return result
292

    
293

    
294
def _OpenTap(vnet_hdr=True):
295
  """Open a new tap device and return its file descriptor.
296

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

300
  @type vnet_hdr: boolean
301
  @param vnet_hdr: Enable the VNET Header
302
  @return: (ifname, tapfd)
303
  @rtype: tuple
304

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

    
311
  flags = IFF_TAP | IFF_NO_PI
312

    
313
  if vnet_hdr and _ProbeTapVnetHdr(tapfd):
314
    flags |= IFF_VNET_HDR
315

    
316
  # The struct ifreq ioctl request (see netdevice(7))
317
  ifr = struct.pack("16sh", "", flags)
318

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

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

    
329

    
330
class QmpMessage:
331
  """QEMU Messaging Protocol (QMP) message.
332

333
  """
334
  def __init__(self, data):
335
    """Creates a new QMP message based on the passed data.
336

337
    """
338
    if not isinstance(data, dict):
339
      raise TypeError("QmpMessage must be initialized with a dict")
340

    
341
    self.data = data
342

    
343
  def __getitem__(self, field_name):
344
    """Get the value of the required field if present, or None.
345

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

351
    """
352
    return self.data.get(field_name, None)
353

    
354
  def __setitem__(self, field_name, field_value):
355
    """Set the value of the required field_name to field_value.
356

357
    """
358
    self.data[field_name] = field_value
359

    
360
  def __len__(self):
361
    """Return the number of fields stored in this QmpMessage.
362

363
    """
364
    return len(self.data)
365

    
366
  def __delitem__(self, key):
367
    """Delete the specified element from the QmpMessage.
368

369
    """
370
    del(self.data[key])
371

    
372
  @staticmethod
373
  def BuildFromJsonString(json_string):
374
    """Build a QmpMessage from a JSON encoded string.
375

376
    @type json_string: str
377
    @param json_string: JSON string representing the message
378
    @rtype: L{QmpMessage}
379
    @return: a L{QmpMessage} built from json_string
380

381
    """
382
    # Parse the string
383
    data = serializer.LoadJson(json_string)
384
    return QmpMessage(data)
385

    
386
  def __str__(self):
387
    # The protocol expects the JSON object to be sent as a single line.
388
    return serializer.DumpJson(self.data)
389

    
390
  def __eq__(self, other):
391
    # When comparing two QmpMessages, we are interested in comparing
392
    # their internal representation of the message data
393
    return self.data == other.data
394

    
395

    
396
class MonitorSocket(object):
397
  _SOCKET_TIMEOUT = 5
398

    
399
  def __init__(self, monitor_filename):
400
    """Instantiates the MonitorSocket object.
401

402
    @type monitor_filename: string
403
    @param monitor_filename: the filename of the UNIX raw socket on which the
404
                             monitor (QMP or simple one) is listening
405

406
    """
407
    self.monitor_filename = monitor_filename
408
    self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
409
    # We want to fail if the server doesn't send a complete message
410
    # in a reasonable amount of time
411
    self.sock.settimeout(self._SOCKET_TIMEOUT)
412
    self._connected = False
413

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

    
427
  def _check_connection(self):
428
    """Make sure that the connection is established.
429

430
    """
431
    if not self._connected:
432
      raise errors.ProgrammerError("To use a MonitorSocket you need to first"
433
                                   " invoke connect() on it")
434

    
435
  def connect(self):
436
    """Connects to the monitor.
437

438
    Connects to the UNIX socket
439

440
    @raise errors.HypervisorError: when there are communication errors
441

442
    """
443
    if self._connected:
444
      raise errors.ProgrammerError("Cannot connect twice")
445

    
446
    self._check_socket()
447

    
448
    # Check file existance/stuff
449
    try:
450
      self.sock.connect(self.monitor_filename)
451
    except EnvironmentError:
452
      raise errors.HypervisorError("Can't connect to qmp socket")
453
    self._connected = True
454

    
455
  def close(self):
456
    """Closes the socket
457

458
    It cannot be used after this call.
459

460
    """
461
    self.sock.close()
462

    
463

    
464
class QmpConnection(MonitorSocket):
465
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
466

467
  """
468
  _FIRST_MESSAGE_KEY = "QMP"
469
  _EVENT_KEY = "event"
470
  _ERROR_KEY = "error"
471
  _RETURN_KEY = RETURN_KEY = "return"
472
  _ACTUAL_KEY = ACTUAL_KEY = "actual"
473
  _ERROR_CLASS_KEY = "class"
474
  _ERROR_DESC_KEY = "desc"
475
  _EXECUTE_KEY = "execute"
476
  _ARGUMENTS_KEY = "arguments"
477
  _CAPABILITIES_COMMAND = "qmp_capabilities"
478
  _MESSAGE_END_TOKEN = "\r\n"
479

    
480
  def __init__(self, monitor_filename):
481
    super(QmpConnection, self).__init__(monitor_filename)
482
    self._buf = ""
483

    
484
  def connect(self):
485
    """Connects to the QMP monitor.
486

487
    Connects to the UNIX socket and makes sure that we can actually send and
488
    receive data to the kvm instance via QMP.
489

490
    @raise errors.HypervisorError: when there are communication errors
491
    @raise errors.ProgrammerError: when there are data serialization errors
492

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

    
503
    # This is needed because QMP can return more than one greetings
504
    # see https://groups.google.com/d/msg/ganeti-devel/gZYcvHKDooU/SnukC8dgS5AJ
505
    self._buf = ""
506

    
507
    # Let's put the monitor in command mode using the qmp_capabilities
508
    # command, or else no command will be executable.
509
    # (As per the QEMU Protocol Specification 0.1 - section 4)
510
    self.Execute(self._CAPABILITIES_COMMAND)
511

    
512
  def _ParseMessage(self, buf):
513
    """Extract and parse a QMP message from the given buffer.
514

515
    Seeks for a QMP message in the given buf. If found, it parses it and
516
    returns it together with the rest of the characters in the buf.
517
    If no message is found, returns None and the whole buffer.
518

519
    @raise errors.ProgrammerError: when there are data serialization errors
520

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

    
533
    return (message, buf)
534

    
535
  def _Recv(self):
536
    """Receives a message from QMP and decodes the received JSON object.
537

538
    @rtype: QmpMessage
539
    @return: the received message
540
    @raise errors.HypervisorError: when there are communication errors
541
    @raise errors.ProgrammerError: when there are data serialization errors
542

543
    """
544
    self._check_connection()
545

    
546
    # Check if there is already a message in the buffer
547
    (message, self._buf) = self._ParseMessage(self._buf)
548
    if message:
549
      return message
550

    
551
    recv_buffer = StringIO.StringIO(self._buf)
552
    recv_buffer.seek(len(self._buf))
553
    try:
554
      while True:
555
        data = self.sock.recv(4096)
556
        if not data:
557
          break
558
        recv_buffer.write(data)
559

    
560
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
561
        if message:
562
          return message
563

    
564
    except socket.timeout, err:
565
      raise errors.HypervisorError("Timeout while receiving a QMP message: "
566
                                   "%s" % (err))
567
    except socket.error, err:
568
      raise errors.HypervisorError("Unable to receive data from KVM using the"
569
                                   " QMP protocol: %s" % err)
570

    
571
  def _Send(self, message):
572
    """Encodes and sends a message to KVM using QMP.
573

574
    @type message: QmpMessage
575
    @param message: message to send to KVM
576
    @raise errors.HypervisorError: when there are communication errors
577
    @raise errors.ProgrammerError: when there are data serialization errors
578

579
    """
580
    self._check_connection()
581
    try:
582
      message_str = str(message)
583
    except Exception, err:
584
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
585

    
586
    try:
587
      self.sock.sendall(message_str)
588
    except socket.timeout, err:
589
      raise errors.HypervisorError("Timeout while sending a QMP message: "
590
                                   "%s (%s)" % (err.string, err.errno))
591
    except socket.error, err:
592
      raise errors.HypervisorError("Unable to send data from KVM using the"
593
                                   " QMP protocol: %s" % err)
594

    
595
  def Execute(self, command, arguments=None):
596
    """Executes a QMP command and returns the response of the server.
597

598
    @type command: str
599
    @param command: the command to execute
600
    @type arguments: dict
601
    @param arguments: dictionary of arguments to be passed to the command
602
    @rtype: dict
603
    @return: dictionary representing the received JSON object
604
    @raise errors.HypervisorError: when there are communication errors
605
    @raise errors.ProgrammerError: when there are data serialization errors
606

607
    """
608
    self._check_connection()
609
    message = QmpMessage({self._EXECUTE_KEY: command})
610
    if arguments:
611
      message[self._ARGUMENTS_KEY] = arguments
612
    self._Send(message)
613

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

    
626
      elif not response[self._EVENT_KEY]:
627
        return response
628

    
629

    
630
class KVMHypervisor(hv_base.BaseHypervisor):
631
  """KVM hypervisor interface
632

633
  """
634
  CAN_MIGRATE = True
635

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

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

    
736
  _VIRTIO = "virtio"
737
  _VIRTIO_NET_PCI = "virtio-net-pci"
738
  _VIRTIO_BLK_PCI = "virtio-blk-pci"
739

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

    
747
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
748
  _MIGRATION_INFO_RETRY_DELAY = 2
749

    
750
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
751

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

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

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

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

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

    
787
  # Slot 0 for Host bridge, Slot 1 for ISA bridge, Slot 2 for VGA controller
788
  _DEFAULT_PCI_RESERVATIONS = "11100000000000000000000000000000"
789
  _SOUNDHW_WITH_PCI_SLOT = ["ac97", "es1370", "hda"]
790

    
791
  ANCILLARY_FILES = [
792
    _KVM_NETWORK_SCRIPT,
793
    ]
794
  ANCILLARY_FILES_OPT = [
795
    _KVM_NETWORK_SCRIPT,
796
    ]
797

    
798
  # Supported kvm options to get output from
799
  _KVMOPT_HELP = "help"
800
  _KVMOPT_MLIST = "mlist"
801
  _KVMOPT_DEVICELIST = "devicelist"
802

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

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

    
818
  @classmethod
819
  def _InstancePidFile(cls, instance_name):
820
    """Returns the instance pidfile.
821

822
    """
823
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
824

    
825
  @classmethod
826
  def _InstanceUidFile(cls, instance_name):
827
    """Returns the instance uidfile.
828

829
    """
830
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
831

    
832
  @classmethod
833
  def _InstancePidInfo(cls, pid):
834
    """Check pid file for instance information.
835

836
    Check that a pid file is associated with an instance, and retrieve
837
    information from its command line.
838

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

845
    """
846
    alive = utils.IsProcessAlive(pid)
847
    if not alive:
848
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
849

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

    
857
    instance = None
858
    memory = 0
859
    vcpus = 0
860

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

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

    
875
    return (instance, memory, vcpus)
876

    
877
  def _InstancePidAlive(self, instance_name):
878
    """Returns the instance pidfile, pid, and liveness.
879

880
    @type instance_name: string
881
    @param instance_name: instance name
882
    @rtype: tuple
883
    @return: (pid file name, pid, liveness)
884

885
    """
886
    pidfile = self._InstancePidFile(instance_name)
887
    pid = utils.ReadPidFile(pidfile)
888

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

    
896
    return (pidfile, pid, alive)
897

    
898
  def _CheckDown(self, instance_name):
899
    """Raises an error unless the given instance is down.
900

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

    
907
  @classmethod
908
  def _InstanceMonitor(cls, instance_name):
909
    """Returns the instance monitor socket name
910

911
    """
912
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
913

    
914
  @classmethod
915
  def _InstanceSerial(cls, instance_name):
916
    """Returns the instance serial socket name
917

918
    """
919
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
920

    
921
  @classmethod
922
  def _InstanceQmpMonitor(cls, instance_name):
923
    """Returns the instance serial QMP socket name
924

925
    """
926
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
927

    
928
  @staticmethod
929
  def _SocatUnixConsoleParams():
930
    """Returns the correct parameters for socat
931

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

934
    """
935
    if constants.SOCAT_USE_ESCAPE:
936
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
937
    else:
938
      return "echo=0,icanon=0"
939

    
940
  @classmethod
941
  def _InstanceKVMRuntime(cls, instance_name):
942
    """Returns the instance KVM runtime filename
943

944
    """
945
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
946

    
947
  @classmethod
948
  def _InstanceChrootDir(cls, instance_name):
949
    """Returns the name of the KVM chroot dir of the instance
950

951
    """
952
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
953

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

959
    """
960
    return utils.PathJoin(cls._NICS_DIR, instance_name)
961

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

966
    """
967
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq_or_uuid))
968

    
969
  @classmethod
970
  def _GetInstanceNICTap(cls, instance_name, nic):
971
    """Returns the tap for the corresponding nic
972

973
    Search for tap file named after NIC's uuid.
974
    For old instances without uuid indexed tap files returns nothing.
975

976
    """
977
    try:
978
      return utils.ReadFile(cls._InstanceNICFile(instance_name, nic.uuid))
979
    except EnvironmentError:
980
      pass
981

    
982
  @classmethod
983
  def _WriteInstanceNICFiles(cls, instance_name, seq, nic, tap):
984
    """Write tap name to both instance NIC files
985

986
    """
987
    for ident in [seq, nic.uuid]:
988
      utils.WriteFile(cls._InstanceNICFile(instance_name, ident), data=tap)
989

    
990
  @classmethod
991
  def _RemoveInstanceNICFiles(cls, instance_name, seq, nic):
992
    """Write tap name to both instance NIC files
993

994
    """
995
    for ident in [seq, nic.uuid]:
996
      utils.RemoveFile(cls._InstanceNICFile(instance_name, ident))
997

    
998
  @classmethod
999
  def _InstanceKeymapFile(cls, instance_name):
1000
    """Returns the name of the file containing the keymap for a given instance
1001

1002
    """
1003
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
1004

    
1005
  @classmethod
1006
  def _TryReadUidFile(cls, uid_file):
1007
    """Try to read a uid file
1008

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1105
    return env
1106

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

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

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

    
1128
  @staticmethod
1129
  def _VerifyAffinityPackage():
1130
    if affinity is None:
1131
      raise errors.HypervisorError("affinity Python package not"
1132
                                   " found; cannot use CPU pinning under KVM")
1133

    
1134
  @staticmethod
1135
  def _BuildAffinityCpuMask(cpu_list):
1136
    """Create a CPU mask suitable for sched_setaffinity from a list of
1137
    CPUs.
1138

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

1142
    @type cpu_list: list of int
1143
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
1144
    @rtype: int
1145
    @return: a bit mask of CPU affinities
1146

1147
    """
1148
    if cpu_list == constants.CPU_PINNING_OFF:
1149
      return constants.CPU_PINNING_ALL_KVM
1150
    else:
1151
      return sum(2 ** cpu for cpu in cpu_list)
1152

    
1153
  @classmethod
1154
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
1155
    """Change CPU affinity for running VM according to given CPU mask.
1156

1157
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
1158
    @type cpu_mask: string
1159
    @param process_id: process ID of KVM process. Used to pin entire VM
1160
                       to physical CPUs.
1161
    @type process_id: int
1162
    @param thread_dict: map of virtual CPUs to KVM thread IDs
1163
    @type thread_dict: dict int:int
1164

1165
    """
1166
    # Convert the string CPU mask to a list of list of int's
1167
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
1168

    
1169
    if len(cpu_list) == 1:
1170
      all_cpu_mapping = cpu_list[0]
1171
      if all_cpu_mapping == constants.CPU_PINNING_OFF:
1172
        # If CPU pinning has 1 entry that's "all", then do nothing
1173
        pass
1174
      else:
1175
        # If CPU pinning has one non-all entry, map the entire VM to
1176
        # one set of physical CPUs
1177
        cls._VerifyAffinityPackage()
1178
        affinity.set_process_affinity_mask(
1179
          process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
1180
    else:
1181
      # The number of vCPUs mapped should match the number of vCPUs
1182
      # reported by KVM. This was already verified earlier, so
1183
      # here only as a sanity check.
1184
      assert len(thread_dict) == len(cpu_list)
1185
      cls._VerifyAffinityPackage()
1186

    
1187
      # For each vCPU, map it to the proper list of physical CPUs
1188
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1189
        affinity.set_process_affinity_mask(thread_dict[i],
1190
                                           cls._BuildAffinityCpuMask(vcpu))
1191

    
1192
  def _GetVcpuThreadIds(self, instance_name):
1193
    """Get a mapping of vCPU no. to thread IDs for the instance
1194

1195
    @type instance_name: string
1196
    @param instance_name: instance in question
1197
    @rtype: dictionary of int:int
1198
    @return: a dictionary mapping vCPU numbers to thread IDs
1199

1200
    """
1201
    result = {}
1202
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1203
    for line in output.stdout.splitlines():
1204
      match = self._CPU_INFO_RE.search(line)
1205
      if not match:
1206
        continue
1207
      grp = map(int, match.groups())
1208
      result[grp[0]] = grp[1]
1209

    
1210
    return result
1211

    
1212
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1213
    """Complete CPU pinning.
1214

1215
    @type instance_name: string
1216
    @param instance_name: name of instance
1217
    @type cpu_mask: string
1218
    @param cpu_mask: CPU pinning mask as entered by user
1219

1220
    """
1221
    # Get KVM process ID, to be used if need to pin entire VM
1222
    _, pid, _ = self._InstancePidAlive(instance_name)
1223
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1224
    thread_dict = self._GetVcpuThreadIds(instance_name)
1225
    # Run CPU pinning, based on configured mask
1226
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1227

    
1228
  def ListInstances(self, hvparams=None):
1229
    """Get the list of running instances.
1230

1231
    We can do this by listing our live instances directory and
1232
    checking whether the associated kvm process is still alive.
1233

1234
    """
1235
    result = []
1236
    for name in os.listdir(self._PIDS_DIR):
1237
      if self._InstancePidAlive(name)[2]:
1238
        result.append(name)
1239
    return result
1240

    
1241
  def GetInstanceInfo(self, instance_name, hvparams=None):
1242
    """Get instance properties.
1243

1244
    @type instance_name: string
1245
    @param instance_name: the instance name
1246
    @type hvparams: dict of strings
1247
    @param hvparams: hvparams to be used with this instance
1248
    @rtype: tuple of strings
1249
    @return: (name, id, memory, vcpus, stat, times)
1250

1251
    """
1252
    _, pid, alive = self._InstancePidAlive(instance_name)
1253
    if not alive:
1254
      return None
1255

    
1256
    _, memory, vcpus = self._InstancePidInfo(pid)
1257
    istat = "---b-"
1258
    times = "0"
1259

    
1260
    try:
1261
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1262
      qmp.connect()
1263
      vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1264
      # Will fail if ballooning is not enabled, but we can then just resort to
1265
      # the value above.
1266
      mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1267
      memory = mem_bytes / 1048576
1268
    except errors.HypervisorError:
1269
      pass
1270

    
1271
    return (instance_name, pid, memory, vcpus, istat, times)
1272

    
1273
  def GetAllInstancesInfo(self, hvparams=None):
1274
    """Get properties of all instances.
1275

1276
    @type hvparams: dict of strings
1277
    @param hvparams: hypervisor parameter
1278
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1279

1280
    """
1281
    data = []
1282
    for name in os.listdir(self._PIDS_DIR):
1283
      try:
1284
        info = self.GetInstanceInfo(name)
1285
      except errors.HypervisorError:
1286
        # Ignore exceptions due to instances being shut down
1287
        continue
1288
      if info:
1289
        data.append(info)
1290
    return data
1291

    
1292
  def _GenerateKVMBlockDevicesOptions(self, instance, up_hvp, kvm_disks,
1293
                                      kvmhelp, devlist):
1294
    """Generate KVM options regarding instance's block devices.
1295

1296
    @type instance: L{objects.Instance}
1297
    @param instance: the instance object
1298
    @type up_hvp: dict
1299
    @param up_hvp: the instance's runtime hypervisor parameters
1300
    @type kvm_disks: list of tuples
1301
    @param kvm_disks: list of tuples [(disk, link_name, uri)..]
1302
    @type kvmhelp: string
1303
    @param kvmhelp: output of kvm --help
1304
    @type devlist: string
1305
    @param devlist: output of kvm -device ?
1306
    @rtype: list
1307
    @return: list of command line options eventually used by kvm executable
1308

1309
    """
1310
    kernel_path = up_hvp[constants.HV_KERNEL_PATH]
1311
    if kernel_path:
1312
      boot_disk = False
1313
    else:
1314
      boot_disk = up_hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1315

    
1316
    # whether this is an older KVM version that uses the boot=on flag
1317
    # on devices
1318
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1319

    
1320
    dev_opts = []
1321
    device_driver = None
1322
    disk_type = up_hvp[constants.HV_DISK_TYPE]
1323
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
1324
      if_val = ",if=%s" % self._VIRTIO
1325
      try:
1326
        if self._VIRTIO_BLK_RE.search(devlist):
1327
          if_val = ",if=none"
1328
          # will be passed in -device option as driver
1329
          device_driver = self._VIRTIO_BLK_PCI
1330
      except errors.HypervisorError, _:
1331
        pass
1332
    else:
1333
      if_val = ",if=%s" % disk_type
1334
    # Cache mode
1335
    disk_cache = up_hvp[constants.HV_DISK_CACHE]
1336
    if instance.disk_template in constants.DTS_EXT_MIRROR:
1337
      if disk_cache != "none":
1338
        # TODO: make this a hard error, instead of a silent overwrite
1339
        logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1340
                        " to prevent shared storage corruption on migration",
1341
                        disk_cache)
1342
      cache_val = ",cache=none"
1343
    elif disk_cache != constants.HT_CACHE_DEFAULT:
1344
      cache_val = ",cache=%s" % disk_cache
1345
    else:
1346
      cache_val = ""
1347
    for cfdev, link_name, uri in kvm_disks:
1348
      if cfdev.mode != constants.DISK_RDWR:
1349
        raise errors.HypervisorError("Instance has read-only disks which"
1350
                                     " are not supported by KVM")
1351
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
1352
      boot_val = ""
1353
      if boot_disk:
1354
        dev_opts.extend(["-boot", "c"])
1355
        boot_disk = False
1356
        if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1357
          boot_val = ",boot=on"
1358

    
1359
      access_mode = cfdev.params.get(constants.LDP_ACCESS,
1360
                                     constants.DISK_KERNELSPACE)
1361
      if (uri and access_mode == constants.DISK_USERSPACE):
1362
        drive_uri = uri
1363
      else:
1364
        drive_uri = link_name
1365

    
1366
      # For ext we allow overriding disk_cache hypervisor params per disk
1367
      disk_cache = cfdev.params.get("cache", None)
1368
      if disk_cache:
1369
        cache_val = ",cache=%s" % disk_cache
1370

    
1371
      drive_val = "file=%s,format=raw%s%s%s" % \
1372
                  (drive_uri, if_val, boot_val, cache_val)
1373

    
1374
      if device_driver:
1375
        # kvm_disks are the 4th entry of runtime file that did not exist in
1376
        # the past. That means that cfdev should always have pci slot and
1377
        # _GenerateDeviceKVMId() will not raise a exception.
1378
        kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_DISK, cfdev)
1379
        drive_val += (",id=%s" % kvm_devid)
1380
        drive_val += (",bus=0,unit=%d" % cfdev.pci)
1381
        dev_val = ("%s,drive=%s,id=%s" %
1382
                   (device_driver, kvm_devid, kvm_devid))
1383
        dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci)
1384
        dev_opts.extend(["-device", dev_val])
1385

    
1386
      # TODO: export disk geometry in IDISK_PARAMS
1387
      heads = cfdev.params.get('heads', None)
1388
      secs = cfdev.params.get('secs', None)
1389
      if heads and secs:
1390
        nr_sectors = cfdev.size * 1024 * 1024 / 512
1391
        cyls = nr_sectors / (int(heads) * int(secs))
1392
        if cyls > 16383:
1393
          cyls = 16383
1394
        elif cyls < 2:
1395
          cyls = 2
1396
        if cyls and heads and secs:
1397
          drive_val += (",cyls=%d,heads=%d,secs=%d" %
1398
                        (cyls, int(heads), int(secs)))
1399

    
1400
      dev_opts.extend(["-drive", drive_val])
1401

    
1402
    return dev_opts
1403

    
1404
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1405
                          kvmhelp):
1406
    """Generate KVM information to start an instance.
1407

1408
    @type kvmhelp: string
1409
    @param kvmhelp: output of kvm --help
1410
    @attention: this function must not have any side-effects; for
1411
        example, it must not write to the filesystem, or read values
1412
        from the current system the are expected to differ between
1413
        nodes, since it is only run once at instance startup;
1414
        actions/kvm arguments that can vary between systems should be
1415
        done in L{_ExecuteKVMRuntime}
1416

1417
    """
1418
    # pylint: disable=R0912,R0914,R0915
1419
    hvp = instance.hvparams
1420
    self.ValidateParameters(hvp)
1421

    
1422
    pidfile = self._InstancePidFile(instance.name)
1423
    kvm = hvp[constants.HV_KVM_PATH]
1424
    kvm_cmd = [kvm]
1425
    # used just by the vnc server, if enabled
1426
    kvm_cmd.extend(["-name", instance.name])
1427
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1428

    
1429
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1430
    if hvp[constants.HV_CPU_CORES]:
1431
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1432
    if hvp[constants.HV_CPU_THREADS]:
1433
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1434
    if hvp[constants.HV_CPU_SOCKETS]:
1435
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1436

    
1437
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1438

    
1439
    kvm_cmd.extend(["-pidfile", pidfile])
1440

    
1441
    pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1442

    
1443
    # As requested by music lovers
1444
    if hvp[constants.HV_SOUNDHW]:
1445
      soundhw = hvp[constants.HV_SOUNDHW]
1446
      # For some reason only few sound devices require a PCI slot
1447
      # while the Audio controller *must* be in slot 3.
1448
      # That's why we bridge this option early in command line
1449
      if soundhw in self._SOUNDHW_WITH_PCI_SLOT:
1450
        _ = _GetFreeSlot(pci_reservations, reserve=True)
1451
      kvm_cmd.extend(["-soundhw", soundhw])
1452

    
1453
    if hvp[constants.HV_DISK_TYPE] == constants.HT_DISK_SCSI:
1454
      # The SCSI controller requires another PCI slot.
1455
      _ = _GetFreeSlot(pci_reservations, reserve=True)
1456

    
1457
    # Add id to ballon and place to the first available slot (3 or 4)
1458
    addr = _GetFreeSlot(pci_reservations, reserve=True)
1459
    pci_info = ",bus=pci.0,addr=%s" % hex(addr)
1460
    kvm_cmd.extend(["-balloon", "virtio,id=balloon%s" % pci_info])
1461
    kvm_cmd.extend(["-daemonize"])
1462
    if not instance.hvparams[constants.HV_ACPI]:
1463
      kvm_cmd.extend(["-no-acpi"])
1464
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1465
        constants.INSTANCE_REBOOT_EXIT:
1466
      kvm_cmd.extend(["-no-reboot"])
1467

    
1468
    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1469
    if not mversion:
1470
      mversion = self._GetDefaultMachineVersion(kvm)
1471
    if self._MACHINE_RE.search(kvmhelp):
1472
      # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1473
      # extra hypervisor parameters. We should also investigate whether and how
1474
      # shadow_mem should be considered for the resource model.
1475
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1476
        specprop = ",accel=kvm"
1477
      else:
1478
        specprop = ""
1479
      machinespec = "%s%s" % (mversion, specprop)
1480
      kvm_cmd.extend(["-machine", machinespec])
1481
    else:
1482
      kvm_cmd.extend(["-M", mversion])
1483
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1484
          self._ENABLE_KVM_RE.search(kvmhelp)):
1485
        kvm_cmd.extend(["-enable-kvm"])
1486
      elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1487
            self._DISABLE_KVM_RE.search(kvmhelp)):
1488
        kvm_cmd.extend(["-disable-kvm"])
1489

    
1490
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1491
    if kernel_path:
1492
      boot_cdrom = boot_floppy = boot_network = False
1493
    else:
1494
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1495
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1496
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1497

    
1498
    if startup_paused:
1499
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1500

    
1501
    if boot_network:
1502
      kvm_cmd.extend(["-boot", "n"])
1503

    
1504
    # whether this is an older KVM version that uses the boot=on flag
1505
    # on devices
1506
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1507

    
1508
    disk_type = hvp[constants.HV_DISK_TYPE]
1509

    
1510
    #Now we can specify a different device type for CDROM devices.
1511
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1512
    if not cdrom_disk_type:
1513
      cdrom_disk_type = disk_type
1514

    
1515
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1516
    if iso_image:
1517
      options = ",format=raw,media=cdrom"
1518
      # set cdrom 'if' type
1519
      if boot_cdrom:
1520
        actual_cdrom_type = constants.HT_DISK_IDE
1521
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1522
        actual_cdrom_type = "virtio"
1523
      else:
1524
        actual_cdrom_type = cdrom_disk_type
1525
      if_val = ",if=%s" % actual_cdrom_type
1526
      # set boot flag, if needed
1527
      boot_val = ""
1528
      if boot_cdrom:
1529
        kvm_cmd.extend(["-boot", "d"])
1530
        if needs_boot_flag:
1531
          boot_val = ",boot=on"
1532
      # and finally build the entire '-drive' value
1533
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1534
      kvm_cmd.extend(["-drive", drive_val])
1535

    
1536
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1537
    if iso_image2:
1538
      options = ",format=raw,media=cdrom"
1539
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1540
        if_val = ",if=virtio"
1541
      else:
1542
        if_val = ",if=%s" % cdrom_disk_type
1543
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1544
      kvm_cmd.extend(["-drive", drive_val])
1545

    
1546
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1547
    if floppy_image:
1548
      options = ",format=raw,media=disk"
1549
      if boot_floppy:
1550
        kvm_cmd.extend(["-boot", "a"])
1551
        options = "%s,boot=on" % options
1552
      if_val = ",if=floppy"
1553
      options = "%s%s" % (options, if_val)
1554
      drive_val = "file=%s%s" % (floppy_image, options)
1555
      kvm_cmd.extend(["-drive", drive_val])
1556

    
1557
    if kernel_path:
1558
      kvm_cmd.extend(["-kernel", kernel_path])
1559
      initrd_path = hvp[constants.HV_INITRD_PATH]
1560
      if initrd_path:
1561
        kvm_cmd.extend(["-initrd", initrd_path])
1562
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1563
                     hvp[constants.HV_KERNEL_ARGS]]
1564
      if hvp[constants.HV_SERIAL_CONSOLE]:
1565
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1566
        root_append.append("console=ttyS0,%s" % serial_speed)
1567
      kvm_cmd.extend(["-append", " ".join(root_append)])
1568

    
1569
    mem_path = hvp[constants.HV_MEM_PATH]
1570
    if mem_path:
1571
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1572

    
1573
    monitor_dev = ("unix:%s,server,nowait" %
1574
                   self._InstanceMonitor(instance.name))
1575
    kvm_cmd.extend(["-monitor", monitor_dev])
1576
    if hvp[constants.HV_SERIAL_CONSOLE]:
1577
      serial_dev = ("unix:%s,server,nowait" %
1578
                    self._InstanceSerial(instance.name))
1579
      kvm_cmd.extend(["-serial", serial_dev])
1580
    else:
1581
      kvm_cmd.extend(["-serial", "none"])
1582

    
1583
    mouse_type = hvp[constants.HV_USB_MOUSE]
1584
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1585
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1586
    spice_ip_version = None
1587

    
1588
    kvm_cmd.extend(["-usb"])
1589

    
1590
    if mouse_type:
1591
      kvm_cmd.extend(["-usbdevice", mouse_type])
1592
    elif vnc_bind_address:
1593
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1594

    
1595
    if vnc_bind_address:
1596
      if netutils.IsValidInterface(vnc_bind_address):
1597
        if_addresses = netutils.GetInterfaceIpAddresses(vnc_bind_address)
1598
        if_ip4_addresses = if_addresses[constants.IP4_VERSION]
1599
        if len(if_ip4_addresses) < 1:
1600
          logging.error("Could not determine IPv4 address of interface %s",
1601
                        vnc_bind_address)
1602
        else:
1603
          vnc_bind_address = if_ip4_addresses[0]
1604
      if netutils.IP4Address.IsValid(vnc_bind_address):
1605
        if instance.network_port > constants.VNC_BASE_PORT:
1606
          display = instance.network_port - constants.VNC_BASE_PORT
1607
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1608
            vnc_arg = ":%d" % (display)
1609
          else:
1610
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1611
        else:
1612
          logging.error("Network port is not a valid VNC display (%d < %d),"
1613
                        " not starting VNC",
1614
                        instance.network_port, constants.VNC_BASE_PORT)
1615
          vnc_arg = "none"
1616

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

    
1631
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1632

    
1633
      else:
1634
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1635

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

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

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

    
1670
        spice_address = addresses[spice_ip_version][0]
1671

    
1672
      else:
1673
        # spice_bind is known to be a valid IP address, because
1674
        # ValidateParameters checked it.
1675
        spice_address = spice_bind
1676

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

    
1691
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1692
        spice_arg = "%s,disable-ticketing" % spice_arg
1693

    
1694
      if spice_ip_version:
1695
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1696

    
1697
      # Image compression options
1698
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1699
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1700
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1701
      if img_lossless:
1702
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1703
      if img_jpeg:
1704
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1705
      if img_zlib_glz:
1706
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1707

    
1708
      # Video stream detection
1709
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1710
      if video_streaming:
1711
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1712

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

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

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

    
1741
    if hvp[constants.HV_USE_LOCALTIME]:
1742
      kvm_cmd.extend(["-localtime"])
1743

    
1744
    if hvp[constants.HV_KVM_USE_CHROOT]:
1745
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1746

    
1747
    # Add qemu-KVM -cpu param
1748
    if hvp[constants.HV_CPU_TYPE]:
1749
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1750

    
1751
    # Pass a -vga option if requested, or if spice is used, for backwards
1752
    # compatibility.
1753
    if hvp[constants.HV_VGA]:
1754
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1755
    elif spice_bind:
1756
      kvm_cmd.extend(["-vga", "qxl"])
1757

    
1758
    # Various types of usb devices, comma separated
1759
    if hvp[constants.HV_USB_DEVICES]:
1760
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1761
        kvm_cmd.extend(["-usbdevice", dev])
1762

    
1763
    # Set system UUID to instance UUID
1764
    if self._UUID_RE.search(kvmhelp):
1765
      kvm_cmd.extend(["-uuid", instance.uuid])
1766

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

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

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

    
1780
    hvparams = hvp
1781

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

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

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

    
1794
  def _ReadKVMRuntime(self, instance_name):
1795
    """Read an instance's KVM runtime
1796

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

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

1807
    """
1808
    kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1809

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

    
1816
    self._WriteKVMRuntime(instance.name, serialized_form)
1817

    
1818
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1819
    """Load an instance's KVM runtime
1820

1821
    """
1822
    if not serialized_runtime:
1823
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1824

    
1825
    return _AnalyzeSerializedRuntime(serialized_runtime)
1826

    
1827
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1828
    """Run the KVM cmd and check for errors
1829

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

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

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

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

1855
    @type incoming: tuple of strings
1856
    @param incoming: (target_host_ip, port)
1857
    @type kvmhelp: string
1858
    @param kvmhelp: output of kvm --help
1859

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

    
1873
    temp_files = []
1874

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

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

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

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

    
1903
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1904
                                                     up_hvp,
1905
                                                     kvm_disks,
1906
                                                     kvmhelp,
1907
                                                     devlist)
1908
    kvm_cmd.extend(bdev_opts)
1909

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

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

    
1937
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1938

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

    
1963
    if incoming:
1964
      target, port = incoming
1965
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1966

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

    
1979
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1980
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1981
                         constants.SECURE_DIR_MODE)])
1982

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

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

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

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

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

    
2029
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
2030
                     constants.RUN_DIRS_MODE)])
2031
    for nic_seq, tap in enumerate(taps):
2032
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
2033
                      data=tap)
2034

    
2035
    if vnc_pwd:
2036
      change_cmd = "change vnc password %s" % vnc_pwd
2037
      self._CallMonitorCommand(instance.name, change_cmd)
2038

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

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

    
2061
    for filename in temp_files:
2062
      utils.RemoveFile(filename)
2063

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

    
2068
    start_memory = self._InstanceStartupMemory(instance)
2069
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
2070
      self.BalloonInstanceMemory(instance, start_memory)
2071

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

    
2078
  def StartInstance(self, instance, block_devices, startup_paused):
2079
    """Start an instance.
2080

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

    
2090
  def _CallMonitorCommand(self, instance_name, command, timeout=None):
2091
    """Invoke a command on the instance monitor.
2092

2093
    """
2094
    if timeout is not None:
2095
      timeout_cmd = "timeout %s" % (timeout, )
2096
    else:
2097
      timeout_cmd = ""
2098

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

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

    
2119
    return result
2120

    
2121
  def _GetFreePCISlot(self, instance, dev):
2122
    """Get the first available pci slot of a runnung instance.
2123

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

    
2134
    dev.pci = _GetFreeSlot(slots)
2135

    
2136
  def VerifyHotplugSupport(self, instance, action, dev_type):
2137
    """Verifies that hotplug is supported.
2138

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

2143
    @raise errors.HypervisorError: in one of the previous cases
2144

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

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

    
2162
  def HotplugSupported(self, instance):
2163
    """Checks if hotplug is generally supported.
2164

2165
    Hotplug is *not* supported in case of:
2166
     - qemu versions < 1.0
2167
     - for stopped instances
2168

2169
    @raise errors.HypervisorError: in one of the previous cases
2170

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

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

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

    
2186
  def _CallHotplugCommands(self, name, cmds):
2187
    for c in cmds:
2188
      self._CallMonitorCommand(name, c)
2189
      time.sleep(1)
2190

    
2191
  def _VerifyHotplugCommand(self, instance_name, device, dev_type,
2192
                            should_exist):
2193
    """Checks if a previous hotplug command has succeeded.
2194

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

2198
    @raise errors.HypervisorError: if result is not the expected one
2199

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

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

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

    
2215
  def HotAddDevice(self, instance, dev_type, device, extra, seq):
2216
    """ Helper method to hot-add a new device
2217

2218
    It gets free pci slot generates the device name and invokes the
2219
    device specific method.
2220

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

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

    
2250
  def HotDelDevice(self, instance, dev_type, device, _, seq):
2251
    """ Helper method for hot-del device
2252

2253
    It gets device info from runtime file, generates the device name and
2254
    invokes the device specific method.
2255

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

    
2274
    return kvm_device.pci
2275

    
2276
  def HotModDevice(self, instance, dev_type, device, _, seq):
2277
    """ Helper method for hot-mod device
2278

2279
    It gets device info from runtime file, generates the device name and
2280
    invokes the device specific method. Currently only NICs support hot-mod
2281

2282
    """
2283
    if dev_type == constants.HOTPLUG_TARGET_NIC:
2284
      # putting it back in the same pci slot
2285
      device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2286
      self.HotAddDevice(instance, dev_type, device, _, seq)
2287

    
2288
  def _PassTapFd(self, instance, fd, nic):
2289
    """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2290

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

    
2305
  @classmethod
2306
  def _ParseKVMVersion(cls, text):
2307
    """Parse the KVM version from the --help output.
2308

2309
    @type text: string
2310
    @param text: output of kvm --help
2311
    @return: (version, v_maj, v_min, v_rev)
2312
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2313

2314
    """
2315
    match = cls._VERSION_RE.search(text.splitlines()[0])
2316
    if not match:
2317
      raise errors.HypervisorError("Unable to get KVM version")
2318

    
2319
    v_all = match.group(0)
2320
    v_maj = int(match.group(1))
2321
    v_min = int(match.group(2))
2322
    if match.group(4):
2323
      v_rev = int(match.group(4))
2324
    else:
2325
      v_rev = 0
2326
    return (v_all, v_maj, v_min, v_rev)
2327

    
2328
  @classmethod
2329
  def _GetKVMOutput(cls, kvm_path, option):
2330
    """Return the output of a kvm invocation
2331

2332
    @type kvm_path: string
2333
    @param kvm_path: path to the kvm executable
2334
    @type option: a key of _KVMOPTS_CMDS
2335
    @param option: kvm option to fetch the output from
2336
    @return: output a supported kvm invocation
2337
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2338

2339
    """
2340
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2341

    
2342
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
2343

    
2344
    result = utils.RunCmd([kvm_path] + optlist)
2345
    if result.failed and not can_fail:
2346
      raise errors.HypervisorError("Unable to get KVM %s output" %
2347
                                    " ".join(optlist))
2348
    return result.output
2349

    
2350
  @classmethod
2351
  def _GetKVMVersion(cls, kvm_path):
2352
    """Return the installed KVM version.
2353

2354
    @return: (version, v_maj, v_min, v_rev)
2355
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2356

2357
    """
2358
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2359

    
2360
  @classmethod
2361
  def _GetDefaultMachineVersion(cls, kvm_path):
2362
    """Return the default hardware revision (e.g. pc-1.1)
2363

2364
    """
2365
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2366
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2367
    if match:
2368
      return match.group(1)
2369
    else:
2370
      return "pc"
2371

    
2372
  def StopInstance(self, instance, force=False, retry=False, name=None,
2373
                   timeout=None):
2374
    """Stop an instance.
2375

2376
    """
2377
    assert(timeout is None or force is not None)
2378

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

    
2393
  def CleanupInstance(self, instance_name):
2394
    """Cleanup after a stopped instance
2395

2396
    """
2397
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
2398
    if pid > 0 and alive:
2399
      raise errors.HypervisorError("Cannot cleanup a live instance")
2400
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2401

    
2402
  def RebootInstance(self, instance):
2403
    """Reboot an instance.
2404

2405
    """
2406
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2407
    # socket the instance will stop, but now power up again. So we'll resort
2408
    # to shutdown and restart.
2409
    _, _, alive = self._InstancePidAlive(instance.name)
2410
    if not alive:
2411
      raise errors.HypervisorError("Failed to reboot instance %s:"
2412
                                   " not running" % instance.name)
2413
    # StopInstance will delete the saved KVM runtime so:
2414
    # ...first load it...
2415
    kvm_runtime = self._LoadKVMRuntime(instance)
2416
    # ...now we can safely call StopInstance...
2417
    if not self.StopInstance(instance):
2418
      self.StopInstance(instance, force=True)
2419
    # ...and finally we can save it again, and execute it...
2420
    self._SaveKVMRuntime(instance, kvm_runtime)
2421
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2422
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2423
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2424

    
2425
  def MigrationInfo(self, instance):
2426
    """Get instance information to perform a migration.
2427

2428
    @type instance: L{objects.Instance}
2429
    @param instance: instance to be migrated
2430
    @rtype: string
2431
    @return: content of the KVM runtime file
2432

2433
    """
2434
    return self._ReadKVMRuntime(instance.name)
2435

    
2436
  def AcceptInstance(self, instance, info, target):
2437
    """Prepare to accept an instance.
2438

2439
    @type instance: L{objects.Instance}
2440
    @param instance: instance to be accepted
2441
    @type info: string
2442
    @param info: content of the KVM runtime file on the source node
2443
    @type target: string
2444
    @param target: target host (usually ip), on this node
2445

2446
    """
2447
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2448
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2449
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2450
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2451
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2452
                            incoming=incoming_address)
2453

    
2454
  def FinalizeMigrationDst(self, instance, info, success):
2455
    """Finalize the instance migration on the target node.
2456

2457
    Stop the incoming mode KVM.
2458

2459
    @type instance: L{objects.Instance}
2460
    @param instance: instance whose migration is being finalized
2461

2462
    """
2463
    if success:
2464
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2465
      kvm_nics = kvm_runtime[1]
2466

    
2467
      for nic_seq, nic in enumerate(kvm_nics):
2468
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2469
          # Bridged interfaces have already been configured
2470
          continue
2471
        try:
2472
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2473
        except EnvironmentError, err:
2474
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
2475
                          instance.name, nic_seq, str(err))
2476
          continue
2477
        try:
2478
          self._ConfigureNIC(instance, nic_seq, nic, tap)
2479
        except errors.HypervisorError, err:
2480
          logging.warning(str(err))
2481

    
2482
      self._WriteKVMRuntime(instance.name, info)
2483
    else:
2484
      self.StopInstance(instance, force=True)
2485

    
2486
  def MigrateInstance(self, cluster_name, instance, target, live):
2487
    """Migrate an instance to a target node.
2488

2489
    The migration will not be attempted if the instance is not
2490
    currently running.
2491

2492
    @type cluster_name: string
2493
    @param cluster_name: name of the cluster
2494
    @type instance: L{objects.Instance}
2495
    @param instance: the instance to be migrated
2496
    @type target: string
2497
    @param target: ip address of the target node
2498
    @type live: boolean
2499
    @param live: perform a live migration
2500

2501
    """
2502
    instance_name = instance.name
2503
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
2504
    _, _, alive = self._InstancePidAlive(instance_name)
2505
    if not alive:
2506
      raise errors.HypervisorError("Instance not running, cannot migrate")
2507

    
2508
    if not live:
2509
      self._CallMonitorCommand(instance_name, "stop")
2510

    
2511
    migrate_command = ("migrate_set_speed %dm" %
2512
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2513
    self._CallMonitorCommand(instance_name, migrate_command)
2514

    
2515
    migrate_command = ("migrate_set_downtime %dms" %
2516
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2517
    self._CallMonitorCommand(instance_name, migrate_command)
2518

    
2519
    migration_caps = instance.hvparams[constants.HV_KVM_MIGRATION_CAPS]
2520
    if migration_caps:
2521
      for c in migration_caps.split(_MIGRATION_CAPS_DELIM):
2522
        migrate_command = ("migrate_set_capability %s on" % c)
2523
        self._CallMonitorCommand(instance_name, migrate_command)
2524

    
2525
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2526
    self._CallMonitorCommand(instance_name, migrate_command)
2527

    
2528
  def FinalizeMigrationSource(self, instance, success, live):
2529
    """Finalize the instance migration on the source node.
2530

2531
    @type instance: L{objects.Instance}
2532
    @param instance: the instance that was migrated
2533
    @type success: bool
2534
    @param success: whether the migration succeeded or not
2535
    @type live: bool
2536
    @param live: whether the user requested a live migration or not
2537

2538
    """
2539
    if success:
2540
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2541
      utils.KillProcess(pid)
2542
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2543
    elif live:
2544
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2545

    
2546
  def GetMigrationStatus(self, instance):
2547
    """Get the migration status
2548

2549
    @type instance: L{objects.Instance}
2550
    @param instance: the instance that is being migrated
2551
    @rtype: L{objects.MigrationStatus}
2552
    @return: the status of the current migration (one of
2553
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2554
             progress info that can be retrieved from the hypervisor
2555

2556
    """
2557
    info_command = "info migrate"
2558
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2559
      result = self._CallMonitorCommand(instance.name, info_command)
2560
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
2561
      if not match:
2562
        if not result.stdout:
2563
          logging.info("KVM: empty 'info migrate' result")
2564
        else:
2565
          logging.warning("KVM: unknown 'info migrate' result: %s",
2566
                          result.stdout)
2567
      else:
2568
        status = match.group(1)
2569
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2570
          migration_status = objects.MigrationStatus(status=status)
2571
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2572
          if match:
2573
            migration_status.transferred_ram = match.group("transferred")
2574
            migration_status.total_ram = match.group("total")
2575

    
2576
          return migration_status
2577

    
2578
        logging.warning("KVM: unknown migration status '%s'", status)
2579

    
2580
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2581

    
2582
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2583

    
2584
  def BalloonInstanceMemory(self, instance, mem):
2585
    """Balloon an instance memory to a certain value.
2586

2587
    @type instance: L{objects.Instance}
2588
    @param instance: instance to be accepted
2589
    @type mem: int
2590
    @param mem: actual memory size to use for instance runtime
2591

2592
    """
2593
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2594

    
2595
  def GetNodeInfo(self, hvparams=None):
2596
    """Return information about the node.
2597

2598
    @type hvparams: dict of strings
2599
    @param hvparams: hypervisor parameters, not used in this class
2600

2601
    @return: a dict as returned by L{BaseHypervisor.GetLinuxNodeInfo} plus
2602
        the following keys:
2603
          - hv_version: the hypervisor version in the form (major, minor,
2604
                        revision)
2605

2606
    """
2607
    result = self.GetLinuxNodeInfo()
2608
    kvmpath = constants.KVM_PATH
2609
    if hvparams is not None:
2610
      kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2611
    _, v_major, v_min, v_rev = self._GetKVMVersion(kvmpath)
2612
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2613
    return result
2614

    
2615
  @classmethod
2616
  def GetInstanceConsole(cls, instance, primary_node, hvparams, beparams):
2617
    """Return a command for connecting to the console of an instance.
2618

2619
    """
2620
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2621
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2622
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2623
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2624
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2625
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2626
      return objects.InstanceConsole(instance=instance.name,
2627
                                     kind=constants.CONS_SSH,
2628
                                     host=primary_node.name,
2629
                                     user=constants.SSH_CONSOLE_USER,
2630
                                     command=cmd)
2631

    
2632
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2633
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2634
      display = instance.network_port - constants.VNC_BASE_PORT
2635
      return objects.InstanceConsole(instance=instance.name,
2636
                                     kind=constants.CONS_VNC,
2637
                                     host=vnc_bind_address,
2638
                                     port=instance.network_port,
2639
                                     display=display)
2640

    
2641
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2642
    if spice_bind:
2643
      return objects.InstanceConsole(instance=instance.name,
2644
                                     kind=constants.CONS_SPICE,
2645
                                     host=spice_bind,
2646
                                     port=instance.network_port)
2647

    
2648
    return objects.InstanceConsole(instance=instance.name,
2649
                                   kind=constants.CONS_MESSAGE,
2650
                                   message=("No serial shell for instance %s" %
2651
                                            instance.name))
2652

    
2653
  def Verify(self, hvparams=None):
2654
    """Verify the hypervisor.
2655

2656
    Check that the required binaries exist.
2657

2658
    @type hvparams: dict of strings
2659
    @param hvparams: hypervisor parameters to be verified against, not used here
2660

2661
    @return: Problem description if something is wrong, C{None} otherwise
2662

2663
    """
2664
    msgs = []
2665
    kvmpath = constants.KVM_PATH
2666
    if hvparams is not None:
2667
      kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2668
    if not os.path.exists(kvmpath):
2669
      msgs.append("The KVM binary ('%s') does not exist" % kvmpath)
2670
    if not os.path.exists(constants.SOCAT_PATH):
2671
      msgs.append("The socat binary ('%s') does not exist" %
2672
                  constants.SOCAT_PATH)
2673

    
2674
    return self._FormatVerifyResults(msgs)
2675

    
2676
  @classmethod
2677
  def CheckParameterSyntax(cls, hvparams):
2678
    """Check the given parameters for validity.
2679

2680
    @type hvparams:  dict
2681
    @param hvparams: dictionary with parameter names/value
2682
    @raise errors.HypervisorError: when a parameter is not valid
2683

2684
    """
2685
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2686

    
2687
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2688
    if kernel_path:
2689
      if not hvparams[constants.HV_ROOT_PATH]:
2690
        raise errors.HypervisorError("Need a root partition for the instance,"
2691
                                     " if a kernel is defined")
2692

    
2693
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2694
        not hvparams[constants.HV_VNC_X509]):
2695
      raise errors.HypervisorError("%s must be defined, if %s is" %
2696
                                   (constants.HV_VNC_X509,
2697
                                    constants.HV_VNC_X509_VERIFY))
2698

    
2699
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2700
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2701
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2702
      if not serial_speed or serial_speed not in valid_speeds:
2703
        raise errors.HypervisorError("Invalid serial console speed, must be"
2704
                                     " one of: %s" %
2705
                                     utils.CommaJoin(valid_speeds))
2706

    
2707
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2708
    if (boot_order == constants.HT_BO_CDROM and
2709
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2710
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2711
                                   " ISO path")
2712

    
2713
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2714
    if security_model == constants.HT_SM_USER:
2715
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2716
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2717
                                     " must be specified")
2718
    elif (security_model == constants.HT_SM_NONE or
2719
          security_model == constants.HT_SM_POOL):
2720
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2721
        raise errors.HypervisorError("Cannot have a security domain when the"
2722
                                     " security model is 'none' or 'pool'")
2723

    
2724
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2725
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2726
    if spice_bind:
2727
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2728
        # if an IP version is specified, the spice_bind parameter must be an
2729
        # IP of that family
2730
        if (netutils.IP4Address.IsValid(spice_bind) and
2731
            spice_ip_version != constants.IP4_VERSION):
2732
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2733
                                       " the specified IP version is %s" %
2734
                                       (spice_bind, spice_ip_version))
2735

    
2736
        if (netutils.IP6Address.IsValid(spice_bind) and
2737
            spice_ip_version != constants.IP6_VERSION):
2738
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2739
                                       " the specified IP version is %s" %
2740
                                       (spice_bind, spice_ip_version))
2741
    else:
2742
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2743
      # error if any of them is set without it.
2744
      for param in _SPICE_ADDITIONAL_PARAMS:
2745
        if hvparams[param]:
2746
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2747
                                       (param, constants.HV_KVM_SPICE_BIND))
2748

    
2749
  @classmethod
2750
  def ValidateParameters(cls, hvparams):
2751
    """Check the given parameters for validity.
2752

2753
    @type hvparams:  dict
2754
    @param hvparams: dictionary with parameter names/value
2755
    @raise errors.HypervisorError: when a parameter is not valid
2756

2757
    """
2758
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2759

    
2760
    kvm_path = hvparams[constants.HV_KVM_PATH]
2761

    
2762
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2763
    if security_model == constants.HT_SM_USER:
2764
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2765
      try:
2766
        pwd.getpwnam(username)
2767
      except KeyError:
2768
        raise errors.HypervisorError("Unknown security domain user %s"
2769
                                     % username)
2770
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2771
    if vnc_bind_address:
2772
      bound_to_addr = netutils.IP4Address.IsValid(vnc_bind_address)
2773
      is_interface = netutils.IsValidInterface(vnc_bind_address)
2774
      is_path = utils.IsNormAbsPath(vnc_bind_address)
2775
      if not bound_to_addr and not is_interface and not is_path:
2776
        raise errors.HypervisorError("VNC: The %s parameter must be either"
2777
                                     " a valid IP address, an interface name,"
2778
                                     " or an absolute path" %
2779
                                     constants.HV_KVM_SPICE_BIND)
2780

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

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

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

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

    
2810
  @classmethod
2811
  def PowercycleNode(cls, hvparams=None):
2812
    """KVM powercycle, just a wrapper over Linux powercycle.
2813

2814
    @type hvparams: dict of strings
2815
    @param hvparams: hypervisor params to be used on this node
2816

2817
    """
2818
    cls.LinuxPowercycle()