Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 0d2863a2

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_ONE_QUEUE = 0x2000
75
IFF_VNET_HDR = 0x4000
76

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

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

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

    
118
_MIGRATION_CAPS_DELIM = ":"
119

    
120

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

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

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

134
  """
135

    
136
  if not dev.pci:
137
    raise errors.HotplugError("Hotplug is not supported for %s with UUID %s" %
138
                              (dev_type, dev.uuid))
139

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

    
142

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

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

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

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

    
167
    slot = int(avail[0])
168

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

    
172
  return slot
173

    
174

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

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

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

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

    
198
  return found[0]
199

    
200

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

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

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

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

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

    
226
  return kvm_cmd, serialized_nics, hvparams, serialized_disks
227

    
228

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

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

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

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

    
246

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

250
  @see: L{_ProbeTapVnetHdr}
251

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

    
263

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

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

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

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

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

    
287
  result = bool(flags & IFF_VNET_HDR)
288

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

    
292
  return result
293

    
294

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

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

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

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

    
312
  flags = IFF_TAP | IFF_NO_PI | IFF_ONE_QUEUE
313

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

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

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

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

    
330

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

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

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

    
342
    self.data = data
343

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
396

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

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

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

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

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

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

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

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

439
    Connects to the UNIX socket
440

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

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

    
447
    self._check_socket()
448

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

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

459
    It cannot be used after this call.
460

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

    
464

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

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

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

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

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

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

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

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

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

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

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

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

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

    
534
    return (message, buf)
535

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

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

544
    """
545
    self._check_connection()
546

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

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

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

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

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

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

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

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

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

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

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

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

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

    
630

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

634
  """
635
  CAN_MIGRATE = True
636

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

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

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

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

    
748
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
749
  _MIGRATION_INFO_RETRY_DELAY = 2
750

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
876
    return (instance, memory, vcpus)
877

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

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

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

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

    
897
    return (pidfile, pid, alive)
898

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1106
    return env
1107

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1211
    return result
1212

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1403
    return dev_opts
1404

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

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

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

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

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

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

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

    
1442
    pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1443

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

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

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

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

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

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

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

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

    
1509
    disk_type = hvp[constants.HV_DISK_TYPE]
1510

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1671
        spice_address = addresses[spice_ip_version][0]
1672

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1781
    hvparams = hvp
1782

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

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

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

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

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

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

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

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

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

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

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

    
1826
    return _AnalyzeSerializedRuntime(serialized_runtime)
1827

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

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

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

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

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

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

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

    
1874
    temp_files = []
1875

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2120
    return result
2121

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

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

    
2135
    dev.pci = _GetFreeSlot(slots)
2136

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2275
    return kvm_device.pci
2276

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2458
    Stop the incoming mode KVM.
2459

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2577
          return migration_status
2578

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

    
2581
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2582

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2657
    Check that the required binaries exist.
2658

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

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

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

    
2675
    return self._FormatVerifyResults(msgs)
2676

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2761
    kvm_path = hvparams[constants.HV_KVM_PATH]
2762

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

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

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

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

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

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

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

2818
    """
2819
    cls.LinuxPowercycle()