Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ f8b4ec36

History | View | Annotate | Download (95.1 kB)

1
#
2
#
3

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

    
21

    
22
"""KVM hypervisor
23

24
"""
25

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

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

    
62

    
63
_KVM_NETWORK_SCRIPT = pathutils.CONF_DIR + "/kvm-vif-bridge"
64
_KVM_START_PAUSED_FLAG = "-S"
65

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

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

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

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

    
116

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

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

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

130
  """
131

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

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

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

    
144

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

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

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

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

    
167
  pci_reservations[free] = True
168

    
169

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

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

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

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

    
193
  return found[0]
194

    
195

    
196
def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
197
  """Retrieves supported TUN features from file descriptor.
198

199
  @see: L{_ProbeTapVnetHdr}
200

201
  """
202
  req = struct.pack("I", 0)
203
  try:
204
    buf = _ioctl(fd, TUNGETFEATURES, req)
205
  except EnvironmentError, err:
206
    logging.warning("ioctl(TUNGETFEATURES) failed: %s", err)
207
    return None
208
  else:
209
    (flags, ) = struct.unpack("I", buf)
210
    return flags
211

    
212

    
213
def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
214
  """Check whether to enable the IFF_VNET_HDR flag.
215

216
  To do this, _all_ of the following conditions must be met:
217
   1. TUNGETFEATURES ioctl() *must* be implemented
218
   2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
219
   3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
220
      drivers/net/tun.c there is no way to test this until after the tap device
221
      has been created using TUNSETIFF, and there is no way to change the
222
      IFF_VNET_HDR flag after creating the interface, catch-22! However both
223
      TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
224
      thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
225

226
   @type fd: int
227
   @param fd: the file descriptor of /dev/net/tun
228

229
  """
230
  flags = _features_fn(fd)
231

    
232
  if flags is None:
233
    # Not supported
234
    return False
235

    
236
  result = bool(flags & IFF_VNET_HDR)
237

    
238
  if not result:
239
    logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
240

    
241
  return result
242

    
243

    
244
def _OpenTap(vnet_hdr=True):
245
  """Open a new tap device and return its file descriptor.
246

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

250
  @type vnet_hdr: boolean
251
  @param vnet_hdr: Enable the VNET Header
252
  @return: (ifname, tapfd)
253
  @rtype: tuple
254

255
  """
256
  try:
257
    tapfd = os.open("/dev/net/tun", os.O_RDWR)
258
  except EnvironmentError:
259
    raise errors.HypervisorError("Failed to open /dev/net/tun")
260

    
261
  flags = IFF_TAP | IFF_NO_PI
262

    
263
  if vnet_hdr and _ProbeTapVnetHdr(tapfd):
264
    flags |= IFF_VNET_HDR
265

    
266
  # The struct ifreq ioctl request (see netdevice(7))
267
  ifr = struct.pack("16sh", "", flags)
268

    
269
  try:
270
    res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
271
  except EnvironmentError, err:
272
    raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
273
                                 err)
274

    
275
  # Get the interface name from the ioctl
276
  ifname = struct.unpack("16sh", res)[0].strip("\x00")
277
  return (ifname, tapfd)
278

    
279

    
280
class QmpMessage:
281
  """QEMU Messaging Protocol (QMP) message.
282

283
  """
284
  def __init__(self, data):
285
    """Creates a new QMP message based on the passed data.
286

287
    """
288
    if not isinstance(data, dict):
289
      raise TypeError("QmpMessage must be initialized with a dict")
290

    
291
    self.data = data
292

    
293
  def __getitem__(self, field_name):
294
    """Get the value of the required field if present, or None.
295

296
    Overrides the [] operator to provide access to the message data,
297
    returning None if the required item is not in the message
298
    @return: the value of the field_name field, or None if field_name
299
             is not contained in the message
300

301
    """
302
    return self.data.get(field_name, None)
303

    
304
  def __setitem__(self, field_name, field_value):
305
    """Set the value of the required field_name to field_value.
306

307
    """
308
    self.data[field_name] = field_value
309

    
310
  @staticmethod
311
  def BuildFromJsonString(json_string):
312
    """Build a QmpMessage from a JSON encoded string.
313

314
    @type json_string: str
315
    @param json_string: JSON string representing the message
316
    @rtype: L{QmpMessage}
317
    @return: a L{QmpMessage} built from json_string
318

319
    """
320
    # Parse the string
321
    data = serializer.LoadJson(json_string)
322
    return QmpMessage(data)
323

    
324
  def __str__(self):
325
    # The protocol expects the JSON object to be sent as a single line.
326
    return serializer.DumpJson(self.data)
327

    
328
  def __eq__(self, other):
329
    # When comparing two QmpMessages, we are interested in comparing
330
    # their internal representation of the message data
331
    return self.data == other.data
332

    
333

    
334
class MonitorSocket(object):
335
  _SOCKET_TIMEOUT = 5
336

    
337
  def __init__(self, monitor_filename):
338
    """Instantiates the MonitorSocket object.
339

340
    @type monitor_filename: string
341
    @param monitor_filename: the filename of the UNIX raw socket on which the
342
                             monitor (QMP or simple one) is listening
343

344
    """
345
    self.monitor_filename = monitor_filename
346
    self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
347
    # We want to fail if the server doesn't send a complete message
348
    # in a reasonable amount of time
349
    self.sock.settimeout(self._SOCKET_TIMEOUT)
350
    self._connected = False
351

    
352
  def _check_socket(self):
353
    sock_stat = None
354
    try:
355
      sock_stat = os.stat(self.monitor_filename)
356
    except EnvironmentError, err:
357
      if err.errno == errno.ENOENT:
358
        raise errors.HypervisorError("No monitor socket found")
359
      else:
360
        raise errors.HypervisorError("Error checking monitor socket: %s",
361
                                     utils.ErrnoOrStr(err))
362
    if not stat.S_ISSOCK(sock_stat.st_mode):
363
      raise errors.HypervisorError("Monitor socket is not a socket")
364

    
365
  def _check_connection(self):
366
    """Make sure that the connection is established.
367

368
    """
369
    if not self._connected:
370
      raise errors.ProgrammerError("To use a MonitorSocket you need to first"
371
                                   " invoke connect() on it")
372

    
373
  def connect(self):
374
    """Connects to the monitor.
375

376
    Connects to the UNIX socket
377

378
    @raise errors.HypervisorError: when there are communication errors
379

380
    """
381
    if self._connected:
382
      raise errors.ProgrammerError("Cannot connect twice")
383

    
384
    self._check_socket()
385

    
386
    # Check file existance/stuff
387
    try:
388
      self.sock.connect(self.monitor_filename)
389
    except EnvironmentError:
390
      raise errors.HypervisorError("Can't connect to qmp socket")
391
    self._connected = True
392

    
393
  def close(self):
394
    """Closes the socket
395

396
    It cannot be used after this call.
397

398
    """
399
    self.sock.close()
400

    
401

    
402
class QmpConnection(MonitorSocket):
403
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
404

405
  """
406
  _FIRST_MESSAGE_KEY = "QMP"
407
  _EVENT_KEY = "event"
408
  _ERROR_KEY = "error"
409
  _RETURN_KEY = RETURN_KEY = "return"
410
  _ACTUAL_KEY = ACTUAL_KEY = "actual"
411
  _ERROR_CLASS_KEY = "class"
412
  _ERROR_DATA_KEY = "data"
413
  _ERROR_DESC_KEY = "desc"
414
  _EXECUTE_KEY = "execute"
415
  _ARGUMENTS_KEY = "arguments"
416
  _CAPABILITIES_COMMAND = "qmp_capabilities"
417
  _MESSAGE_END_TOKEN = "\r\n"
418

    
419
  def __init__(self, monitor_filename):
420
    super(QmpConnection, self).__init__(monitor_filename)
421
    self._buf = ""
422

    
423
  def connect(self):
424
    """Connects to the QMP monitor.
425

426
    Connects to the UNIX socket and makes sure that we can actually send and
427
    receive data to the kvm instance via QMP.
428

429
    @raise errors.HypervisorError: when there are communication errors
430
    @raise errors.ProgrammerError: when there are data serialization errors
431

432
    """
433
    super(QmpConnection, self).connect()
434
    # Check if we receive a correct greeting message from the server
435
    # (As per the QEMU Protocol Specification 0.1 - section 2.2)
436
    greeting = self._Recv()
437
    if not greeting[self._FIRST_MESSAGE_KEY]:
438
      self._connected = False
439
      raise errors.HypervisorError("kvm: QMP communication error (wrong"
440
                                   " server greeting")
441

    
442
    # Let's put the monitor in command mode using the qmp_capabilities
443
    # command, or else no command will be executable.
444
    # (As per the QEMU Protocol Specification 0.1 - section 4)
445
    self.Execute(self._CAPABILITIES_COMMAND)
446

    
447
  def _ParseMessage(self, buf):
448
    """Extract and parse a QMP message from the given buffer.
449

450
    Seeks for a QMP message in the given buf. If found, it parses it and
451
    returns it together with the rest of the characters in the buf.
452
    If no message is found, returns None and the whole buffer.
453

454
    @raise errors.ProgrammerError: when there are data serialization errors
455

456
    """
457
    message = None
458
    # Check if we got the message end token (CRLF, as per the QEMU Protocol
459
    # Specification 0.1 - Section 2.1.1)
460
    pos = buf.find(self._MESSAGE_END_TOKEN)
461
    if pos >= 0:
462
      try:
463
        message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
464
      except Exception, err:
465
        raise errors.ProgrammerError("QMP data serialization error: %s" % err)
466
      buf = buf[pos + 1:]
467

    
468
    return (message, buf)
469

    
470
  def _Recv(self):
471
    """Receives a message from QMP and decodes the received JSON object.
472

473
    @rtype: QmpMessage
474
    @return: the received message
475
    @raise errors.HypervisorError: when there are communication errors
476
    @raise errors.ProgrammerError: when there are data serialization errors
477

478
    """
479
    self._check_connection()
480

    
481
    # Check if there is already a message in the buffer
482
    (message, self._buf) = self._ParseMessage(self._buf)
483
    if message:
484
      return message
485

    
486
    recv_buffer = StringIO.StringIO(self._buf)
487
    recv_buffer.seek(len(self._buf))
488
    try:
489
      while True:
490
        data = self.sock.recv(4096)
491
        if not data:
492
          break
493
        recv_buffer.write(data)
494

    
495
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
496
        if message:
497
          return message
498

    
499
    except socket.timeout, err:
500
      raise errors.HypervisorError("Timeout while receiving a QMP message: "
501
                                   "%s" % (err))
502
    except socket.error, err:
503
      raise errors.HypervisorError("Unable to receive data from KVM using the"
504
                                   " QMP protocol: %s" % err)
505

    
506
  def _Send(self, message):
507
    """Encodes and sends a message to KVM using QMP.
508

509
    @type message: QmpMessage
510
    @param message: message to send to KVM
511
    @raise errors.HypervisorError: when there are communication errors
512
    @raise errors.ProgrammerError: when there are data serialization errors
513

514
    """
515
    self._check_connection()
516
    try:
517
      message_str = str(message)
518
    except Exception, err:
519
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
520

    
521
    try:
522
      self.sock.sendall(message_str)
523
    except socket.timeout, err:
524
      raise errors.HypervisorError("Timeout while sending a QMP message: "
525
                                   "%s (%s)" % (err.string, err.errno))
526
    except socket.error, err:
527
      raise errors.HypervisorError("Unable to send data from KVM using the"
528
                                   " QMP protocol: %s" % err)
529

    
530
  def Execute(self, command, arguments=None):
531
    """Executes a QMP command and returns the response of the server.
532

533
    @type command: str
534
    @param command: the command to execute
535
    @type arguments: dict
536
    @param arguments: dictionary of arguments to be passed to the command
537
    @rtype: dict
538
    @return: dictionary representing the received JSON object
539
    @raise errors.HypervisorError: when there are communication errors
540
    @raise errors.ProgrammerError: when there are data serialization errors
541

542
    """
543
    self._check_connection()
544
    message = QmpMessage({self._EXECUTE_KEY: command})
545
    if arguments:
546
      message[self._ARGUMENTS_KEY] = arguments
547
    self._Send(message)
548

    
549
    # Events can occur between the sending of the command and the reception
550
    # of the response, so we need to filter out messages with the event key.
551
    while True:
552
      response = self._Recv()
553
      err = response[self._ERROR_KEY]
554
      if err:
555
        raise errors.HypervisorError("kvm: error executing the %s"
556
                                     " command: %s (%s, %s):" %
557
                                     (command,
558
                                      err[self._ERROR_DESC_KEY],
559
                                      err[self._ERROR_CLASS_KEY],
560
                                      err[self._ERROR_DATA_KEY]))
561

    
562
      elif not response[self._EVENT_KEY]:
563
        return response
564

    
565

    
566
class KVMHypervisor(hv_base.BaseHypervisor):
567
  """KVM hypervisor interface
568

569
  """
570
  CAN_MIGRATE = True
571

    
572
  _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
573
  _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
574
  _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
575
  _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
576
  _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
577
  _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
578
  _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
579
  # KVM instances with chroot enabled are started in empty chroot directories.
580
  _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
581
  # After an instance is stopped, its chroot directory is removed.
582
  # If the chroot directory is not empty, it can't be removed.
583
  # A non-empty chroot directory indicates a possible security incident.
584
  # To support forensics, the non-empty chroot directory is quarantined in
585
  # a separate directory, called 'chroot-quarantine'.
586
  _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
587
  _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
588
           _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
589

    
590
  PARAMETERS = {
591
    constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
592
    constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
593
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
594
    constants.HV_ROOT_PATH: hv_base.NO_CHECK,
595
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
596
    constants.HV_ACPI: hv_base.NO_CHECK,
597
    constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
598
    constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
599
    constants.HV_VNC_BIND_ADDRESS:
600
      (False, lambda x: (netutils.IP4Address.IsValid(x) or
601
                         utils.IsNormAbsPath(x)),
602
       "The VNC bind address must be either a valid IP address or an absolute"
603
       " pathname", None, None),
604
    constants.HV_VNC_TLS: hv_base.NO_CHECK,
605
    constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
606
    constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
607
    constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
608
    constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
609
    constants.HV_KVM_SPICE_IP_VERSION:
610
      (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
611
                         x in constants.VALID_IP_VERSIONS),
612
       "The SPICE IP version should be 4 or 6",
613
       None, None),
614
    constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
615
    constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
616
      hv_base.ParamInSet(
617
        False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
618
    constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
619
      hv_base.ParamInSet(
620
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
621
    constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
622
      hv_base.ParamInSet(
623
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
624
    constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
625
      hv_base.ParamInSet(
626
        False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
627
    constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
628
    constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
629
    constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
630
    constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
631
    constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
632
    constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
633
    constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
634
    constants.HV_BOOT_ORDER:
635
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
636
    constants.HV_NIC_TYPE:
637
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
638
    constants.HV_DISK_TYPE:
639
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
640
    constants.HV_KVM_CDROM_DISK_TYPE:
641
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
642
    constants.HV_USB_MOUSE:
643
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
644
    constants.HV_KEYMAP: hv_base.NO_CHECK,
645
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
646
    constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
647
    constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
648
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
649
    constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
650
    constants.HV_DISK_CACHE:
651
      hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
652
    constants.HV_SECURITY_MODEL:
653
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
654
    constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
655
    constants.HV_KVM_FLAG:
656
      hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
657
    constants.HV_VHOST_NET: hv_base.NO_CHECK,
658
    constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
659
    constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
660
    constants.HV_REBOOT_BEHAVIOR:
661
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
662
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
663
    constants.HV_CPU_TYPE: hv_base.NO_CHECK,
664
    constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
665
    constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
666
    constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
667
    constants.HV_SOUNDHW: hv_base.NO_CHECK,
668
    constants.HV_USB_DEVICES: hv_base.NO_CHECK,
669
    constants.HV_VGA: hv_base.NO_CHECK,
670
    constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
671
    constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
672
    constants.HV_VNET_HDR: hv_base.NO_CHECK,
673
    }
674

    
675
  _VIRTIO = "virtio"
676
  _VIRTIO_NET_PCI = "virtio-net-pci"
677
  _VIRTIO_BLK_PCI = "virtio-blk-pci"
678

    
679
  _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
680
                                    re.M | re.I)
681
  _MIGRATION_PROGRESS_RE = \
682
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
683
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
684
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
685

    
686
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
687
  _MIGRATION_INFO_RETRY_DELAY = 2
688

    
689
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
690

    
691
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
692
  _CPU_INFO_CMD = "info cpus"
693
  _CONT_CMD = "cont"
694

    
695
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
696
  _CHECK_MACHINE_VERSION_RE = \
697
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
698

    
699
  _QMP_RE = re.compile(r"^-qmp\s", re.M)
700
  _SPICE_RE = re.compile(r"^-spice\s", re.M)
701
  _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
702
  _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
703
  _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
704
  _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
705
  _DISPLAY_RE = re.compile(r"^-display\s", re.M)
706
  _MACHINE_RE = re.compile(r"^-machine\s", re.M)
707
  _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
708
  _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M)
709
  # match  -drive.*boot=on|off on different lines, but in between accept only
710
  # dashes not preceeded by a new line (which would mean another option
711
  # different than -drive is starting)
712
  _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
713

    
714
  _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
715
  _INFO_PCI_CMD = "info pci"
716
  _INFO_VERSION_RE = \
717
    re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
718
  _INFO_VERSION_CMD = "info version"
719

    
720
  _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
721

    
722
  ANCILLARY_FILES = [
723
    _KVM_NETWORK_SCRIPT,
724
    ]
725
  ANCILLARY_FILES_OPT = [
726
    _KVM_NETWORK_SCRIPT,
727
    ]
728

    
729
  # Supported kvm options to get output from
730
  _KVMOPT_HELP = "help"
731
  _KVMOPT_MLIST = "mlist"
732
  _KVMOPT_DEVICELIST = "devicelist"
733

    
734
  # Command to execute to get the output from kvm, and whether to
735
  # accept the output even on failure.
736
  _KVMOPTS_CMDS = {
737
    _KVMOPT_HELP: (["--help"], False),
738
    _KVMOPT_MLIST: (["-M", "?"], False),
739
    _KVMOPT_DEVICELIST: (["-device", "?"], True),
740
  }
741

    
742
  def __init__(self):
743
    hv_base.BaseHypervisor.__init__(self)
744
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
745
    # in a tmpfs filesystem or has been otherwise wiped out.
746
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
747
    utils.EnsureDirs(dirs)
748

    
749
  @classmethod
750
  def _InstancePidFile(cls, instance_name):
751
    """Returns the instance pidfile.
752

753
    """
754
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
755

    
756
  @classmethod
757
  def _InstanceUidFile(cls, instance_name):
758
    """Returns the instance uidfile.
759

760
    """
761
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
762

    
763
  @classmethod
764
  def _InstancePidInfo(cls, pid):
765
    """Check pid file for instance information.
766

767
    Check that a pid file is associated with an instance, and retrieve
768
    information from its command line.
769

770
    @type pid: string or int
771
    @param pid: process id of the instance to check
772
    @rtype: tuple
773
    @return: (instance_name, memory, vcpus)
774
    @raise errors.HypervisorError: when an instance cannot be found
775

776
    """
777
    alive = utils.IsProcessAlive(pid)
778
    if not alive:
779
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
780

    
781
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
782
    try:
783
      cmdline = utils.ReadFile(cmdline_file)
784
    except EnvironmentError, err:
785
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
786
                                   (pid, err))
787

    
788
    instance = None
789
    memory = 0
790
    vcpus = 0
791

    
792
    arg_list = cmdline.split("\x00")
793
    while arg_list:
794
      arg = arg_list.pop(0)
795
      if arg == "-name":
796
        instance = arg_list.pop(0)
797
      elif arg == "-m":
798
        memory = int(arg_list.pop(0))
799
      elif arg == "-smp":
800
        vcpus = int(arg_list.pop(0).split(",")[0])
801

    
802
    if instance is None:
803
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
804
                                   " instance" % pid)
805

    
806
    return (instance, memory, vcpus)
807

    
808
  def _InstancePidAlive(self, instance_name):
809
    """Returns the instance pidfile, pid, and liveness.
810

811
    @type instance_name: string
812
    @param instance_name: instance name
813
    @rtype: tuple
814
    @return: (pid file name, pid, liveness)
815

816
    """
817
    pidfile = self._InstancePidFile(instance_name)
818
    pid = utils.ReadPidFile(pidfile)
819

    
820
    alive = False
821
    try:
822
      cmd_instance = self._InstancePidInfo(pid)[0]
823
      alive = (cmd_instance == instance_name)
824
    except errors.HypervisorError:
825
      pass
826

    
827
    return (pidfile, pid, alive)
828

    
829
  def _CheckDown(self, instance_name):
830
    """Raises an error unless the given instance is down.
831

832
    """
833
    alive = self._InstancePidAlive(instance_name)[2]
834
    if alive:
835
      raise errors.HypervisorError("Failed to start instance %s: %s" %
836
                                   (instance_name, "already running"))
837

    
838
  @classmethod
839
  def _InstanceMonitor(cls, instance_name):
840
    """Returns the instance monitor socket name
841

842
    """
843
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
844

    
845
  @classmethod
846
  def _InstanceSerial(cls, instance_name):
847
    """Returns the instance serial socket name
848

849
    """
850
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
851

    
852
  @classmethod
853
  def _InstanceQmpMonitor(cls, instance_name):
854
    """Returns the instance serial QMP socket name
855

856
    """
857
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
858

    
859
  @staticmethod
860
  def _SocatUnixConsoleParams():
861
    """Returns the correct parameters for socat
862

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

865
    """
866
    if constants.SOCAT_USE_ESCAPE:
867
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
868
    else:
869
      return "echo=0,icanon=0"
870

    
871
  @classmethod
872
  def _InstanceKVMRuntime(cls, instance_name):
873
    """Returns the instance KVM runtime filename
874

875
    """
876
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
877

    
878
  @classmethod
879
  def _InstanceChrootDir(cls, instance_name):
880
    """Returns the name of the KVM chroot dir of the instance
881

882
    """
883
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
884

    
885
  @classmethod
886
  def _InstanceNICDir(cls, instance_name):
887
    """Returns the name of the directory holding the tap device files for a
888
    given instance.
889

890
    """
891
    return utils.PathJoin(cls._NICS_DIR, instance_name)
892

    
893
  @classmethod
894
  def _InstanceNICFile(cls, instance_name, seq):
895
    """Returns the name of the file containing the tap device for a given NIC
896

897
    """
898
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
899

    
900
  @classmethod
901
  def _InstanceKeymapFile(cls, instance_name):
902
    """Returns the name of the file containing the keymap for a given instance
903

904
    """
905
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
906

    
907
  @classmethod
908
  def _TryReadUidFile(cls, uid_file):
909
    """Try to read a uid file
910

911
    """
912
    if os.path.exists(uid_file):
913
      try:
914
        uid = int(utils.ReadOneLineFile(uid_file))
915
        return uid
916
      except EnvironmentError:
917
        logging.warning("Can't read uid file", exc_info=True)
918
      except (TypeError, ValueError):
919
        logging.warning("Can't parse uid file contents", exc_info=True)
920
    return None
921

    
922
  @classmethod
923
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
924
    """Removes an instance's rutime sockets/files/dirs.
925

926
    """
927
    utils.RemoveFile(pidfile)
928
    utils.RemoveFile(cls._InstanceMonitor(instance_name))
929
    utils.RemoveFile(cls._InstanceSerial(instance_name))
930
    utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
931
    utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
932
    utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
933
    uid_file = cls._InstanceUidFile(instance_name)
934
    uid = cls._TryReadUidFile(uid_file)
935
    utils.RemoveFile(uid_file)
936
    if uid is not None:
937
      uidpool.ReleaseUid(uid)
938
    try:
939
      shutil.rmtree(cls._InstanceNICDir(instance_name))
940
    except OSError, err:
941
      if err.errno != errno.ENOENT:
942
        raise
943
    try:
944
      chroot_dir = cls._InstanceChrootDir(instance_name)
945
      utils.RemoveDir(chroot_dir)
946
    except OSError, err:
947
      if err.errno == errno.ENOTEMPTY:
948
        # The chroot directory is expected to be empty, but it isn't.
949
        new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
950
                                          prefix="%s-%s-" %
951
                                          (instance_name,
952
                                           utils.TimestampForFilename()))
953
        logging.warning("The chroot directory of instance %s can not be"
954
                        " removed as it is not empty. Moving it to the"
955
                        " quarantine instead. Please investigate the"
956
                        " contents (%s) and clean up manually",
957
                        instance_name, new_chroot_dir)
958
        utils.RenameFile(chroot_dir, new_chroot_dir)
959
      else:
960
        raise
961

    
962
  @staticmethod
963
  def _ConfigureNIC(instance, seq, nic, tap):
964
    """Run the network configuration script for a specified NIC
965

966
    @param instance: instance we're acting on
967
    @type instance: instance object
968
    @param seq: nic sequence number
969
    @type seq: int
970
    @param nic: nic we're acting on
971
    @type nic: nic object
972
    @param tap: the host's tap interface this NIC corresponds to
973
    @type tap: str
974

975
    """
976
    env = {
977
      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
978
      "INSTANCE": instance.name,
979
      "MAC": nic.mac,
980
      "MODE": nic.nicparams[constants.NIC_MODE],
981
      "INTERFACE": tap,
982
      "INTERFACE_INDEX": str(seq),
983
      "TAGS": " ".join(instance.GetTags()),
984
    }
985
    if nic.uuid:
986
      env["INTERFACE_UUID"] = nic.uuid
987

    
988
    if nic.ip:
989
      env["IP"] = nic.ip
990

    
991
    if nic.name:
992
      env["INTERFACE_NAME"] = nic.name
993

    
994
    if nic.nicparams[constants.NIC_LINK]:
995
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
996

    
997
    if nic.network:
998
      n = objects.Network.FromDict(nic.netinfo)
999
      env.update(n.HooksDict())
1000

    
1001
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1002
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
1003

    
1004
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
1005
    if result.failed:
1006
      raise errors.HypervisorError("Failed to configure interface %s: %s;"
1007
                                   " network configuration script output: %s" %
1008
                                   (tap, result.fail_reason, result.output))
1009

    
1010
  @staticmethod
1011
  def _VerifyAffinityPackage():
1012
    if affinity is None:
1013
      raise errors.HypervisorError("affinity Python package not"
1014
                                   " found; cannot use CPU pinning under KVM")
1015

    
1016
  @staticmethod
1017
  def _BuildAffinityCpuMask(cpu_list):
1018
    """Create a CPU mask suitable for sched_setaffinity from a list of
1019
    CPUs.
1020

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

1024
    @type cpu_list: list of int
1025
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
1026
    @rtype: int
1027
    @return: a bit mask of CPU affinities
1028

1029
    """
1030
    if cpu_list == constants.CPU_PINNING_OFF:
1031
      return constants.CPU_PINNING_ALL_KVM
1032
    else:
1033
      return sum(2 ** cpu for cpu in cpu_list)
1034

    
1035
  @classmethod
1036
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
1037
    """Change CPU affinity for running VM according to given CPU mask.
1038

1039
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
1040
    @type cpu_mask: string
1041
    @param process_id: process ID of KVM process. Used to pin entire VM
1042
                       to physical CPUs.
1043
    @type process_id: int
1044
    @param thread_dict: map of virtual CPUs to KVM thread IDs
1045
    @type thread_dict: dict int:int
1046

1047
    """
1048
    # Convert the string CPU mask to a list of list of int's
1049
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
1050

    
1051
    if len(cpu_list) == 1:
1052
      all_cpu_mapping = cpu_list[0]
1053
      if all_cpu_mapping == constants.CPU_PINNING_OFF:
1054
        # If CPU pinning has 1 entry that's "all", then do nothing
1055
        pass
1056
      else:
1057
        # If CPU pinning has one non-all entry, map the entire VM to
1058
        # one set of physical CPUs
1059
        cls._VerifyAffinityPackage()
1060
        affinity.set_process_affinity_mask(
1061
          process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
1062
    else:
1063
      # The number of vCPUs mapped should match the number of vCPUs
1064
      # reported by KVM. This was already verified earlier, so
1065
      # here only as a sanity check.
1066
      assert len(thread_dict) == len(cpu_list)
1067
      cls._VerifyAffinityPackage()
1068

    
1069
      # For each vCPU, map it to the proper list of physical CPUs
1070
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1071
        affinity.set_process_affinity_mask(thread_dict[i],
1072
                                           cls._BuildAffinityCpuMask(vcpu))
1073

    
1074
  def _GetVcpuThreadIds(self, instance_name):
1075
    """Get a mapping of vCPU no. to thread IDs for the instance
1076

1077
    @type instance_name: string
1078
    @param instance_name: instance in question
1079
    @rtype: dictionary of int:int
1080
    @return: a dictionary mapping vCPU numbers to thread IDs
1081

1082
    """
1083
    result = {}
1084
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1085
    for line in output.stdout.splitlines():
1086
      match = self._CPU_INFO_RE.search(line)
1087
      if not match:
1088
        continue
1089
      grp = map(int, match.groups())
1090
      result[grp[0]] = grp[1]
1091

    
1092
    return result
1093

    
1094
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1095
    """Complete CPU pinning.
1096

1097
    @type instance_name: string
1098
    @param instance_name: name of instance
1099
    @type cpu_mask: string
1100
    @param cpu_mask: CPU pinning mask as entered by user
1101

1102
    """
1103
    # Get KVM process ID, to be used if need to pin entire VM
1104
    _, pid, _ = self._InstancePidAlive(instance_name)
1105
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1106
    thread_dict = self._GetVcpuThreadIds(instance_name)
1107
    # Run CPU pinning, based on configured mask
1108
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1109

    
1110
  def ListInstances(self):
1111
    """Get the list of running instances.
1112

1113
    We can do this by listing our live instances directory and
1114
    checking whether the associated kvm process is still alive.
1115

1116
    """
1117
    result = []
1118
    for name in os.listdir(self._PIDS_DIR):
1119
      if self._InstancePidAlive(name)[2]:
1120
        result.append(name)
1121
    return result
1122

    
1123
  def GetInstanceInfo(self, instance_name):
1124
    """Get instance properties.
1125

1126
    @type instance_name: string
1127
    @param instance_name: the instance name
1128
    @rtype: tuple of strings
1129
    @return: (name, id, memory, vcpus, stat, times)
1130

1131
    """
1132
    _, pid, alive = self._InstancePidAlive(instance_name)
1133
    if not alive:
1134
      return None
1135

    
1136
    _, memory, vcpus = self._InstancePidInfo(pid)
1137
    istat = "---b-"
1138
    times = "0"
1139

    
1140
    try:
1141
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1142
      qmp.connect()
1143
      vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1144
      # Will fail if ballooning is not enabled, but we can then just resort to
1145
      # the value above.
1146
      mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1147
      memory = mem_bytes / 1048576
1148
    except errors.HypervisorError:
1149
      pass
1150

    
1151
    return (instance_name, pid, memory, vcpus, istat, times)
1152

    
1153
  def GetAllInstancesInfo(self):
1154
    """Get properties of all instances.
1155

1156
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1157

1158
    """
1159
    data = []
1160
    for name in os.listdir(self._PIDS_DIR):
1161
      try:
1162
        info = self.GetInstanceInfo(name)
1163
      except errors.HypervisorError:
1164
        # Ignore exceptions due to instances being shut down
1165
        continue
1166
      if info:
1167
        data.append(info)
1168
    return data
1169

    
1170
  def _GenerateKVMBlockDevicesOptions(self, instance, block_devices,
1171
                                      kvmhelp, devlist):
1172
    """Generate KVM options regarding instance's block devices.
1173

1174
    @type instance: L{objects.Instance}
1175
    @param instance: the instance object
1176
    @type block_devices: list of tuples
1177
    @param block_devices: list of tuples [(disk, link_name)..]
1178
    @type kvmhelp: string
1179
    @param kvmhelp: output of kvm --help
1180
    @type devlist: string
1181
    @param devlist: output of kvm -device ?
1182
    @rtype: list
1183
    @return: list of command line options eventually used by kvm executable
1184

1185
    """
1186
    hvp = instance.hvparams
1187
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1188
    if kernel_path:
1189
      boot_disk = False
1190
    else:
1191
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1192

    
1193
    # whether this is an older KVM version that uses the boot=on flag
1194
    # on devices
1195
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1196

    
1197
    dev_opts = []
1198
    device_driver = None
1199
    disk_type = hvp[constants.HV_DISK_TYPE]
1200
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
1201
      if_val = ",if=%s" % self._VIRTIO
1202
      try:
1203
        if self._VIRTIO_BLK_RE.search(devlist):
1204
          if_val = ",if=none"
1205
          # will be passed in -device option as driver
1206
          device_driver = self._VIRTIO_BLK_PCI
1207
      except errors.HypervisorError, _:
1208
        pass
1209
    else:
1210
      if_val = ",if=%s" % disk_type
1211
    # Cache mode
1212
    disk_cache = hvp[constants.HV_DISK_CACHE]
1213
    if instance.disk_template in constants.DTS_EXT_MIRROR:
1214
      if disk_cache != "none":
1215
        # TODO: make this a hard error, instead of a silent overwrite
1216
        logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1217
                        " to prevent shared storage corruption on migration",
1218
                        disk_cache)
1219
      cache_val = ",cache=none"
1220
    elif disk_cache != constants.HT_CACHE_DEFAULT:
1221
      cache_val = ",cache=%s" % disk_cache
1222
    else:
1223
      cache_val = ""
1224
    for idx, (cfdev, dev_path) in enumerate(block_devices):
1225
      if cfdev.mode != constants.DISK_RDWR:
1226
        raise errors.HypervisorError("Instance has read-only disks which"
1227
                                     " are not supported by KVM")
1228
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
1229
      boot_val = ""
1230
      if boot_disk:
1231
        dev_opts.extend(["-boot", "c"])
1232
        boot_disk = False
1233
        if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1234
          boot_val = ",boot=on"
1235
      drive_val = "file=%s,format=raw%s%s%s" % \
1236
                  (dev_path, if_val, boot_val, cache_val)
1237

    
1238
      if device_driver:
1239
        # block_devices are the 4th entry of runtime file that did not exist in
1240
        # the past. That means that cfdev should always have pci slot and
1241
        # _GenerateDeviceKVMId() will not raise a exception.
1242
        kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_DISK,
1243
                                         cfdev, idx)
1244
        drive_val += (",id=%s" % kvm_devid)
1245
        if cfdev.pci:
1246
          drive_val += (",bus=0,unit=%d" % cfdev.pci)
1247
        dev_val = ("%s,drive=%s,id=%s" %
1248
                   (device_driver, kvm_devid, kvm_devid))
1249
        if cfdev.pci:
1250
          dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci)
1251
        dev_opts.extend(["-device", dev_val])
1252

    
1253
      # TODO: export disk geometry in IDISK_PARAMS
1254
      heads = cfdev.params.get('heads', None)
1255
      secs = cfdev.params.get('secs', None)
1256
      if heads and secs:
1257
        nr_sectors = cfdev.size * 1024 * 1024 / 512
1258
        cyls = nr_sectors / (int(heads) * int(secs))
1259
        if cyls and heads and secs:
1260
          drive_val += (",cyls=%d,heads=%d,secs=%d" %
1261
                        (cyls, int(heads), int(secs)))
1262

    
1263
      dev_opts.extend(["-drive", drive_val])
1264

    
1265
    return dev_opts
1266

    
1267
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1268
                          kvmhelp):
1269
    """Generate KVM information to start an instance.
1270

1271
    @type kvmhelp: string
1272
    @param kvmhelp: output of kvm --help
1273
    @attention: this function must not have any side-effects; for
1274
        example, it must not write to the filesystem, or read values
1275
        from the current system the are expected to differ between
1276
        nodes, since it is only run once at instance startup;
1277
        actions/kvm arguments that can vary between systems should be
1278
        done in L{_ExecuteKVMRuntime}
1279

1280
    """
1281
    # pylint: disable=R0912,R0914,R0915
1282
    hvp = instance.hvparams
1283
    self.ValidateParameters(hvp)
1284

    
1285
    pidfile = self._InstancePidFile(instance.name)
1286
    kvm = hvp[constants.HV_KVM_PATH]
1287
    kvm_cmd = [kvm]
1288
    # used just by the vnc server, if enabled
1289
    kvm_cmd.extend(["-name", instance.name])
1290
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1291

    
1292
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1293
    if hvp[constants.HV_CPU_CORES]:
1294
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1295
    if hvp[constants.HV_CPU_THREADS]:
1296
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1297
    if hvp[constants.HV_CPU_SOCKETS]:
1298
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1299

    
1300
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1301

    
1302
    kvm_cmd.extend(["-pidfile", pidfile])
1303
    kvm_cmd.extend(["-balloon", "virtio"])
1304
    kvm_cmd.extend(["-daemonize"])
1305
    if not instance.hvparams[constants.HV_ACPI]:
1306
      kvm_cmd.extend(["-no-acpi"])
1307
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1308
        constants.INSTANCE_REBOOT_EXIT:
1309
      kvm_cmd.extend(["-no-reboot"])
1310

    
1311
    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1312
    if not mversion:
1313
      mversion = self._GetDefaultMachineVersion(kvm)
1314
    if self._MACHINE_RE.search(kvmhelp):
1315
      # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1316
      # extra hypervisor parameters. We should also investigate whether and how
1317
      # shadow_mem should be considered for the resource model.
1318
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1319
        specprop = ",accel=kvm"
1320
      else:
1321
        specprop = ""
1322
      machinespec = "%s%s" % (mversion, specprop)
1323
      kvm_cmd.extend(["-machine", machinespec])
1324
    else:
1325
      kvm_cmd.extend(["-M", mversion])
1326
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1327
          self._ENABLE_KVM_RE.search(kvmhelp)):
1328
        kvm_cmd.extend(["-enable-kvm"])
1329
      elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1330
            self._DISABLE_KVM_RE.search(kvmhelp)):
1331
        kvm_cmd.extend(["-disable-kvm"])
1332

    
1333
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1334
    if kernel_path:
1335
      boot_cdrom = boot_floppy = boot_network = False
1336
    else:
1337
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1338
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1339
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1340

    
1341
    if startup_paused:
1342
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1343

    
1344
    if boot_network:
1345
      kvm_cmd.extend(["-boot", "n"])
1346

    
1347
    # whether this is an older KVM version that uses the boot=on flag
1348
    # on devices
1349
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1350

    
1351
    disk_type = hvp[constants.HV_DISK_TYPE]
1352

    
1353
    #Now we can specify a different device type for CDROM devices.
1354
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1355
    if not cdrom_disk_type:
1356
      cdrom_disk_type = disk_type
1357

    
1358
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1359
    if iso_image:
1360
      options = ",format=raw,media=cdrom"
1361
      # set cdrom 'if' type
1362
      if boot_cdrom:
1363
        actual_cdrom_type = constants.HT_DISK_IDE
1364
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1365
        actual_cdrom_type = "virtio"
1366
      else:
1367
        actual_cdrom_type = cdrom_disk_type
1368
      if_val = ",if=%s" % actual_cdrom_type
1369
      # set boot flag, if needed
1370
      boot_val = ""
1371
      if boot_cdrom:
1372
        kvm_cmd.extend(["-boot", "d"])
1373
        if needs_boot_flag:
1374
          boot_val = ",boot=on"
1375
      # and finally build the entire '-drive' value
1376
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1377
      kvm_cmd.extend(["-drive", drive_val])
1378

    
1379
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1380
    if iso_image2:
1381
      options = ",format=raw,media=cdrom"
1382
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1383
        if_val = ",if=virtio"
1384
      else:
1385
        if_val = ",if=%s" % cdrom_disk_type
1386
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1387
      kvm_cmd.extend(["-drive", drive_val])
1388

    
1389
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1390
    if floppy_image:
1391
      options = ",format=raw,media=disk"
1392
      if boot_floppy:
1393
        kvm_cmd.extend(["-boot", "a"])
1394
        options = "%s,boot=on" % options
1395
      if_val = ",if=floppy"
1396
      options = "%s%s" % (options, if_val)
1397
      drive_val = "file=%s%s" % (floppy_image, options)
1398
      kvm_cmd.extend(["-drive", drive_val])
1399

    
1400
    if kernel_path:
1401
      kvm_cmd.extend(["-kernel", kernel_path])
1402
      initrd_path = hvp[constants.HV_INITRD_PATH]
1403
      if initrd_path:
1404
        kvm_cmd.extend(["-initrd", initrd_path])
1405
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1406
                     hvp[constants.HV_KERNEL_ARGS]]
1407
      if hvp[constants.HV_SERIAL_CONSOLE]:
1408
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1409
        root_append.append("console=ttyS0,%s" % serial_speed)
1410
      kvm_cmd.extend(["-append", " ".join(root_append)])
1411

    
1412
    mem_path = hvp[constants.HV_MEM_PATH]
1413
    if mem_path:
1414
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1415

    
1416
    monitor_dev = ("unix:%s,server,nowait" %
1417
                   self._InstanceMonitor(instance.name))
1418
    kvm_cmd.extend(["-monitor", monitor_dev])
1419
    if hvp[constants.HV_SERIAL_CONSOLE]:
1420
      serial_dev = ("unix:%s,server,nowait" %
1421
                    self._InstanceSerial(instance.name))
1422
      kvm_cmd.extend(["-serial", serial_dev])
1423
    else:
1424
      kvm_cmd.extend(["-serial", "none"])
1425

    
1426
    mouse_type = hvp[constants.HV_USB_MOUSE]
1427
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1428
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1429
    spice_ip_version = None
1430

    
1431
    kvm_cmd.extend(["-usb"])
1432

    
1433
    if mouse_type:
1434
      kvm_cmd.extend(["-usbdevice", mouse_type])
1435
    elif vnc_bind_address:
1436
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1437

    
1438
    if vnc_bind_address:
1439
      if netutils.IP4Address.IsValid(vnc_bind_address):
1440
        if instance.network_port > constants.VNC_BASE_PORT:
1441
          display = instance.network_port - constants.VNC_BASE_PORT
1442
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1443
            vnc_arg = ":%d" % (display)
1444
          else:
1445
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1446
        else:
1447
          logging.error("Network port is not a valid VNC display (%d < %d),"
1448
                        " not starting VNC",
1449
                        instance.network_port, constants.VNC_BASE_PORT)
1450
          vnc_arg = "none"
1451

    
1452
        # Only allow tls and other option when not binding to a file, for now.
1453
        # kvm/qemu gets confused otherwise about the filename to use.
1454
        vnc_append = ""
1455
        if hvp[constants.HV_VNC_TLS]:
1456
          vnc_append = "%s,tls" % vnc_append
1457
          if hvp[constants.HV_VNC_X509_VERIFY]:
1458
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1459
                                               hvp[constants.HV_VNC_X509])
1460
          elif hvp[constants.HV_VNC_X509]:
1461
            vnc_append = "%s,x509=%s" % (vnc_append,
1462
                                         hvp[constants.HV_VNC_X509])
1463
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1464
          vnc_append = "%s,password" % vnc_append
1465

    
1466
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1467

    
1468
      else:
1469
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1470

    
1471
      kvm_cmd.extend(["-vnc", vnc_arg])
1472
    elif spice_bind:
1473
      # FIXME: this is wrong here; the iface ip address differs
1474
      # between systems, so it should be done in _ExecuteKVMRuntime
1475
      if netutils.IsValidInterface(spice_bind):
1476
        # The user specified a network interface, we have to figure out the IP
1477
        # address.
1478
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1479
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1480

    
1481
        # if the user specified an IP version and the interface does not
1482
        # have that kind of IP addresses, throw an exception
1483
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1484
          if not addresses[spice_ip_version]:
1485
            raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1486
                                         " for %s" % (spice_ip_version,
1487
                                                      spice_bind))
1488

    
1489
        # the user did not specify an IP version, we have to figure it out
1490
        elif (addresses[constants.IP4_VERSION] and
1491
              addresses[constants.IP6_VERSION]):
1492
          # we have both ipv4 and ipv6, let's use the cluster default IP
1493
          # version
1494
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1495
          spice_ip_version = \
1496
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1497
        elif addresses[constants.IP4_VERSION]:
1498
          spice_ip_version = constants.IP4_VERSION
1499
        elif addresses[constants.IP6_VERSION]:
1500
          spice_ip_version = constants.IP6_VERSION
1501
        else:
1502
          raise errors.HypervisorError("SPICE: Unable to get an IP address"
1503
                                       " for %s" % (spice_bind))
1504

    
1505
        spice_address = addresses[spice_ip_version][0]
1506

    
1507
      else:
1508
        # spice_bind is known to be a valid IP address, because
1509
        # ValidateParameters checked it.
1510
        spice_address = spice_bind
1511

    
1512
      spice_arg = "addr=%s" % spice_address
1513
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1514
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1515
                     (spice_arg, instance.network_port,
1516
                      pathutils.SPICE_CACERT_FILE))
1517
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1518
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1519
                      pathutils.SPICE_CERT_FILE))
1520
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1521
        if tls_ciphers:
1522
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1523
      else:
1524
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1525

    
1526
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1527
        spice_arg = "%s,disable-ticketing" % spice_arg
1528

    
1529
      if spice_ip_version:
1530
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1531

    
1532
      # Image compression options
1533
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1534
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1535
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1536
      if img_lossless:
1537
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1538
      if img_jpeg:
1539
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1540
      if img_zlib_glz:
1541
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1542

    
1543
      # Video stream detection
1544
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1545
      if video_streaming:
1546
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1547

    
1548
      # Audio compression, by default in qemu-kvm it is on
1549
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1550
        spice_arg = "%s,playback-compression=off" % spice_arg
1551
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1552
        spice_arg = "%s,agent-mouse=off" % spice_arg
1553
      else:
1554
        # Enable the spice agent communication channel between the host and the
1555
        # agent.
1556
        kvm_cmd.extend(["-device", "virtio-serial-pci"])
1557
        kvm_cmd.extend([
1558
          "-device",
1559
          "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1560
          ])
1561
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1562

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

    
1566
    else:
1567
      # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1568
      # also works in earlier versions though (tested with 1.1 and 1.3)
1569
      if self._DISPLAY_RE.search(kvmhelp):
1570
        kvm_cmd.extend(["-display", "none"])
1571
      else:
1572
        kvm_cmd.extend(["-nographic"])
1573

    
1574
    if hvp[constants.HV_USE_LOCALTIME]:
1575
      kvm_cmd.extend(["-localtime"])
1576

    
1577
    if hvp[constants.HV_KVM_USE_CHROOT]:
1578
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1579

    
1580
    # Add qemu-KVM -cpu param
1581
    if hvp[constants.HV_CPU_TYPE]:
1582
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1583

    
1584
    # As requested by music lovers
1585
    if hvp[constants.HV_SOUNDHW]:
1586
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1587

    
1588
    # Pass a -vga option if requested, or if spice is used, for backwards
1589
    # compatibility.
1590
    if hvp[constants.HV_VGA]:
1591
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1592
    elif spice_bind:
1593
      kvm_cmd.extend(["-vga", "qxl"])
1594

    
1595
    # Various types of usb devices, comma separated
1596
    if hvp[constants.HV_USB_DEVICES]:
1597
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1598
        kvm_cmd.extend(["-usbdevice", dev])
1599

    
1600
    if hvp[constants.HV_KVM_EXTRA]:
1601
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1602

    
1603
    pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1604
    kvm_disks = []
1605
    for disk, dev_path in block_devices:
1606
      _UpdatePCISlots(disk, pci_reservations)
1607
      kvm_disks.append((disk, dev_path))
1608

    
1609
    kvm_nics = []
1610
    for nic in instance.nics:
1611
      _UpdatePCISlots(nic, pci_reservations)
1612
      kvm_nics.append(nic)
1613

    
1614
    hvparams = hvp
1615

    
1616
    return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1617

    
1618
  def _WriteKVMRuntime(self, instance_name, data):
1619
    """Write an instance's KVM runtime
1620

1621
    """
1622
    try:
1623
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1624
                      data=data)
1625
    except EnvironmentError, err:
1626
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1627

    
1628
  def _ReadKVMRuntime(self, instance_name):
1629
    """Read an instance's KVM runtime
1630

1631
    """
1632
    try:
1633
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1634
    except EnvironmentError, err:
1635
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1636
    return file_content
1637

    
1638
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1639
    """Save an instance's KVM runtime
1640

1641
    """
1642
    kvm_cmd, kvm_nics, hvparams, block_devices = kvm_runtime
1643

    
1644
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1645
    serialized_blockdevs = [(blk.ToDict(), link) for blk, link in block_devices]
1646
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1647
                                      serialized_blockdevs))
1648

    
1649
    self._WriteKVMRuntime(instance.name, serialized_form)
1650

    
1651
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1652
    """Load an instance's KVM runtime
1653

1654
    """
1655
    if not serialized_runtime:
1656
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1657

    
1658
    loaded_runtime = serializer.Load(serialized_runtime)
1659
    if len(loaded_runtime) == 3:
1660
      serialized_blockdevs = []
1661
      kvm_cmd, serialized_nics, hvparams = loaded_runtime
1662
    else:
1663
      kvm_cmd, serialized_nics, hvparams, serialized_blockdevs = loaded_runtime
1664

    
1665
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1666
    block_devices = [(objects.Disk.FromDict(sdisk), link)
1667
                     for sdisk, link in serialized_blockdevs]
1668

    
1669
    # Upgrade kvm_nics and block_devices with missing uuid slot
1670
    # This adds a dummy uuid that will be overriden after reboot
1671
    # These uuids will be writen to runtime files only if
1672
    # a hotplug action takes place.
1673
    for n in kvm_nics:
1674
      if not n.uuid:
1675
        n.uuid = utils.NewUUID()
1676

    
1677
    for d, p in block_devices:
1678
      if not d.uuid:
1679
        d.uuid = utils.NewUUID()
1680

    
1681
    return (kvm_cmd, kvm_nics, hvparams, block_devices)
1682

    
1683
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1684
    """Run the KVM cmd and check for errors
1685

1686
    @type name: string
1687
    @param name: instance name
1688
    @type kvm_cmd: list of strings
1689
    @param kvm_cmd: runcmd input for kvm
1690
    @type tap_fds: list of int
1691
    @param tap_fds: fds of tap devices opened by Ganeti
1692

1693
    """
1694
    try:
1695
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1696
    finally:
1697
      for fd in tap_fds:
1698
        utils_wrapper.CloseFdNoError(fd)
1699

    
1700
    if result.failed:
1701
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1702
                                   (name, result.fail_reason, result.output))
1703
    if not self._InstancePidAlive(name)[2]:
1704
      raise errors.HypervisorError("Failed to start instance %s" % name)
1705

    
1706
  # 52/50 local variables
1707
  # pylint: disable=R0914
1708
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1709
    """Execute a KVM cmd, after completing it with some last minute data.
1710

1711
    @type incoming: tuple of strings
1712
    @param incoming: (target_host_ip, port)
1713
    @type kvmhelp: string
1714
    @param kvmhelp: output of kvm --help
1715

1716
    """
1717
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1718
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1719
    #    have changed since the instance started; only use them if the change
1720
    #    won't affect the inside of the instance (which hasn't been rebooted).
1721
    #  - up_hvp contains the parameters as they were when the instance was
1722
    #    started, plus any new parameter which has been added between ganeti
1723
    #    versions: it is paramount that those default to a value which won't
1724
    #    affect the inside of the instance as well.
1725
    conf_hvp = instance.hvparams
1726
    name = instance.name
1727
    self._CheckDown(name)
1728

    
1729
    temp_files = []
1730

    
1731
    kvm_cmd, kvm_nics, up_hvp, block_devices = kvm_runtime
1732
    # the first element of kvm_cmd is always the path to the kvm binary
1733
    kvm_path = kvm_cmd[0]
1734
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1735

    
1736
    # We know it's safe to run as a different user upon migration, so we'll use
1737
    # the latest conf, from conf_hvp.
1738
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1739
    if security_model == constants.HT_SM_USER:
1740
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1741

    
1742
    keymap = conf_hvp[constants.HV_KEYMAP]
1743
    if keymap:
1744
      keymap_path = self._InstanceKeymapFile(name)
1745
      # If a keymap file is specified, KVM won't use its internal defaults. By
1746
      # first including the "en-us" layout, an error on loading the actual
1747
      # layout (e.g. because it can't be found) won't lead to a non-functional
1748
      # keyboard. A keyboard with incorrect keys is still better than none.
1749
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1750
      kvm_cmd.extend(["-k", keymap_path])
1751

    
1752
    # We have reasons to believe changing something like the nic driver/type
1753
    # upon migration won't exactly fly with the instance kernel, so for nic
1754
    # related parameters we'll use up_hvp
1755
    tapfds = []
1756
    taps = []
1757
    devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1758

    
1759
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1760
                                                     block_devices,
1761
                                                     kvmhelp,
1762
                                                     devlist)
1763
    kvm_cmd.extend(bdev_opts)
1764

    
1765
    if not kvm_nics:
1766
      kvm_cmd.extend(["-net", "none"])
1767
    else:
1768
      vnet_hdr = False
1769
      tap_extra = ""
1770
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1771
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1772
        nic_model = self._VIRTIO
1773
        try:
1774
          if self._VIRTIO_NET_RE.search(devlist):
1775
            nic_model = self._VIRTIO_NET_PCI
1776
            vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1777
        except errors.HypervisorError, _:
1778
          # Older versions of kvm don't support DEVICE_LIST, but they don't
1779
          # have new virtio syntax either.
1780
          pass
1781

    
1782
        if up_hvp[constants.HV_VHOST_NET]:
1783
          # check for vhost_net support
1784
          if self._VHOST_RE.search(kvmhelp):
1785
            tap_extra = ",vhost=on"
1786
          else:
1787
            raise errors.HypervisorError("vhost_net is configured"
1788
                                         " but it is not available")
1789
      else:
1790
        nic_model = nic_type
1791

    
1792
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1793

    
1794
      for nic_seq, nic in enumerate(kvm_nics):
1795
        tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1796
        tapfds.append(tapfd)
1797
        taps.append(tapname)
1798
        if kvm_supports_netdev:
1799
          nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1800
          try:
1801
            # kvm_nics already exist in old runtime files and thus there might
1802
            # be some entries without pci slot (therefore try: except:)
1803
            kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1804
            netdev = kvm_devid
1805
            nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1806
          except errors.HotplugError:
1807
            netdev = "netdev%d" % nic_seq
1808
          nic_val += (",netdev=%s" % netdev)
1809
          tap_val = ("type=tap,id=%s,fd=%d%s" %
1810
                     (netdev, tapfd, tap_extra))
1811
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1812
        else:
1813
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1814
                                                         nic.mac, nic_model)
1815
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1816
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1817

    
1818
    if incoming:
1819
      target, port = incoming
1820
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1821

    
1822
    # Changing the vnc password doesn't bother the guest that much. At most it
1823
    # will surprise people who connect to it. Whether positively or negatively
1824
    # it's debatable.
1825
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1826
    vnc_pwd = None
1827
    if vnc_pwd_file:
1828
      try:
1829
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1830
      except EnvironmentError, err:
1831
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1832
                                     % (vnc_pwd_file, err))
1833

    
1834
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1835
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1836
                         constants.SECURE_DIR_MODE)])
1837

    
1838
    # Automatically enable QMP if version is >= 0.14
1839
    if self._QMP_RE.search(kvmhelp):
1840
      logging.debug("Enabling QMP")
1841
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1842
                      self._InstanceQmpMonitor(instance.name)])
1843

    
1844
    # Configure the network now for starting instances and bridged interfaces,
1845
    # during FinalizeMigration for incoming instances' routed interfaces
1846
    for nic_seq, nic in enumerate(kvm_nics):
1847
      if (incoming and
1848
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1849
        continue
1850
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1851

    
1852
    # CPU affinity requires kvm to start paused, so we set this flag if the
1853
    # instance is not already paused and if we are not going to accept a
1854
    # migrating instance. In the latter case, pausing is not needed.
1855
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1856
    if start_kvm_paused:
1857
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1858

    
1859
    # Note: CPU pinning is using up_hvp since changes take effect
1860
    # during instance startup anyway, and to avoid problems when soft
1861
    # rebooting the instance.
1862
    cpu_pinning = False
1863
    if up_hvp.get(constants.HV_CPU_MASK, None):
1864
      cpu_pinning = True
1865

    
1866
    if security_model == constants.HT_SM_POOL:
1867
      ss = ssconf.SimpleStore()
1868
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1869
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1870
      uid = uidpool.RequestUnusedUid(all_uids)
1871
      try:
1872
        username = pwd.getpwuid(uid.GetUid()).pw_name
1873
        kvm_cmd.extend(["-runas", username])
1874
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1875
      except:
1876
        uidpool.ReleaseUid(uid)
1877
        raise
1878
      else:
1879
        uid.Unlock()
1880
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1881
    else:
1882
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1883

    
1884
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1885
                     constants.RUN_DIRS_MODE)])
1886
    for nic_seq, tap in enumerate(taps):
1887
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1888
                      data=tap)
1889

    
1890
    if vnc_pwd:
1891
      change_cmd = "change vnc password %s" % vnc_pwd
1892
      self._CallMonitorCommand(instance.name, change_cmd)
1893

    
1894
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1895
    # connection attempts because SPICE by default does not allow connections
1896
    # if neither a password nor the "disable_ticketing" options are specified.
1897
    # As soon as we send the password via QMP, that password is a valid ticket
1898
    # for connection.
1899
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1900
    if spice_password_file:
1901
      spice_pwd = ""
1902
      try:
1903
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1904
      except EnvironmentError, err:
1905
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1906
                                     % (spice_password_file, err))
1907

    
1908
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1909
      qmp.connect()
1910
      arguments = {
1911
          "protocol": "spice",
1912
          "password": spice_pwd,
1913
      }
1914
      qmp.Execute("set_password", arguments)
1915

    
1916
    for filename in temp_files:
1917
      utils.RemoveFile(filename)
1918

    
1919
    # If requested, set CPU affinity and resume instance execution
1920
    if cpu_pinning:
1921
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1922

    
1923
    start_memory = self._InstanceStartupMemory(instance)
1924
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1925
      self.BalloonInstanceMemory(instance, start_memory)
1926

    
1927
    if start_kvm_paused:
1928
      # To control CPU pinning, ballooning, and vnc/spice passwords
1929
      # the VM was started in a frozen state. If freezing was not
1930
      # explicitly requested resume the vm status.
1931
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1932

    
1933
  def StartInstance(self, instance, block_devices, startup_paused):
1934
    """Start an instance.
1935

1936
    """
1937
    self._CheckDown(instance.name)
1938
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1939
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1940
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1941
                                           startup_paused, kvmhelp)
1942
    self._SaveKVMRuntime(instance, kvm_runtime)
1943
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1944

    
1945
  def _CallMonitorCommand(self, instance_name, command):
1946
    """Invoke a command on the instance monitor.
1947

1948
    """
1949
    # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1950
    # version. The monitor protocol is designed for human consumption, whereas
1951
    # QMP is made for programmatic usage. In the worst case QMP can also
1952
    # execute monitor commands. As it is, all calls to socat take at least
1953
    # 500ms and likely more: socat can't detect the end of the reply and waits
1954
    # for 500ms of no data received before exiting (500 ms is the default for
1955
    # the "-t" parameter).
1956
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1957
             (utils.ShellQuote(command),
1958
              constants.SOCAT_PATH,
1959
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1960
    result = utils.RunCmd(socat)
1961
    if result.failed:
1962
      msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1963
             " output: %s" %
1964
             (command, instance_name, result.fail_reason, result.output))
1965
      raise errors.HypervisorError(msg)
1966

    
1967
    return result
1968

    
1969
  def _GetFreePCISlot(self, instance, dev):
1970
    """Get the first available pci slot of a runnung instance.
1971

1972
    """
1973
    slots = bitarray(32)
1974
    slots.setall(False) # pylint: disable=E1101
1975
    output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
1976
    for line in output.stdout.splitlines():
1977
      match = self._INFO_PCI_RE.search(line)
1978
      if match:
1979
        slot = int(match.group(1))
1980
        slots[slot] = True
1981

    
1982
    [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
1983
    if not free:
1984
      raise errors.HypervisorError("All PCI slots occupied")
1985

    
1986
    dev.pci = int(free)
1987

    
1988
  def VerifyHotplugSupport(self, instance, action, dev_type):
1989
    """Check if hotplug is supported.
1990

1991
    Hotplug is *not* supported in case of:
1992
     - security models and chroot (disk hotplug)
1993
     - fdsend module is missing (nic hot-add)
1994

1995
    @raise errors.HypervisorError: in previous cases
1996

1997
    """
1998
    if dev_type == constants.HOTPLUG_TARGET_DISK:
1999
      hvp = instance.hvparams
2000
      security_model = hvp[constants.HV_SECURITY_MODEL]
2001
      use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
2002
      if use_chroot:
2003
        raise errors.HotplugError("Disk hotplug is not supported"
2004
                                  " in case of chroot.")
2005
      if security_model != constants.HT_SM_NONE:
2006
        raise errors.HotplugError("Disk Hotplug is not supported in case"
2007
                                  " security models are used.")
2008

    
2009
    if (dev_type == constants.HOTPLUG_TARGET_NIC and
2010
        action == constants.HOTPLUG_ACTION_ADD and not fdsend):
2011
      raise errors.HotplugError("Cannot hot-add NIC."
2012
                                " fdsend python module is missing.")
2013
    return True
2014

    
2015
  def HotplugSupported(self, instance):
2016
    """Checks if hotplug is generally supported.
2017

2018
    Hotplug is *not* supported in case of:
2019
     - qemu versions < 1.0
2020
     - for stopped instances
2021

2022
    @raise errors.HypervisorError: in one of the previous cases
2023

2024
    """
2025
    try:
2026
      output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2027
    except errors.HypervisorError:
2028
      raise errors.HotplugError("Instance is probably down")
2029

    
2030
    # TODO: search for netdev_add, drive_add, device_add.....
2031
    match = self._INFO_VERSION_RE.search(output.stdout)
2032
    if not match:
2033
      raise errors.HotplugError("Cannot parse qemu version via monitor")
2034

    
2035
    v_major, v_min, _, _ = match.groups()
2036
    if (int(v_major), int(v_min)) < (1, 0):
2037
      raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2038

    
2039
  def _CallHotplugCommand(self, name, cmd):
2040
    output = self._CallMonitorCommand(name, cmd)
2041
    # TODO: parse output and check if succeeded
2042
    for line in output.stdout.splitlines():
2043
      logging.info("%s", line)
2044

    
2045
  def HotAddDevice(self, instance, dev_type, device, extra, seq):
2046
    """ Helper method to hot-add a new device
2047

2048
    It gets free pci slot generates the device name and invokes the
2049
    device specific method.
2050

2051
    """
2052
    # in case of hot-mod this is given
2053
    if device.pci is None:
2054
      self._GetFreePCISlot(instance, device)
2055
    kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2056
    runtime = self._LoadKVMRuntime(instance)
2057
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2058
      command = "drive_add dummy file=%s,if=none,id=%s,format=raw\n" % \
2059
                 (extra, kvm_devid)
2060
      command += ("device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
2061
                  (hex(device.pci), kvm_devid, kvm_devid))
2062
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
2063
      (tap, fd) = _OpenTap()
2064
      self._ConfigureNIC(instance, seq, device, tap)
2065
      self._PassTapFd(instance, fd, device)
2066
      command = "netdev_add tap,id=%s,fd=%s\n" % (kvm_devid, kvm_devid)
2067
      args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
2068
               (hex(device.pci), device.mac, kvm_devid, kvm_devid)
2069
      command += "device_add %s" % args
2070
      utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
2071

    
2072
    self._CallHotplugCommand(instance.name, command)
2073
    # update relevant entries in runtime file
2074
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2075
    entry = _RUNTIME_ENTRY[dev_type](device, extra)
2076
    runtime[index].append(entry)
2077
    self._SaveKVMRuntime(instance, runtime)
2078

    
2079
  def HotDelDevice(self, instance, dev_type, device, _, seq):
2080
    """ Helper method for hot-del device
2081

2082
    It gets device info from runtime file, generates the device name and
2083
    invokes the device specific method.
2084

2085
    """
2086
    runtime = self._LoadKVMRuntime(instance)
2087
    entry = _GetExistingDeviceInfo(dev_type, device, runtime)
2088
    kvm_device = _RUNTIME_DEVICE[dev_type](entry)
2089
    kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
2090
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2091
      command = "device_del %s\n" % kvm_devid
2092
      command += "drive_del %s" % kvm_devid
2093
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
2094
      command = "device_del %s\n" % kvm_devid
2095
      command += "netdev_del %s" % kvm_devid
2096
      utils.RemoveFile(self._InstanceNICFile(instance.name, seq))
2097
    self._CallHotplugCommand(instance.name, command)
2098
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2099
    runtime[index].remove(entry)
2100
    self._SaveKVMRuntime(instance, runtime)
2101

    
2102
    return kvm_device.pci
2103

    
2104
  def HotModDevice(self, instance, dev_type, device, _, seq):
2105
    """ Helper method for hot-mod device
2106

2107
    It gets device info from runtime file, generates the device name and
2108
    invokes the device specific method. Currently only NICs support hot-mod
2109

2110
    """
2111
    if dev_type == constants.HOTPLUG_TARGET_NIC:
2112
      # putting it back in the same pci slot
2113
      device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2114
      # TODO: remove sleep when socat gets removed
2115
      time.sleep(2)
2116
      self.HotAddDevice(instance, dev_type, device, _, seq)
2117

    
2118
  def _PassTapFd(self, instance, fd, nic):
2119
    """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2120

2121
    """
2122
    # TODO: factor out code related to unix sockets.
2123
    #       squash common parts between monitor and qmp
2124
    kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2125
    command = "getfd %s\n" % kvm_devid
2126
    fds = [fd]
2127
    logging.info("%s", fds)
2128
    try:
2129
      monsock = MonitorSocket(self._InstanceMonitor(instance.name))
2130
      monsock.connect()
2131
      fdsend.sendfds(monsock.sock, command, fds=fds)
2132
    finally:
2133
      monsock.close()
2134

    
2135
  @classmethod
2136
  def _ParseKVMVersion(cls, text):
2137
    """Parse the KVM version from the --help output.
2138

2139
    @type text: string
2140
    @param text: output of kvm --help
2141
    @return: (version, v_maj, v_min, v_rev)
2142
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2143

2144
    """
2145
    match = cls._VERSION_RE.search(text.splitlines()[0])
2146
    if not match:
2147
      raise errors.HypervisorError("Unable to get KVM version")
2148

    
2149
    v_all = match.group(0)
2150
    v_maj = int(match.group(1))
2151
    v_min = int(match.group(2))
2152
    if match.group(4):
2153
      v_rev = int(match.group(4))
2154
    else:
2155
      v_rev = 0
2156
    return (v_all, v_maj, v_min, v_rev)
2157

    
2158
  @classmethod
2159
  def _GetKVMOutput(cls, kvm_path, option):
2160
    """Return the output of a kvm invocation
2161

2162
    @type kvm_path: string
2163
    @param kvm_path: path to the kvm executable
2164
    @type option: a key of _KVMOPTS_CMDS
2165
    @param option: kvm option to fetch the output from
2166
    @return: output a supported kvm invocation
2167
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2168

2169
    """
2170
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2171

    
2172
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
2173

    
2174
    result = utils.RunCmd([kvm_path] + optlist)
2175
    if result.failed and not can_fail:
2176
      raise errors.HypervisorError("Unable to get KVM %s output" %
2177
                                    " ".join(cls._KVMOPTS_CMDS[option]))
2178
    return result.output
2179

    
2180
  @classmethod
2181
  def _GetKVMVersion(cls, kvm_path):
2182
    """Return the installed KVM version.
2183

2184
    @return: (version, v_maj, v_min, v_rev)
2185
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2186

2187
    """
2188
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2189

    
2190
  @classmethod
2191
  def _GetDefaultMachineVersion(cls, kvm_path):
2192
    """Return the default hardware revision (e.g. pc-1.1)
2193

2194
    """
2195
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2196
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2197
    if match:
2198
      return match.group(1)
2199
    else:
2200
      return "pc"
2201

    
2202
  def StopInstance(self, instance, force=False, retry=False, name=None):
2203
    """Stop an instance.
2204

2205
    """
2206
    if name is not None and not force:
2207
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2208
    if name is None:
2209
      name = instance.name
2210
      acpi = instance.hvparams[constants.HV_ACPI]
2211
    else:
2212
      acpi = False
2213
    _, pid, alive = self._InstancePidAlive(name)
2214
    if pid > 0 and alive:
2215
      if force or not acpi:
2216
        utils.KillProcess(pid)
2217
      else:
2218
        self._CallMonitorCommand(name, "system_powerdown")
2219

    
2220
  def CleanupInstance(self, instance_name):
2221
    """Cleanup after a stopped instance
2222

2223
    """
2224
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
2225
    if pid > 0 and alive:
2226
      raise errors.HypervisorError("Cannot cleanup a live instance")
2227
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2228

    
2229
  def RebootInstance(self, instance):
2230
    """Reboot an instance.
2231

2232
    """
2233
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2234
    # socket the instance will stop, but now power up again. So we'll resort
2235
    # to shutdown and restart.
2236
    _, _, alive = self._InstancePidAlive(instance.name)
2237
    if not alive:
2238
      raise errors.HypervisorError("Failed to reboot instance %s:"
2239
                                   " not running" % instance.name)
2240
    # StopInstance will delete the saved KVM runtime so:
2241
    # ...first load it...
2242
    kvm_runtime = self._LoadKVMRuntime(instance)
2243
    # ...now we can safely call StopInstance...
2244
    if not self.StopInstance(instance):
2245
      self.StopInstance(instance, force=True)
2246
    # ...and finally we can save it again, and execute it...
2247
    self._SaveKVMRuntime(instance, kvm_runtime)
2248
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2249
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2250
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2251

    
2252
  def MigrationInfo(self, instance):
2253
    """Get instance information to perform a migration.
2254

2255
    @type instance: L{objects.Instance}
2256
    @param instance: instance to be migrated
2257
    @rtype: string
2258
    @return: content of the KVM runtime file
2259

2260
    """
2261
    return self._ReadKVMRuntime(instance.name)
2262

    
2263
  def AcceptInstance(self, instance, info, target):
2264
    """Prepare to accept an instance.
2265

2266
    @type instance: L{objects.Instance}
2267
    @param instance: instance to be accepted
2268
    @type info: string
2269
    @param info: content of the KVM runtime file on the source node
2270
    @type target: string
2271
    @param target: target host (usually ip), on this node
2272

2273
    """
2274
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2275
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2276
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2277
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2278
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2279
                            incoming=incoming_address)
2280

    
2281
  def FinalizeMigrationDst(self, instance, info, success):
2282
    """Finalize the instance migration on the target node.
2283

2284
    Stop the incoming mode KVM.
2285

2286
    @type instance: L{objects.Instance}
2287
    @param instance: instance whose migration is being finalized
2288

2289
    """
2290
    if success:
2291
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2292
      kvm_nics = kvm_runtime[1]
2293

    
2294
      for nic_seq, nic in enumerate(kvm_nics):
2295
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2296
          # Bridged interfaces have already been configured
2297
          continue
2298
        try:
2299
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2300
        except EnvironmentError, err:
2301
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
2302
                          instance.name, nic_seq, str(err))
2303
          continue
2304
        try:
2305
          self._ConfigureNIC(instance, nic_seq, nic, tap)
2306
        except errors.HypervisorError, err:
2307
          logging.warning(str(err))
2308

    
2309
      self._WriteKVMRuntime(instance.name, info)
2310
    else:
2311
      self.StopInstance(instance, force=True)
2312

    
2313
  def MigrateInstance(self, instance, target, live):
2314
    """Migrate an instance to a target node.
2315

2316
    The migration will not be attempted if the instance is not
2317
    currently running.
2318

2319
    @type instance: L{objects.Instance}
2320
    @param instance: the instance to be migrated
2321
    @type target: string
2322
    @param target: ip address of the target node
2323
    @type live: boolean
2324
    @param live: perform a live migration
2325

2326
    """
2327
    instance_name = instance.name
2328
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
2329
    _, _, alive = self._InstancePidAlive(instance_name)
2330
    if not alive:
2331
      raise errors.HypervisorError("Instance not running, cannot migrate")
2332

    
2333
    if not live:
2334
      self._CallMonitorCommand(instance_name, "stop")
2335

    
2336
    migrate_command = ("migrate_set_speed %dm" %
2337
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2338
    self._CallMonitorCommand(instance_name, migrate_command)
2339

    
2340
    migrate_command = ("migrate_set_downtime %dms" %
2341
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2342
    self._CallMonitorCommand(instance_name, migrate_command)
2343

    
2344
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2345
    self._CallMonitorCommand(instance_name, migrate_command)
2346

    
2347
  def FinalizeMigrationSource(self, instance, success, live):
2348
    """Finalize the instance migration on the source node.
2349

2350
    @type instance: L{objects.Instance}
2351
    @param instance: the instance that was migrated
2352
    @type success: bool
2353
    @param success: whether the migration succeeded or not
2354
    @type live: bool
2355
    @param live: whether the user requested a live migration or not
2356

2357
    """
2358
    if success:
2359
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2360
      utils.KillProcess(pid)
2361
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2362
    elif live:
2363
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2364

    
2365
  def GetMigrationStatus(self, instance):
2366
    """Get the migration status
2367

2368
    @type instance: L{objects.Instance}
2369
    @param instance: the instance that is being migrated
2370
    @rtype: L{objects.MigrationStatus}
2371
    @return: the status of the current migration (one of
2372
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2373
             progress info that can be retrieved from the hypervisor
2374

2375
    """
2376
    info_command = "info migrate"
2377
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2378
      result = self._CallMonitorCommand(instance.name, info_command)
2379
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
2380
      if not match:
2381
        if not result.stdout:
2382
          logging.info("KVM: empty 'info migrate' result")
2383
        else:
2384
          logging.warning("KVM: unknown 'info migrate' result: %s",
2385
                          result.stdout)
2386
      else:
2387
        status = match.group(1)
2388
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2389
          migration_status = objects.MigrationStatus(status=status)
2390
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2391
          if match:
2392
            migration_status.transferred_ram = match.group("transferred")
2393
            migration_status.total_ram = match.group("total")
2394

    
2395
          return migration_status
2396

    
2397
        logging.warning("KVM: unknown migration status '%s'", status)
2398

    
2399
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2400

    
2401
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2402

    
2403
  def BalloonInstanceMemory(self, instance, mem):
2404
    """Balloon an instance memory to a certain value.
2405

2406
    @type instance: L{objects.Instance}
2407
    @param instance: instance to be accepted
2408
    @type mem: int
2409
    @param mem: actual memory size to use for instance runtime
2410

2411
    """
2412
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2413

    
2414
  def GetNodeInfo(self):
2415
    """Return information about the node.
2416

2417
    @return: a dict with the following keys (values in MiB):
2418
          - memory_total: the total memory size on the node
2419
          - memory_free: the available memory on the node for instances
2420
          - memory_dom0: the memory used by the node itself, if available
2421
          - hv_version: the hypervisor version in the form (major, minor,
2422
                        revision)
2423

2424
    """
2425
    result = self.GetLinuxNodeInfo()
2426
    # FIXME: this is the global kvm version, but the actual version can be
2427
    # customized as an hv parameter. we should use the nodegroup's default kvm
2428
    # path parameter here.
2429
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2430
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2431
    return result
2432

    
2433
  @classmethod
2434
  def GetInstanceConsole(cls, instance, hvparams, beparams):
2435
    """Return a command for connecting to the console of an instance.
2436

2437
    """
2438
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2439
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2440
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2441
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2442
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2443
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2444
      return objects.InstanceConsole(instance=instance.name,
2445
                                     kind=constants.CONS_SSH,
2446
                                     host=instance.primary_node,
2447
                                     user=constants.SSH_CONSOLE_USER,
2448
                                     command=cmd)
2449

    
2450
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2451
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2452
      display = instance.network_port - constants.VNC_BASE_PORT
2453
      return objects.InstanceConsole(instance=instance.name,
2454
                                     kind=constants.CONS_VNC,
2455
                                     host=vnc_bind_address,
2456
                                     port=instance.network_port,
2457
                                     display=display)
2458

    
2459
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2460
    if spice_bind:
2461
      return objects.InstanceConsole(instance=instance.name,
2462
                                     kind=constants.CONS_SPICE,
2463
                                     host=spice_bind,
2464
                                     port=instance.network_port)
2465

    
2466
    return objects.InstanceConsole(instance=instance.name,
2467
                                   kind=constants.CONS_MESSAGE,
2468
                                   message=("No serial shell for instance %s" %
2469
                                            instance.name))
2470

    
2471
  def Verify(self):
2472
    """Verify the hypervisor.
2473

2474
    Check that the required binaries exist.
2475

2476
    @return: Problem description if something is wrong, C{None} otherwise
2477

2478
    """
2479
    msgs = []
2480
    # FIXME: this is the global kvm binary, but the actual path can be
2481
    # customized as an hv parameter; we should use the nodegroup's
2482
    # default kvm path parameter here.
2483
    if not os.path.exists(constants.KVM_PATH):
2484
      msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2485
    if not os.path.exists(constants.SOCAT_PATH):
2486
      msgs.append("The socat binary ('%s') does not exist" %
2487
                  constants.SOCAT_PATH)
2488

    
2489
    return self._FormatVerifyResults(msgs)
2490

    
2491
  @classmethod
2492
  def CheckParameterSyntax(cls, hvparams):
2493
    """Check the given parameters for validity.
2494

2495
    @type hvparams:  dict
2496
    @param hvparams: dictionary with parameter names/value
2497
    @raise errors.HypervisorError: when a parameter is not valid
2498

2499
    """
2500
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2501

    
2502
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2503
    if kernel_path:
2504
      if not hvparams[constants.HV_ROOT_PATH]:
2505
        raise errors.HypervisorError("Need a root partition for the instance,"
2506
                                     " if a kernel is defined")
2507

    
2508
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2509
        not hvparams[constants.HV_VNC_X509]):
2510
      raise errors.HypervisorError("%s must be defined, if %s is" %
2511
                                   (constants.HV_VNC_X509,
2512
                                    constants.HV_VNC_X509_VERIFY))
2513

    
2514
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2515
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2516
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2517
      if not serial_speed or serial_speed not in valid_speeds:
2518
        raise errors.HypervisorError("Invalid serial console speed, must be"
2519
                                     " one of: %s" %
2520
                                     utils.CommaJoin(valid_speeds))
2521

    
2522
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2523
    if (boot_order == constants.HT_BO_CDROM and
2524
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2525
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2526
                                   " ISO path")
2527

    
2528
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2529
    if security_model == constants.HT_SM_USER:
2530
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2531
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2532
                                     " must be specified")
2533
    elif (security_model == constants.HT_SM_NONE or
2534
          security_model == constants.HT_SM_POOL):
2535
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2536
        raise errors.HypervisorError("Cannot have a security domain when the"
2537
                                     " security model is 'none' or 'pool'")
2538

    
2539
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2540
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2541
    if spice_bind:
2542
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2543
        # if an IP version is specified, the spice_bind parameter must be an
2544
        # IP of that family
2545
        if (netutils.IP4Address.IsValid(spice_bind) and
2546
            spice_ip_version != constants.IP4_VERSION):
2547
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2548
                                       " the specified IP version is %s" %
2549
                                       (spice_bind, spice_ip_version))
2550

    
2551
        if (netutils.IP6Address.IsValid(spice_bind) and
2552
            spice_ip_version != constants.IP6_VERSION):
2553
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2554
                                       " the specified IP version is %s" %
2555
                                       (spice_bind, spice_ip_version))
2556
    else:
2557
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2558
      # error if any of them is set without it.
2559
      for param in _SPICE_ADDITIONAL_PARAMS:
2560
        if hvparams[param]:
2561
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2562
                                       (param, constants.HV_KVM_SPICE_BIND))
2563

    
2564
  @classmethod
2565
  def ValidateParameters(cls, hvparams):
2566
    """Check the given parameters for validity.
2567

2568
    @type hvparams:  dict
2569
    @param hvparams: dictionary with parameter names/value
2570
    @raise errors.HypervisorError: when a parameter is not valid
2571

2572
    """
2573
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2574

    
2575
    kvm_path = hvparams[constants.HV_KVM_PATH]
2576

    
2577
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2578
    if security_model == constants.HT_SM_USER:
2579
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2580
      try:
2581
        pwd.getpwnam(username)
2582
      except KeyError:
2583
        raise errors.HypervisorError("Unknown security domain user %s"
2584
                                     % username)
2585

    
2586
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2587
    if spice_bind:
2588
      # only one of VNC and SPICE can be used currently.
2589
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2590
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2591
                                     " only one of them can be used at a"
2592
                                     " given time")
2593

    
2594
      # check that KVM supports SPICE
2595
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2596
      if not cls._SPICE_RE.search(kvmhelp):
2597
        raise errors.HypervisorError("SPICE is configured, but it is not"
2598
                                     " supported according to 'kvm --help'")
2599

    
2600
      # if spice_bind is not an IP address, it must be a valid interface
2601
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2602
                       netutils.IP6Address.IsValid(spice_bind))
2603
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2604
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2605
                                     " a valid IP address or interface name" %
2606
                                     constants.HV_KVM_SPICE_BIND)
2607

    
2608
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2609
    if machine_version:
2610
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2611
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2612
        raise errors.HypervisorError("Unsupported machine version: %s" %
2613
                                     machine_version)
2614

    
2615
  @classmethod
2616
  def PowercycleNode(cls):
2617
    """KVM powercycle, just a wrapper over Linux powercycle.
2618

2619
    """
2620
    cls.LinuxPowercycle()