Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 061a6a1d

History | View | Annotate | Download (95.8 kB)

1
#
2
#
3

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

    
21

    
22
"""KVM hypervisor
23

24
"""
25

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

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

    
62

    
63
_KVM_NETWORK_SCRIPT = pathutils.CONF_DIR + "/kvm-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

    
1236
      # For ext we allow overriding disk_cache hypervisor params per disk
1237
      disk_cache = cfdev.params.get("cache", None)
1238
      if disk_cache:
1239
        cache_val = ",cache=%s" % disk_cache
1240
      drive_val = "file=%s,format=raw%s%s%s" % \
1241
                  (dev_path, if_val, boot_val, cache_val)
1242

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

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

    
1268
      dev_opts.extend(["-drive", drive_val])
1269

    
1270
    return dev_opts
1271

    
1272
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1273
                          kvmhelp):
1274
    """Generate KVM information to start an instance.
1275

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

1285
    """
1286
    # pylint: disable=R0912,R0914,R0915
1287
    hvp = instance.hvparams
1288
    self.ValidateParameters(hvp)
1289

    
1290
    pidfile = self._InstancePidFile(instance.name)
1291
    kvm = hvp[constants.HV_KVM_PATH]
1292
    kvm_cmd = [kvm]
1293
    # used just by the vnc server, if enabled
1294
    kvm_cmd.extend(["-name", instance.name])
1295
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1296

    
1297
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1298
    if hvp[constants.HV_CPU_CORES]:
1299
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1300
    if hvp[constants.HV_CPU_THREADS]:
1301
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1302
    if hvp[constants.HV_CPU_SOCKETS]:
1303
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1304

    
1305
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1306

    
1307
    kvm_cmd.extend(["-pidfile", pidfile])
1308
    kvm_cmd.extend(["-balloon", "virtio"])
1309
    kvm_cmd.extend(["-daemonize"])
1310
    if not instance.hvparams[constants.HV_ACPI]:
1311
      kvm_cmd.extend(["-no-acpi"])
1312
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1313
        constants.INSTANCE_REBOOT_EXIT:
1314
      kvm_cmd.extend(["-no-reboot"])
1315

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

    
1338
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1339
    if kernel_path:
1340
      boot_cdrom = boot_floppy = boot_network = False
1341
    else:
1342
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1343
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1344
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1345

    
1346
    if startup_paused:
1347
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1348

    
1349
    if boot_network:
1350
      kvm_cmd.extend(["-boot", "n"])
1351

    
1352
    # whether this is an older KVM version that uses the boot=on flag
1353
    # on devices
1354
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1355

    
1356
    disk_type = hvp[constants.HV_DISK_TYPE]
1357

    
1358
    #Now we can specify a different device type for CDROM devices.
1359
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1360
    if not cdrom_disk_type:
1361
      cdrom_disk_type = disk_type
1362

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

    
1384
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1385
    if iso_image2:
1386
      options = ",format=raw,media=cdrom"
1387
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1388
        if_val = ",if=virtio"
1389
      else:
1390
        if_val = ",if=%s" % cdrom_disk_type
1391
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1392
      kvm_cmd.extend(["-drive", drive_val])
1393

    
1394
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1395
    if floppy_image:
1396
      options = ",format=raw,media=disk"
1397
      if boot_floppy:
1398
        kvm_cmd.extend(["-boot", "a"])
1399
        options = "%s,boot=on" % options
1400
      if_val = ",if=floppy"
1401
      options = "%s%s" % (options, if_val)
1402
      drive_val = "file=%s%s" % (floppy_image, options)
1403
      kvm_cmd.extend(["-drive", drive_val])
1404

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

    
1417
    mem_path = hvp[constants.HV_MEM_PATH]
1418
    if mem_path:
1419
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1420

    
1421
    monitor_dev = ("unix:%s,server,nowait" %
1422
                   self._InstanceMonitor(instance.name))
1423
    kvm_cmd.extend(["-monitor", monitor_dev])
1424
    if hvp[constants.HV_SERIAL_CONSOLE]:
1425
      serial_dev = ("unix:%s,server,nowait" %
1426
                    self._InstanceSerial(instance.name))
1427
      kvm_cmd.extend(["-serial", serial_dev])
1428
    else:
1429
      kvm_cmd.extend(["-serial", "none"])
1430

    
1431
    mouse_type = hvp[constants.HV_USB_MOUSE]
1432
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1433
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1434
    spice_ip_version = None
1435

    
1436
    kvm_cmd.extend(["-usb"])
1437

    
1438
    if mouse_type:
1439
      kvm_cmd.extend(["-usbdevice", mouse_type])
1440
    elif vnc_bind_address:
1441
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1442

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

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

    
1471
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1472

    
1473
      else:
1474
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1475

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

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

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

    
1510
        spice_address = addresses[spice_ip_version][0]
1511

    
1512
      else:
1513
        # spice_bind is known to be a valid IP address, because
1514
        # ValidateParameters checked it.
1515
        spice_address = spice_bind
1516

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

    
1531
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1532
        spice_arg = "%s,disable-ticketing" % spice_arg
1533

    
1534
      if spice_ip_version:
1535
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1536

    
1537
      # Image compression options
1538
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1539
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1540
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1541
      if img_lossless:
1542
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1543
      if img_jpeg:
1544
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1545
      if img_zlib_glz:
1546
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1547

    
1548
      # Video stream detection
1549
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1550
      if video_streaming:
1551
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1552

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

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

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

    
1579
    if hvp[constants.HV_USE_LOCALTIME]:
1580
      kvm_cmd.extend(["-localtime"])
1581

    
1582
    if hvp[constants.HV_KVM_USE_CHROOT]:
1583
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1584

    
1585
    # Add qemu-KVM -cpu param
1586
    if hvp[constants.HV_CPU_TYPE]:
1587
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1588

    
1589
    # As requested by music lovers
1590
    if hvp[constants.HV_SOUNDHW]:
1591
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1592

    
1593
    # Pass a -vga option if requested, or if spice is used, for backwards
1594
    # compatibility.
1595
    if hvp[constants.HV_VGA]:
1596
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1597
    elif spice_bind:
1598
      kvm_cmd.extend(["-vga", "qxl"])
1599

    
1600
    # Various types of usb devices, comma separated
1601
    if hvp[constants.HV_USB_DEVICES]:
1602
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1603
        kvm_cmd.extend(["-usbdevice", dev])
1604

    
1605
    if hvp[constants.HV_KVM_EXTRA]:
1606
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1607

    
1608
    pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1609
    kvm_disks = []
1610
    for disk, dev_path in block_devices:
1611
      _UpdatePCISlots(disk, pci_reservations)
1612
      kvm_disks.append((disk, dev_path))
1613

    
1614
    kvm_nics = []
1615
    for nic in instance.nics:
1616
      _UpdatePCISlots(nic, pci_reservations)
1617
      kvm_nics.append(nic)
1618

    
1619
    hvparams = hvp
1620

    
1621
    return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1622

    
1623
  def _WriteKVMRuntime(self, instance_name, data):
1624
    """Write an instance's KVM runtime
1625

1626
    """
1627
    try:
1628
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1629
                      data=data)
1630
    except EnvironmentError, err:
1631
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1632

    
1633
  def _ReadKVMRuntime(self, instance_name):
1634
    """Read an instance's KVM runtime
1635

1636
    """
1637
    try:
1638
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1639
    except EnvironmentError, err:
1640
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1641
    return file_content
1642

    
1643
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1644
    """Save an instance's KVM runtime
1645

1646
    """
1647
    kvm_cmd, kvm_nics, hvparams, block_devices = kvm_runtime
1648

    
1649
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1650
    serialized_blockdevs = [(blk.ToDict(), link) for blk, link in block_devices]
1651
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1652
                                      serialized_blockdevs))
1653

    
1654
    self._WriteKVMRuntime(instance.name, serialized_form)
1655

    
1656
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1657
    """Load an instance's KVM runtime
1658

1659
    """
1660
    if not serialized_runtime:
1661
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1662

    
1663
    loaded_runtime = serializer.Load(serialized_runtime)
1664
    if len(loaded_runtime) == 3:
1665
      serialized_blockdevs = []
1666
      kvm_cmd, serialized_nics, hvparams = loaded_runtime
1667
    else:
1668
      kvm_cmd, serialized_nics, hvparams, serialized_blockdevs = loaded_runtime
1669

    
1670
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1671
    block_devices = [(objects.Disk.FromDict(sdisk), link)
1672
                     for sdisk, link in serialized_blockdevs]
1673

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

    
1682
    for d, p in block_devices:
1683
      if not d.uuid:
1684
        d.uuid = utils.NewUUID()
1685

    
1686
    return (kvm_cmd, kvm_nics, hvparams, block_devices)
1687

    
1688
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1689
    """Run the KVM cmd and check for errors
1690

1691
    @type name: string
1692
    @param name: instance name
1693
    @type kvm_cmd: list of strings
1694
    @param kvm_cmd: runcmd input for kvm
1695
    @type tap_fds: list of int
1696
    @param tap_fds: fds of tap devices opened by Ganeti
1697

1698
    """
1699
    try:
1700
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1701
    finally:
1702
      for fd in tap_fds:
1703
        utils_wrapper.CloseFdNoError(fd)
1704

    
1705
    if result.failed:
1706
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1707
                                   (name, result.fail_reason, result.output))
1708
    if not self._InstancePidAlive(name)[2]:
1709
      raise errors.HypervisorError("Failed to start instance %s" % name)
1710

    
1711
  # 52/50 local variables
1712
  # pylint: disable=R0914
1713
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1714
    """Execute a KVM cmd, after completing it with some last minute data.
1715

1716
    @type incoming: tuple of strings
1717
    @param incoming: (target_host_ip, port)
1718
    @type kvmhelp: string
1719
    @param kvmhelp: output of kvm --help
1720

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

    
1734
    temp_files = []
1735

    
1736
    kvm_cmd, kvm_nics, up_hvp, block_devices = kvm_runtime
1737
    # the first element of kvm_cmd is always the path to the kvm binary
1738
    kvm_path = kvm_cmd[0]
1739
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1740

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

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

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

    
1764
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1765
                                                     block_devices,
1766
                                                     kvmhelp,
1767
                                                     devlist)
1768
    kvm_cmd.extend(bdev_opts)
1769

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

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

    
1797
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1798

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

    
1823
    if incoming:
1824
      target, port = incoming
1825
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1826

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

    
1839
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1840
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1841
                         constants.SECURE_DIR_MODE)])
1842

    
1843
    # Automatically enable QMP if version is >= 0.14
1844
    if self._QMP_RE.search(kvmhelp):
1845
      logging.debug("Enabling QMP")
1846
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1847
                      self._InstanceQmpMonitor(instance.name)])
1848

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

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

    
1864
    # Note: CPU pinning is using up_hvp since changes take effect
1865
    # during instance startup anyway, and to avoid problems when soft
1866
    # rebooting the instance.
1867
    cpu_pinning = False
1868
    if up_hvp.get(constants.HV_CPU_MASK, None):
1869
      cpu_pinning = True
1870

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

    
1889
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1890
                     constants.RUN_DIRS_MODE)])
1891
    for nic_seq, tap in enumerate(taps):
1892
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1893
                      data=tap)
1894

    
1895
    if vnc_pwd:
1896
      change_cmd = "change vnc password %s" % vnc_pwd
1897
      self._CallMonitorCommand(instance.name, change_cmd)
1898

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

    
1913
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1914
      qmp.connect()
1915
      arguments = {
1916
          "protocol": "spice",
1917
          "password": spice_pwd,
1918
      }
1919
      qmp.Execute("set_password", arguments)
1920

    
1921
    for filename in temp_files:
1922
      utils.RemoveFile(filename)
1923

    
1924
    # If requested, set CPU affinity and resume instance execution
1925
    if cpu_pinning:
1926
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1927

    
1928
    start_memory = self._InstanceStartupMemory(instance)
1929
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1930
      self.BalloonInstanceMemory(instance, start_memory)
1931

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

    
1938
  def StartInstance(self, instance, block_devices, startup_paused):
1939
    """Start an instance.
1940

1941
    """
1942
    self._CheckDown(instance.name)
1943
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1944
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1945
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1946
                                           startup_paused, kvmhelp)
1947
    self._SaveKVMRuntime(instance, kvm_runtime)
1948
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1949

    
1950
  def _CallMonitorCommand(self, instance_name, command):
1951
    """Invoke a command on the instance monitor.
1952

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

    
1972
    return result
1973

    
1974
  def _GetFreePCISlot(self, instance, dev):
1975
    """Get the first available pci slot of a runnung instance.
1976

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

    
1987
    [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
1988
    if not free:
1989
      raise errors.HypervisorError("All PCI slots occupied")
1990

    
1991
    dev.pci = int(free)
1992

    
1993
  def VerifyHotplugSupport(self, instance, action, dev_type):
1994
    """Check if hotplug is supported.
1995

1996
    Hotplug is *not* supported in case of:
1997
     - security models and chroot (disk hotplug)
1998
     - fdsend module is missing (nic hot-add)
1999

2000
    @raise errors.HypervisorError: in previous cases
2001

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

    
2014
    if (dev_type == constants.HOTPLUG_TARGET_NIC and
2015
        action == constants.HOTPLUG_ACTION_ADD and not fdsend):
2016
      raise errors.HotplugError("Cannot hot-add NIC."
2017
                                " fdsend python module is missing.")
2018
    return True
2019

    
2020
  def HotplugSupported(self, instance):
2021
    """Checks if hotplug is generally supported.
2022

2023
    Hotplug is *not* supported in case of:
2024
     - qemu versions < 1.0
2025
     - for stopped instances
2026

2027
    @raise errors.HypervisorError: in one of the previous cases
2028

2029
    """
2030
    try:
2031
      output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2032
    except errors.HypervisorError:
2033
      raise errors.HotplugError("Instance is probably down")
2034

    
2035
    # TODO: search for netdev_add, drive_add, device_add.....
2036
    match = self._INFO_VERSION_RE.search(output.stdout)
2037
    if not match:
2038
      raise errors.HotplugError("Cannot parse qemu version via monitor")
2039

    
2040
    v_major, v_min, _, _ = match.groups()
2041
    if (int(v_major), int(v_min)) < (1, 0):
2042
      raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2043

    
2044
  def _CallHotplugCommand(self, name, cmd):
2045
    output = self._CallMonitorCommand(name, cmd)
2046
    # TODO: parse output and check if succeeded
2047
    for line in output.stdout.splitlines():
2048
      logging.info("%s", line)
2049

    
2050
  def HotAddDevice(self, instance, dev_type, device, extra, seq):
2051
    """ Helper method to hot-add a new device
2052

2053
    It gets free pci slot generates the device name and invokes the
2054
    device specific method.
2055

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

    
2077
    self._CallHotplugCommand(instance.name, command)
2078
    # update relevant entries in runtime file
2079
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2080
    entry = _RUNTIME_ENTRY[dev_type](device, extra)
2081
    runtime[index].append(entry)
2082
    self._SaveKVMRuntime(instance, runtime)
2083

    
2084
  def HotDelDevice(self, instance, dev_type, device, _, seq):
2085
    """ Helper method for hot-del device
2086

2087
    It gets device info from runtime file, generates the device name and
2088
    invokes the device specific method.
2089

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

    
2107
    return kvm_device.pci
2108

    
2109
  def HotModDevice(self, instance, dev_type, device, _, seq):
2110
    """ Helper method for hot-mod device
2111

2112
    It gets device info from runtime file, generates the device name and
2113
    invokes the device specific method. Currently only NICs support hot-mod
2114

2115
    """
2116
    if dev_type == constants.HOTPLUG_TARGET_NIC:
2117
      # putting it back in the same pci slot
2118
      device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2119
      # TODO: remove sleep when socat gets removed
2120
      time.sleep(2)
2121
      self.HotAddDevice(instance, dev_type, device, _, seq)
2122

    
2123
  def _PassTapFd(self, instance, fd, nic):
2124
    """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2125

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

    
2140
  @classmethod
2141
  def _ParseKVMVersion(cls, text):
2142
    """Parse the KVM version from the --help output.
2143

2144
    @type text: string
2145
    @param text: output of kvm --help
2146
    @return: (version, v_maj, v_min, v_rev)
2147
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2148

2149
    """
2150
    match = cls._VERSION_RE.search(text.splitlines()[0])
2151
    if not match:
2152
      raise errors.HypervisorError("Unable to get KVM version")
2153

    
2154
    v_all = match.group(0)
2155
    v_maj = int(match.group(1))
2156
    v_min = int(match.group(2))
2157
    if match.group(4):
2158
      v_rev = int(match.group(4))
2159
    else:
2160
      v_rev = 0
2161
    return (v_all, v_maj, v_min, v_rev)
2162

    
2163
  @classmethod
2164
  def _GetKVMOutput(cls, kvm_path, option):
2165
    """Return the output of a kvm invocation
2166

2167
    @type kvm_path: string
2168
    @param kvm_path: path to the kvm executable
2169
    @type option: a key of _KVMOPTS_CMDS
2170
    @param option: kvm option to fetch the output from
2171
    @return: output a supported kvm invocation
2172
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2173

2174
    """
2175
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2176

    
2177
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
2178

    
2179
    result = utils.RunCmd([kvm_path] + optlist)
2180
    if result.failed and not can_fail:
2181
      raise errors.HypervisorError("Unable to get KVM %s output" %
2182
                                    " ".join(cls._KVMOPTS_CMDS[option]))
2183
    return result.output
2184

    
2185
  @classmethod
2186
  def _GetKVMVersion(cls, kvm_path):
2187
    """Return the installed KVM version.
2188

2189
    @return: (version, v_maj, v_min, v_rev)
2190
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2191

2192
    """
2193
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2194

    
2195
  @classmethod
2196
  def _GetDefaultMachineVersion(cls, kvm_path):
2197
    """Return the default hardware revision (e.g. pc-1.1)
2198

2199
    """
2200
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2201
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2202
    if match:
2203
      return match.group(1)
2204
    else:
2205
      return "pc"
2206

    
2207
  def StopInstance(self, instance, force=False, retry=False, name=None):
2208
    """Stop an instance.
2209

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

    
2225
  def CleanupInstance(self, instance_name):
2226
    """Cleanup after a stopped instance
2227

2228
    """
2229
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
2230
    if pid > 0 and alive:
2231
      raise errors.HypervisorError("Cannot cleanup a live instance")
2232
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2233

    
2234
  def RebootInstance(self, instance):
2235
    """Reboot an instance.
2236

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

    
2257
  def MigrationInfo(self, instance):
2258
    """Get instance information to perform a migration.
2259

2260
    @type instance: L{objects.Instance}
2261
    @param instance: instance to be migrated
2262
    @rtype: string
2263
    @return: content of the KVM runtime file
2264

2265
    """
2266
    return self._ReadKVMRuntime(instance.name)
2267

    
2268
  def AcceptInstance(self, instance, info, target):
2269
    """Prepare to accept an instance.
2270

2271
    @type instance: L{objects.Instance}
2272
    @param instance: instance to be accepted
2273
    @type info: string
2274
    @param info: content of the KVM runtime file on the source node
2275
    @type target: string
2276
    @param target: target host (usually ip), on this node
2277

2278
    """
2279
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2280
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2281
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2282
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2283
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2284
                            incoming=incoming_address)
2285

    
2286
  def FinalizeMigrationDst(self, instance, info, success):
2287
    """Finalize the instance migration on the target node.
2288

2289
    Stop the incoming mode KVM.
2290

2291
    @type instance: L{objects.Instance}
2292
    @param instance: instance whose migration is being finalized
2293

2294
    """
2295
    if success:
2296
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2297
      kvm_nics = kvm_runtime[1]
2298

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

    
2314
      self._WriteKVMRuntime(instance.name, info)
2315
    else:
2316
      self.StopInstance(instance, force=True)
2317

    
2318
  def MigrateInstance(self, instance, target, live):
2319
    """Migrate an instance to a target node.
2320

2321
    The migration will not be attempted if the instance is not
2322
    currently running.
2323

2324
    @type instance: L{objects.Instance}
2325
    @param instance: the instance to be migrated
2326
    @type target: string
2327
    @param target: ip address of the target node
2328
    @type live: boolean
2329
    @param live: perform a live migration
2330

2331
    """
2332
    instance_name = instance.name
2333
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
2334
    _, _, alive = self._InstancePidAlive(instance_name)
2335
    if not alive:
2336
      raise errors.HypervisorError("Instance not running, cannot migrate")
2337

    
2338
    if not live:
2339
      self._CallMonitorCommand(instance_name, "stop")
2340

    
2341
    migrate_command = ("migrate_set_speed %dm" %
2342
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2343
    self._CallMonitorCommand(instance_name, migrate_command)
2344

    
2345
    migrate_command = ("migrate_set_downtime %dms" %
2346
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2347
    self._CallMonitorCommand(instance_name, migrate_command)
2348

    
2349
    # These commands are supported in latest qemu versions.
2350
    # Since _CallMonitorCommand does not catch monitor errors
2351
    # this does not raise an exception in case command is not supported
2352
    # TODO: either parse output of command or see if the command supported
2353
    # via info help (see hotplug)
2354
    migrate_command = ("migrate_set_capability xbzrle on")
2355
    self._CallMonitorCommand(instance_name, migrate_command)
2356

    
2357
    migrate_command = ("migrate_set_capability auto-converge on")
2358
    self._CallMonitorCommand(instance_name, migrate_command)
2359

    
2360
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2361
    self._CallMonitorCommand(instance_name, migrate_command)
2362

    
2363
  def FinalizeMigrationSource(self, instance, success, live):
2364
    """Finalize the instance migration on the source node.
2365

2366
    @type instance: L{objects.Instance}
2367
    @param instance: the instance that was migrated
2368
    @type success: bool
2369
    @param success: whether the migration succeeded or not
2370
    @type live: bool
2371
    @param live: whether the user requested a live migration or not
2372

2373
    """
2374
    if success:
2375
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2376
      utils.KillProcess(pid)
2377
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2378
    elif live:
2379
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2380

    
2381
  def GetMigrationStatus(self, instance):
2382
    """Get the migration status
2383

2384
    @type instance: L{objects.Instance}
2385
    @param instance: the instance that is being migrated
2386
    @rtype: L{objects.MigrationStatus}
2387
    @return: the status of the current migration (one of
2388
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2389
             progress info that can be retrieved from the hypervisor
2390

2391
    """
2392
    info_command = "info migrate"
2393
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2394
      result = self._CallMonitorCommand(instance.name, info_command)
2395
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
2396
      if not match:
2397
        if not result.stdout:
2398
          logging.info("KVM: empty 'info migrate' result")
2399
        else:
2400
          logging.warning("KVM: unknown 'info migrate' result: %s",
2401
                          result.stdout)
2402
      else:
2403
        status = match.group(1)
2404
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2405
          migration_status = objects.MigrationStatus(status=status)
2406
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2407
          if match:
2408
            migration_status.transferred_ram = match.group("transferred")
2409
            migration_status.total_ram = match.group("total")
2410

    
2411
          return migration_status
2412

    
2413
        logging.warning("KVM: unknown migration status '%s'", status)
2414

    
2415
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2416

    
2417
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2418

    
2419
  def BalloonInstanceMemory(self, instance, mem):
2420
    """Balloon an instance memory to a certain value.
2421

2422
    @type instance: L{objects.Instance}
2423
    @param instance: instance to be accepted
2424
    @type mem: int
2425
    @param mem: actual memory size to use for instance runtime
2426

2427
    """
2428
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2429

    
2430
  def GetNodeInfo(self):
2431
    """Return information about the node.
2432

2433
    @return: a dict with the following keys (values in MiB):
2434
          - memory_total: the total memory size on the node
2435
          - memory_free: the available memory on the node for instances
2436
          - memory_dom0: the memory used by the node itself, if available
2437
          - hv_version: the hypervisor version in the form (major, minor,
2438
                        revision)
2439

2440
    """
2441
    result = self.GetLinuxNodeInfo()
2442
    # FIXME: this is the global kvm version, but the actual version can be
2443
    # customized as an hv parameter. we should use the nodegroup's default kvm
2444
    # path parameter here.
2445
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2446
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2447
    return result
2448

    
2449
  @classmethod
2450
  def GetInstanceConsole(cls, instance, hvparams, beparams):
2451
    """Return a command for connecting to the console of an instance.
2452

2453
    """
2454
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2455
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2456
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2457
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2458
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2459
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2460
      return objects.InstanceConsole(instance=instance.name,
2461
                                     kind=constants.CONS_SSH,
2462
                                     host=instance.primary_node,
2463
                                     user=constants.SSH_CONSOLE_USER,
2464
                                     command=cmd)
2465

    
2466
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2467
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2468
      display = instance.network_port - constants.VNC_BASE_PORT
2469
      return objects.InstanceConsole(instance=instance.name,
2470
                                     kind=constants.CONS_VNC,
2471
                                     host=vnc_bind_address,
2472
                                     port=instance.network_port,
2473
                                     display=display)
2474

    
2475
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2476
    if spice_bind:
2477
      return objects.InstanceConsole(instance=instance.name,
2478
                                     kind=constants.CONS_SPICE,
2479
                                     host=spice_bind,
2480
                                     port=instance.network_port)
2481

    
2482
    return objects.InstanceConsole(instance=instance.name,
2483
                                   kind=constants.CONS_MESSAGE,
2484
                                   message=("No serial shell for instance %s" %
2485
                                            instance.name))
2486

    
2487
  def Verify(self):
2488
    """Verify the hypervisor.
2489

2490
    Check that the required binaries exist.
2491

2492
    @return: Problem description if something is wrong, C{None} otherwise
2493

2494
    """
2495
    msgs = []
2496
    # FIXME: this is the global kvm binary, but the actual path can be
2497
    # customized as an hv parameter; we should use the nodegroup's
2498
    # default kvm path parameter here.
2499
    if not os.path.exists(constants.KVM_PATH):
2500
      msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2501
    if not os.path.exists(constants.SOCAT_PATH):
2502
      msgs.append("The socat binary ('%s') does not exist" %
2503
                  constants.SOCAT_PATH)
2504

    
2505
    return self._FormatVerifyResults(msgs)
2506

    
2507
  @classmethod
2508
  def CheckParameterSyntax(cls, hvparams):
2509
    """Check the given parameters for validity.
2510

2511
    @type hvparams:  dict
2512
    @param hvparams: dictionary with parameter names/value
2513
    @raise errors.HypervisorError: when a parameter is not valid
2514

2515
    """
2516
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2517

    
2518
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2519
    if kernel_path:
2520
      if not hvparams[constants.HV_ROOT_PATH]:
2521
        raise errors.HypervisorError("Need a root partition for the instance,"
2522
                                     " if a kernel is defined")
2523

    
2524
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2525
        not hvparams[constants.HV_VNC_X509]):
2526
      raise errors.HypervisorError("%s must be defined, if %s is" %
2527
                                   (constants.HV_VNC_X509,
2528
                                    constants.HV_VNC_X509_VERIFY))
2529

    
2530
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2531
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2532
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2533
      if not serial_speed or serial_speed not in valid_speeds:
2534
        raise errors.HypervisorError("Invalid serial console speed, must be"
2535
                                     " one of: %s" %
2536
                                     utils.CommaJoin(valid_speeds))
2537

    
2538
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2539
    if (boot_order == constants.HT_BO_CDROM and
2540
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2541
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2542
                                   " ISO path")
2543

    
2544
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2545
    if security_model == constants.HT_SM_USER:
2546
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2547
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2548
                                     " must be specified")
2549
    elif (security_model == constants.HT_SM_NONE or
2550
          security_model == constants.HT_SM_POOL):
2551
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2552
        raise errors.HypervisorError("Cannot have a security domain when the"
2553
                                     " security model is 'none' or 'pool'")
2554

    
2555
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2556
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2557
    if spice_bind:
2558
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2559
        # if an IP version is specified, the spice_bind parameter must be an
2560
        # IP of that family
2561
        if (netutils.IP4Address.IsValid(spice_bind) and
2562
            spice_ip_version != constants.IP4_VERSION):
2563
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2564
                                       " the specified IP version is %s" %
2565
                                       (spice_bind, spice_ip_version))
2566

    
2567
        if (netutils.IP6Address.IsValid(spice_bind) and
2568
            spice_ip_version != constants.IP6_VERSION):
2569
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2570
                                       " the specified IP version is %s" %
2571
                                       (spice_bind, spice_ip_version))
2572
    else:
2573
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2574
      # error if any of them is set without it.
2575
      for param in _SPICE_ADDITIONAL_PARAMS:
2576
        if hvparams[param]:
2577
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2578
                                       (param, constants.HV_KVM_SPICE_BIND))
2579

    
2580
  @classmethod
2581
  def ValidateParameters(cls, hvparams):
2582
    """Check the given parameters for validity.
2583

2584
    @type hvparams:  dict
2585
    @param hvparams: dictionary with parameter names/value
2586
    @raise errors.HypervisorError: when a parameter is not valid
2587

2588
    """
2589
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2590

    
2591
    kvm_path = hvparams[constants.HV_KVM_PATH]
2592

    
2593
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2594
    if security_model == constants.HT_SM_USER:
2595
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2596
      try:
2597
        pwd.getpwnam(username)
2598
      except KeyError:
2599
        raise errors.HypervisorError("Unknown security domain user %s"
2600
                                     % username)
2601

    
2602
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2603
    if spice_bind:
2604
      # only one of VNC and SPICE can be used currently.
2605
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2606
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2607
                                     " only one of them can be used at a"
2608
                                     " given time")
2609

    
2610
      # check that KVM supports SPICE
2611
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2612
      if not cls._SPICE_RE.search(kvmhelp):
2613
        raise errors.HypervisorError("SPICE is configured, but it is not"
2614
                                     " supported according to 'kvm --help'")
2615

    
2616
      # if spice_bind is not an IP address, it must be a valid interface
2617
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2618
                       netutils.IP6Address.IsValid(spice_bind))
2619
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2620
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2621
                                     " a valid IP address or interface name" %
2622
                                     constants.HV_KVM_SPICE_BIND)
2623

    
2624
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2625
    if machine_version:
2626
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2627
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2628
        raise errors.HypervisorError("Unsupported machine version: %s" %
2629
                                     machine_version)
2630

    
2631
  @classmethod
2632
  def PowercycleNode(cls):
2633
    """KVM powercycle, just a wrapper over Linux powercycle.
2634

2635
    """
2636
    cls.LinuxPowercycle()