Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 26ce25ef

History | View | Annotate | Download (93.9 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):
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
  if not dev.pci:
133
    raise errors.HotplugError("Hotplug is not supported for %s with UUID %s" %
134
                              (dev_type, dev.uuid))
135

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

    
138

    
139
def _UpdatePCISlots(dev, pci_reservations):
140
  """Update pci configuration for a stopped instance
141

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

146
  @type dev: L{objects.Disk} or L{objects.NIC}
147
  @param dev: the device object for which we update its pci slot
148
  @type pci_reservations: bitarray
149
  @param pci_reservations: existing pci reservations for an instance
150
  @raise errors.HotplugError: in case an instance has all its slot occupied
151

152
  """
153
  if dev.pci:
154
    free = dev.pci
155
  else: # pylint: disable=E1103
156
    [free] = pci_reservations.search(_AVAILABLE_PCI_SLOT, 1)
157
    if not free:
158
      raise errors.HypervisorError("All PCI slots occupied")
159
    dev.pci = int(free)
160

    
161
  pci_reservations[free] = True
162

    
163

    
164
def _GetExistingDeviceInfo(dev_type, device, runtime):
165
  """Helper function to get an existing device inside the runtime file
166

167
  Used when an instance is running. Load kvm runtime file and search
168
  for a device based on its type and uuid.
169

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

180
  """
181
  index = _DEVICE_RUNTIME_INDEX[dev_type]
182
  found = _FIND_RUNTIME_ENTRY[dev_type](device, runtime[index])
183
  if not found:
184
    raise errors.HotplugError("Cannot find runtime info for %s with UUID %s" %
185
                              (dev_type, device.uuid))
186

    
187
  return found[0]
188

    
189

    
190
def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
191
  """Retrieves supported TUN features from file descriptor.
192

193
  @see: L{_ProbeTapVnetHdr}
194

195
  """
196
  req = struct.pack("I", 0)
197
  try:
198
    buf = _ioctl(fd, TUNGETFEATURES, req)
199
  except EnvironmentError, err:
200
    logging.warning("ioctl(TUNGETFEATURES) failed: %s", err)
201
    return None
202
  else:
203
    (flags, ) = struct.unpack("I", buf)
204
    return flags
205

    
206

    
207
def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
208
  """Check whether to enable the IFF_VNET_HDR flag.
209

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

220
   @type fd: int
221
   @param fd: the file descriptor of /dev/net/tun
222

223
  """
224
  flags = _features_fn(fd)
225

    
226
  if flags is None:
227
    # Not supported
228
    return False
229

    
230
  result = bool(flags & IFF_VNET_HDR)
231

    
232
  if not result:
233
    logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
234

    
235
  return result
236

    
237

    
238
def _OpenTap(vnet_hdr=True):
239
  """Open a new tap device and return its file descriptor.
240

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

244
  @type vnet_hdr: boolean
245
  @param vnet_hdr: Enable the VNET Header
246
  @return: (ifname, tapfd)
247
  @rtype: tuple
248

249
  """
250
  try:
251
    tapfd = os.open("/dev/net/tun", os.O_RDWR)
252
  except EnvironmentError:
253
    raise errors.HypervisorError("Failed to open /dev/net/tun")
254

    
255
  flags = IFF_TAP | IFF_NO_PI
256

    
257
  if vnet_hdr and _ProbeTapVnetHdr(tapfd):
258
    flags |= IFF_VNET_HDR
259

    
260
  # The struct ifreq ioctl request (see netdevice(7))
261
  ifr = struct.pack("16sh", "", flags)
262

    
263
  try:
264
    res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
265
  except EnvironmentError, err:
266
    raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
267
                                 err)
268

    
269
  # Get the interface name from the ioctl
270
  ifname = struct.unpack("16sh", res)[0].strip("\x00")
271
  return (ifname, tapfd)
272

    
273

    
274
class QmpMessage:
275
  """QEMU Messaging Protocol (QMP) message.
276

277
  """
278
  def __init__(self, data):
279
    """Creates a new QMP message based on the passed data.
280

281
    """
282
    if not isinstance(data, dict):
283
      raise TypeError("QmpMessage must be initialized with a dict")
284

    
285
    self.data = data
286

    
287
  def __getitem__(self, field_name):
288
    """Get the value of the required field if present, or None.
289

290
    Overrides the [] operator to provide access to the message data,
291
    returning None if the required item is not in the message
292
    @return: the value of the field_name field, or None if field_name
293
             is not contained in the message
294

295
    """
296
    return self.data.get(field_name, None)
297

    
298
  def __setitem__(self, field_name, field_value):
299
    """Set the value of the required field_name to field_value.
300

301
    """
302
    self.data[field_name] = field_value
303

    
304
  @staticmethod
305
  def BuildFromJsonString(json_string):
306
    """Build a QmpMessage from a JSON encoded string.
307

308
    @type json_string: str
309
    @param json_string: JSON string representing the message
310
    @rtype: L{QmpMessage}
311
    @return: a L{QmpMessage} built from json_string
312

313
    """
314
    # Parse the string
315
    data = serializer.LoadJson(json_string)
316
    return QmpMessage(data)
317

    
318
  def __str__(self):
319
    # The protocol expects the JSON object to be sent as a single line.
320
    return serializer.DumpJson(self.data)
321

    
322
  def __eq__(self, other):
323
    # When comparing two QmpMessages, we are interested in comparing
324
    # their internal representation of the message data
325
    return self.data == other.data
326

    
327

    
328
class MonitorSocket(object):
329
  _SOCKET_TIMEOUT = 5
330

    
331
  def __init__(self, monitor_filename):
332
    """Instantiates the MonitorSocket object.
333

334
    @type monitor_filename: string
335
    @param monitor_filename: the filename of the UNIX raw socket on which the
336
                             monitor (QMP or simple one) is listening
337

338
    """
339
    self.monitor_filename = monitor_filename
340
    self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
341
    # We want to fail if the server doesn't send a complete message
342
    # in a reasonable amount of time
343
    self.sock.settimeout(self._SOCKET_TIMEOUT)
344
    self._connected = False
345

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

    
359
  def _check_connection(self):
360
    """Make sure that the connection is established.
361

362
    """
363
    if not self._connected:
364
      raise errors.ProgrammerError("To use a MonitorSocket you need to first"
365
                                   " invoke connect() on it")
366

    
367
  def connect(self):
368
    """Connects to the monitor.
369

370
    Connects to the UNIX socket
371

372
    @raise errors.HypervisorError: when there are communication errors
373

374
    """
375
    if self._connected:
376
      raise errors.ProgrammerError("Cannot connect twice")
377

    
378
    self._check_socket()
379

    
380
    # Check file existance/stuff
381
    try:
382
      self.sock.connect(self.monitor_filename)
383
    except EnvironmentError:
384
      raise errors.HypervisorError("Can't connect to qmp socket")
385
    self._connected = True
386

    
387
  def close(self):
388
    """Closes the socket
389

390
    It cannot be used after this call.
391

392
    """
393
    self.sock.close()
394

    
395

    
396
class QmpConnection(MonitorSocket):
397
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
398

399
  """
400
  _FIRST_MESSAGE_KEY = "QMP"
401
  _EVENT_KEY = "event"
402
  _ERROR_KEY = "error"
403
  _RETURN_KEY = RETURN_KEY = "return"
404
  _ACTUAL_KEY = ACTUAL_KEY = "actual"
405
  _ERROR_CLASS_KEY = "class"
406
  _ERROR_DATA_KEY = "data"
407
  _ERROR_DESC_KEY = "desc"
408
  _EXECUTE_KEY = "execute"
409
  _ARGUMENTS_KEY = "arguments"
410
  _CAPABILITIES_COMMAND = "qmp_capabilities"
411
  _MESSAGE_END_TOKEN = "\r\n"
412

    
413
  def __init__(self, monitor_filename):
414
    super(QmpConnection, self).__init__(monitor_filename)
415
    self._buf = ""
416

    
417
  def connect(self):
418
    """Connects to the QMP monitor.
419

420
    Connects to the UNIX socket and makes sure that we can actually send and
421
    receive data to the kvm instance via QMP.
422

423
    @raise errors.HypervisorError: when there are communication errors
424
    @raise errors.ProgrammerError: when there are data serialization errors
425

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

    
436
    # Let's put the monitor in command mode using the qmp_capabilities
437
    # command, or else no command will be executable.
438
    # (As per the QEMU Protocol Specification 0.1 - section 4)
439
    self.Execute(self._CAPABILITIES_COMMAND)
440

    
441
  def _ParseMessage(self, buf):
442
    """Extract and parse a QMP message from the given buffer.
443

444
    Seeks for a QMP message in the given buf. If found, it parses it and
445
    returns it together with the rest of the characters in the buf.
446
    If no message is found, returns None and the whole buffer.
447

448
    @raise errors.ProgrammerError: when there are data serialization errors
449

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

    
462
    return (message, buf)
463

    
464
  def _Recv(self):
465
    """Receives a message from QMP and decodes the received JSON object.
466

467
    @rtype: QmpMessage
468
    @return: the received message
469
    @raise errors.HypervisorError: when there are communication errors
470
    @raise errors.ProgrammerError: when there are data serialization errors
471

472
    """
473
    self._check_connection()
474

    
475
    # Check if there is already a message in the buffer
476
    (message, self._buf) = self._ParseMessage(self._buf)
477
    if message:
478
      return message
479

    
480
    recv_buffer = StringIO.StringIO(self._buf)
481
    recv_buffer.seek(len(self._buf))
482
    try:
483
      while True:
484
        data = self.sock.recv(4096)
485
        if not data:
486
          break
487
        recv_buffer.write(data)
488

    
489
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
490
        if message:
491
          return message
492

    
493
    except socket.timeout, err:
494
      raise errors.HypervisorError("Timeout while receiving a QMP message: "
495
                                   "%s" % (err))
496
    except socket.error, err:
497
      raise errors.HypervisorError("Unable to receive data from KVM using the"
498
                                   " QMP protocol: %s" % err)
499

    
500
  def _Send(self, message):
501
    """Encodes and sends a message to KVM using QMP.
502

503
    @type message: QmpMessage
504
    @param message: message to send to KVM
505
    @raise errors.HypervisorError: when there are communication errors
506
    @raise errors.ProgrammerError: when there are data serialization errors
507

508
    """
509
    self._check_connection()
510
    try:
511
      message_str = str(message)
512
    except Exception, err:
513
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
514

    
515
    try:
516
      self.sock.sendall(message_str)
517
    except socket.timeout, err:
518
      raise errors.HypervisorError("Timeout while sending a QMP message: "
519
                                   "%s (%s)" % (err.string, err.errno))
520
    except socket.error, err:
521
      raise errors.HypervisorError("Unable to send data from KVM using the"
522
                                   " QMP protocol: %s" % err)
523

    
524
  def Execute(self, command, arguments=None):
525
    """Executes a QMP command and returns the response of the server.
526

527
    @type command: str
528
    @param command: the command to execute
529
    @type arguments: dict
530
    @param arguments: dictionary of arguments to be passed to the command
531
    @rtype: dict
532
    @return: dictionary representing the received JSON object
533
    @raise errors.HypervisorError: when there are communication errors
534
    @raise errors.ProgrammerError: when there are data serialization errors
535

536
    """
537
    self._check_connection()
538
    message = QmpMessage({self._EXECUTE_KEY: command})
539
    if arguments:
540
      message[self._ARGUMENTS_KEY] = arguments
541
    self._Send(message)
542

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

    
556
      elif not response[self._EVENT_KEY]:
557
        return response
558

    
559

    
560
class KVMHypervisor(hv_base.BaseHypervisor):
561
  """KVM hypervisor interface
562

563
  """
564
  CAN_MIGRATE = True
565

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

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

    
669
  _VIRTIO = "virtio"
670
  _VIRTIO_NET_PCI = "virtio-net-pci"
671
  _VIRTIO_BLK_PCI = "virtio-blk-pci"
672

    
673
  _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
674
                                    re.M | re.I)
675
  _MIGRATION_PROGRESS_RE = \
676
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
677
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
678
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
679

    
680
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
681
  _MIGRATION_INFO_RETRY_DELAY = 2
682

    
683
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
684

    
685
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
686
  _CPU_INFO_CMD = "info cpus"
687
  _CONT_CMD = "cont"
688

    
689
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
690
  _CHECK_MACHINE_VERSION_RE = \
691
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
692

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

    
708
  _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
709
  _INFO_PCI_CMD = "info pci"
710
  _INFO_VERSION_RE = \
711
    re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
712
  _INFO_VERSION_CMD = "info version"
713

    
714
  _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
715

    
716
  ANCILLARY_FILES = [
717
    _KVM_NETWORK_SCRIPT,
718
    ]
719
  ANCILLARY_FILES_OPT = [
720
    _KVM_NETWORK_SCRIPT,
721
    ]
722

    
723
  # Supported kvm options to get output from
724
  _KVMOPT_HELP = "help"
725
  _KVMOPT_MLIST = "mlist"
726
  _KVMOPT_DEVICELIST = "devicelist"
727

    
728
  # Command to execute to get the output from kvm, and whether to
729
  # accept the output even on failure.
730
  _KVMOPTS_CMDS = {
731
    _KVMOPT_HELP: (["--help"], False),
732
    _KVMOPT_MLIST: (["-M", "?"], False),
733
    _KVMOPT_DEVICELIST: (["-device", "?"], True),
734
  }
735

    
736
  def __init__(self):
737
    hv_base.BaseHypervisor.__init__(self)
738
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
739
    # in a tmpfs filesystem or has been otherwise wiped out.
740
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
741
    utils.EnsureDirs(dirs)
742

    
743
  @classmethod
744
  def _InstancePidFile(cls, instance_name):
745
    """Returns the instance pidfile.
746

747
    """
748
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
749

    
750
  @classmethod
751
  def _InstanceUidFile(cls, instance_name):
752
    """Returns the instance uidfile.
753

754
    """
755
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
756

    
757
  @classmethod
758
  def _InstancePidInfo(cls, pid):
759
    """Check pid file for instance information.
760

761
    Check that a pid file is associated with an instance, and retrieve
762
    information from its command line.
763

764
    @type pid: string or int
765
    @param pid: process id of the instance to check
766
    @rtype: tuple
767
    @return: (instance_name, memory, vcpus)
768
    @raise errors.HypervisorError: when an instance cannot be found
769

770
    """
771
    alive = utils.IsProcessAlive(pid)
772
    if not alive:
773
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
774

    
775
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
776
    try:
777
      cmdline = utils.ReadFile(cmdline_file)
778
    except EnvironmentError, err:
779
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
780
                                   (pid, err))
781

    
782
    instance = None
783
    memory = 0
784
    vcpus = 0
785

    
786
    arg_list = cmdline.split("\x00")
787
    while arg_list:
788
      arg = arg_list.pop(0)
789
      if arg == "-name":
790
        instance = arg_list.pop(0)
791
      elif arg == "-m":
792
        memory = int(arg_list.pop(0))
793
      elif arg == "-smp":
794
        vcpus = int(arg_list.pop(0).split(",")[0])
795

    
796
    if instance is None:
797
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
798
                                   " instance" % pid)
799

    
800
    return (instance, memory, vcpus)
801

    
802
  def _InstancePidAlive(self, instance_name):
803
    """Returns the instance pidfile, pid, and liveness.
804

805
    @type instance_name: string
806
    @param instance_name: instance name
807
    @rtype: tuple
808
    @return: (pid file name, pid, liveness)
809

810
    """
811
    pidfile = self._InstancePidFile(instance_name)
812
    pid = utils.ReadPidFile(pidfile)
813

    
814
    alive = False
815
    try:
816
      cmd_instance = self._InstancePidInfo(pid)[0]
817
      alive = (cmd_instance == instance_name)
818
    except errors.HypervisorError:
819
      pass
820

    
821
    return (pidfile, pid, alive)
822

    
823
  def _CheckDown(self, instance_name):
824
    """Raises an error unless the given instance is down.
825

826
    """
827
    alive = self._InstancePidAlive(instance_name)[2]
828
    if alive:
829
      raise errors.HypervisorError("Failed to start instance %s: %s" %
830
                                   (instance_name, "already running"))
831

    
832
  @classmethod
833
  def _InstanceMonitor(cls, instance_name):
834
    """Returns the instance monitor socket name
835

836
    """
837
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
838

    
839
  @classmethod
840
  def _InstanceSerial(cls, instance_name):
841
    """Returns the instance serial socket name
842

843
    """
844
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
845

    
846
  @classmethod
847
  def _InstanceQmpMonitor(cls, instance_name):
848
    """Returns the instance serial QMP socket name
849

850
    """
851
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
852

    
853
  @staticmethod
854
  def _SocatUnixConsoleParams():
855
    """Returns the correct parameters for socat
856

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

859
    """
860
    if constants.SOCAT_USE_ESCAPE:
861
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
862
    else:
863
      return "echo=0,icanon=0"
864

    
865
  @classmethod
866
  def _InstanceKVMRuntime(cls, instance_name):
867
    """Returns the instance KVM runtime filename
868

869
    """
870
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
871

    
872
  @classmethod
873
  def _InstanceChrootDir(cls, instance_name):
874
    """Returns the name of the KVM chroot dir of the instance
875

876
    """
877
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
878

    
879
  @classmethod
880
  def _InstanceNICDir(cls, instance_name):
881
    """Returns the name of the directory holding the tap device files for a
882
    given instance.
883

884
    """
885
    return utils.PathJoin(cls._NICS_DIR, instance_name)
886

    
887
  @classmethod
888
  def _InstanceNICFile(cls, instance_name, seq):
889
    """Returns the name of the file containing the tap device for a given NIC
890

891
    """
892
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
893

    
894
  @classmethod
895
  def _InstanceKeymapFile(cls, instance_name):
896
    """Returns the name of the file containing the keymap for a given instance
897

898
    """
899
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
900

    
901
  @classmethod
902
  def _TryReadUidFile(cls, uid_file):
903
    """Try to read a uid file
904

905
    """
906
    if os.path.exists(uid_file):
907
      try:
908
        uid = int(utils.ReadOneLineFile(uid_file))
909
        return uid
910
      except EnvironmentError:
911
        logging.warning("Can't read uid file", exc_info=True)
912
      except (TypeError, ValueError):
913
        logging.warning("Can't parse uid file contents", exc_info=True)
914
    return None
915

    
916
  @classmethod
917
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
918
    """Removes an instance's rutime sockets/files/dirs.
919

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

    
956
  @staticmethod
957
  def _ConfigureNIC(instance, seq, nic, tap):
958
    """Run the network configuration script for a specified NIC
959

960
    @param instance: instance we're acting on
961
    @type instance: instance object
962
    @param seq: nic sequence number
963
    @type seq: int
964
    @param nic: nic we're acting on
965
    @type nic: nic object
966
    @param tap: the host's tap interface this NIC corresponds to
967
    @type tap: str
968

969
    """
970
    if instance.tags:
971
      tags = " ".join(instance.tags)
972
    else:
973
      tags = ""
974

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

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

    
990
    if nic.nicparams[constants.NIC_LINK]:
991
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
992

    
993
    if nic.network:
994
      n = objects.Network.FromDict(nic.netinfo)
995
      env.update(n.HooksDict())
996

    
997
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
998
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
999

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

    
1006
  @staticmethod
1007
  def _VerifyAffinityPackage():
1008
    if affinity is None:
1009
      raise errors.HypervisorError("affinity Python package not"
1010
                                   " found; cannot use CPU pinning under KVM")
1011

    
1012
  @staticmethod
1013
  def _BuildAffinityCpuMask(cpu_list):
1014
    """Create a CPU mask suitable for sched_setaffinity from a list of
1015
    CPUs.
1016

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

1020
    @type cpu_list: list of int
1021
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
1022
    @rtype: int
1023
    @return: a bit mask of CPU affinities
1024

1025
    """
1026
    if cpu_list == constants.CPU_PINNING_OFF:
1027
      return constants.CPU_PINNING_ALL_KVM
1028
    else:
1029
      return sum(2 ** cpu for cpu in cpu_list)
1030

    
1031
  @classmethod
1032
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
1033
    """Change CPU affinity for running VM according to given CPU mask.
1034

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

1043
    """
1044
    # Convert the string CPU mask to a list of list of int's
1045
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
1046

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

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

    
1070
  def _GetVcpuThreadIds(self, instance_name):
1071
    """Get a mapping of vCPU no. to thread IDs for the instance
1072

1073
    @type instance_name: string
1074
    @param instance_name: instance in question
1075
    @rtype: dictionary of int:int
1076
    @return: a dictionary mapping vCPU numbers to thread IDs
1077

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

    
1088
    return result
1089

    
1090
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1091
    """Complete CPU pinning.
1092

1093
    @type instance_name: string
1094
    @param instance_name: name of instance
1095
    @type cpu_mask: string
1096
    @param cpu_mask: CPU pinning mask as entered by user
1097

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

    
1106
  def ListInstances(self):
1107
    """Get the list of running instances.
1108

1109
    We can do this by listing our live instances directory and
1110
    checking whether the associated kvm process is still alive.
1111

1112
    """
1113
    result = []
1114
    for name in os.listdir(self._PIDS_DIR):
1115
      if self._InstancePidAlive(name)[2]:
1116
        result.append(name)
1117
    return result
1118

    
1119
  def GetInstanceInfo(self, instance_name):
1120
    """Get instance properties.
1121

1122
    @type instance_name: string
1123
    @param instance_name: the instance name
1124
    @rtype: tuple of strings
1125
    @return: (name, id, memory, vcpus, stat, times)
1126

1127
    """
1128
    _, pid, alive = self._InstancePidAlive(instance_name)
1129
    if not alive:
1130
      return None
1131

    
1132
    _, memory, vcpus = self._InstancePidInfo(pid)
1133
    istat = "---b-"
1134
    times = "0"
1135

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

    
1147
    return (instance_name, pid, memory, vcpus, istat, times)
1148

    
1149
  def GetAllInstancesInfo(self):
1150
    """Get properties of all instances.
1151

1152
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1153

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

    
1166
  def _GenerateKVMBlockDevicesOptions(self, instance, block_devices,
1167
                                      kvmhelp, devlist):
1168
    """Generate KVM options regarding instance's block devices.
1169

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

1181
    """
1182
    hvp = instance.hvparams
1183
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1184
    if kernel_path:
1185
      boot_disk = False
1186
    else:
1187
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1188

    
1189
    # whether this is an older KVM version that uses the boot=on flag
1190
    # on devices
1191
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1192

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

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

    
1246
      dev_opts.extend(["-drive", drive_val])
1247

    
1248
    return dev_opts
1249

    
1250
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1251
                          kvmhelp):
1252
    """Generate KVM information to start an instance.
1253

1254
    @type kvmhelp: string
1255
    @param kvmhelp: output of kvm --help
1256
    @attention: this function must not have any side-effects; for
1257
        example, it must not write to the filesystem, or read values
1258
        from the current system the are expected to differ between
1259
        nodes, since it is only run once at instance startup;
1260
        actions/kvm arguments that can vary between systems should be
1261
        done in L{_ExecuteKVMRuntime}
1262

1263
    """
1264
    # pylint: disable=R0912,R0914,R0915
1265
    hvp = instance.hvparams
1266
    self.ValidateParameters(hvp)
1267

    
1268
    pidfile = self._InstancePidFile(instance.name)
1269
    kvm = hvp[constants.HV_KVM_PATH]
1270
    kvm_cmd = [kvm]
1271
    # used just by the vnc server, if enabled
1272
    kvm_cmd.extend(["-name", instance.name])
1273
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1274

    
1275
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1276
    if hvp[constants.HV_CPU_CORES]:
1277
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1278
    if hvp[constants.HV_CPU_THREADS]:
1279
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1280
    if hvp[constants.HV_CPU_SOCKETS]:
1281
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1282

    
1283
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1284

    
1285
    kvm_cmd.extend(["-pidfile", pidfile])
1286
    kvm_cmd.extend(["-balloon", "virtio"])
1287
    kvm_cmd.extend(["-daemonize"])
1288
    if not instance.hvparams[constants.HV_ACPI]:
1289
      kvm_cmd.extend(["-no-acpi"])
1290
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1291
        constants.INSTANCE_REBOOT_EXIT:
1292
      kvm_cmd.extend(["-no-reboot"])
1293

    
1294
    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1295
    if not mversion:
1296
      mversion = self._GetDefaultMachineVersion(kvm)
1297
    if self._MACHINE_RE.search(kvmhelp):
1298
      # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1299
      # extra hypervisor parameters. We should also investigate whether and how
1300
      # shadow_mem should be considered for the resource model.
1301
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1302
        specprop = ",accel=kvm"
1303
      else:
1304
        specprop = ""
1305
      machinespec = "%s%s" % (mversion, specprop)
1306
      kvm_cmd.extend(["-machine", machinespec])
1307
    else:
1308
      kvm_cmd.extend(["-M", mversion])
1309
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1310
          self._ENABLE_KVM_RE.search(kvmhelp)):
1311
        kvm_cmd.extend(["-enable-kvm"])
1312
      elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1313
            self._DISABLE_KVM_RE.search(kvmhelp)):
1314
        kvm_cmd.extend(["-disable-kvm"])
1315

    
1316
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1317
    if kernel_path:
1318
      boot_cdrom = boot_floppy = boot_network = False
1319
    else:
1320
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1321
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1322
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1323

    
1324
    if startup_paused:
1325
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1326

    
1327
    if boot_network:
1328
      kvm_cmd.extend(["-boot", "n"])
1329

    
1330
    # whether this is an older KVM version that uses the boot=on flag
1331
    # on devices
1332
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1333

    
1334
    disk_type = hvp[constants.HV_DISK_TYPE]
1335

    
1336
    #Now we can specify a different device type for CDROM devices.
1337
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1338
    if not cdrom_disk_type:
1339
      cdrom_disk_type = disk_type
1340

    
1341
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1342
    if iso_image:
1343
      options = ",format=raw,media=cdrom"
1344
      # set cdrom 'if' type
1345
      if boot_cdrom:
1346
        actual_cdrom_type = constants.HT_DISK_IDE
1347
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1348
        actual_cdrom_type = "virtio"
1349
      else:
1350
        actual_cdrom_type = cdrom_disk_type
1351
      if_val = ",if=%s" % actual_cdrom_type
1352
      # set boot flag, if needed
1353
      boot_val = ""
1354
      if boot_cdrom:
1355
        kvm_cmd.extend(["-boot", "d"])
1356
        if needs_boot_flag:
1357
          boot_val = ",boot=on"
1358
      # and finally build the entire '-drive' value
1359
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1360
      kvm_cmd.extend(["-drive", drive_val])
1361

    
1362
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1363
    if iso_image2:
1364
      options = ",format=raw,media=cdrom"
1365
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1366
        if_val = ",if=virtio"
1367
      else:
1368
        if_val = ",if=%s" % cdrom_disk_type
1369
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1370
      kvm_cmd.extend(["-drive", drive_val])
1371

    
1372
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1373
    if floppy_image:
1374
      options = ",format=raw,media=disk"
1375
      if boot_floppy:
1376
        kvm_cmd.extend(["-boot", "a"])
1377
        options = "%s,boot=on" % options
1378
      if_val = ",if=floppy"
1379
      options = "%s%s" % (options, if_val)
1380
      drive_val = "file=%s%s" % (floppy_image, options)
1381
      kvm_cmd.extend(["-drive", drive_val])
1382

    
1383
    if kernel_path:
1384
      kvm_cmd.extend(["-kernel", kernel_path])
1385
      initrd_path = hvp[constants.HV_INITRD_PATH]
1386
      if initrd_path:
1387
        kvm_cmd.extend(["-initrd", initrd_path])
1388
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1389
                     hvp[constants.HV_KERNEL_ARGS]]
1390
      if hvp[constants.HV_SERIAL_CONSOLE]:
1391
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1392
        root_append.append("console=ttyS0,%s" % serial_speed)
1393
      kvm_cmd.extend(["-append", " ".join(root_append)])
1394

    
1395
    mem_path = hvp[constants.HV_MEM_PATH]
1396
    if mem_path:
1397
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1398

    
1399
    monitor_dev = ("unix:%s,server,nowait" %
1400
                   self._InstanceMonitor(instance.name))
1401
    kvm_cmd.extend(["-monitor", monitor_dev])
1402
    if hvp[constants.HV_SERIAL_CONSOLE]:
1403
      serial_dev = ("unix:%s,server,nowait" %
1404
                    self._InstanceSerial(instance.name))
1405
      kvm_cmd.extend(["-serial", serial_dev])
1406
    else:
1407
      kvm_cmd.extend(["-serial", "none"])
1408

    
1409
    mouse_type = hvp[constants.HV_USB_MOUSE]
1410
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1411
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1412
    spice_ip_version = None
1413

    
1414
    kvm_cmd.extend(["-usb"])
1415

    
1416
    if mouse_type:
1417
      kvm_cmd.extend(["-usbdevice", mouse_type])
1418
    elif vnc_bind_address:
1419
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1420

    
1421
    if vnc_bind_address:
1422
      if netutils.IP4Address.IsValid(vnc_bind_address):
1423
        if instance.network_port > constants.VNC_BASE_PORT:
1424
          display = instance.network_port - constants.VNC_BASE_PORT
1425
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1426
            vnc_arg = ":%d" % (display)
1427
          else:
1428
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1429
        else:
1430
          logging.error("Network port is not a valid VNC display (%d < %d),"
1431
                        " not starting VNC",
1432
                        instance.network_port, constants.VNC_BASE_PORT)
1433
          vnc_arg = "none"
1434

    
1435
        # Only allow tls and other option when not binding to a file, for now.
1436
        # kvm/qemu gets confused otherwise about the filename to use.
1437
        vnc_append = ""
1438
        if hvp[constants.HV_VNC_TLS]:
1439
          vnc_append = "%s,tls" % vnc_append
1440
          if hvp[constants.HV_VNC_X509_VERIFY]:
1441
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1442
                                               hvp[constants.HV_VNC_X509])
1443
          elif hvp[constants.HV_VNC_X509]:
1444
            vnc_append = "%s,x509=%s" % (vnc_append,
1445
                                         hvp[constants.HV_VNC_X509])
1446
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1447
          vnc_append = "%s,password" % vnc_append
1448

    
1449
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1450

    
1451
      else:
1452
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1453

    
1454
      kvm_cmd.extend(["-vnc", vnc_arg])
1455
    elif spice_bind:
1456
      # FIXME: this is wrong here; the iface ip address differs
1457
      # between systems, so it should be done in _ExecuteKVMRuntime
1458
      if netutils.IsValidInterface(spice_bind):
1459
        # The user specified a network interface, we have to figure out the IP
1460
        # address.
1461
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1462
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1463

    
1464
        # if the user specified an IP version and the interface does not
1465
        # have that kind of IP addresses, throw an exception
1466
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1467
          if not addresses[spice_ip_version]:
1468
            raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1469
                                         " for %s" % (spice_ip_version,
1470
                                                      spice_bind))
1471

    
1472
        # the user did not specify an IP version, we have to figure it out
1473
        elif (addresses[constants.IP4_VERSION] and
1474
              addresses[constants.IP6_VERSION]):
1475
          # we have both ipv4 and ipv6, let's use the cluster default IP
1476
          # version
1477
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1478
          spice_ip_version = \
1479
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1480
        elif addresses[constants.IP4_VERSION]:
1481
          spice_ip_version = constants.IP4_VERSION
1482
        elif addresses[constants.IP6_VERSION]:
1483
          spice_ip_version = constants.IP6_VERSION
1484
        else:
1485
          raise errors.HypervisorError("SPICE: Unable to get an IP address"
1486
                                       " for %s" % (spice_bind))
1487

    
1488
        spice_address = addresses[spice_ip_version][0]
1489

    
1490
      else:
1491
        # spice_bind is known to be a valid IP address, because
1492
        # ValidateParameters checked it.
1493
        spice_address = spice_bind
1494

    
1495
      spice_arg = "addr=%s" % spice_address
1496
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1497
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1498
                     (spice_arg, instance.network_port,
1499
                      pathutils.SPICE_CACERT_FILE))
1500
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1501
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1502
                      pathutils.SPICE_CERT_FILE))
1503
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1504
        if tls_ciphers:
1505
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1506
      else:
1507
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1508

    
1509
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1510
        spice_arg = "%s,disable-ticketing" % spice_arg
1511

    
1512
      if spice_ip_version:
1513
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1514

    
1515
      # Image compression options
1516
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1517
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1518
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1519
      if img_lossless:
1520
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1521
      if img_jpeg:
1522
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1523
      if img_zlib_glz:
1524
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1525

    
1526
      # Video stream detection
1527
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1528
      if video_streaming:
1529
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1530

    
1531
      # Audio compression, by default in qemu-kvm it is on
1532
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1533
        spice_arg = "%s,playback-compression=off" % spice_arg
1534
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1535
        spice_arg = "%s,agent-mouse=off" % spice_arg
1536
      else:
1537
        # Enable the spice agent communication channel between the host and the
1538
        # agent.
1539
        kvm_cmd.extend(["-device", "virtio-serial-pci"])
1540
        kvm_cmd.extend([
1541
          "-device",
1542
          "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1543
          ])
1544
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1545

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

    
1549
    else:
1550
      # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1551
      # also works in earlier versions though (tested with 1.1 and 1.3)
1552
      if self._DISPLAY_RE.search(kvmhelp):
1553
        kvm_cmd.extend(["-display", "none"])
1554
      else:
1555
        kvm_cmd.extend(["-nographic"])
1556

    
1557
    if hvp[constants.HV_USE_LOCALTIME]:
1558
      kvm_cmd.extend(["-localtime"])
1559

    
1560
    if hvp[constants.HV_KVM_USE_CHROOT]:
1561
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1562

    
1563
    # Add qemu-KVM -cpu param
1564
    if hvp[constants.HV_CPU_TYPE]:
1565
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1566

    
1567
    # As requested by music lovers
1568
    if hvp[constants.HV_SOUNDHW]:
1569
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1570

    
1571
    # Pass a -vga option if requested, or if spice is used, for backwards
1572
    # compatibility.
1573
    if hvp[constants.HV_VGA]:
1574
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1575
    elif spice_bind:
1576
      kvm_cmd.extend(["-vga", "qxl"])
1577

    
1578
    # Various types of usb devices, comma separated
1579
    if hvp[constants.HV_USB_DEVICES]:
1580
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1581
        kvm_cmd.extend(["-usbdevice", dev])
1582

    
1583
    if hvp[constants.HV_KVM_EXTRA]:
1584
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1585

    
1586
    pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1587
    kvm_disks = []
1588
    for disk, dev_path in block_devices:
1589
      _UpdatePCISlots(disk, pci_reservations)
1590
      kvm_disks.append((disk, dev_path))
1591

    
1592
    kvm_nics = []
1593
    for nic in instance.nics:
1594
      _UpdatePCISlots(nic, pci_reservations)
1595
      kvm_nics.append(nic)
1596

    
1597
    hvparams = hvp
1598

    
1599
    return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1600

    
1601
  def _WriteKVMRuntime(self, instance_name, data):
1602
    """Write an instance's KVM runtime
1603

1604
    """
1605
    try:
1606
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1607
                      data=data)
1608
    except EnvironmentError, err:
1609
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1610

    
1611
  def _ReadKVMRuntime(self, instance_name):
1612
    """Read an instance's KVM runtime
1613

1614
    """
1615
    try:
1616
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1617
    except EnvironmentError, err:
1618
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1619
    return file_content
1620

    
1621
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1622
    """Save an instance's KVM runtime
1623

1624
    """
1625
    kvm_cmd, kvm_nics, hvparams, block_devices = kvm_runtime
1626

    
1627
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1628
    serialized_blockdevs = [(blk.ToDict(), link) for blk, link in block_devices]
1629
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1630
                                      serialized_blockdevs))
1631

    
1632
    self._WriteKVMRuntime(instance.name, serialized_form)
1633

    
1634
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1635
    """Load an instance's KVM runtime
1636

1637
    """
1638
    if not serialized_runtime:
1639
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1640

    
1641
    loaded_runtime = serializer.Load(serialized_runtime)
1642
    if len(loaded_runtime) == 3:
1643
      serialized_blockdevs = []
1644
      kvm_cmd, serialized_nics, hvparams = loaded_runtime
1645
    else:
1646
      kvm_cmd, serialized_nics, hvparams, serialized_blockdevs = loaded_runtime
1647

    
1648
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1649
    block_devices = [(objects.Disk.FromDict(sdisk), link)
1650
                     for sdisk, link in serialized_blockdevs]
1651

    
1652
    return (kvm_cmd, kvm_nics, hvparams, block_devices)
1653

    
1654
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1655
    """Run the KVM cmd and check for errors
1656

1657
    @type name: string
1658
    @param name: instance name
1659
    @type kvm_cmd: list of strings
1660
    @param kvm_cmd: runcmd input for kvm
1661
    @type tap_fds: list of int
1662
    @param tap_fds: fds of tap devices opened by Ganeti
1663

1664
    """
1665
    try:
1666
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1667
    finally:
1668
      for fd in tap_fds:
1669
        utils_wrapper.CloseFdNoError(fd)
1670

    
1671
    if result.failed:
1672
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1673
                                   (name, result.fail_reason, result.output))
1674
    if not self._InstancePidAlive(name)[2]:
1675
      raise errors.HypervisorError("Failed to start instance %s" % name)
1676

    
1677
  # 52/50 local variables
1678
  # pylint: disable=R0914
1679
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1680
    """Execute a KVM cmd, after completing it with some last minute data.
1681

1682
    @type incoming: tuple of strings
1683
    @param incoming: (target_host_ip, port)
1684
    @type kvmhelp: string
1685
    @param kvmhelp: output of kvm --help
1686

1687
    """
1688
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1689
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1690
    #    have changed since the instance started; only use them if the change
1691
    #    won't affect the inside of the instance (which hasn't been rebooted).
1692
    #  - up_hvp contains the parameters as they were when the instance was
1693
    #    started, plus any new parameter which has been added between ganeti
1694
    #    versions: it is paramount that those default to a value which won't
1695
    #    affect the inside of the instance as well.
1696
    conf_hvp = instance.hvparams
1697
    name = instance.name
1698
    self._CheckDown(name)
1699

    
1700
    temp_files = []
1701

    
1702
    kvm_cmd, kvm_nics, up_hvp, block_devices = kvm_runtime
1703
    # the first element of kvm_cmd is always the path to the kvm binary
1704
    kvm_path = kvm_cmd[0]
1705
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1706

    
1707
    # We know it's safe to run as a different user upon migration, so we'll use
1708
    # the latest conf, from conf_hvp.
1709
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1710
    if security_model == constants.HT_SM_USER:
1711
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1712

    
1713
    keymap = conf_hvp[constants.HV_KEYMAP]
1714
    if keymap:
1715
      keymap_path = self._InstanceKeymapFile(name)
1716
      # If a keymap file is specified, KVM won't use its internal defaults. By
1717
      # first including the "en-us" layout, an error on loading the actual
1718
      # layout (e.g. because it can't be found) won't lead to a non-functional
1719
      # keyboard. A keyboard with incorrect keys is still better than none.
1720
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1721
      kvm_cmd.extend(["-k", keymap_path])
1722

    
1723
    # We have reasons to believe changing something like the nic driver/type
1724
    # upon migration won't exactly fly with the instance kernel, so for nic
1725
    # related parameters we'll use up_hvp
1726
    tapfds = []
1727
    taps = []
1728
    devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1729
    if not kvm_nics:
1730
      kvm_cmd.extend(["-net", "none"])
1731
    else:
1732
      vnet_hdr = False
1733
      tap_extra = ""
1734
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1735
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1736
        nic_model = self._VIRTIO
1737
        try:
1738
          if self._VIRTIO_NET_RE.search(devlist):
1739
            nic_model = self._VIRTIO_NET_PCI
1740
            vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1741
        except errors.HypervisorError, _:
1742
          # Older versions of kvm don't support DEVICE_LIST, but they don't
1743
          # have new virtio syntax either.
1744
          pass
1745

    
1746
        if up_hvp[constants.HV_VHOST_NET]:
1747
          # check for vhost_net support
1748
          if self._VHOST_RE.search(kvmhelp):
1749
            tap_extra = ",vhost=on"
1750
          else:
1751
            raise errors.HypervisorError("vhost_net is configured"
1752
                                         " but it is not available")
1753
      else:
1754
        nic_model = nic_type
1755

    
1756
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1757

    
1758
      for nic_seq, nic in enumerate(kvm_nics):
1759
        tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1760
        tapfds.append(tapfd)
1761
        taps.append(tapname)
1762
        if kvm_supports_netdev:
1763
          nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1764
          try:
1765
            # kvm_nics already exist in old runtime files and thus there might
1766
            # be some entries without pci slot (therefore try: except:)
1767
            kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1768
            netdev = kvm_devid
1769
            nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1770
          except errors.HotplugError:
1771
            netdev = "netdev%d" % nic_seq
1772
          nic_val += (",netdev=%s" % netdev)
1773
          tap_val = ("type=tap,id=%s,fd=%d%s" %
1774
                     (netdev, tapfd, tap_extra))
1775
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1776
        else:
1777
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1778
                                                         nic.mac, nic_model)
1779
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1780
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1781

    
1782
    if incoming:
1783
      target, port = incoming
1784
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1785

    
1786
    # Changing the vnc password doesn't bother the guest that much. At most it
1787
    # will surprise people who connect to it. Whether positively or negatively
1788
    # it's debatable.
1789
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1790
    vnc_pwd = None
1791
    if vnc_pwd_file:
1792
      try:
1793
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1794
      except EnvironmentError, err:
1795
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1796
                                     % (vnc_pwd_file, err))
1797

    
1798
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1799
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1800
                         constants.SECURE_DIR_MODE)])
1801

    
1802
    # Automatically enable QMP if version is >= 0.14
1803
    if self._QMP_RE.search(kvmhelp):
1804
      logging.debug("Enabling QMP")
1805
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1806
                      self._InstanceQmpMonitor(instance.name)])
1807

    
1808
    # Configure the network now for starting instances and bridged interfaces,
1809
    # during FinalizeMigration for incoming instances' routed interfaces
1810
    for nic_seq, nic in enumerate(kvm_nics):
1811
      if (incoming and
1812
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1813
        continue
1814
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1815

    
1816
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1817
                                                     block_devices,
1818
                                                     kvmhelp,
1819
                                                     devlist)
1820
    kvm_cmd.extend(bdev_opts)
1821
    # CPU affinity requires kvm to start paused, so we set this flag if the
1822
    # instance is not already paused and if we are not going to accept a
1823
    # migrating instance. In the latter case, pausing is not needed.
1824
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1825
    if start_kvm_paused:
1826
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1827

    
1828
    # Note: CPU pinning is using up_hvp since changes take effect
1829
    # during instance startup anyway, and to avoid problems when soft
1830
    # rebooting the instance.
1831
    cpu_pinning = False
1832
    if up_hvp.get(constants.HV_CPU_MASK, None):
1833
      cpu_pinning = True
1834

    
1835
    if security_model == constants.HT_SM_POOL:
1836
      ss = ssconf.SimpleStore()
1837
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1838
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1839
      uid = uidpool.RequestUnusedUid(all_uids)
1840
      try:
1841
        username = pwd.getpwuid(uid.GetUid()).pw_name
1842
        kvm_cmd.extend(["-runas", username])
1843
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1844
      except:
1845
        uidpool.ReleaseUid(uid)
1846
        raise
1847
      else:
1848
        uid.Unlock()
1849
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1850
    else:
1851
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1852

    
1853
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1854
                     constants.RUN_DIRS_MODE)])
1855
    for nic_seq, tap in enumerate(taps):
1856
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1857
                      data=tap)
1858

    
1859
    if vnc_pwd:
1860
      change_cmd = "change vnc password %s" % vnc_pwd
1861
      self._CallMonitorCommand(instance.name, change_cmd)
1862

    
1863
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1864
    # connection attempts because SPICE by default does not allow connections
1865
    # if neither a password nor the "disable_ticketing" options are specified.
1866
    # As soon as we send the password via QMP, that password is a valid ticket
1867
    # for connection.
1868
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1869
    if spice_password_file:
1870
      spice_pwd = ""
1871
      try:
1872
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1873
      except EnvironmentError, err:
1874
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1875
                                     % (spice_password_file, err))
1876

    
1877
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1878
      qmp.connect()
1879
      arguments = {
1880
          "protocol": "spice",
1881
          "password": spice_pwd,
1882
      }
1883
      qmp.Execute("set_password", arguments)
1884

    
1885
    for filename in temp_files:
1886
      utils.RemoveFile(filename)
1887

    
1888
    # If requested, set CPU affinity and resume instance execution
1889
    if cpu_pinning:
1890
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1891

    
1892
    start_memory = self._InstanceStartupMemory(instance)
1893
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1894
      self.BalloonInstanceMemory(instance, start_memory)
1895

    
1896
    if start_kvm_paused:
1897
      # To control CPU pinning, ballooning, and vnc/spice passwords
1898
      # the VM was started in a frozen state. If freezing was not
1899
      # explicitly requested resume the vm status.
1900
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1901

    
1902
  def StartInstance(self, instance, block_devices, startup_paused):
1903
    """Start an instance.
1904

1905
    """
1906
    self._CheckDown(instance.name)
1907
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1908
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1909
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1910
                                           startup_paused, kvmhelp)
1911
    self._SaveKVMRuntime(instance, kvm_runtime)
1912
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1913

    
1914
  def _CallMonitorCommand(self, instance_name, command):
1915
    """Invoke a command on the instance monitor.
1916

1917
    """
1918
    # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1919
    # version. The monitor protocol is designed for human consumption, whereas
1920
    # QMP is made for programmatic usage. In the worst case QMP can also
1921
    # execute monitor commands. As it is, all calls to socat take at least
1922
    # 500ms and likely more: socat can't detect the end of the reply and waits
1923
    # for 500ms of no data received before exiting (500 ms is the default for
1924
    # the "-t" parameter).
1925
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1926
             (utils.ShellQuote(command),
1927
              constants.SOCAT_PATH,
1928
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1929
    result = utils.RunCmd(socat)
1930
    if result.failed:
1931
      msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1932
             " output: %s" %
1933
             (command, instance_name, result.fail_reason, result.output))
1934
      raise errors.HypervisorError(msg)
1935

    
1936
    return result
1937

    
1938
  def _GetFreePCISlot(self, instance, dev):
1939
    """Get the first available pci slot of a runnung instance.
1940

1941
    """
1942
    slots = bitarray(32)
1943
    slots.setall(False) # pylint: disable=E1101
1944
    output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
1945
    for line in output.stdout.splitlines():
1946
      match = self._INFO_PCI_RE.search(line)
1947
      if match:
1948
        slot = int(match.group(1))
1949
        slots[slot] = True
1950

    
1951
    [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
1952
    if not free:
1953
      raise errors.HypervisorError("All PCI slots occupied")
1954

    
1955
    dev.pci = int(free)
1956

    
1957
  def VerifyHotplugSupport(self, instance, action, dev_type):
1958
    """Check if hotplug is supported.
1959

1960
    Hotplug is *not* supported in case of:
1961
     - security models and chroot (disk hotplug)
1962
     - fdsend module is missing (nic hot-add)
1963

1964
    @raise errors.HypervisorError: in previous cases
1965

1966
    """
1967
    if dev_type == constants.HOTPLUG_TARGET_DISK:
1968
      hvp = instance.hvparams
1969
      security_model = hvp[constants.HV_SECURITY_MODEL]
1970
      use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
1971
      if use_chroot:
1972
        raise errors.HotplugError("Disk hotplug is not supported"
1973
                                  " in case of chroot.")
1974
      if security_model != constants.HT_SM_NONE:
1975
        raise errors.HotplugError("Disk Hotplug is not supported in case"
1976
                                  " security models are used.")
1977

    
1978
    if (dev_type == constants.HOTPLUG_TARGET_NIC and
1979
        action == constants.HOTPLUG_ACTION_ADD and not fdsend):
1980
      raise errors.HotplugError("Cannot hot-add NIC."
1981
                                " fdsend python module is missing.")
1982
    return True
1983

    
1984
  def HotplugSupported(self, instance):
1985
    """Checks if hotplug is generally supported.
1986

1987
    Hotplug is *not* supported in case of:
1988
     - qemu versions < 1.0
1989
     - for stopped instances
1990

1991
    @raise errors.HypervisorError: in one of the previous cases
1992

1993
    """
1994
    try:
1995
      output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
1996
    except errors.HypervisorError:
1997
      raise errors.HotplugError("Instance is probably down")
1998

    
1999
    # TODO: search for netdev_add, drive_add, device_add.....
2000
    match = self._INFO_VERSION_RE.search(output.stdout)
2001
    if not match:
2002
      raise errors.HotplugError("Cannot parse qemu version via monitor")
2003

    
2004
    v_major, v_min, _, _ = match.groups()
2005
    if (int(v_major), int(v_min)) < (1, 0):
2006
      raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2007

    
2008
  def _CallHotplugCommand(self, name, cmd):
2009
    output = self._CallMonitorCommand(name, cmd)
2010
    # TODO: parse output and check if succeeded
2011
    for line in output.stdout.splitlines():
2012
      logging.info("%s", line)
2013

    
2014
  def HotAddDevice(self, instance, dev_type, device, extra, seq):
2015
    """ Helper method to hot-add a new device
2016

2017
    It gets free pci slot generates the device name and invokes the
2018
    device specific method.
2019

2020
    """
2021
    # in case of hot-mod this is given
2022
    if device.pci is None:
2023
      self._GetFreePCISlot(instance, device)
2024
    kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2025
    runtime = self._LoadKVMRuntime(instance)
2026
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2027
      command = "drive_add dummy file=%s,if=none,id=%s,format=raw\n" % \
2028
                 (extra, kvm_devid)
2029
      command += ("device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
2030
                  (hex(device.pci), kvm_devid, kvm_devid))
2031
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
2032
      (tap, fd) = _OpenTap()
2033
      self._ConfigureNIC(instance, seq, device, tap)
2034
      self._PassTapFd(instance, fd, device)
2035
      command = "netdev_add tap,id=%s,fd=%s\n" % (kvm_devid, kvm_devid)
2036
      args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
2037
               (hex(device.pci), device.mac, kvm_devid, kvm_devid)
2038
      command += "device_add %s" % args
2039
      utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
2040

    
2041
    self._CallHotplugCommand(instance.name, command)
2042
    # update relevant entries in runtime file
2043
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2044
    entry = _RUNTIME_ENTRY[dev_type](device, extra)
2045
    runtime[index].append(entry)
2046
    self._SaveKVMRuntime(instance, runtime)
2047

    
2048
  def HotDelDevice(self, instance, dev_type, device, _, seq):
2049
    """ Helper method for hot-del device
2050

2051
    It gets device info from runtime file, generates the device name and
2052
    invokes the device specific method.
2053

2054
    """
2055
    runtime = self._LoadKVMRuntime(instance)
2056
    entry = _GetExistingDeviceInfo(dev_type, device, runtime)
2057
    kvm_device = _RUNTIME_DEVICE[dev_type](entry)
2058
    kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
2059
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2060
      command = "device_del %s\n" % kvm_devid
2061
      command += "drive_del %s" % kvm_devid
2062
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
2063
      command = "device_del %s\n" % kvm_devid
2064
      command += "netdev_del %s" % kvm_devid
2065
      utils.RemoveFile(self._InstanceNICFile(instance.name, seq))
2066
    self._CallHotplugCommand(instance.name, command)
2067
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2068
    runtime[index].remove(entry)
2069
    self._SaveKVMRuntime(instance, runtime)
2070

    
2071
    return kvm_device.pci
2072

    
2073
  def HotModDevice(self, instance, dev_type, device, _, seq):
2074
    """ Helper method for hot-mod device
2075

2076
    It gets device info from runtime file, generates the device name and
2077
    invokes the device specific method. Currently only NICs support hot-mod
2078

2079
    """
2080
    if dev_type == constants.HOTPLUG_TARGET_NIC:
2081
      # putting it back in the same pci slot
2082
      device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2083
      # TODO: remove sleep when socat gets removed
2084
      time.sleep(2)
2085
      self.HotAddDevice(instance, dev_type, device, _, seq)
2086

    
2087
  def _PassTapFd(self, instance, fd, nic):
2088
    """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2089

2090
    """
2091
    # TODO: factor out code related to unix sockets.
2092
    #       squash common parts between monitor and qmp
2093
    kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2094
    command = "getfd %s\n" % kvm_devid
2095
    fds = [fd]
2096
    logging.info("%s", fds)
2097
    try:
2098
      monsock = MonitorSocket(self._InstanceMonitor(instance.name))
2099
      monsock.connect()
2100
      fdsend.sendfds(monsock.sock, command, fds=fds)
2101
    finally:
2102
      monsock.close()
2103

    
2104
  @classmethod
2105
  def _ParseKVMVersion(cls, text):
2106
    """Parse the KVM version from the --help output.
2107

2108
    @type text: string
2109
    @param text: output of kvm --help
2110
    @return: (version, v_maj, v_min, v_rev)
2111
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2112

2113
    """
2114
    match = cls._VERSION_RE.search(text.splitlines()[0])
2115
    if not match:
2116
      raise errors.HypervisorError("Unable to get KVM version")
2117

    
2118
    v_all = match.group(0)
2119
    v_maj = int(match.group(1))
2120
    v_min = int(match.group(2))
2121
    if match.group(4):
2122
      v_rev = int(match.group(4))
2123
    else:
2124
      v_rev = 0
2125
    return (v_all, v_maj, v_min, v_rev)
2126

    
2127
  @classmethod
2128
  def _GetKVMOutput(cls, kvm_path, option):
2129
    """Return the output of a kvm invocation
2130

2131
    @type kvm_path: string
2132
    @param kvm_path: path to the kvm executable
2133
    @type option: a key of _KVMOPTS_CMDS
2134
    @param option: kvm option to fetch the output from
2135
    @return: output a supported kvm invocation
2136
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2137

2138
    """
2139
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2140

    
2141
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
2142

    
2143
    result = utils.RunCmd([kvm_path] + optlist)
2144
    if result.failed and not can_fail:
2145
      raise errors.HypervisorError("Unable to get KVM %s output" %
2146
                                    " ".join(cls._KVMOPTS_CMDS[option]))
2147
    return result.output
2148

    
2149
  @classmethod
2150
  def _GetKVMVersion(cls, kvm_path):
2151
    """Return the installed KVM version.
2152

2153
    @return: (version, v_maj, v_min, v_rev)
2154
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2155

2156
    """
2157
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2158

    
2159
  @classmethod
2160
  def _GetDefaultMachineVersion(cls, kvm_path):
2161
    """Return the default hardware revision (e.g. pc-1.1)
2162

2163
    """
2164
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2165
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2166
    if match:
2167
      return match.group(1)
2168
    else:
2169
      return "pc"
2170

    
2171
  def StopInstance(self, instance, force=False, retry=False, name=None):
2172
    """Stop an instance.
2173

2174
    """
2175
    if name is not None and not force:
2176
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2177
    if name is None:
2178
      name = instance.name
2179
      acpi = instance.hvparams[constants.HV_ACPI]
2180
    else:
2181
      acpi = False
2182
    _, pid, alive = self._InstancePidAlive(name)
2183
    if pid > 0 and alive:
2184
      if force or not acpi:
2185
        utils.KillProcess(pid)
2186
      else:
2187
        self._CallMonitorCommand(name, "system_powerdown")
2188

    
2189
  def CleanupInstance(self, instance_name):
2190
    """Cleanup after a stopped instance
2191

2192
    """
2193
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
2194
    if pid > 0 and alive:
2195
      raise errors.HypervisorError("Cannot cleanup a live instance")
2196
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2197

    
2198
  def RebootInstance(self, instance):
2199
    """Reboot an instance.
2200

2201
    """
2202
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2203
    # socket the instance will stop, but now power up again. So we'll resort
2204
    # to shutdown and restart.
2205
    _, _, alive = self._InstancePidAlive(instance.name)
2206
    if not alive:
2207
      raise errors.HypervisorError("Failed to reboot instance %s:"
2208
                                   " not running" % instance.name)
2209
    # StopInstance will delete the saved KVM runtime so:
2210
    # ...first load it...
2211
    kvm_runtime = self._LoadKVMRuntime(instance)
2212
    # ...now we can safely call StopInstance...
2213
    if not self.StopInstance(instance):
2214
      self.StopInstance(instance, force=True)
2215
    # ...and finally we can save it again, and execute it...
2216
    self._SaveKVMRuntime(instance, kvm_runtime)
2217
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2218
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2219
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2220

    
2221
  def MigrationInfo(self, instance):
2222
    """Get instance information to perform a migration.
2223

2224
    @type instance: L{objects.Instance}
2225
    @param instance: instance to be migrated
2226
    @rtype: string
2227
    @return: content of the KVM runtime file
2228

2229
    """
2230
    return self._ReadKVMRuntime(instance.name)
2231

    
2232
  def AcceptInstance(self, instance, info, target):
2233
    """Prepare to accept an instance.
2234

2235
    @type instance: L{objects.Instance}
2236
    @param instance: instance to be accepted
2237
    @type info: string
2238
    @param info: content of the KVM runtime file on the source node
2239
    @type target: string
2240
    @param target: target host (usually ip), on this node
2241

2242
    """
2243
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2244
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2245
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2246
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2247
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2248
                            incoming=incoming_address)
2249

    
2250
  def FinalizeMigrationDst(self, instance, info, success):
2251
    """Finalize the instance migration on the target node.
2252

2253
    Stop the incoming mode KVM.
2254

2255
    @type instance: L{objects.Instance}
2256
    @param instance: instance whose migration is being finalized
2257

2258
    """
2259
    if success:
2260
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2261
      kvm_nics = kvm_runtime[1]
2262

    
2263
      for nic_seq, nic in enumerate(kvm_nics):
2264
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2265
          # Bridged interfaces have already been configured
2266
          continue
2267
        try:
2268
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2269
        except EnvironmentError, err:
2270
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
2271
                          instance.name, nic_seq, str(err))
2272
          continue
2273
        try:
2274
          self._ConfigureNIC(instance, nic_seq, nic, tap)
2275
        except errors.HypervisorError, err:
2276
          logging.warning(str(err))
2277

    
2278
      self._WriteKVMRuntime(instance.name, info)
2279
    else:
2280
      self.StopInstance(instance, force=True)
2281

    
2282
  def MigrateInstance(self, instance, target, live):
2283
    """Migrate an instance to a target node.
2284

2285
    The migration will not be attempted if the instance is not
2286
    currently running.
2287

2288
    @type instance: L{objects.Instance}
2289
    @param instance: the instance to be migrated
2290
    @type target: string
2291
    @param target: ip address of the target node
2292
    @type live: boolean
2293
    @param live: perform a live migration
2294

2295
    """
2296
    instance_name = instance.name
2297
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
2298
    _, _, alive = self._InstancePidAlive(instance_name)
2299
    if not alive:
2300
      raise errors.HypervisorError("Instance not running, cannot migrate")
2301

    
2302
    if not live:
2303
      self._CallMonitorCommand(instance_name, "stop")
2304

    
2305
    migrate_command = ("migrate_set_speed %dm" %
2306
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2307
    self._CallMonitorCommand(instance_name, migrate_command)
2308

    
2309
    migrate_command = ("migrate_set_downtime %dms" %
2310
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2311
    self._CallMonitorCommand(instance_name, migrate_command)
2312

    
2313
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2314
    self._CallMonitorCommand(instance_name, migrate_command)
2315

    
2316
  def FinalizeMigrationSource(self, instance, success, live):
2317
    """Finalize the instance migration on the source node.
2318

2319
    @type instance: L{objects.Instance}
2320
    @param instance: the instance that was migrated
2321
    @type success: bool
2322
    @param success: whether the migration succeeded or not
2323
    @type live: bool
2324
    @param live: whether the user requested a live migration or not
2325

2326
    """
2327
    if success:
2328
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2329
      utils.KillProcess(pid)
2330
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2331
    elif live:
2332
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2333

    
2334
  def GetMigrationStatus(self, instance):
2335
    """Get the migration status
2336

2337
    @type instance: L{objects.Instance}
2338
    @param instance: the instance that is being migrated
2339
    @rtype: L{objects.MigrationStatus}
2340
    @return: the status of the current migration (one of
2341
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2342
             progress info that can be retrieved from the hypervisor
2343

2344
    """
2345
    info_command = "info migrate"
2346
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2347
      result = self._CallMonitorCommand(instance.name, info_command)
2348
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
2349
      if not match:
2350
        if not result.stdout:
2351
          logging.info("KVM: empty 'info migrate' result")
2352
        else:
2353
          logging.warning("KVM: unknown 'info migrate' result: %s",
2354
                          result.stdout)
2355
      else:
2356
        status = match.group(1)
2357
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2358
          migration_status = objects.MigrationStatus(status=status)
2359
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2360
          if match:
2361
            migration_status.transferred_ram = match.group("transferred")
2362
            migration_status.total_ram = match.group("total")
2363

    
2364
          return migration_status
2365

    
2366
        logging.warning("KVM: unknown migration status '%s'", status)
2367

    
2368
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2369

    
2370
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2371

    
2372
  def BalloonInstanceMemory(self, instance, mem):
2373
    """Balloon an instance memory to a certain value.
2374

2375
    @type instance: L{objects.Instance}
2376
    @param instance: instance to be accepted
2377
    @type mem: int
2378
    @param mem: actual memory size to use for instance runtime
2379

2380
    """
2381
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2382

    
2383
  def GetNodeInfo(self):
2384
    """Return information about the node.
2385

2386
    @return: a dict with the following keys (values in MiB):
2387
          - memory_total: the total memory size on the node
2388
          - memory_free: the available memory on the node for instances
2389
          - memory_dom0: the memory used by the node itself, if available
2390
          - hv_version: the hypervisor version in the form (major, minor,
2391
                        revision)
2392

2393
    """
2394
    result = self.GetLinuxNodeInfo()
2395
    # FIXME: this is the global kvm version, but the actual version can be
2396
    # customized as an hv parameter. we should use the nodegroup's default kvm
2397
    # path parameter here.
2398
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2399
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2400
    return result
2401

    
2402
  @classmethod
2403
  def GetInstanceConsole(cls, instance, hvparams, beparams):
2404
    """Return a command for connecting to the console of an instance.
2405

2406
    """
2407
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2408
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2409
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2410
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2411
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2412
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2413
      return objects.InstanceConsole(instance=instance.name,
2414
                                     kind=constants.CONS_SSH,
2415
                                     host=instance.primary_node,
2416
                                     user=constants.SSH_CONSOLE_USER,
2417
                                     command=cmd)
2418

    
2419
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2420
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2421
      display = instance.network_port - constants.VNC_BASE_PORT
2422
      return objects.InstanceConsole(instance=instance.name,
2423
                                     kind=constants.CONS_VNC,
2424
                                     host=vnc_bind_address,
2425
                                     port=instance.network_port,
2426
                                     display=display)
2427

    
2428
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2429
    if spice_bind:
2430
      return objects.InstanceConsole(instance=instance.name,
2431
                                     kind=constants.CONS_SPICE,
2432
                                     host=spice_bind,
2433
                                     port=instance.network_port)
2434

    
2435
    return objects.InstanceConsole(instance=instance.name,
2436
                                   kind=constants.CONS_MESSAGE,
2437
                                   message=("No serial shell for instance %s" %
2438
                                            instance.name))
2439

    
2440
  def Verify(self):
2441
    """Verify the hypervisor.
2442

2443
    Check that the required binaries exist.
2444

2445
    @return: Problem description if something is wrong, C{None} otherwise
2446

2447
    """
2448
    msgs = []
2449
    # FIXME: this is the global kvm binary, but the actual path can be
2450
    # customized as an hv parameter; we should use the nodegroup's
2451
    # default kvm path parameter here.
2452
    if not os.path.exists(constants.KVM_PATH):
2453
      msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2454
    if not os.path.exists(constants.SOCAT_PATH):
2455
      msgs.append("The socat binary ('%s') does not exist" %
2456
                  constants.SOCAT_PATH)
2457

    
2458
    return self._FormatVerifyResults(msgs)
2459

    
2460
  @classmethod
2461
  def CheckParameterSyntax(cls, hvparams):
2462
    """Check the given parameters for validity.
2463

2464
    @type hvparams:  dict
2465
    @param hvparams: dictionary with parameter names/value
2466
    @raise errors.HypervisorError: when a parameter is not valid
2467

2468
    """
2469
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2470

    
2471
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2472
    if kernel_path:
2473
      if not hvparams[constants.HV_ROOT_PATH]:
2474
        raise errors.HypervisorError("Need a root partition for the instance,"
2475
                                     " if a kernel is defined")
2476

    
2477
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2478
        not hvparams[constants.HV_VNC_X509]):
2479
      raise errors.HypervisorError("%s must be defined, if %s is" %
2480
                                   (constants.HV_VNC_X509,
2481
                                    constants.HV_VNC_X509_VERIFY))
2482

    
2483
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2484
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2485
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2486
      if not serial_speed or serial_speed not in valid_speeds:
2487
        raise errors.HypervisorError("Invalid serial console speed, must be"
2488
                                     " one of: %s" %
2489
                                     utils.CommaJoin(valid_speeds))
2490

    
2491
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2492
    if (boot_order == constants.HT_BO_CDROM and
2493
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2494
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2495
                                   " ISO path")
2496

    
2497
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2498
    if security_model == constants.HT_SM_USER:
2499
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2500
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2501
                                     " must be specified")
2502
    elif (security_model == constants.HT_SM_NONE or
2503
          security_model == constants.HT_SM_POOL):
2504
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2505
        raise errors.HypervisorError("Cannot have a security domain when the"
2506
                                     " security model is 'none' or 'pool'")
2507

    
2508
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2509
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2510
    if spice_bind:
2511
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2512
        # if an IP version is specified, the spice_bind parameter must be an
2513
        # IP of that family
2514
        if (netutils.IP4Address.IsValid(spice_bind) and
2515
            spice_ip_version != constants.IP4_VERSION):
2516
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2517
                                       " the specified IP version is %s" %
2518
                                       (spice_bind, spice_ip_version))
2519

    
2520
        if (netutils.IP6Address.IsValid(spice_bind) and
2521
            spice_ip_version != constants.IP6_VERSION):
2522
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2523
                                       " the specified IP version is %s" %
2524
                                       (spice_bind, spice_ip_version))
2525
    else:
2526
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2527
      # error if any of them is set without it.
2528
      for param in _SPICE_ADDITIONAL_PARAMS:
2529
        if hvparams[param]:
2530
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2531
                                       (param, constants.HV_KVM_SPICE_BIND))
2532

    
2533
  @classmethod
2534
  def ValidateParameters(cls, hvparams):
2535
    """Check the given parameters for validity.
2536

2537
    @type hvparams:  dict
2538
    @param hvparams: dictionary with parameter names/value
2539
    @raise errors.HypervisorError: when a parameter is not valid
2540

2541
    """
2542
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2543

    
2544
    kvm_path = hvparams[constants.HV_KVM_PATH]
2545

    
2546
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2547
    if security_model == constants.HT_SM_USER:
2548
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2549
      try:
2550
        pwd.getpwnam(username)
2551
      except KeyError:
2552
        raise errors.HypervisorError("Unknown security domain user %s"
2553
                                     % username)
2554

    
2555
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2556
    if spice_bind:
2557
      # only one of VNC and SPICE can be used currently.
2558
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2559
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2560
                                     " only one of them can be used at a"
2561
                                     " given time")
2562

    
2563
      # check that KVM supports SPICE
2564
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2565
      if not cls._SPICE_RE.search(kvmhelp):
2566
        raise errors.HypervisorError("SPICE is configured, but it is not"
2567
                                     " supported according to 'kvm --help'")
2568

    
2569
      # if spice_bind is not an IP address, it must be a valid interface
2570
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2571
                       netutils.IP6Address.IsValid(spice_bind))
2572
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2573
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2574
                                     " a valid IP address or interface name" %
2575
                                     constants.HV_KVM_SPICE_BIND)
2576

    
2577
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2578
    if machine_version:
2579
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2580
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2581
        raise errors.HypervisorError("Unsupported machine version: %s" %
2582
                                     machine_version)
2583

    
2584
  @classmethod
2585
  def PowercycleNode(cls):
2586
    """KVM powercycle, just a wrapper over Linux powercycle.
2587

2588
    """
2589
    cls.LinuxPowercycle()