Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ ed6d006b

History | View | Annotate | Download (100.8 kB)

1
#
2
#
3

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

    
21

    
22
"""KVM hypervisor
23

24
"""
25

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

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

    
62

    
63
_KVM_NETWORK_SCRIPT = pathutils.CONF_DIR + "/kvm-ifup-custom"
64
_KVM_START_PAUSED_FLAG = "-S"
65

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

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

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

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

    
117

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

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

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

131
  """
132

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

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

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

    
145

    
146
def _UpdatePCISlots(dev, pci_reservations):
147
  """Update pci configuration for a stopped instance
148

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

153
  @type dev: L{objects.Disk} or L{objects.NIC}
154
  @param dev: the device object for which we update its pci slot
155
  @type pci_reservations: bitarray
156
  @param pci_reservations: existing pci reservations for an instance
157
  @raise errors.HotplugError: in case an instance has all its slot occupied
158

159
  """
160
  if dev.pci:
161
    free = dev.pci
162
  else: # pylint: disable=E1103
163
    [free] = pci_reservations.search(_AVAILABLE_PCI_SLOT, 1)
164
    if not free:
165
      raise errors.HypervisorError("All PCI slots occupied")
166
    dev.pci = int(free)
167

    
168
  pci_reservations[free] = True
169

    
170

    
171
def _GetExistingDeviceInfo(dev_type, device, runtime):
172
  """Helper function to get an existing device inside the runtime file
173

174
  Used when an instance is running. Load kvm runtime file and search
175
  for a device based on its type and uuid.
176

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

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

    
194
  return found[0]
195

    
196

    
197
def _UpgradeSerializedRuntime(serialized_runtime):
198
  """Upgrade runtime data
199

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

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

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

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

    
222
  return kvm_cmd, serialized_nics, hvparams, serialized_disks
223

    
224

    
225
def _AnalyzeSerializedRuntime(serialized_runtime):
226
  """Return runtime entries for a serialized runtime file
227

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

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

    
240
  return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
241

    
242

    
243
def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
244
  """Retrieves supported TUN features from file descriptor.
245

246
  @see: L{_ProbeTapVnetHdr}
247

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

    
259

    
260
def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
261
  """Check whether to enable the IFF_VNET_HDR flag.
262

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

273
   @type fd: int
274
   @param fd: the file descriptor of /dev/net/tun
275

276
  """
277
  flags = _features_fn(fd)
278

    
279
  if flags is None:
280
    # Not supported
281
    return False
282

    
283
  result = bool(flags & IFF_VNET_HDR)
284

    
285
  if not result:
286
    logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
287

    
288
  return result
289

    
290

    
291
def _OpenTap(vnet_hdr=True):
292
  """Open a new tap device and return its file descriptor.
293

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

297
  @type vnet_hdr: boolean
298
  @param vnet_hdr: Enable the VNET Header
299
  @return: (ifname, tapfd)
300
  @rtype: tuple
301

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

    
308
  flags = IFF_TAP | IFF_NO_PI
309

    
310
  if vnet_hdr and _ProbeTapVnetHdr(tapfd):
311
    flags |= IFF_VNET_HDR
312

    
313
  # The struct ifreq ioctl request (see netdevice(7))
314
  ifr = struct.pack("16sh", "", flags)
315

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

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

    
326

    
327
class QmpMessage:
328
  """QEMU Messaging Protocol (QMP) message.
329

330
  """
331
  def __init__(self, data):
332
    """Creates a new QMP message based on the passed data.
333

334
    """
335
    if not isinstance(data, dict):
336
      raise TypeError("QmpMessage must be initialized with a dict")
337

    
338
    self.data = data
339

    
340
  def __getitem__(self, field_name):
341
    """Get the value of the required field if present, or None.
342

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

348
    """
349
    return self.data.get(field_name, None)
350

    
351
  def __setitem__(self, field_name, field_value):
352
    """Set the value of the required field_name to field_value.
353

354
    """
355
    self.data[field_name] = field_value
356

    
357
  @staticmethod
358
  def BuildFromJsonString(json_string):
359
    """Build a QmpMessage from a JSON encoded string.
360

361
    @type json_string: str
362
    @param json_string: JSON string representing the message
363
    @rtype: L{QmpMessage}
364
    @return: a L{QmpMessage} built from json_string
365

366
    """
367
    # Parse the string
368
    data = serializer.LoadJson(json_string)
369
    return QmpMessage(data)
370

    
371
  def __str__(self):
372
    # The protocol expects the JSON object to be sent as a single line.
373
    return serializer.DumpJson(self.data)
374

    
375
  def __eq__(self, other):
376
    # When comparing two QmpMessages, we are interested in comparing
377
    # their internal representation of the message data
378
    return self.data == other.data
379

    
380

    
381
class MonitorSocket(object):
382
  _SOCKET_TIMEOUT = 5
383

    
384
  def __init__(self, monitor_filename):
385
    """Instantiates the MonitorSocket object.
386

387
    @type monitor_filename: string
388
    @param monitor_filename: the filename of the UNIX raw socket on which the
389
                             monitor (QMP or simple one) is listening
390

391
    """
392
    self.monitor_filename = monitor_filename
393
    self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
394
    # We want to fail if the server doesn't send a complete message
395
    # in a reasonable amount of time
396
    self.sock.settimeout(self._SOCKET_TIMEOUT)
397
    self._connected = False
398

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

    
412
  def _check_connection(self):
413
    """Make sure that the connection is established.
414

415
    """
416
    if not self._connected:
417
      raise errors.ProgrammerError("To use a MonitorSocket you need to first"
418
                                   " invoke connect() on it")
419

    
420
  def connect(self):
421
    """Connects to the monitor.
422

423
    Connects to the UNIX socket
424

425
    @raise errors.HypervisorError: when there are communication errors
426

427
    """
428
    if self._connected:
429
      raise errors.ProgrammerError("Cannot connect twice")
430

    
431
    self._check_socket()
432

    
433
    # Check file existance/stuff
434
    try:
435
      self.sock.connect(self.monitor_filename)
436
    except EnvironmentError:
437
      raise errors.HypervisorError("Can't connect to qmp socket")
438
    self._connected = True
439

    
440
  def close(self):
441
    """Closes the socket
442

443
    It cannot be used after this call.
444

445
    """
446
    self.sock.close()
447

    
448

    
449
class QmpConnection(MonitorSocket):
450
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
451

452
  """
453
  _FIRST_MESSAGE_KEY = "QMP"
454
  _EVENT_KEY = "event"
455
  _ERROR_KEY = "error"
456
  _RETURN_KEY = RETURN_KEY = "return"
457
  _ACTUAL_KEY = ACTUAL_KEY = "actual"
458
  _ERROR_CLASS_KEY = "class"
459
  _ERROR_DESC_KEY = "desc"
460
  _EXECUTE_KEY = "execute"
461
  _ARGUMENTS_KEY = "arguments"
462
  _CAPABILITIES_COMMAND = "qmp_capabilities"
463
  _MESSAGE_END_TOKEN = "\r\n"
464

    
465
  def __init__(self, monitor_filename):
466
    super(QmpConnection, self).__init__(monitor_filename)
467
    self._buf = ""
468

    
469
  def connect(self):
470
    """Connects to the QMP monitor.
471

472
    Connects to the UNIX socket and makes sure that we can actually send and
473
    receive data to the kvm instance via QMP.
474

475
    @raise errors.HypervisorError: when there are communication errors
476
    @raise errors.ProgrammerError: when there are data serialization errors
477

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

    
488
    # This is needed because QMP can return more than one greetings
489
    # see https://groups.google.com/d/msg/ganeti-devel/gZYcvHKDooU/SnukC8dgS5AJ
490
    self._buf = ""
491

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

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

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

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

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

    
518
    return (message, buf)
519

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

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

528
    """
529
    self._check_connection()
530

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

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

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

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

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

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

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

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

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

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

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

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

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

    
614

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

618
  """
619
  CAN_MIGRATE = True
620

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

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

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

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

    
735
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
736
  _MIGRATION_INFO_RETRY_DELAY = 2
737

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

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

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

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

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

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

    
774
  _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
775

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
860
    return (instance, memory, vcpus)
861

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

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

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

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

    
881
    return (pidfile, pid, alive)
882

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
954
  @classmethod
955
  def _GetInstanceNICTap(cls, instance_name, nic):
956
    """Returns the tap for the corresponding nic
957

958
    Search for tap file named after NIC's uuid.
959
    For old instances without uuid indexed tap files returns nothing.
960

961
    """
962
    try:
963
      return utils.ReadFile(cls._InstanceNICFile(instance_name, nic.uuid))
964
    except EnvironmentError:
965
      pass
966

    
967
  @classmethod
968
  def _WriteInstanceNICFiles(cls, instance_name, seq, nic, tap):
969
    """Write tap name to both instance NIC files
970

971
    """
972
    for ident in [seq, nic.uuid]:
973
      utils.WriteFile(cls._InstanceNICFile(instance_name, ident), data=tap)
974

    
975
  @classmethod
976
  def _RemoveInstanceNICFiles(cls, instance_name, seq, nic):
977
    """Write tap name to both instance NIC files
978

979
    """
980
    for ident in [seq, nic.uuid]:
981
      utils.RemoveFile(cls._InstanceNICFile(instance_name, ident))
982

    
983
  @classmethod
984
  def _InstanceKeymapFile(cls, instance_name):
985
    """Returns the name of the file containing the keymap for a given instance
986

987
    """
988
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
989

    
990
  @classmethod
991
  def _TryReadUidFile(cls, uid_file):
992
    """Try to read a uid file
993

994
    """
995
    if os.path.exists(uid_file):
996
      try:
997
        uid = int(utils.ReadOneLineFile(uid_file))
998
        return uid
999
      except EnvironmentError:
1000
        logging.warning("Can't read uid file", exc_info=True)
1001
      except (TypeError, ValueError):
1002
        logging.warning("Can't parse uid file contents", exc_info=True)
1003
    return None
1004

    
1005
  @classmethod
1006
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
1007
    """Removes an instance's rutime sockets/files/dirs.
1008

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

    
1047
  @staticmethod
1048
  def _CreateNICEnv(instance_name, nic, tap, seq=None, instance_tags=None):
1049
    """Create environment variables for a specific NIC
1050

1051
    This is needed during NIC ifup/ifdown scripts.
1052
    Since instance tags may change during NIC creation and removal
1053
    and because during cleanup instance object is not available we
1054
    pass them only upon NIC creation (instance startup/NIC hot-plugging).
1055

1056
    """
1057
    env = {
1058
      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
1059
      "INSTANCE": instance_name,
1060
      "MAC": nic.mac,
1061
      "MODE": nic.nicparams[constants.NIC_MODE],
1062
      "INTERFACE_UUID": nic.uuid,
1063
    }
1064

    
1065
    if instance_tags:
1066
      env["TAGS"] = " ".join(instance_tags)
1067

    
1068
    # This should always be available except for old instances in the
1069
    # cluster without uuid indexed tap files.
1070
    if tap:
1071
      env["INTERFACE"] = tap
1072

    
1073
    if seq:
1074
      env["INTERFACE_INDEX"] = str(seq)
1075

    
1076
    if nic.ip:
1077
      env["IP"] = nic.ip
1078

    
1079
    if nic.name:
1080
      env["INTERFACE_NAME"] = nic.name
1081

    
1082
    if nic.nicparams[constants.NIC_LINK]:
1083
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
1084

    
1085
    if nic.network:
1086
      n = objects.Network.FromDict(nic.netinfo)
1087
      env.update(n.HooksDict())
1088

    
1089
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1090
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
1091

    
1092
    return env
1093

    
1094
  @classmethod
1095
  def _ConfigureNIC(cls, instance, seq, nic, tap):
1096
    """Run the network configuration script for a specified NIC
1097

1098
    @param instance: instance we're acting on
1099
    @type instance: instance object
1100
    @param seq: nic sequence number
1101
    @type seq: int
1102
    @param nic: nic we're acting on
1103
    @type nic: nic object
1104
    @param tap: the host's tap interface this NIC corresponds to
1105
    @type tap: str
1106

1107
    """
1108
    env = cls._CreateNICEnv(instance.name, nic, tap, seq, instance.GetTags())
1109
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
1110
    if result.failed:
1111
      raise errors.HypervisorError("Failed to configure interface %s: %s;"
1112
                                   " network configuration script output: %s" %
1113
                                   (tap, result.fail_reason, result.output))
1114

    
1115
  @classmethod
1116
  def _UnconfigureNic(cls, instance_name, nic, only_local=True):
1117
    """Run ifdown script for a specific NIC
1118

1119
    This is executed during instance cleanup and NIC hot-unplug
1120

1121
    @param instance: instance we're acting on
1122
    @type instance: instance object
1123
    @param nic: nic we're acting on
1124
    @type nic: nic object
1125
    @param localy: whether ifdown script should reset global conf (dns) or not
1126
    @type localy: boolean
1127

1128
    """
1129
    tap = cls._GetInstanceNICTap(instance_name, nic)
1130
    env = cls._CreateNICEnv(instance_name, nic, tap)
1131
    arg2 = str(only_local).lower()
1132
    result = utils.RunCmd([pathutils.KVM_IFDOWN, tap, arg2], env=env)
1133
    if result.failed:
1134
      raise errors.HypervisorError("Failed to unconfigure interface %s: %s;"
1135
                                   " network configuration script output: %s" %
1136
                                   (tap, result.fail_reason, result.output))
1137

    
1138
  @staticmethod
1139
  def _VerifyAffinityPackage():
1140
    if affinity is None:
1141
      raise errors.HypervisorError("affinity Python package not"
1142
                                   " found; cannot use CPU pinning under KVM")
1143

    
1144
  @staticmethod
1145
  def _BuildAffinityCpuMask(cpu_list):
1146
    """Create a CPU mask suitable for sched_setaffinity from a list of
1147
    CPUs.
1148

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

1152
    @type cpu_list: list of int
1153
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
1154
    @rtype: int
1155
    @return: a bit mask of CPU affinities
1156

1157
    """
1158
    if cpu_list == constants.CPU_PINNING_OFF:
1159
      return constants.CPU_PINNING_ALL_KVM
1160
    else:
1161
      return sum(2 ** cpu for cpu in cpu_list)
1162

    
1163
  @classmethod
1164
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
1165
    """Change CPU affinity for running VM according to given CPU mask.
1166

1167
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
1168
    @type cpu_mask: string
1169
    @param process_id: process ID of KVM process. Used to pin entire VM
1170
                       to physical CPUs.
1171
    @type process_id: int
1172
    @param thread_dict: map of virtual CPUs to KVM thread IDs
1173
    @type thread_dict: dict int:int
1174

1175
    """
1176
    # Convert the string CPU mask to a list of list of int's
1177
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
1178

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

    
1197
      # For each vCPU, map it to the proper list of physical CPUs
1198
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1199
        affinity.set_process_affinity_mask(thread_dict[i],
1200
                                           cls._BuildAffinityCpuMask(vcpu))
1201

    
1202
  def _GetVcpuThreadIds(self, instance_name):
1203
    """Get a mapping of vCPU no. to thread IDs for the instance
1204

1205
    @type instance_name: string
1206
    @param instance_name: instance in question
1207
    @rtype: dictionary of int:int
1208
    @return: a dictionary mapping vCPU numbers to thread IDs
1209

1210
    """
1211
    result = {}
1212
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1213
    for line in output.stdout.splitlines():
1214
      match = self._CPU_INFO_RE.search(line)
1215
      if not match:
1216
        continue
1217
      grp = map(int, match.groups())
1218
      result[grp[0]] = grp[1]
1219

    
1220
    return result
1221

    
1222
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1223
    """Complete CPU pinning.
1224

1225
    @type instance_name: string
1226
    @param instance_name: name of instance
1227
    @type cpu_mask: string
1228
    @param cpu_mask: CPU pinning mask as entered by user
1229

1230
    """
1231
    # Get KVM process ID, to be used if need to pin entire VM
1232
    _, pid, _ = self._InstancePidAlive(instance_name)
1233
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1234
    thread_dict = self._GetVcpuThreadIds(instance_name)
1235
    # Run CPU pinning, based on configured mask
1236
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1237

    
1238
  def ListInstances(self):
1239
    """Get the list of running instances.
1240

1241
    We can do this by listing our live instances directory and
1242
    checking whether the associated kvm process is still alive.
1243

1244
    """
1245
    result = []
1246
    for name in os.listdir(self._PIDS_DIR):
1247
      if self._InstancePidAlive(name)[2]:
1248
        result.append(name)
1249
    return result
1250

    
1251
  def GetInstanceInfo(self, instance_name):
1252
    """Get instance properties.
1253

1254
    @type instance_name: string
1255
    @param instance_name: the instance name
1256
    @rtype: tuple of strings
1257
    @return: (name, id, memory, vcpus, stat, times)
1258

1259
    """
1260
    _, pid, alive = self._InstancePidAlive(instance_name)
1261
    if not alive:
1262
      return None
1263

    
1264
    _, memory, vcpus = self._InstancePidInfo(pid)
1265
    istat = "---b-"
1266
    times = "0"
1267

    
1268
    try:
1269
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1270
      qmp.connect()
1271
      vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1272
      # Will fail if ballooning is not enabled, but we can then just resort to
1273
      # the value above.
1274
      mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1275
      memory = mem_bytes / 1048576
1276
    except errors.HypervisorError:
1277
      pass
1278

    
1279
    return (instance_name, pid, memory, vcpus, istat, times)
1280

    
1281
  def GetAllInstancesInfo(self):
1282
    """Get properties of all instances.
1283

1284
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1285

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

    
1298
  def _GenerateKVMBlockDevicesOptions(self, instance, kvm_disks,
1299
                                      kvmhelp, devlist):
1300
    """Generate KVM options regarding instance's block devices.
1301

1302
    @type instance: L{objects.Instance}
1303
    @param instance: the instance object
1304
    @type kvm_disks: list of tuples
1305
    @param kvm_disks: list of tuples [(disk, link_name)..]
1306
    @type kvmhelp: string
1307
    @param kvmhelp: output of kvm --help
1308
    @type devlist: string
1309
    @param devlist: output of kvm -device ?
1310
    @rtype: list
1311
    @return: list of command line options eventually used by kvm executable
1312

1313
    """
1314
    hvp = instance.hvparams
1315
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1316
    if kernel_path:
1317
      boot_disk = False
1318
    else:
1319
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1320

    
1321
    # whether this is an older KVM version that uses the boot=on flag
1322
    # on devices
1323
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1324

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

    
1364
      # For ext we allow overriding disk_cache hypervisor params per disk
1365
      disk_cache = cfdev.params.get("cache", None)
1366
      if disk_cache:
1367
        cache_val = ",cache=%s" % disk_cache
1368
      drive_val = "file=%s,format=raw%s%s%s" % \
1369
                  (link_name, if_val, boot_val, cache_val)
1370

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

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

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

    
1402
    return dev_opts
1403

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

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

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

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

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

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

    
1439
    kvm_cmd.extend(["-pidfile", pidfile])
1440
    kvm_cmd.extend(["-balloon", "virtio"])
1441
    kvm_cmd.extend(["-daemonize"])
1442
    if not instance.hvparams[constants.HV_ACPI]:
1443
      kvm_cmd.extend(["-no-acpi"])
1444
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1445
        constants.INSTANCE_REBOOT_EXIT:
1446
      kvm_cmd.extend(["-no-reboot"])
1447

    
1448
    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1449
    if not mversion:
1450
      mversion = self._GetDefaultMachineVersion(kvm)
1451
    if self._MACHINE_RE.search(kvmhelp):
1452
      # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1453
      # extra hypervisor parameters. We should also investigate whether and how
1454
      # shadow_mem should be considered for the resource model.
1455
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1456
        specprop = ",accel=kvm"
1457
      else:
1458
        specprop = ""
1459
      machinespec = "%s%s" % (mversion, specprop)
1460
      kvm_cmd.extend(["-machine", machinespec])
1461
    else:
1462
      kvm_cmd.extend(["-M", mversion])
1463
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1464
          self._ENABLE_KVM_RE.search(kvmhelp)):
1465
        kvm_cmd.extend(["-enable-kvm"])
1466
      elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1467
            self._DISABLE_KVM_RE.search(kvmhelp)):
1468
        kvm_cmd.extend(["-disable-kvm"])
1469

    
1470
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1471
    if kernel_path:
1472
      boot_cdrom = boot_floppy = boot_network = False
1473
    else:
1474
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1475
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1476
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1477

    
1478
    if startup_paused:
1479
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1480

    
1481
    if boot_network:
1482
      kvm_cmd.extend(["-boot", "n"])
1483

    
1484
    # whether this is an older KVM version that uses the boot=on flag
1485
    # on devices
1486
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1487

    
1488
    disk_type = hvp[constants.HV_DISK_TYPE]
1489

    
1490
    #Now we can specify a different device type for CDROM devices.
1491
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1492
    if not cdrom_disk_type:
1493
      cdrom_disk_type = disk_type
1494

    
1495
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1496
    if iso_image:
1497
      options = ",format=raw,media=cdrom"
1498
      # set cdrom 'if' type
1499
      if boot_cdrom:
1500
        actual_cdrom_type = constants.HT_DISK_IDE
1501
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1502
        actual_cdrom_type = "virtio"
1503
      else:
1504
        actual_cdrom_type = cdrom_disk_type
1505
      if_val = ",if=%s" % actual_cdrom_type
1506
      # set boot flag, if needed
1507
      boot_val = ""
1508
      if boot_cdrom:
1509
        kvm_cmd.extend(["-boot", "d"])
1510
        if needs_boot_flag:
1511
          boot_val = ",boot=on"
1512
      # and finally build the entire '-drive' value
1513
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1514
      kvm_cmd.extend(["-drive", drive_val])
1515

    
1516
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1517
    if iso_image2:
1518
      options = ",format=raw,media=cdrom"
1519
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1520
        if_val = ",if=virtio"
1521
      else:
1522
        if_val = ",if=%s" % cdrom_disk_type
1523
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1524
      kvm_cmd.extend(["-drive", drive_val])
1525

    
1526
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1527
    if floppy_image:
1528
      options = ",format=raw,media=disk"
1529
      if boot_floppy:
1530
        kvm_cmd.extend(["-boot", "a"])
1531
        options = "%s,boot=on" % options
1532
      if_val = ",if=floppy"
1533
      options = "%s%s" % (options, if_val)
1534
      drive_val = "file=%s%s" % (floppy_image, options)
1535
      kvm_cmd.extend(["-drive", drive_val])
1536

    
1537
    if kernel_path:
1538
      kvm_cmd.extend(["-kernel", kernel_path])
1539
      initrd_path = hvp[constants.HV_INITRD_PATH]
1540
      if initrd_path:
1541
        kvm_cmd.extend(["-initrd", initrd_path])
1542
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1543
                     hvp[constants.HV_KERNEL_ARGS]]
1544
      if hvp[constants.HV_SERIAL_CONSOLE]:
1545
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1546
        root_append.append("console=ttyS0,%s" % serial_speed)
1547
      kvm_cmd.extend(["-append", " ".join(root_append)])
1548

    
1549
    mem_path = hvp[constants.HV_MEM_PATH]
1550
    if mem_path:
1551
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1552

    
1553
    monitor_dev = ("unix:%s,server,nowait" %
1554
                   self._InstanceMonitor(instance.name))
1555
    kvm_cmd.extend(["-monitor", monitor_dev])
1556
    if hvp[constants.HV_SERIAL_CONSOLE]:
1557
      serial_dev = ("unix:%s,server,nowait" %
1558
                    self._InstanceSerial(instance.name))
1559
      kvm_cmd.extend(["-serial", serial_dev])
1560
    else:
1561
      kvm_cmd.extend(["-serial", "none"])
1562

    
1563
    mouse_type = hvp[constants.HV_USB_MOUSE]
1564
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1565
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1566
    spice_ip_version = None
1567

    
1568
    kvm_cmd.extend(["-usb"])
1569

    
1570
    if mouse_type:
1571
      kvm_cmd.extend(["-usbdevice", mouse_type])
1572
    elif vnc_bind_address:
1573
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1574

    
1575
    if vnc_bind_address:
1576
      if netutils.IP4Address.IsValid(vnc_bind_address):
1577
        if instance.network_port > constants.VNC_BASE_PORT:
1578
          display = instance.network_port - constants.VNC_BASE_PORT
1579
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1580
            vnc_arg = ":%d" % (display)
1581
          else:
1582
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1583
        else:
1584
          logging.error("Network port is not a valid VNC display (%d < %d),"
1585
                        " not starting VNC",
1586
                        instance.network_port, constants.VNC_BASE_PORT)
1587
          vnc_arg = "none"
1588

    
1589
        # Only allow tls and other option when not binding to a file, for now.
1590
        # kvm/qemu gets confused otherwise about the filename to use.
1591
        vnc_append = ""
1592
        if hvp[constants.HV_VNC_TLS]:
1593
          vnc_append = "%s,tls" % vnc_append
1594
          if hvp[constants.HV_VNC_X509_VERIFY]:
1595
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1596
                                               hvp[constants.HV_VNC_X509])
1597
          elif hvp[constants.HV_VNC_X509]:
1598
            vnc_append = "%s,x509=%s" % (vnc_append,
1599
                                         hvp[constants.HV_VNC_X509])
1600
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1601
          vnc_append = "%s,password" % vnc_append
1602

    
1603
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1604

    
1605
      else:
1606
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1607

    
1608
      kvm_cmd.extend(["-vnc", vnc_arg])
1609
    elif spice_bind:
1610
      # FIXME: this is wrong here; the iface ip address differs
1611
      # between systems, so it should be done in _ExecuteKVMRuntime
1612
      if netutils.IsValidInterface(spice_bind):
1613
        # The user specified a network interface, we have to figure out the IP
1614
        # address.
1615
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1616
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1617

    
1618
        # if the user specified an IP version and the interface does not
1619
        # have that kind of IP addresses, throw an exception
1620
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1621
          if not addresses[spice_ip_version]:
1622
            raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1623
                                         " for %s" % (spice_ip_version,
1624
                                                      spice_bind))
1625

    
1626
        # the user did not specify an IP version, we have to figure it out
1627
        elif (addresses[constants.IP4_VERSION] and
1628
              addresses[constants.IP6_VERSION]):
1629
          # we have both ipv4 and ipv6, let's use the cluster default IP
1630
          # version
1631
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1632
          spice_ip_version = \
1633
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1634
        elif addresses[constants.IP4_VERSION]:
1635
          spice_ip_version = constants.IP4_VERSION
1636
        elif addresses[constants.IP6_VERSION]:
1637
          spice_ip_version = constants.IP6_VERSION
1638
        else:
1639
          raise errors.HypervisorError("SPICE: Unable to get an IP address"
1640
                                       " for %s" % (spice_bind))
1641

    
1642
        spice_address = addresses[spice_ip_version][0]
1643

    
1644
      else:
1645
        # spice_bind is known to be a valid IP address, because
1646
        # ValidateParameters checked it.
1647
        spice_address = spice_bind
1648

    
1649
      spice_arg = "addr=%s" % spice_address
1650
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1651
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1652
                     (spice_arg, instance.network_port,
1653
                      pathutils.SPICE_CACERT_FILE))
1654
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1655
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1656
                      pathutils.SPICE_CERT_FILE))
1657
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1658
        if tls_ciphers:
1659
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1660
      else:
1661
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1662

    
1663
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1664
        spice_arg = "%s,disable-ticketing" % spice_arg
1665

    
1666
      if spice_ip_version:
1667
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1668

    
1669
      # Image compression options
1670
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1671
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1672
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1673
      if img_lossless:
1674
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1675
      if img_jpeg:
1676
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1677
      if img_zlib_glz:
1678
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1679

    
1680
      # Video stream detection
1681
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1682
      if video_streaming:
1683
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1684

    
1685
      # Audio compression, by default in qemu-kvm it is on
1686
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1687
        spice_arg = "%s,playback-compression=off" % spice_arg
1688
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1689
        spice_arg = "%s,agent-mouse=off" % spice_arg
1690
      else:
1691
        # Enable the spice agent communication channel between the host and the
1692
        # agent.
1693
        kvm_cmd.extend(["-device", "virtio-serial-pci"])
1694
        kvm_cmd.extend([
1695
          "-device",
1696
          "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1697
          ])
1698
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1699

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

    
1703
    else:
1704
      # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1705
      # also works in earlier versions though (tested with 1.1 and 1.3)
1706
      if self._DISPLAY_RE.search(kvmhelp):
1707
        kvm_cmd.extend(["-display", "none"])
1708
      else:
1709
        kvm_cmd.extend(["-nographic"])
1710

    
1711
    if hvp[constants.HV_USE_LOCALTIME]:
1712
      kvm_cmd.extend(["-localtime"])
1713

    
1714
    if hvp[constants.HV_KVM_USE_CHROOT]:
1715
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1716

    
1717
    # Add qemu-KVM -cpu param
1718
    if hvp[constants.HV_CPU_TYPE]:
1719
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1720

    
1721
    # As requested by music lovers
1722
    if hvp[constants.HV_SOUNDHW]:
1723
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1724

    
1725
    # Pass a -vga option if requested, or if spice is used, for backwards
1726
    # compatibility.
1727
    if hvp[constants.HV_VGA]:
1728
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1729
    elif spice_bind:
1730
      kvm_cmd.extend(["-vga", "qxl"])
1731

    
1732
    # Various types of usb devices, comma separated
1733
    if hvp[constants.HV_USB_DEVICES]:
1734
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1735
        kvm_cmd.extend(["-usbdevice", dev])
1736

    
1737
    if hvp[constants.HV_KVM_EXTRA]:
1738
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1739

    
1740
    pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1741
    kvm_disks = []
1742
    for disk, link_name in block_devices:
1743
      _UpdatePCISlots(disk, pci_reservations)
1744
      kvm_disks.append((disk, link_name))
1745

    
1746
    kvm_nics = []
1747
    for nic in instance.nics:
1748
      _UpdatePCISlots(nic, pci_reservations)
1749
      kvm_nics.append(nic)
1750

    
1751
    hvparams = hvp
1752

    
1753
    return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1754

    
1755
  def _WriteKVMRuntime(self, instance_name, data):
1756
    """Write an instance's KVM runtime
1757

1758
    """
1759
    try:
1760
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1761
                      data=data)
1762
    except EnvironmentError, err:
1763
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1764

    
1765
  @classmethod
1766
  def _ReadKVMRuntime(cls, instance_name):
1767
    """Read an instance's KVM runtime
1768

1769
    """
1770
    try:
1771
      file_content = utils.ReadFile(cls._InstanceKVMRuntime(instance_name))
1772
    except EnvironmentError, err:
1773
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1774
    return file_content
1775

    
1776
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1777
    """Save an instance's KVM runtime
1778

1779
    """
1780
    kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1781

    
1782
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1783
    serialized_disks = [(blk.ToDict(), link)
1784
                            for blk, link in kvm_disks]
1785
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1786
                                      serialized_disks))
1787

    
1788
    self._WriteKVMRuntime(instance.name, serialized_form)
1789

    
1790
  @classmethod
1791
  def _LoadKVMRuntime(cls, instance_name, serialized_runtime=None):
1792
    """Load an instance's KVM runtime
1793

1794
    """
1795
    if not serialized_runtime:
1796
      serialized_runtime = cls._ReadKVMRuntime(instance_name)
1797

    
1798
    return _AnalyzeSerializedRuntime(serialized_runtime)
1799

    
1800
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1801
    """Run the KVM cmd and check for errors
1802

1803
    @type name: string
1804
    @param name: instance name
1805
    @type kvm_cmd: list of strings
1806
    @param kvm_cmd: runcmd input for kvm
1807
    @type tap_fds: list of int
1808
    @param tap_fds: fds of tap devices opened by Ganeti
1809

1810
    """
1811
    try:
1812
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1813
    finally:
1814
      for fd in tap_fds:
1815
        utils_wrapper.CloseFdNoError(fd)
1816

    
1817
    if result.failed:
1818
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1819
                                   (name, result.fail_reason, result.output))
1820
    if not self._InstancePidAlive(name)[2]:
1821
      raise errors.HypervisorError("Failed to start instance %s" % name)
1822

    
1823
  # too many local variables
1824
  # pylint: disable=R0914
1825
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1826
    """Execute a KVM cmd, after completing it with some last minute data.
1827

1828
    @type incoming: tuple of strings
1829
    @param incoming: (target_host_ip, port)
1830
    @type kvmhelp: string
1831
    @param kvmhelp: output of kvm --help
1832

1833
    """
1834
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1835
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1836
    #    have changed since the instance started; only use them if the change
1837
    #    won't affect the inside of the instance (which hasn't been rebooted).
1838
    #  - up_hvp contains the parameters as they were when the instance was
1839
    #    started, plus any new parameter which has been added between ganeti
1840
    #    versions: it is paramount that those default to a value which won't
1841
    #    affect the inside of the instance as well.
1842
    conf_hvp = instance.hvparams
1843
    name = instance.name
1844
    self._CheckDown(name)
1845

    
1846
    temp_files = []
1847

    
1848
    kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1849
    # the first element of kvm_cmd is always the path to the kvm binary
1850
    kvm_path = kvm_cmd[0]
1851
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1852

    
1853
    # We know it's safe to run as a different user upon migration, so we'll use
1854
    # the latest conf, from conf_hvp.
1855
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1856
    if security_model == constants.HT_SM_USER:
1857
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1858

    
1859
    keymap = conf_hvp[constants.HV_KEYMAP]
1860
    if keymap:
1861
      keymap_path = self._InstanceKeymapFile(name)
1862
      # If a keymap file is specified, KVM won't use its internal defaults. By
1863
      # first including the "en-us" layout, an error on loading the actual
1864
      # layout (e.g. because it can't be found) won't lead to a non-functional
1865
      # keyboard. A keyboard with incorrect keys is still better than none.
1866
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1867
      kvm_cmd.extend(["-k", keymap_path])
1868

    
1869
    # We have reasons to believe changing something like the nic driver/type
1870
    # upon migration won't exactly fly with the instance kernel, so for nic
1871
    # related parameters we'll use up_hvp
1872
    tapfds = []
1873
    taps = []
1874
    devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1875

    
1876
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1877
                                                     kvm_disks,
1878
                                                     kvmhelp,
1879
                                                     devlist)
1880
    kvm_cmd.extend(bdev_opts)
1881

    
1882
    if not kvm_nics:
1883
      kvm_cmd.extend(["-net", "none"])
1884
    else:
1885
      vnet_hdr = False
1886
      tap_extra = ""
1887
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1888
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1889
        nic_model = self._VIRTIO
1890
        try:
1891
          if self._VIRTIO_NET_RE.search(devlist):
1892
            nic_model = self._VIRTIO_NET_PCI
1893
            vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1894
        except errors.HypervisorError, _:
1895
          # Older versions of kvm don't support DEVICE_LIST, but they don't
1896
          # have new virtio syntax either.
1897
          pass
1898

    
1899
        if up_hvp[constants.HV_VHOST_NET]:
1900
          # check for vhost_net support
1901
          if self._VHOST_RE.search(kvmhelp):
1902
            tap_extra = ",vhost=on"
1903
          else:
1904
            raise errors.HypervisorError("vhost_net is configured"
1905
                                         " but it is not available")
1906
      else:
1907
        nic_model = nic_type
1908

    
1909
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1910

    
1911
      for nic_seq, nic in enumerate(kvm_nics):
1912
        tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1913
        tapfds.append(tapfd)
1914
        taps.append(tapname)
1915
        if kvm_supports_netdev:
1916
          nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1917
          try:
1918
            # kvm_nics already exist in old runtime files and thus there might
1919
            # be some entries without pci slot (therefore try: except:)
1920
            kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1921
            netdev = kvm_devid
1922
            nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1923
          except errors.HotplugError:
1924
            netdev = "netdev%d" % nic_seq
1925
          nic_val += (",netdev=%s" % netdev)
1926
          tap_val = ("type=tap,id=%s,fd=%d%s" %
1927
                     (netdev, tapfd, tap_extra))
1928
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1929
        else:
1930
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1931
                                                         nic.mac, nic_model)
1932
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1933
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1934

    
1935
    if incoming:
1936
      target, port = incoming
1937
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1938

    
1939
    # Changing the vnc password doesn't bother the guest that much. At most it
1940
    # will surprise people who connect to it. Whether positively or negatively
1941
    # it's debatable.
1942
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1943
    vnc_pwd = None
1944
    if vnc_pwd_file:
1945
      try:
1946
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1947
      except EnvironmentError, err:
1948
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1949
                                     % (vnc_pwd_file, err))
1950

    
1951
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1952
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1953
                         constants.SECURE_DIR_MODE)])
1954

    
1955
    # Automatically enable QMP if version is >= 0.14
1956
    if self._QMP_RE.search(kvmhelp):
1957
      logging.debug("Enabling QMP")
1958
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1959
                      self._InstanceQmpMonitor(instance.name)])
1960

    
1961
    # Configure the network now for starting instances and bridged interfaces,
1962
    # during FinalizeMigration for incoming instances' routed interfaces
1963
    for nic_seq, nic in enumerate(kvm_nics):
1964
      if (incoming and
1965
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1966
        continue
1967
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1968

    
1969
    # CPU affinity requires kvm to start paused, so we set this flag if the
1970
    # instance is not already paused and if we are not going to accept a
1971
    # migrating instance. In the latter case, pausing is not needed.
1972
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1973
    if start_kvm_paused:
1974
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1975

    
1976
    # Note: CPU pinning is using up_hvp since changes take effect
1977
    # during instance startup anyway, and to avoid problems when soft
1978
    # rebooting the instance.
1979
    cpu_pinning = False
1980
    if up_hvp.get(constants.HV_CPU_MASK, None):
1981
      cpu_pinning = True
1982

    
1983
    if security_model == constants.HT_SM_POOL:
1984
      ss = ssconf.SimpleStore()
1985
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1986
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1987
      uid = uidpool.RequestUnusedUid(all_uids)
1988
      try:
1989
        username = pwd.getpwuid(uid.GetUid()).pw_name
1990
        kvm_cmd.extend(["-runas", username])
1991
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1992
      except:
1993
        uidpool.ReleaseUid(uid)
1994
        raise
1995
      else:
1996
        uid.Unlock()
1997
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1998
    else:
1999
      self._RunKVMCmd(name, kvm_cmd, tapfds)
2000

    
2001
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
2002
                     constants.RUN_DIRS_MODE)])
2003
    for nic_seq, tap in enumerate(taps):
2004
      nic = kvm_nics[nic_seq]
2005
      self._WriteInstanceNICFiles(instance.name, nic_seq, nic, tap)
2006

    
2007
    if vnc_pwd:
2008
      change_cmd = "change vnc password %s" % vnc_pwd
2009
      self._CallMonitorCommand(instance.name, change_cmd)
2010

    
2011
    # Setting SPICE password. We are not vulnerable to malicious passwordless
2012
    # connection attempts because SPICE by default does not allow connections
2013
    # if neither a password nor the "disable_ticketing" options are specified.
2014
    # As soon as we send the password via QMP, that password is a valid ticket
2015
    # for connection.
2016
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
2017
    if spice_password_file:
2018
      spice_pwd = ""
2019
      try:
2020
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
2021
      except EnvironmentError, err:
2022
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
2023
                                     % (spice_password_file, err))
2024

    
2025
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
2026
      qmp.connect()
2027
      arguments = {
2028
          "protocol": "spice",
2029
          "password": spice_pwd,
2030
      }
2031
      qmp.Execute("set_password", arguments)
2032

    
2033
    for filename in temp_files:
2034
      utils.RemoveFile(filename)
2035

    
2036
    # If requested, set CPU affinity and resume instance execution
2037
    if cpu_pinning:
2038
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
2039

    
2040
    start_memory = self._InstanceStartupMemory(instance)
2041
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
2042
      self.BalloonInstanceMemory(instance, start_memory)
2043

    
2044
    if start_kvm_paused:
2045
      # To control CPU pinning, ballooning, and vnc/spice passwords
2046
      # the VM was started in a frozen state. If freezing was not
2047
      # explicitly requested resume the vm status.
2048
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2049

    
2050
  def StartInstance(self, instance, block_devices, startup_paused):
2051
    """Start an instance.
2052

2053
    """
2054
    self._CheckDown(instance.name)
2055
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2056
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2057
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
2058
                                           startup_paused, kvmhelp)
2059
    self._SaveKVMRuntime(instance, kvm_runtime)
2060
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2061

    
2062
  def _CallMonitorCommand(self, instance_name, command):
2063
    """Invoke a command on the instance monitor.
2064

2065
    """
2066
    # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
2067
    # version. The monitor protocol is designed for human consumption, whereas
2068
    # QMP is made for programmatic usage. In the worst case QMP can also
2069
    # execute monitor commands. As it is, all calls to socat take at least
2070
    # 500ms and likely more: socat can't detect the end of the reply and waits
2071
    # for 500ms of no data received before exiting (500 ms is the default for
2072
    # the "-t" parameter).
2073
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
2074
             (utils.ShellQuote(command),
2075
              constants.SOCAT_PATH,
2076
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
2077
    result = utils.RunCmd(socat)
2078
    if result.failed:
2079
      msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
2080
             " output: %s" %
2081
             (command, instance_name, result.fail_reason, result.output))
2082
      raise errors.HypervisorError(msg)
2083

    
2084
    return result
2085

    
2086
  def _GetFreePCISlot(self, instance, dev):
2087
    """Get the first available pci slot of a runnung instance.
2088

2089
    """
2090
    slots = bitarray(32)
2091
    slots.setall(False) # pylint: disable=E1101
2092
    output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
2093
    for line in output.stdout.splitlines():
2094
      match = self._INFO_PCI_RE.search(line)
2095
      if match:
2096
        slot = int(match.group(1))
2097
        slots[slot] = True
2098

    
2099
    [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
2100
    if not free:
2101
      raise errors.HypervisorError("All PCI slots occupied")
2102

    
2103
    dev.pci = int(free)
2104

    
2105
  def VerifyHotplugSupport(self, instance, action, dev_type):
2106
    """Verifies that hotplug is supported.
2107

2108
    Hotplug is *not* supported in case of:
2109
     - security models and chroot (disk hotplug)
2110
     - fdsend module is missing (nic hot-add)
2111

2112
    @raise errors.HypervisorError: in one of the previous cases
2113

2114
    """
2115
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2116
      hvp = instance.hvparams
2117
      security_model = hvp[constants.HV_SECURITY_MODEL]
2118
      use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
2119
      if use_chroot:
2120
        raise errors.HotplugError("Disk hotplug is not supported"
2121
                                  " in case of chroot.")
2122
      if security_model != constants.HT_SM_NONE:
2123
        raise errors.HotplugError("Disk Hotplug is not supported in case"
2124
                                  " security models are used.")
2125

    
2126
    if (dev_type == constants.HOTPLUG_TARGET_NIC and
2127
        action == constants.HOTPLUG_ACTION_ADD and not fdsend):
2128
      raise errors.HotplugError("Cannot hot-add NIC."
2129
                                " fdsend python module is missing.")
2130

    
2131
  def HotplugSupported(self, instance):
2132
    """Checks if hotplug is generally supported.
2133

2134
    Hotplug is *not* supported in case of:
2135
     - qemu versions < 1.0
2136
     - for stopped instances
2137

2138
    @raise errors.HypervisorError: in one of the previous cases
2139

2140
    """
2141
    try:
2142
      output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2143
    except errors.HypervisorError:
2144
      raise errors.HotplugError("Instance is probably down")
2145

    
2146
    # TODO: search for netdev_add, drive_add, device_add.....
2147
    match = self._INFO_VERSION_RE.search(output.stdout)
2148
    if not match:
2149
      raise errors.HotplugError("Cannot parse qemu version via monitor")
2150

    
2151
    v_major, v_min, _, _ = match.groups()
2152
    if (int(v_major), int(v_min)) < (1, 0):
2153
      raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2154

    
2155
  def _CallHotplugCommands(self, name, cmds):
2156
    for c in cmds:
2157
      self._CallMonitorCommand(name, c)
2158
      time.sleep(1)
2159

    
2160
  def _VerifyHotplugCommand(self, instance_name, device, dev_type,
2161
                            should_exist):
2162
    """Checks if a previous hotplug command has succeeded.
2163

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

2167
    @raise errors.HypervisorError: if result is not the expected one
2168

2169
    """
2170
    output = self._CallMonitorCommand(instance_name, self._INFO_PCI_CMD)
2171
    kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2172
    match = \
2173
      self._FIND_PCI_DEVICE_RE(device.pci, kvm_devid).search(output.stdout)
2174
    if match and not should_exist:
2175
      msg = "Device %s should have been removed but is still there" % kvm_devid
2176
      raise errors.HypervisorError(msg)
2177

    
2178
    if not match and should_exist:
2179
      msg = "Device %s should have been added but is missing" % kvm_devid
2180
      raise errors.HypervisorError(msg)
2181

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

    
2184
  def HotAddDevice(self, instance, dev_type, device, extra, seq):
2185
    """ Helper method to hot-add a new device
2186

2187
    It gets free pci slot generates the device name and invokes the
2188
    device specific method.
2189

2190
    """
2191
    # in case of hot-mod if the device already exists this is given
2192
    if device.pci is None:
2193
      self._GetFreePCISlot(instance, device)
2194
    kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2195
    runtime = self._LoadKVMRuntime(instance.name)
2196
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2197
      cmds = ["drive_add dummy file=%s,if=none,id=%s,format=raw" %
2198
                (extra, kvm_devid)]
2199
      cmds += ["device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
2200
                (hex(device.pci), kvm_devid, kvm_devid)]
2201
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
2202
      (tap, fd) = _OpenTap()
2203
      self._ConfigureNIC(instance, seq, device, tap)
2204
      self._PassTapFd(instance, fd, device)
2205
      cmds = ["netdev_add tap,id=%s,fd=%s" % (kvm_devid, kvm_devid)]
2206
      args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
2207
               (hex(device.pci), device.mac, kvm_devid, kvm_devid)
2208
      cmds += ["device_add %s" % args]
2209
      self._WriteInstanceNICFiles(instance.name, seq, device, tap)
2210

    
2211
    self._CallHotplugCommands(instance.name, cmds)
2212
    self._VerifyHotplugCommand(instance.name, device, dev_type, True)
2213
    # update relevant entries in runtime file
2214
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2215
    entry = _RUNTIME_ENTRY[dev_type](device, extra)
2216
    runtime[index].append(entry)
2217
    self._SaveKVMRuntime(instance, runtime)
2218

    
2219
  def HotDelDevice(self, instance, dev_type, device, _, seq):
2220
    """ Helper method for hot-del device
2221

2222
    It gets device info from runtime file, generates the device name and
2223
    invokes the device specific method.
2224

2225
    """
2226
    runtime = self._LoadKVMRuntime(instance.name)
2227
    entry = _GetExistingDeviceInfo(dev_type, device, runtime)
2228
    kvm_device = _RUNTIME_DEVICE[dev_type](entry)
2229
    kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
2230
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2231
      cmds = ["device_del %s" % kvm_devid]
2232
      cmds += ["drive_del %s" % kvm_devid]
2233
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
2234
      cmds = ["device_del %s" % kvm_devid]
2235
      cmds += ["netdev_del %s" % kvm_devid]
2236
      self._UnconfigureNic(instance.name, kvm_device, False)
2237
      self._RemoveInstanceNICFiles(instance.name, seq, device)
2238
    self._CallHotplugCommands(instance.name, cmds)
2239
    self._VerifyHotplugCommand(instance.name, kvm_device, dev_type, False)
2240
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2241
    runtime[index].remove(entry)
2242
    self._SaveKVMRuntime(instance, runtime)
2243

    
2244
    return kvm_device.pci
2245

    
2246
  def HotModDevice(self, instance, dev_type, device, _, seq):
2247
    """ Helper method for hot-mod device
2248

2249
    It gets device info from runtime file, generates the device name and
2250
    invokes the device specific method. Currently only NICs support hot-mod
2251

2252
    """
2253
    if dev_type == constants.HOTPLUG_TARGET_NIC:
2254
      # putting it back in the same pci slot
2255
      try:
2256
        device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2257
      except errors.HotplugError:
2258
        logging.info("Device not found in runtime file. Assuming it was"
2259
                     " previously added without --hotplug option.")
2260
      # TODO: remove sleep when socat gets removed
2261
      self.HotAddDevice(instance, dev_type, device, _, seq)
2262

    
2263
  def _PassTapFd(self, instance, fd, nic):
2264
    """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2265

2266
    """
2267
    # TODO: factor out code related to unix sockets.
2268
    #       squash common parts between monitor and qmp
2269
    kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2270
    command = "getfd %s\n" % kvm_devid
2271
    fds = [fd]
2272
    logging.info("%s", fds)
2273
    try:
2274
      monsock = MonitorSocket(self._InstanceMonitor(instance.name))
2275
      monsock.connect()
2276
      fdsend.sendfds(monsock.sock, command, fds=fds)
2277
    finally:
2278
      monsock.close()
2279

    
2280
  @classmethod
2281
  def _ParseKVMVersion(cls, text):
2282
    """Parse the KVM version from the --help output.
2283

2284
    @type text: string
2285
    @param text: output of kvm --help
2286
    @return: (version, v_maj, v_min, v_rev)
2287
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2288

2289
    """
2290
    match = cls._VERSION_RE.search(text.splitlines()[0])
2291
    if not match:
2292
      raise errors.HypervisorError("Unable to get KVM version")
2293

    
2294
    v_all = match.group(0)
2295
    v_maj = int(match.group(1))
2296
    v_min = int(match.group(2))
2297
    if match.group(4):
2298
      v_rev = int(match.group(4))
2299
    else:
2300
      v_rev = 0
2301
    return (v_all, v_maj, v_min, v_rev)
2302

    
2303
  @classmethod
2304
  def _GetKVMOutput(cls, kvm_path, option):
2305
    """Return the output of a kvm invocation
2306

2307
    @type kvm_path: string
2308
    @param kvm_path: path to the kvm executable
2309
    @type option: a key of _KVMOPTS_CMDS
2310
    @param option: kvm option to fetch the output from
2311
    @return: output a supported kvm invocation
2312
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2313

2314
    """
2315
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2316

    
2317
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
2318

    
2319
    result = utils.RunCmd([kvm_path] + optlist)
2320
    if result.failed and not can_fail:
2321
      raise errors.HypervisorError("Unable to get KVM %s output" %
2322
                                    " ".join(optlist))
2323
    return result.output
2324

    
2325
  @classmethod
2326
  def _GetKVMVersion(cls, kvm_path):
2327
    """Return the installed KVM version.
2328

2329
    @return: (version, v_maj, v_min, v_rev)
2330
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2331

2332
    """
2333
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2334

    
2335
  @classmethod
2336
  def _GetDefaultMachineVersion(cls, kvm_path):
2337
    """Return the default hardware revision (e.g. pc-1.1)
2338

2339
    """
2340
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2341
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2342
    if match:
2343
      return match.group(1)
2344
    else:
2345
      return "pc"
2346

    
2347
  def StopInstance(self, instance, force=False, retry=False, name=None):
2348
    """Stop an instance.
2349

2350
    """
2351
    if name is not None and not force:
2352
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2353
    if name is None:
2354
      name = instance.name
2355
      acpi = instance.hvparams[constants.HV_ACPI]
2356
    else:
2357
      acpi = False
2358
    _, pid, alive = self._InstancePidAlive(name)
2359
    if pid > 0 and alive:
2360
      if force or not acpi:
2361
        utils.KillProcess(pid)
2362
      else:
2363
        self._CallMonitorCommand(name, "system_powerdown")
2364

    
2365
  @classmethod
2366
  def _UnconfigureInstanceNICs(cls, instance_name, info=None):
2367
    """Get runtime NICs of an instance and unconfigure them
2368

2369
    """
2370
    _, kvm_nics, __, ___ = cls._LoadKVMRuntime(instance_name, info)
2371
    for nic in kvm_nics:
2372
      cls._UnconfigureNic(instance_name, nic)
2373

    
2374
  def CleanupInstance(self, instance_name):
2375
    """Cleanup after a stopped instance
2376

2377
    """
2378
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
2379
    if pid > 0 and alive:
2380
      raise errors.HypervisorError("Cannot cleanup a live instance")
2381
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2382

    
2383
  def RebootInstance(self, instance):
2384
    """Reboot an instance.
2385

2386
    """
2387
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2388
    # socket the instance will stop, but now power up again. So we'll resort
2389
    # to shutdown and restart.
2390
    _, _, alive = self._InstancePidAlive(instance.name)
2391
    if not alive:
2392
      raise errors.HypervisorError("Failed to reboot instance %s:"
2393
                                   " not running" % instance.name)
2394
    # StopInstance will delete the saved KVM runtime so:
2395
    # ...first load it...
2396
    kvm_runtime = self._LoadKVMRuntime(instance.name)
2397
    # ...now we can safely call StopInstance...
2398
    if not self.StopInstance(instance):
2399
      self.StopInstance(instance, force=True)
2400
    # ...and finally we can save it again, and execute it...
2401
    self._SaveKVMRuntime(instance, kvm_runtime)
2402
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2403
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2404
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2405

    
2406
  def MigrationInfo(self, instance):
2407
    """Get instance information to perform a migration.
2408

2409
    @type instance: L{objects.Instance}
2410
    @param instance: instance to be migrated
2411
    @rtype: string
2412
    @return: content of the KVM runtime file
2413

2414
    """
2415
    return self._ReadKVMRuntime(instance.name)
2416

    
2417
  def AcceptInstance(self, instance, info, target):
2418
    """Prepare to accept an instance.
2419

2420
    @type instance: L{objects.Instance}
2421
    @param instance: instance to be accepted
2422
    @type info: string
2423
    @param info: content of the KVM runtime file on the source node
2424
    @type target: string
2425
    @param target: target host (usually ip), on this node
2426

2427
    """
2428
    kvm_runtime = self._LoadKVMRuntime(instance.name, serialized_runtime=info)
2429
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2430
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2431
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2432
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2433
                            incoming=incoming_address)
2434

    
2435
  def FinalizeMigrationDst(self, instance, info, success):
2436
    """Finalize the instance migration on the target node.
2437

2438
    Stop the incoming mode KVM.
2439

2440
    @type instance: L{objects.Instance}
2441
    @param instance: instance whose migration is being finalized
2442

2443
    """
2444
    if success:
2445
      kvm_runtime = self._LoadKVMRuntime(instance.name, serialized_runtime=info)
2446
      kvm_nics = kvm_runtime[1]
2447

    
2448
      for nic_seq, nic in enumerate(kvm_nics):
2449
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2450
          # Bridged interfaces have already been configured
2451
          continue
2452
        try:
2453
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2454
        except EnvironmentError, err:
2455
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
2456
                          instance.name, nic_seq, str(err))
2457
          continue
2458
        try:
2459
          self._ConfigureNIC(instance, nic_seq, nic, tap)
2460
        except errors.HypervisorError, err:
2461
          logging.warning(str(err))
2462

    
2463
      self._WriteKVMRuntime(instance.name, info)
2464
    else:
2465
      self._UnconfigureInstanceNICs(instance.name, info)
2466
      self.StopInstance(instance, force=True)
2467

    
2468
  def MigrateInstance(self, instance, target, live):
2469
    """Migrate an instance to a target node.
2470

2471
    The migration will not be attempted if the instance is not
2472
    currently running.
2473

2474
    @type instance: L{objects.Instance}
2475
    @param instance: the instance to be migrated
2476
    @type target: string
2477
    @param target: ip address of the target node
2478
    @type live: boolean
2479
    @param live: perform a live migration
2480

2481
    """
2482
    instance_name = instance.name
2483
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
2484
    _, _, alive = self._InstancePidAlive(instance_name)
2485
    if not alive:
2486
      raise errors.HypervisorError("Instance not running, cannot migrate")
2487

    
2488
    if not live:
2489
      self._CallMonitorCommand(instance_name, "stop")
2490

    
2491
    migrate_command = ("migrate_set_speed %dm" %
2492
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2493
    self._CallMonitorCommand(instance_name, migrate_command)
2494

    
2495
    migrate_command = ("migrate_set_downtime %dms" %
2496
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2497
    self._CallMonitorCommand(instance_name, migrate_command)
2498

    
2499
    # These commands are supported in latest qemu versions.
2500
    # Since _CallMonitorCommand does not catch monitor errors
2501
    # this does not raise an exception in case command is not supported
2502
    # TODO: either parse output of command or see if the command supported
2503
    # via info help (see hotplug)
2504
    migrate_command = ("migrate_set_capability xbzrle on")
2505
    self._CallMonitorCommand(instance_name, migrate_command)
2506

    
2507
    migrate_command = ("migrate_set_capability auto-converge on")
2508
    self._CallMonitorCommand(instance_name, migrate_command)
2509

    
2510
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2511
    self._CallMonitorCommand(instance_name, migrate_command)
2512

    
2513
  def FinalizeMigrationSource(self, instance, success, live):
2514
    """Finalize the instance migration on the source node.
2515

2516
    @type instance: L{objects.Instance}
2517
    @param instance: the instance that was migrated
2518
    @type success: bool
2519
    @param success: whether the migration succeeded or not
2520
    @type live: bool
2521
    @param live: whether the user requested a live migration or not
2522

2523
    """
2524
    if success:
2525
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2526
      utils.KillProcess(pid)
2527
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2528
    elif live:
2529
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2530

    
2531
  def GetMigrationStatus(self, instance):
2532
    """Get the migration status
2533

2534
    @type instance: L{objects.Instance}
2535
    @param instance: the instance that is being migrated
2536
    @rtype: L{objects.MigrationStatus}
2537
    @return: the status of the current migration (one of
2538
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2539
             progress info that can be retrieved from the hypervisor
2540

2541
    """
2542
    info_command = "info migrate"
2543
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2544
      result = self._CallMonitorCommand(instance.name, info_command)
2545
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
2546
      if not match:
2547
        if not result.stdout:
2548
          logging.info("KVM: empty 'info migrate' result")
2549
        else:
2550
          logging.warning("KVM: unknown 'info migrate' result: %s",
2551
                          result.stdout)
2552
      else:
2553
        status = match.group(1)
2554
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2555
          migration_status = objects.MigrationStatus(status=status)
2556
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2557
          if match:
2558
            migration_status.transferred_ram = match.group("transferred")
2559
            migration_status.total_ram = match.group("total")
2560

    
2561
          return migration_status
2562

    
2563
        logging.warning("KVM: unknown migration status '%s'", status)
2564

    
2565
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2566

    
2567
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2568

    
2569
  def BalloonInstanceMemory(self, instance, mem):
2570
    """Balloon an instance memory to a certain value.
2571

2572
    @type instance: L{objects.Instance}
2573
    @param instance: instance to be accepted
2574
    @type mem: int
2575
    @param mem: actual memory size to use for instance runtime
2576

2577
    """
2578
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2579

    
2580
  def GetNodeInfo(self):
2581
    """Return information about the node.
2582

2583
    @return: a dict with the following keys (values in MiB):
2584
          - memory_total: the total memory size on the node
2585
          - memory_free: the available memory on the node for instances
2586
          - memory_dom0: the memory used by the node itself, if available
2587
          - hv_version: the hypervisor version in the form (major, minor,
2588
                        revision)
2589

2590
    """
2591
    result = self.GetLinuxNodeInfo()
2592
    # FIXME: this is the global kvm version, but the actual version can be
2593
    # customized as an hv parameter. we should use the nodegroup's default kvm
2594
    # path parameter here.
2595
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2596
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2597
    return result
2598

    
2599
  @classmethod
2600
  def GetInstanceConsole(cls, instance, hvparams, beparams):
2601
    """Return a command for connecting to the console of an instance.
2602

2603
    """
2604
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2605
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2606
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2607
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2608
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2609
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2610
      return objects.InstanceConsole(instance=instance.name,
2611
                                     kind=constants.CONS_SSH,
2612
                                     host=instance.primary_node,
2613
                                     user=constants.SSH_CONSOLE_USER,
2614
                                     command=cmd)
2615

    
2616
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2617
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2618
      display = instance.network_port - constants.VNC_BASE_PORT
2619
      return objects.InstanceConsole(instance=instance.name,
2620
                                     kind=constants.CONS_VNC,
2621
                                     host=vnc_bind_address,
2622
                                     port=instance.network_port,
2623
                                     display=display)
2624

    
2625
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2626
    if spice_bind:
2627
      return objects.InstanceConsole(instance=instance.name,
2628
                                     kind=constants.CONS_SPICE,
2629
                                     host=spice_bind,
2630
                                     port=instance.network_port)
2631

    
2632
    return objects.InstanceConsole(instance=instance.name,
2633
                                   kind=constants.CONS_MESSAGE,
2634
                                   message=("No serial shell for instance %s" %
2635
                                            instance.name))
2636

    
2637
  def Verify(self):
2638
    """Verify the hypervisor.
2639

2640
    Check that the required binaries exist.
2641

2642
    @return: Problem description if something is wrong, C{None} otherwise
2643

2644
    """
2645
    msgs = []
2646
    # FIXME: this is the global kvm binary, but the actual path can be
2647
    # customized as an hv parameter; we should use the nodegroup's
2648
    # default kvm path parameter here.
2649
    if not os.path.exists(constants.KVM_PATH):
2650
      msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2651
    if not os.path.exists(constants.SOCAT_PATH):
2652
      msgs.append("The socat binary ('%s') does not exist" %
2653
                  constants.SOCAT_PATH)
2654

    
2655
    return self._FormatVerifyResults(msgs)
2656

    
2657
  @classmethod
2658
  def CheckParameterSyntax(cls, hvparams):
2659
    """Check the given parameters for validity.
2660

2661
    @type hvparams:  dict
2662
    @param hvparams: dictionary with parameter names/value
2663
    @raise errors.HypervisorError: when a parameter is not valid
2664

2665
    """
2666
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2667

    
2668
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2669
    if kernel_path:
2670
      if not hvparams[constants.HV_ROOT_PATH]:
2671
        raise errors.HypervisorError("Need a root partition for the instance,"
2672
                                     " if a kernel is defined")
2673

    
2674
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2675
        not hvparams[constants.HV_VNC_X509]):
2676
      raise errors.HypervisorError("%s must be defined, if %s is" %
2677
                                   (constants.HV_VNC_X509,
2678
                                    constants.HV_VNC_X509_VERIFY))
2679

    
2680
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2681
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2682
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2683
      if not serial_speed or serial_speed not in valid_speeds:
2684
        raise errors.HypervisorError("Invalid serial console speed, must be"
2685
                                     " one of: %s" %
2686
                                     utils.CommaJoin(valid_speeds))
2687

    
2688
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2689
    if (boot_order == constants.HT_BO_CDROM and
2690
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2691
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2692
                                   " ISO path")
2693

    
2694
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2695
    if security_model == constants.HT_SM_USER:
2696
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2697
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2698
                                     " must be specified")
2699
    elif (security_model == constants.HT_SM_NONE or
2700
          security_model == constants.HT_SM_POOL):
2701
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2702
        raise errors.HypervisorError("Cannot have a security domain when the"
2703
                                     " security model is 'none' or 'pool'")
2704

    
2705
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2706
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2707
    if spice_bind:
2708
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2709
        # if an IP version is specified, the spice_bind parameter must be an
2710
        # IP of that family
2711
        if (netutils.IP4Address.IsValid(spice_bind) and
2712
            spice_ip_version != constants.IP4_VERSION):
2713
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2714
                                       " the specified IP version is %s" %
2715
                                       (spice_bind, spice_ip_version))
2716

    
2717
        if (netutils.IP6Address.IsValid(spice_bind) and
2718
            spice_ip_version != constants.IP6_VERSION):
2719
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2720
                                       " the specified IP version is %s" %
2721
                                       (spice_bind, spice_ip_version))
2722
    else:
2723
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2724
      # error if any of them is set without it.
2725
      for param in _SPICE_ADDITIONAL_PARAMS:
2726
        if hvparams[param]:
2727
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2728
                                       (param, constants.HV_KVM_SPICE_BIND))
2729

    
2730
  @classmethod
2731
  def ValidateParameters(cls, hvparams):
2732
    """Check the given parameters for validity.
2733

2734
    @type hvparams:  dict
2735
    @param hvparams: dictionary with parameter names/value
2736
    @raise errors.HypervisorError: when a parameter is not valid
2737

2738
    """
2739
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2740

    
2741
    kvm_path = hvparams[constants.HV_KVM_PATH]
2742

    
2743
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2744
    if security_model == constants.HT_SM_USER:
2745
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2746
      try:
2747
        pwd.getpwnam(username)
2748
      except KeyError:
2749
        raise errors.HypervisorError("Unknown security domain user %s"
2750
                                     % username)
2751

    
2752
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2753
    if spice_bind:
2754
      # only one of VNC and SPICE can be used currently.
2755
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2756
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2757
                                     " only one of them can be used at a"
2758
                                     " given time")
2759

    
2760
      # check that KVM supports SPICE
2761
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2762
      if not cls._SPICE_RE.search(kvmhelp):
2763
        raise errors.HypervisorError("SPICE is configured, but it is not"
2764
                                     " supported according to 'kvm --help'")
2765

    
2766
      # if spice_bind is not an IP address, it must be a valid interface
2767
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2768
                       netutils.IP6Address.IsValid(spice_bind))
2769
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2770
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2771
                                     " a valid IP address or interface name" %
2772
                                     constants.HV_KVM_SPICE_BIND)
2773

    
2774
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2775
    if machine_version:
2776
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2777
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2778
        raise errors.HypervisorError("Unsupported machine version: %s" %
2779
                                     machine_version)
2780

    
2781
  @classmethod
2782
  def PowercycleNode(cls):
2783
    """KVM powercycle, just a wrapper over Linux powercycle.
2784

2785
    """
2786
    cls.LinuxPowercycle()