Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 191cc0d6

History | View | Annotate | Download (87.5 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
def _GenerateDeviceKVMId(dev_type, dev):
117
  """Helper function to generate a unique device name used by KVM
118

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

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

129
  """
130

    
131
  if not dev.pci:
132
    raise errors.HotplugError("Hotplug is not supported for %s with UUID %s" %
133
                              (dev_type, dev.uuid))
134

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

    
137

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

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

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

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

    
160
  pci_reservations[free] = True
161

    
162

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

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

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

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

    
186
  return found[0]
187

    
188

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

192
  @see: L{_ProbeTapVnetHdr}
193

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

    
205

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

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

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

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

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

    
229
  result = bool(flags & IFF_VNET_HDR)
230

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

    
234
  return result
235

    
236

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

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

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

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

    
254
  flags = IFF_TAP | IFF_NO_PI
255

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

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

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

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

    
272

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

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

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

    
284
    self.data = data
285

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

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

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

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

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

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

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

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

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

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

    
326

    
327
class QmpConnection:
328
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
329

330
  """
331
  _FIRST_MESSAGE_KEY = "QMP"
332
  _EVENT_KEY = "event"
333
  _ERROR_KEY = "error"
334
  _RETURN_KEY = RETURN_KEY = "return"
335
  _ACTUAL_KEY = ACTUAL_KEY = "actual"
336
  _ERROR_CLASS_KEY = "class"
337
  _ERROR_DATA_KEY = "data"
338
  _ERROR_DESC_KEY = "desc"
339
  _EXECUTE_KEY = "execute"
340
  _ARGUMENTS_KEY = "arguments"
341
  _CAPABILITIES_COMMAND = "qmp_capabilities"
342
  _MESSAGE_END_TOKEN = "\r\n"
343
  _SOCKET_TIMEOUT = 5
344

    
345
  def __init__(self, monitor_filename):
346
    """Instantiates the QmpConnection object.
347

348
    @type monitor_filename: string
349
    @param monitor_filename: the filename of the UNIX raw socket on which the
350
                             QMP monitor is listening
351

352
    """
353
    self.monitor_filename = monitor_filename
354
    self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
355
    # We want to fail if the server doesn't send a complete message
356
    # in a reasonable amount of time
357
    self.sock.settimeout(self._SOCKET_TIMEOUT)
358
    self._connected = False
359
    self._buf = ""
360

    
361
  def _check_socket(self):
362
    sock_stat = None
363
    try:
364
      sock_stat = os.stat(self.monitor_filename)
365
    except EnvironmentError, err:
366
      if err.errno == errno.ENOENT:
367
        raise errors.HypervisorError("No qmp socket found")
368
      else:
369
        raise errors.HypervisorError("Error checking qmp socket: %s",
370
                                     utils.ErrnoOrStr(err))
371
    if not stat.S_ISSOCK(sock_stat.st_mode):
372
      raise errors.HypervisorError("Qmp socket is not a socket")
373

    
374
  def _check_connection(self):
375
    """Make sure that the connection is established.
376

377
    """
378
    if not self._connected:
379
      raise errors.ProgrammerError("To use a QmpConnection you need to first"
380
                                   " invoke connect() on it")
381

    
382
  def connect(self):
383
    """Connects to the QMP monitor.
384

385
    Connects to the UNIX socket and makes sure that we can actually send and
386
    receive data to the kvm instance via QMP.
387

388
    @raise errors.HypervisorError: when there are communication errors
389
    @raise errors.ProgrammerError: when there are data serialization errors
390

391
    """
392
    if self._connected:
393
      raise errors.ProgrammerError("Cannot connect twice")
394

    
395
    self._check_socket()
396

    
397
    # Check file existance/stuff
398
    try:
399
      self.sock.connect(self.monitor_filename)
400
    except EnvironmentError:
401
      raise errors.HypervisorError("Can't connect to qmp socket")
402
    self._connected = True
403

    
404
    # Check if we receive a correct greeting message from the server
405
    # (As per the QEMU Protocol Specification 0.1 - section 2.2)
406
    greeting = self._Recv()
407
    if not greeting[self._FIRST_MESSAGE_KEY]:
408
      self._connected = False
409
      raise errors.HypervisorError("kvm: QMP communication error (wrong"
410
                                   " server greeting")
411

    
412
    # Let's put the monitor in command mode using the qmp_capabilities
413
    # command, or else no command will be executable.
414
    # (As per the QEMU Protocol Specification 0.1 - section 4)
415
    self.Execute(self._CAPABILITIES_COMMAND)
416

    
417
  def _ParseMessage(self, buf):
418
    """Extract and parse a QMP message from the given buffer.
419

420
    Seeks for a QMP message in the given buf. If found, it parses it and
421
    returns it together with the rest of the characters in the buf.
422
    If no message is found, returns None and the whole buffer.
423

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

426
    """
427
    message = None
428
    # Check if we got the message end token (CRLF, as per the QEMU Protocol
429
    # Specification 0.1 - Section 2.1.1)
430
    pos = buf.find(self._MESSAGE_END_TOKEN)
431
    if pos >= 0:
432
      try:
433
        message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
434
      except Exception, err:
435
        raise errors.ProgrammerError("QMP data serialization error: %s" % err)
436
      buf = buf[pos + 1:]
437

    
438
    return (message, buf)
439

    
440
  def _Recv(self):
441
    """Receives a message from QMP and decodes the received JSON object.
442

443
    @rtype: QmpMessage
444
    @return: the received message
445
    @raise errors.HypervisorError: when there are communication errors
446
    @raise errors.ProgrammerError: when there are data serialization errors
447

448
    """
449
    self._check_connection()
450

    
451
    # Check if there is already a message in the buffer
452
    (message, self._buf) = self._ParseMessage(self._buf)
453
    if message:
454
      return message
455

    
456
    recv_buffer = StringIO.StringIO(self._buf)
457
    recv_buffer.seek(len(self._buf))
458
    try:
459
      while True:
460
        data = self.sock.recv(4096)
461
        if not data:
462
          break
463
        recv_buffer.write(data)
464

    
465
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
466
        if message:
467
          return message
468

    
469
    except socket.timeout, err:
470
      raise errors.HypervisorError("Timeout while receiving a QMP message: "
471
                                   "%s" % (err))
472
    except socket.error, err:
473
      raise errors.HypervisorError("Unable to receive data from KVM using the"
474
                                   " QMP protocol: %s" % err)
475

    
476
  def _Send(self, message):
477
    """Encodes and sends a message to KVM using QMP.
478

479
    @type message: QmpMessage
480
    @param message: message to send to KVM
481
    @raise errors.HypervisorError: when there are communication errors
482
    @raise errors.ProgrammerError: when there are data serialization errors
483

484
    """
485
    self._check_connection()
486
    try:
487
      message_str = str(message)
488
    except Exception, err:
489
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
490

    
491
    try:
492
      self.sock.sendall(message_str)
493
    except socket.timeout, err:
494
      raise errors.HypervisorError("Timeout while sending a QMP message: "
495
                                   "%s (%s)" % (err.string, err.errno))
496
    except socket.error, err:
497
      raise errors.HypervisorError("Unable to send data from KVM using the"
498
                                   " QMP protocol: %s" % err)
499

    
500
  def Execute(self, command, arguments=None):
501
    """Executes a QMP command and returns the response of the server.
502

503
    @type command: str
504
    @param command: the command to execute
505
    @type arguments: dict
506
    @param arguments: dictionary of arguments to be passed to the command
507
    @rtype: dict
508
    @return: dictionary representing the received JSON object
509
    @raise errors.HypervisorError: when there are communication errors
510
    @raise errors.ProgrammerError: when there are data serialization errors
511

512
    """
513
    self._check_connection()
514
    message = QmpMessage({self._EXECUTE_KEY: command})
515
    if arguments:
516
      message[self._ARGUMENTS_KEY] = arguments
517
    self._Send(message)
518

    
519
    # Events can occur between the sending of the command and the reception
520
    # of the response, so we need to filter out messages with the event key.
521
    while True:
522
      response = self._Recv()
523
      err = response[self._ERROR_KEY]
524
      if err:
525
        raise errors.HypervisorError("kvm: error executing the %s"
526
                                     " command: %s (%s, %s):" %
527
                                     (command,
528
                                      err[self._ERROR_DESC_KEY],
529
                                      err[self._ERROR_CLASS_KEY],
530
                                      err[self._ERROR_DATA_KEY]))
531

    
532
      elif not response[self._EVENT_KEY]:
533
        return response
534

    
535

    
536
class KVMHypervisor(hv_base.BaseHypervisor):
537
  """KVM hypervisor interface
538

539
  """
540
  CAN_MIGRATE = True
541

    
542
  _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
543
  _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
544
  _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
545
  _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
546
  _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
547
  _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
548
  _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
549
  # KVM instances with chroot enabled are started in empty chroot directories.
550
  _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
551
  # After an instance is stopped, its chroot directory is removed.
552
  # If the chroot directory is not empty, it can't be removed.
553
  # A non-empty chroot directory indicates a possible security incident.
554
  # To support forensics, the non-empty chroot directory is quarantined in
555
  # a separate directory, called 'chroot-quarantine'.
556
  _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
557
  _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
558
           _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
559

    
560
  PARAMETERS = {
561
    constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
562
    constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
563
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
564
    constants.HV_ROOT_PATH: hv_base.NO_CHECK,
565
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
566
    constants.HV_ACPI: hv_base.NO_CHECK,
567
    constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
568
    constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
569
    constants.HV_VNC_BIND_ADDRESS: hv_base.NO_CHECK, # will be checked later
570
    constants.HV_VNC_TLS: hv_base.NO_CHECK,
571
    constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
572
    constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
573
    constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
574
    constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
575
    constants.HV_KVM_SPICE_IP_VERSION:
576
      (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
577
                         x in constants.VALID_IP_VERSIONS),
578
       "The SPICE IP version should be 4 or 6",
579
       None, None),
580
    constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
581
    constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
582
      hv_base.ParamInSet(
583
        False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
584
    constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
585
      hv_base.ParamInSet(
586
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
587
    constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
588
      hv_base.ParamInSet(
589
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
590
    constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
591
      hv_base.ParamInSet(
592
        False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
593
    constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
594
    constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
595
    constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
596
    constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
597
    constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
598
    constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
599
    constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
600
    constants.HV_BOOT_ORDER:
601
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
602
    constants.HV_NIC_TYPE:
603
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
604
    constants.HV_DISK_TYPE:
605
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
606
    constants.HV_KVM_CDROM_DISK_TYPE:
607
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
608
    constants.HV_USB_MOUSE:
609
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
610
    constants.HV_KEYMAP: hv_base.NO_CHECK,
611
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
612
    constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
613
    constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
614
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
615
    constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
616
    constants.HV_DISK_CACHE:
617
      hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
618
    constants.HV_SECURITY_MODEL:
619
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
620
    constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
621
    constants.HV_KVM_FLAG:
622
      hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
623
    constants.HV_VHOST_NET: hv_base.NO_CHECK,
624
    constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
625
    constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
626
    constants.HV_REBOOT_BEHAVIOR:
627
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
628
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
629
    constants.HV_CPU_TYPE: hv_base.NO_CHECK,
630
    constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
631
    constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
632
    constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
633
    constants.HV_SOUNDHW: hv_base.NO_CHECK,
634
    constants.HV_USB_DEVICES: hv_base.NO_CHECK,
635
    constants.HV_VGA: hv_base.NO_CHECK,
636
    constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
637
    constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
638
    }
639

    
640
  _VIRTIO = "virtio"
641
  _VIRTIO_NET_PCI = "virtio-net-pci"
642
  _VIRTIO_BLK_PCI = "virtio-blk-pci"
643

    
644
  _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
645
                                    re.M | re.I)
646
  _MIGRATION_PROGRESS_RE = \
647
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
648
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
649
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
650

    
651
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
652
  _MIGRATION_INFO_RETRY_DELAY = 2
653

    
654
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
655

    
656
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
657
  _CPU_INFO_CMD = "info cpus"
658
  _CONT_CMD = "cont"
659

    
660
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
661
  _CHECK_MACHINE_VERSION_RE = \
662
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
663

    
664
  _QMP_RE = re.compile(r"^-qmp\s", re.M)
665
  _SPICE_RE = re.compile(r"^-spice\s", re.M)
666
  _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
667
  _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
668
  _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
669
  _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
670
  _DISPLAY_RE = re.compile(r"^-display\s", re.M)
671
  _MACHINE_RE = re.compile(r"^-machine\s", re.M)
672
  _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
673
  _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M)
674
  # match  -drive.*boot=on|off on different lines, but in between accept only
675
  # dashes not preceeded by a new line (which would mean another option
676
  # different than -drive is starting)
677
  _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
678
  _UUID_RE = re.compile(r"^-uuid\s", re.M)
679

    
680
  _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
681
  _INFO_PCI_CMD = "info pci"
682
  _INFO_VERSION_RE = \
683
    re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
684
  _INFO_VERSION_CMD = "info version"
685

    
686
  _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
687

    
688
  ANCILLARY_FILES = [
689
    _KVM_NETWORK_SCRIPT,
690
    ]
691
  ANCILLARY_FILES_OPT = [
692
    _KVM_NETWORK_SCRIPT,
693
    ]
694

    
695
  # Supported kvm options to get output from
696
  _KVMOPT_HELP = "help"
697
  _KVMOPT_MLIST = "mlist"
698
  _KVMOPT_DEVICELIST = "devicelist"
699

    
700
  # Command to execute to get the output from kvm, and whether to
701
  # accept the output even on failure.
702
  _KVMOPTS_CMDS = {
703
    _KVMOPT_HELP: (["--help"], False),
704
    _KVMOPT_MLIST: (["-M", "?"], False),
705
    _KVMOPT_DEVICELIST: (["-device", "?"], True),
706
  }
707

    
708
  def __init__(self):
709
    hv_base.BaseHypervisor.__init__(self)
710
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
711
    # in a tmpfs filesystem or has been otherwise wiped out.
712
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
713
    utils.EnsureDirs(dirs)
714

    
715
  @classmethod
716
  def _InstancePidFile(cls, instance_name):
717
    """Returns the instance pidfile.
718

719
    """
720
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
721

    
722
  @classmethod
723
  def _InstanceUidFile(cls, instance_name):
724
    """Returns the instance uidfile.
725

726
    """
727
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
728

    
729
  @classmethod
730
  def _InstancePidInfo(cls, pid):
731
    """Check pid file for instance information.
732

733
    Check that a pid file is associated with an instance, and retrieve
734
    information from its command line.
735

736
    @type pid: string or int
737
    @param pid: process id of the instance to check
738
    @rtype: tuple
739
    @return: (instance_name, memory, vcpus)
740
    @raise errors.HypervisorError: when an instance cannot be found
741

742
    """
743
    alive = utils.IsProcessAlive(pid)
744
    if not alive:
745
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
746

    
747
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
748
    try:
749
      cmdline = utils.ReadFile(cmdline_file)
750
    except EnvironmentError, err:
751
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
752
                                   (pid, err))
753

    
754
    instance = None
755
    memory = 0
756
    vcpus = 0
757

    
758
    arg_list = cmdline.split("\x00")
759
    while arg_list:
760
      arg = arg_list.pop(0)
761
      if arg == "-name":
762
        instance = arg_list.pop(0)
763
      elif arg == "-m":
764
        memory = int(arg_list.pop(0))
765
      elif arg == "-smp":
766
        vcpus = int(arg_list.pop(0).split(",")[0])
767

    
768
    if instance is None:
769
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
770
                                   " instance" % pid)
771

    
772
    return (instance, memory, vcpus)
773

    
774
  def _InstancePidAlive(self, instance_name):
775
    """Returns the instance pidfile, pid, and liveness.
776

777
    @type instance_name: string
778
    @param instance_name: instance name
779
    @rtype: tuple
780
    @return: (pid file name, pid, liveness)
781

782
    """
783
    pidfile = self._InstancePidFile(instance_name)
784
    pid = utils.ReadPidFile(pidfile)
785

    
786
    alive = False
787
    try:
788
      cmd_instance = self._InstancePidInfo(pid)[0]
789
      alive = (cmd_instance == instance_name)
790
    except errors.HypervisorError:
791
      pass
792

    
793
    return (pidfile, pid, alive)
794

    
795
  def _CheckDown(self, instance_name):
796
    """Raises an error unless the given instance is down.
797

798
    """
799
    alive = self._InstancePidAlive(instance_name)[2]
800
    if alive:
801
      raise errors.HypervisorError("Failed to start instance %s: %s" %
802
                                   (instance_name, "already running"))
803

    
804
  @classmethod
805
  def _InstanceMonitor(cls, instance_name):
806
    """Returns the instance monitor socket name
807

808
    """
809
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
810

    
811
  @classmethod
812
  def _InstanceSerial(cls, instance_name):
813
    """Returns the instance serial socket name
814

815
    """
816
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
817

    
818
  @classmethod
819
  def _InstanceQmpMonitor(cls, instance_name):
820
    """Returns the instance serial QMP socket name
821

822
    """
823
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
824

    
825
  @staticmethod
826
  def _SocatUnixConsoleParams():
827
    """Returns the correct parameters for socat
828

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

831
    """
832
    if constants.SOCAT_USE_ESCAPE:
833
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
834
    else:
835
      return "echo=0,icanon=0"
836

    
837
  @classmethod
838
  def _InstanceKVMRuntime(cls, instance_name):
839
    """Returns the instance KVM runtime filename
840

841
    """
842
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
843

    
844
  @classmethod
845
  def _InstanceChrootDir(cls, instance_name):
846
    """Returns the name of the KVM chroot dir of the instance
847

848
    """
849
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
850

    
851
  @classmethod
852
  def _InstanceNICDir(cls, instance_name):
853
    """Returns the name of the directory holding the tap device files for a
854
    given instance.
855

856
    """
857
    return utils.PathJoin(cls._NICS_DIR, instance_name)
858

    
859
  @classmethod
860
  def _InstanceNICFile(cls, instance_name, seq):
861
    """Returns the name of the file containing the tap device for a given NIC
862

863
    """
864
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
865

    
866
  @classmethod
867
  def _InstanceKeymapFile(cls, instance_name):
868
    """Returns the name of the file containing the keymap for a given instance
869

870
    """
871
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
872

    
873
  @classmethod
874
  def _TryReadUidFile(cls, uid_file):
875
    """Try to read a uid file
876

877
    """
878
    if os.path.exists(uid_file):
879
      try:
880
        uid = int(utils.ReadOneLineFile(uid_file))
881
        return uid
882
      except EnvironmentError:
883
        logging.warning("Can't read uid file", exc_info=True)
884
      except (TypeError, ValueError):
885
        logging.warning("Can't parse uid file contents", exc_info=True)
886
    return None
887

    
888
  @classmethod
889
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
890
    """Removes an instance's rutime sockets/files/dirs.
891

892
    """
893
    utils.RemoveFile(pidfile)
894
    utils.RemoveFile(cls._InstanceMonitor(instance_name))
895
    utils.RemoveFile(cls._InstanceSerial(instance_name))
896
    utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
897
    utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
898
    utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
899
    uid_file = cls._InstanceUidFile(instance_name)
900
    uid = cls._TryReadUidFile(uid_file)
901
    utils.RemoveFile(uid_file)
902
    if uid is not None:
903
      uidpool.ReleaseUid(uid)
904
    try:
905
      shutil.rmtree(cls._InstanceNICDir(instance_name))
906
    except OSError, err:
907
      if err.errno != errno.ENOENT:
908
        raise
909
    try:
910
      chroot_dir = cls._InstanceChrootDir(instance_name)
911
      utils.RemoveDir(chroot_dir)
912
    except OSError, err:
913
      if err.errno == errno.ENOTEMPTY:
914
        # The chroot directory is expected to be empty, but it isn't.
915
        new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
916
                                          prefix="%s-%s-" %
917
                                          (instance_name,
918
                                           utils.TimestampForFilename()))
919
        logging.warning("The chroot directory of instance %s can not be"
920
                        " removed as it is not empty. Moving it to the"
921
                        " quarantine instead. Please investigate the"
922
                        " contents (%s) and clean up manually",
923
                        instance_name, new_chroot_dir)
924
        utils.RenameFile(chroot_dir, new_chroot_dir)
925
      else:
926
        raise
927

    
928
  @staticmethod
929
  def _ConfigureNIC(instance, seq, nic, tap):
930
    """Run the network configuration script for a specified NIC
931

932
    @param instance: instance we're acting on
933
    @type instance: instance object
934
    @param seq: nic sequence number
935
    @type seq: int
936
    @param nic: nic we're acting on
937
    @type nic: nic object
938
    @param tap: the host's tap interface this NIC corresponds to
939
    @type tap: str
940

941
    """
942
    if instance.tags:
943
      tags = " ".join(instance.tags)
944
    else:
945
      tags = ""
946

    
947
    env = {
948
      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
949
      "INSTANCE": instance.name,
950
      "MAC": nic.mac,
951
      "MODE": nic.nicparams[constants.NIC_MODE],
952
      "INTERFACE": tap,
953
      "INTERFACE_INDEX": str(seq),
954
      "TAGS": tags,
955
    }
956

    
957
    if nic.ip:
958
      env["IP"] = nic.ip
959

    
960
    if nic.nicparams[constants.NIC_LINK]:
961
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
962

    
963
    if nic.network:
964
      n = objects.Network.FromDict(nic.netinfo)
965
      env.update(n.HooksDict())
966

    
967
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
968
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
969

    
970
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
971
    if result.failed:
972
      raise errors.HypervisorError("Failed to configure interface %s: %s;"
973
                                   " network configuration script output: %s" %
974
                                   (tap, result.fail_reason, result.output))
975

    
976
  @staticmethod
977
  def _VerifyAffinityPackage():
978
    if affinity is None:
979
      raise errors.HypervisorError("affinity Python package not"
980
                                   " found; cannot use CPU pinning under KVM")
981

    
982
  @staticmethod
983
  def _BuildAffinityCpuMask(cpu_list):
984
    """Create a CPU mask suitable for sched_setaffinity from a list of
985
    CPUs.
986

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

990
    @type cpu_list: list of int
991
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
992
    @rtype: int
993
    @return: a bit mask of CPU affinities
994

995
    """
996
    if cpu_list == constants.CPU_PINNING_OFF:
997
      return constants.CPU_PINNING_ALL_KVM
998
    else:
999
      return sum(2 ** cpu for cpu in cpu_list)
1000

    
1001
  @classmethod
1002
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
1003
    """Change CPU affinity for running VM according to given CPU mask.
1004

1005
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
1006
    @type cpu_mask: string
1007
    @param process_id: process ID of KVM process. Used to pin entire VM
1008
                       to physical CPUs.
1009
    @type process_id: int
1010
    @param thread_dict: map of virtual CPUs to KVM thread IDs
1011
    @type thread_dict: dict int:int
1012

1013
    """
1014
    # Convert the string CPU mask to a list of list of int's
1015
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
1016

    
1017
    if len(cpu_list) == 1:
1018
      all_cpu_mapping = cpu_list[0]
1019
      if all_cpu_mapping == constants.CPU_PINNING_OFF:
1020
        # If CPU pinning has 1 entry that's "all", then do nothing
1021
        pass
1022
      else:
1023
        # If CPU pinning has one non-all entry, map the entire VM to
1024
        # one set of physical CPUs
1025
        cls._VerifyAffinityPackage()
1026
        affinity.set_process_affinity_mask(
1027
          process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
1028
    else:
1029
      # The number of vCPUs mapped should match the number of vCPUs
1030
      # reported by KVM. This was already verified earlier, so
1031
      # here only as a sanity check.
1032
      assert len(thread_dict) == len(cpu_list)
1033
      cls._VerifyAffinityPackage()
1034

    
1035
      # For each vCPU, map it to the proper list of physical CPUs
1036
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1037
        affinity.set_process_affinity_mask(thread_dict[i],
1038
                                           cls._BuildAffinityCpuMask(vcpu))
1039

    
1040
  def _GetVcpuThreadIds(self, instance_name):
1041
    """Get a mapping of vCPU no. to thread IDs for the instance
1042

1043
    @type instance_name: string
1044
    @param instance_name: instance in question
1045
    @rtype: dictionary of int:int
1046
    @return: a dictionary mapping vCPU numbers to thread IDs
1047

1048
    """
1049
    result = {}
1050
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1051
    for line in output.stdout.splitlines():
1052
      match = self._CPU_INFO_RE.search(line)
1053
      if not match:
1054
        continue
1055
      grp = map(int, match.groups())
1056
      result[grp[0]] = grp[1]
1057

    
1058
    return result
1059

    
1060
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1061
    """Complete CPU pinning.
1062

1063
    @type instance_name: string
1064
    @param instance_name: name of instance
1065
    @type cpu_mask: string
1066
    @param cpu_mask: CPU pinning mask as entered by user
1067

1068
    """
1069
    # Get KVM process ID, to be used if need to pin entire VM
1070
    _, pid, _ = self._InstancePidAlive(instance_name)
1071
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1072
    thread_dict = self._GetVcpuThreadIds(instance_name)
1073
    # Run CPU pinning, based on configured mask
1074
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1075

    
1076
  def ListInstances(self, hvparams=None):
1077
    """Get the list of running instances.
1078

1079
    We can do this by listing our live instances directory and
1080
    checking whether the associated kvm process is still alive.
1081

1082
    """
1083
    result = []
1084
    for name in os.listdir(self._PIDS_DIR):
1085
      if self._InstancePidAlive(name)[2]:
1086
        result.append(name)
1087
    return result
1088

    
1089
  def GetInstanceInfo(self, instance_name, hvparams=None):
1090
    """Get instance properties.
1091

1092
    @type instance_name: string
1093
    @param instance_name: the instance name
1094
    @type hvparams: dict of strings
1095
    @param hvparams: hvparams to be used with this instance
1096
    @rtype: tuple of strings
1097
    @return: (name, id, memory, vcpus, stat, times)
1098

1099
    """
1100
    _, pid, alive = self._InstancePidAlive(instance_name)
1101
    if not alive:
1102
      return None
1103

    
1104
    _, memory, vcpus = self._InstancePidInfo(pid)
1105
    istat = "---b-"
1106
    times = "0"
1107

    
1108
    try:
1109
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1110
      qmp.connect()
1111
      vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1112
      # Will fail if ballooning is not enabled, but we can then just resort to
1113
      # the value above.
1114
      mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1115
      memory = mem_bytes / 1048576
1116
    except errors.HypervisorError:
1117
      pass
1118

    
1119
    return (instance_name, pid, memory, vcpus, istat, times)
1120

    
1121
  def GetAllInstancesInfo(self, hvparams=None):
1122
    """Get properties of all instances.
1123

1124
    @type hvparams: dict of strings
1125
    @param hvparams: hypervisor parameter
1126
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1127

1128
    """
1129
    data = []
1130
    for name in os.listdir(self._PIDS_DIR):
1131
      try:
1132
        info = self.GetInstanceInfo(name)
1133
      except errors.HypervisorError:
1134
        # Ignore exceptions due to instances being shut down
1135
        continue
1136
      if info:
1137
        data.append(info)
1138
    return data
1139

    
1140
  def _GenerateKVMBlockDevicesOptions(self, instance, block_devices,
1141
                                      kvmhelp, kvm_path):
1142

    
1143
    hvp = instance.hvparams
1144
    boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1145

    
1146
    # whether this is an older KVM version that uses the boot=on flag
1147
    # on devices
1148
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1149

    
1150
    dev_opts = []
1151
    device_driver = None
1152
    disk_type = hvp[constants.HV_DISK_TYPE]
1153
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
1154
      if_val = ",if=%s" % self._VIRTIO
1155
      try:
1156
        devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1157
        if self._VIRTIO_BLK_RE.search(devlist):
1158
          # TODO: uncomment when -device is used
1159
          # if_val = ",if=none"
1160
          # will be passed in -device option as driver
1161
          device_driver = self._VIRTIO_BLK_PCI
1162
      except errors.HypervisorError, _:
1163
        pass
1164
    else:
1165
      if_val = ",if=%s" % disk_type
1166
    # Cache mode
1167
    disk_cache = hvp[constants.HV_DISK_CACHE]
1168
    if instance.disk_template in constants.DTS_EXT_MIRROR:
1169
      if disk_cache != "none":
1170
        # TODO: make this a hard error, instead of a silent overwrite
1171
        logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1172
                        " to prevent shared storage corruption on migration",
1173
                        disk_cache)
1174
      cache_val = ",cache=none"
1175
    elif disk_cache != constants.HT_CACHE_DEFAULT:
1176
      cache_val = ",cache=%s" % disk_cache
1177
    else:
1178
      cache_val = ""
1179
    for cfdev, dev_path in block_devices:
1180
      if cfdev.mode != constants.DISK_RDWR:
1181
        raise errors.HypervisorError("Instance has read-only disks which"
1182
                                     " are not supported by KVM")
1183
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
1184
      boot_val = ""
1185
      if boot_disk:
1186
        dev_opts.extend(["-boot", "c"])
1187
        boot_disk = False
1188
        if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1189
          boot_val = ",boot=on"
1190
      drive_val = "file=%s,format=raw%s%s%s" % \
1191
                  (dev_path, if_val, boot_val, cache_val)
1192

    
1193
      if device_driver:
1194
        pass
1195
      dev_opts.extend(["-drive", drive_val])
1196

    
1197
    return dev_opts
1198

    
1199
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1200
                          kvmhelp):
1201
    """Generate KVM information to start an instance.
1202

1203
    @type kvmhelp: string
1204
    @param kvmhelp: output of kvm --help
1205
    @attention: this function must not have any side-effects; for
1206
        example, it must not write to the filesystem, or read values
1207
        from the current system the are expected to differ between
1208
        nodes, since it is only run once at instance startup;
1209
        actions/kvm arguments that can vary between systems should be
1210
        done in L{_ExecuteKVMRuntime}
1211

1212
    """
1213
    # pylint: disable=R0912,R0914,R0915
1214
    hvp = instance.hvparams
1215
    self.ValidateParameters(hvp)
1216

    
1217
    pidfile = self._InstancePidFile(instance.name)
1218
    kvm = hvp[constants.HV_KVM_PATH]
1219
    kvm_cmd = [kvm]
1220
    # used just by the vnc server, if enabled
1221
    kvm_cmd.extend(["-name", instance.name])
1222
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1223

    
1224
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1225
    if hvp[constants.HV_CPU_CORES]:
1226
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1227
    if hvp[constants.HV_CPU_THREADS]:
1228
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1229
    if hvp[constants.HV_CPU_SOCKETS]:
1230
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1231

    
1232
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1233

    
1234
    kvm_cmd.extend(["-pidfile", pidfile])
1235
    kvm_cmd.extend(["-balloon", "virtio"])
1236
    kvm_cmd.extend(["-daemonize"])
1237
    if not instance.hvparams[constants.HV_ACPI]:
1238
      kvm_cmd.extend(["-no-acpi"])
1239
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1240
        constants.INSTANCE_REBOOT_EXIT:
1241
      kvm_cmd.extend(["-no-reboot"])
1242

    
1243
    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1244
    if not mversion:
1245
      mversion = self._GetDefaultMachineVersion(kvm)
1246
    if self._MACHINE_RE.search(kvmhelp):
1247
      # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1248
      # extra hypervisor parameters. We should also investigate whether and how
1249
      # shadow_mem should be considered for the resource model.
1250
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1251
        specprop = ",accel=kvm"
1252
      else:
1253
        specprop = ""
1254
      machinespec = "%s%s" % (mversion, specprop)
1255
      kvm_cmd.extend(["-machine", machinespec])
1256
    else:
1257
      kvm_cmd.extend(["-M", mversion])
1258
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1259
          self._ENABLE_KVM_RE.search(kvmhelp)):
1260
        kvm_cmd.extend(["-enable-kvm"])
1261
      elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1262
            self._DISABLE_KVM_RE.search(kvmhelp)):
1263
        kvm_cmd.extend(["-disable-kvm"])
1264

    
1265
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1266
    if kernel_path:
1267
      boot_cdrom = boot_floppy = boot_network = False
1268
    else:
1269
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1270
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1271
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1272

    
1273
    if startup_paused:
1274
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1275

    
1276
    if boot_network:
1277
      kvm_cmd.extend(["-boot", "n"])
1278

    
1279
    # whether this is an older KVM version that uses the boot=on flag
1280
    # on devices
1281
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1282

    
1283
    disk_type = hvp[constants.HV_DISK_TYPE]
1284

    
1285
    #Now we can specify a different device type for CDROM devices.
1286
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1287
    if not cdrom_disk_type:
1288
      cdrom_disk_type = disk_type
1289

    
1290
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1291
    if iso_image:
1292
      options = ",format=raw,media=cdrom"
1293
      # set cdrom 'if' type
1294
      if boot_cdrom:
1295
        actual_cdrom_type = constants.HT_DISK_IDE
1296
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1297
        actual_cdrom_type = "virtio"
1298
      else:
1299
        actual_cdrom_type = cdrom_disk_type
1300
      if_val = ",if=%s" % actual_cdrom_type
1301
      # set boot flag, if needed
1302
      boot_val = ""
1303
      if boot_cdrom:
1304
        kvm_cmd.extend(["-boot", "d"])
1305
        if needs_boot_flag:
1306
          boot_val = ",boot=on"
1307
      # and finally build the entire '-drive' value
1308
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1309
      kvm_cmd.extend(["-drive", drive_val])
1310

    
1311
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1312
    if iso_image2:
1313
      options = ",format=raw,media=cdrom"
1314
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1315
        if_val = ",if=virtio"
1316
      else:
1317
        if_val = ",if=%s" % cdrom_disk_type
1318
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1319
      kvm_cmd.extend(["-drive", drive_val])
1320

    
1321
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1322
    if floppy_image:
1323
      options = ",format=raw,media=disk"
1324
      if boot_floppy:
1325
        kvm_cmd.extend(["-boot", "a"])
1326
        options = "%s,boot=on" % options
1327
      if_val = ",if=floppy"
1328
      options = "%s%s" % (options, if_val)
1329
      drive_val = "file=%s%s" % (floppy_image, options)
1330
      kvm_cmd.extend(["-drive", drive_val])
1331

    
1332
    if kernel_path:
1333
      kvm_cmd.extend(["-kernel", kernel_path])
1334
      initrd_path = hvp[constants.HV_INITRD_PATH]
1335
      if initrd_path:
1336
        kvm_cmd.extend(["-initrd", initrd_path])
1337
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1338
                     hvp[constants.HV_KERNEL_ARGS]]
1339
      if hvp[constants.HV_SERIAL_CONSOLE]:
1340
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1341
        root_append.append("console=ttyS0,%s" % serial_speed)
1342
      kvm_cmd.extend(["-append", " ".join(root_append)])
1343

    
1344
    mem_path = hvp[constants.HV_MEM_PATH]
1345
    if mem_path:
1346
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1347

    
1348
    monitor_dev = ("unix:%s,server,nowait" %
1349
                   self._InstanceMonitor(instance.name))
1350
    kvm_cmd.extend(["-monitor", monitor_dev])
1351
    if hvp[constants.HV_SERIAL_CONSOLE]:
1352
      serial_dev = ("unix:%s,server,nowait" %
1353
                    self._InstanceSerial(instance.name))
1354
      kvm_cmd.extend(["-serial", serial_dev])
1355
    else:
1356
      kvm_cmd.extend(["-serial", "none"])
1357

    
1358
    mouse_type = hvp[constants.HV_USB_MOUSE]
1359
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1360
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1361
    spice_ip_version = None
1362

    
1363
    kvm_cmd.extend(["-usb"])
1364

    
1365
    if mouse_type:
1366
      kvm_cmd.extend(["-usbdevice", mouse_type])
1367
    elif vnc_bind_address:
1368
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1369

    
1370
    if vnc_bind_address:
1371
      if netutils.IsValidInterface(vnc_bind_address):
1372
        if_addresses = netutils.GetInterfaceIpAddresses(vnc_bind_address)
1373
        if_ip4_addresses = if_addresses[constants.IP4_VERSION]
1374
        if len(if_ip4_addresses) < 1:
1375
          logging.error("Could not determine IPv4 address of interface %s",
1376
                        vnc_bind_address)
1377
        else:
1378
          vnc_bind_address = if_ip4_addresses[0]
1379
      if netutils.IP4Address.IsValid(vnc_bind_address):
1380
        if instance.network_port > constants.VNC_BASE_PORT:
1381
          display = instance.network_port - constants.VNC_BASE_PORT
1382
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1383
            vnc_arg = ":%d" % (display)
1384
          else:
1385
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1386
        else:
1387
          logging.error("Network port is not a valid VNC display (%d < %d),"
1388
                        " not starting VNC",
1389
                        instance.network_port, constants.VNC_BASE_PORT)
1390
          vnc_arg = "none"
1391

    
1392
        # Only allow tls and other option when not binding to a file, for now.
1393
        # kvm/qemu gets confused otherwise about the filename to use.
1394
        vnc_append = ""
1395
        if hvp[constants.HV_VNC_TLS]:
1396
          vnc_append = "%s,tls" % vnc_append
1397
          if hvp[constants.HV_VNC_X509_VERIFY]:
1398
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1399
                                               hvp[constants.HV_VNC_X509])
1400
          elif hvp[constants.HV_VNC_X509]:
1401
            vnc_append = "%s,x509=%s" % (vnc_append,
1402
                                         hvp[constants.HV_VNC_X509])
1403
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1404
          vnc_append = "%s,password" % vnc_append
1405

    
1406
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1407

    
1408
      else:
1409
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1410

    
1411
      kvm_cmd.extend(["-vnc", vnc_arg])
1412
    elif spice_bind:
1413
      # FIXME: this is wrong here; the iface ip address differs
1414
      # between systems, so it should be done in _ExecuteKVMRuntime
1415
      if netutils.IsValidInterface(spice_bind):
1416
        # The user specified a network interface, we have to figure out the IP
1417
        # address.
1418
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1419
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1420

    
1421
        # if the user specified an IP version and the interface does not
1422
        # have that kind of IP addresses, throw an exception
1423
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1424
          if not addresses[spice_ip_version]:
1425
            raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1426
                                         " for %s" % (spice_ip_version,
1427
                                                      spice_bind))
1428

    
1429
        # the user did not specify an IP version, we have to figure it out
1430
        elif (addresses[constants.IP4_VERSION] and
1431
              addresses[constants.IP6_VERSION]):
1432
          # we have both ipv4 and ipv6, let's use the cluster default IP
1433
          # version
1434
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1435
          spice_ip_version = \
1436
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1437
        elif addresses[constants.IP4_VERSION]:
1438
          spice_ip_version = constants.IP4_VERSION
1439
        elif addresses[constants.IP6_VERSION]:
1440
          spice_ip_version = constants.IP6_VERSION
1441
        else:
1442
          raise errors.HypervisorError("SPICE: Unable to get an IP address"
1443
                                       " for %s" % (spice_bind))
1444

    
1445
        spice_address = addresses[spice_ip_version][0]
1446

    
1447
      else:
1448
        # spice_bind is known to be a valid IP address, because
1449
        # ValidateParameters checked it.
1450
        spice_address = spice_bind
1451

    
1452
      spice_arg = "addr=%s" % spice_address
1453
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1454
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1455
                     (spice_arg, instance.network_port,
1456
                      pathutils.SPICE_CACERT_FILE))
1457
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1458
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1459
                      pathutils.SPICE_CERT_FILE))
1460
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1461
        if tls_ciphers:
1462
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1463
      else:
1464
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1465

    
1466
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1467
        spice_arg = "%s,disable-ticketing" % spice_arg
1468

    
1469
      if spice_ip_version:
1470
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1471

    
1472
      # Image compression options
1473
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1474
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1475
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1476
      if img_lossless:
1477
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1478
      if img_jpeg:
1479
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1480
      if img_zlib_glz:
1481
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1482

    
1483
      # Video stream detection
1484
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1485
      if video_streaming:
1486
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1487

    
1488
      # Audio compression, by default in qemu-kvm it is on
1489
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1490
        spice_arg = "%s,playback-compression=off" % spice_arg
1491
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1492
        spice_arg = "%s,agent-mouse=off" % spice_arg
1493
      else:
1494
        # Enable the spice agent communication channel between the host and the
1495
        # agent.
1496
        kvm_cmd.extend(["-device", "virtio-serial-pci"])
1497
        kvm_cmd.extend([
1498
          "-device",
1499
          "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1500
          ])
1501
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1502

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

    
1506
    else:
1507
      # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1508
      # also works in earlier versions though (tested with 1.1 and 1.3)
1509
      if self._DISPLAY_RE.search(kvmhelp):
1510
        kvm_cmd.extend(["-display", "none"])
1511
      else:
1512
        kvm_cmd.extend(["-nographic"])
1513

    
1514
    if hvp[constants.HV_USE_LOCALTIME]:
1515
      kvm_cmd.extend(["-localtime"])
1516

    
1517
    if hvp[constants.HV_KVM_USE_CHROOT]:
1518
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1519

    
1520
    # Add qemu-KVM -cpu param
1521
    if hvp[constants.HV_CPU_TYPE]:
1522
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1523

    
1524
    # As requested by music lovers
1525
    if hvp[constants.HV_SOUNDHW]:
1526
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1527

    
1528
    # Pass a -vga option if requested, or if spice is used, for backwards
1529
    # compatibility.
1530
    if hvp[constants.HV_VGA]:
1531
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1532
    elif spice_bind:
1533
      kvm_cmd.extend(["-vga", "qxl"])
1534

    
1535
    # Various types of usb devices, comma separated
1536
    if hvp[constants.HV_USB_DEVICES]:
1537
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1538
        kvm_cmd.extend(["-usbdevice", dev])
1539

    
1540
    # Set system UUID to instance UUID
1541
    if self._UUID_RE.search(kvmhelp):
1542
      kvm_cmd.extend(["-uuid", instance.uuid])
1543

    
1544
    if hvp[constants.HV_KVM_EXTRA]:
1545
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1546

    
1547
    kvm_disks = []
1548
    for disk, dev_path in block_devices:
1549
      kvm_disks.append((disk, dev_path))
1550

    
1551
    kvm_nics = []
1552
    for nic in instance.nics:
1553
      kvm_nics.append(nic)
1554

    
1555
    hvparams = hvp
1556

    
1557
    return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1558

    
1559
  def _WriteKVMRuntime(self, instance_name, data):
1560
    """Write an instance's KVM runtime
1561

1562
    """
1563
    try:
1564
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1565
                      data=data)
1566
    except EnvironmentError, err:
1567
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1568

    
1569
  def _ReadKVMRuntime(self, instance_name):
1570
    """Read an instance's KVM runtime
1571

1572
    """
1573
    try:
1574
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1575
    except EnvironmentError, err:
1576
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1577
    return file_content
1578

    
1579
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1580
    """Save an instance's KVM runtime
1581

1582
    """
1583
    kvm_cmd, kvm_nics, hvparams, block_devices = kvm_runtime
1584

    
1585
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1586
    serialized_blockdevs = [(blk.ToDict(), link) for blk, link in block_devices]
1587
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1588
                                      serialized_blockdevs))
1589

    
1590
    self._WriteKVMRuntime(instance.name, serialized_form)
1591

    
1592
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1593
    """Load an instance's KVM runtime
1594

1595
    """
1596
    if not serialized_runtime:
1597
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1598

    
1599
    loaded_runtime = serializer.Load(serialized_runtime)
1600
    if len(loaded_runtime)==3:
1601
      serialized_blockdevs = []
1602
      kvm_cmd, serialized_nics, hvparams = loaded_runtime
1603
    else:
1604
      kvm_cmd, serialized_nics, hvparams, serialized_blockdevs = loaded_runtime
1605

    
1606
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1607
    block_devices = [(objects.Disk.FromDict(sdisk), link)
1608
                     for sdisk, link in serialized_blockdevs]
1609

    
1610
    return (kvm_cmd, kvm_nics, hvparams, block_devices)
1611

    
1612
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1613
    """Run the KVM cmd and check for errors
1614

1615
    @type name: string
1616
    @param name: instance name
1617
    @type kvm_cmd: list of strings
1618
    @param kvm_cmd: runcmd input for kvm
1619
    @type tap_fds: list of int
1620
    @param tap_fds: fds of tap devices opened by Ganeti
1621

1622
    """
1623
    try:
1624
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1625
    finally:
1626
      for fd in tap_fds:
1627
        utils_wrapper.CloseFdNoError(fd)
1628

    
1629
    if result.failed:
1630
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1631
                                   (name, result.fail_reason, result.output))
1632
    if not self._InstancePidAlive(name)[2]:
1633
      raise errors.HypervisorError("Failed to start instance %s" % name)
1634

    
1635
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1636
    """Execute a KVM cmd, after completing it with some last minute data.
1637

1638
    @type incoming: tuple of strings
1639
    @param incoming: (target_host_ip, port)
1640
    @type kvmhelp: string
1641
    @param kvmhelp: output of kvm --help
1642

1643
    """
1644
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1645
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1646
    #    have changed since the instance started; only use them if the change
1647
    #    won't affect the inside of the instance (which hasn't been rebooted).
1648
    #  - up_hvp contains the parameters as they were when the instance was
1649
    #    started, plus any new parameter which has been added between ganeti
1650
    #    versions: it is paramount that those default to a value which won't
1651
    #    affect the inside of the instance as well.
1652
    conf_hvp = instance.hvparams
1653
    name = instance.name
1654
    self._CheckDown(name)
1655

    
1656
    temp_files = []
1657

    
1658
    kvm_cmd, kvm_nics, up_hvp, block_devices = kvm_runtime
1659
    # the first element of kvm_cmd is always the path to the kvm binary
1660
    kvm_path = kvm_cmd[0]
1661
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1662

    
1663
    # We know it's safe to run as a different user upon migration, so we'll use
1664
    # the latest conf, from conf_hvp.
1665
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1666
    if security_model == constants.HT_SM_USER:
1667
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1668

    
1669
    keymap = conf_hvp[constants.HV_KEYMAP]
1670
    if keymap:
1671
      keymap_path = self._InstanceKeymapFile(name)
1672
      # If a keymap file is specified, KVM won't use its internal defaults. By
1673
      # first including the "en-us" layout, an error on loading the actual
1674
      # layout (e.g. because it can't be found) won't lead to a non-functional
1675
      # keyboard. A keyboard with incorrect keys is still better than none.
1676
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1677
      kvm_cmd.extend(["-k", keymap_path])
1678

    
1679
    dev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1680
                                                    block_devices,
1681
                                                    kvmhelp, kvm_path)
1682

    
1683
    kvm_cmd.extend(dev_opts)
1684
    # We have reasons to believe changing something like the nic driver/type
1685
    # upon migration won't exactly fly with the instance kernel, so for nic
1686
    # related parameters we'll use up_hvp
1687
    tapfds = []
1688
    taps = []
1689
    if not kvm_nics:
1690
      kvm_cmd.extend(["-net", "none"])
1691
    else:
1692
      vnet_hdr = False
1693
      tap_extra = ""
1694
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1695
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1696
        nic_model = self._VIRTIO
1697
        try:
1698
          devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1699
          if self._VIRTIO_NET_RE.search(devlist):
1700
            nic_model = self._VIRTIO_NET_PCI
1701
            vnet_hdr = True
1702
        except errors.HypervisorError, _:
1703
          # Older versions of kvm don't support DEVICE_LIST, but they don't
1704
          # have new virtio syntax either.
1705
          pass
1706

    
1707
        if up_hvp[constants.HV_VHOST_NET]:
1708
          # check for vhost_net support
1709
          if self._VHOST_RE.search(kvmhelp):
1710
            tap_extra = ",vhost=on"
1711
          else:
1712
            raise errors.HypervisorError("vhost_net is configured"
1713
                                         " but it is not available")
1714
      else:
1715
        nic_model = nic_type
1716

    
1717
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1718

    
1719
      for nic_seq, nic in enumerate(kvm_nics):
1720
        tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1721
        tapfds.append(tapfd)
1722
        taps.append(tapname)
1723
        if kvm_supports_netdev:
1724
          nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1725
          tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1726
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1727
        else:
1728
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1729
                                                         nic.mac, nic_model)
1730
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1731
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1732

    
1733
    if incoming:
1734
      target, port = incoming
1735
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1736

    
1737
    # Changing the vnc password doesn't bother the guest that much. At most it
1738
    # will surprise people who connect to it. Whether positively or negatively
1739
    # it's debatable.
1740
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1741
    vnc_pwd = None
1742
    if vnc_pwd_file:
1743
      try:
1744
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1745
      except EnvironmentError, err:
1746
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1747
                                     % (vnc_pwd_file, err))
1748

    
1749
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1750
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1751
                         constants.SECURE_DIR_MODE)])
1752

    
1753
    # Automatically enable QMP if version is >= 0.14
1754
    if self._QMP_RE.search(kvmhelp):
1755
      logging.debug("Enabling QMP")
1756
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1757
                      self._InstanceQmpMonitor(instance.name)])
1758

    
1759
    # Configure the network now for starting instances and bridged interfaces,
1760
    # during FinalizeMigration for incoming instances' routed interfaces
1761
    for nic_seq, nic in enumerate(kvm_nics):
1762
      if (incoming and
1763
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1764
        continue
1765
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1766

    
1767
    # CPU affinity requires kvm to start paused, so we set this flag if the
1768
    # instance is not already paused and if we are not going to accept a
1769
    # migrating instance. In the latter case, pausing is not needed.
1770
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1771
    if start_kvm_paused:
1772
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1773

    
1774
    # Note: CPU pinning is using up_hvp since changes take effect
1775
    # during instance startup anyway, and to avoid problems when soft
1776
    # rebooting the instance.
1777
    cpu_pinning = False
1778
    if up_hvp.get(constants.HV_CPU_MASK, None):
1779
      cpu_pinning = True
1780

    
1781
    if security_model == constants.HT_SM_POOL:
1782
      ss = ssconf.SimpleStore()
1783
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1784
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1785
      uid = uidpool.RequestUnusedUid(all_uids)
1786
      try:
1787
        username = pwd.getpwuid(uid.GetUid()).pw_name
1788
        kvm_cmd.extend(["-runas", username])
1789
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1790
      except:
1791
        uidpool.ReleaseUid(uid)
1792
        raise
1793
      else:
1794
        uid.Unlock()
1795
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1796
    else:
1797
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1798

    
1799
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1800
                     constants.RUN_DIRS_MODE)])
1801
    for nic_seq, tap in enumerate(taps):
1802
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1803
                      data=tap)
1804

    
1805
    if vnc_pwd:
1806
      change_cmd = "change vnc password %s" % vnc_pwd
1807
      self._CallMonitorCommand(instance.name, change_cmd)
1808

    
1809
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1810
    # connection attempts because SPICE by default does not allow connections
1811
    # if neither a password nor the "disable_ticketing" options are specified.
1812
    # As soon as we send the password via QMP, that password is a valid ticket
1813
    # for connection.
1814
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1815
    if spice_password_file:
1816
      spice_pwd = ""
1817
      try:
1818
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1819
      except EnvironmentError, err:
1820
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1821
                                     % (spice_password_file, err))
1822

    
1823
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1824
      qmp.connect()
1825
      arguments = {
1826
          "protocol": "spice",
1827
          "password": spice_pwd,
1828
      }
1829
      qmp.Execute("set_password", arguments)
1830

    
1831
    for filename in temp_files:
1832
      utils.RemoveFile(filename)
1833

    
1834
    # If requested, set CPU affinity and resume instance execution
1835
    if cpu_pinning:
1836
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1837

    
1838
    start_memory = self._InstanceStartupMemory(instance)
1839
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1840
      self.BalloonInstanceMemory(instance, start_memory)
1841

    
1842
    if start_kvm_paused:
1843
      # To control CPU pinning, ballooning, and vnc/spice passwords
1844
      # the VM was started in a frozen state. If freezing was not
1845
      # explicitly requested resume the vm status.
1846
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1847

    
1848
  def StartInstance(self, instance, block_devices, startup_paused):
1849
    """Start an instance.
1850

1851
    """
1852
    self._CheckDown(instance.name)
1853
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1854
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1855
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1856
                                           startup_paused, kvmhelp)
1857
    self._SaveKVMRuntime(instance, kvm_runtime)
1858
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1859

    
1860
  def _CallMonitorCommand(self, instance_name, command):
1861
    """Invoke a command on the instance monitor.
1862

1863
    """
1864
    # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1865
    # version. The monitor protocol is designed for human consumption, whereas
1866
    # QMP is made for programmatic usage. In the worst case QMP can also
1867
    # execute monitor commands. As it is, all calls to socat take at least
1868
    # 500ms and likely more: socat can't detect the end of the reply and waits
1869
    # for 500ms of no data received before exiting (500 ms is the default for
1870
    # the "-t" parameter).
1871
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1872
             (utils.ShellQuote(command),
1873
              constants.SOCAT_PATH,
1874
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1875
    result = utils.RunCmd(socat)
1876
    if result.failed:
1877
      msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1878
             " output: %s" %
1879
             (command, instance_name, result.fail_reason, result.output))
1880
      raise errors.HypervisorError(msg)
1881

    
1882
    return result
1883

    
1884
  def _GetFreePCISlot(self, instance, dev):
1885
    """Get the first available pci slot of a runnung instance.
1886

1887
    """
1888
    slots = bitarray(32)
1889
    slots.setall(False) # pylint: disable=E1101
1890
    output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
1891
    for line in output.stdout.splitlines():
1892
      match = self._INFO_PCI_RE.search(line)
1893
      if match:
1894
        slot = int(match.group(1))
1895
        slots[slot] = True
1896

    
1897
    [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
1898
    if not free:
1899
      raise errors.HypervisorError("All PCI slots occupied")
1900

    
1901
    dev.pci = int(free)
1902

    
1903
  @classmethod
1904
  def _ParseKVMVersion(cls, text):
1905
    """Parse the KVM version from the --help output.
1906

1907
    @type text: string
1908
    @param text: output of kvm --help
1909
    @return: (version, v_maj, v_min, v_rev)
1910
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1911

1912
    """
1913
    match = cls._VERSION_RE.search(text.splitlines()[0])
1914
    if not match:
1915
      raise errors.HypervisorError("Unable to get KVM version")
1916

    
1917
    v_all = match.group(0)
1918
    v_maj = int(match.group(1))
1919
    v_min = int(match.group(2))
1920
    if match.group(4):
1921
      v_rev = int(match.group(4))
1922
    else:
1923
      v_rev = 0
1924
    return (v_all, v_maj, v_min, v_rev)
1925

    
1926
  @classmethod
1927
  def _GetKVMOutput(cls, kvm_path, option):
1928
    """Return the output of a kvm invocation
1929

1930
    @type kvm_path: string
1931
    @param kvm_path: path to the kvm executable
1932
    @type option: a key of _KVMOPTS_CMDS
1933
    @param option: kvm option to fetch the output from
1934
    @return: output a supported kvm invocation
1935
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1936

1937
    """
1938
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
1939

    
1940
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
1941

    
1942
    result = utils.RunCmd([kvm_path] + optlist)
1943
    if result.failed and not can_fail:
1944
      raise errors.HypervisorError("Unable to get KVM %s output" %
1945
                                    " ".join(cls._KVMOPTS_CMDS[option]))
1946
    return result.output
1947

    
1948
  @classmethod
1949
  def _GetKVMVersion(cls, kvm_path):
1950
    """Return the installed KVM version.
1951

1952
    @return: (version, v_maj, v_min, v_rev)
1953
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1954

1955
    """
1956
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
1957

    
1958
  @classmethod
1959
  def _GetDefaultMachineVersion(cls, kvm_path):
1960
    """Return the default hardware revision (e.g. pc-1.1)
1961

1962
    """
1963
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
1964
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
1965
    if match:
1966
      return match.group(1)
1967
    else:
1968
      return "pc"
1969

    
1970
  def StopInstance(self, instance, force=False, retry=False, name=None):
1971
    """Stop an instance.
1972

1973
    """
1974
    if name is not None and not force:
1975
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1976
    if name is None:
1977
      name = instance.name
1978
      acpi = instance.hvparams[constants.HV_ACPI]
1979
    else:
1980
      acpi = False
1981
    _, pid, alive = self._InstancePidAlive(name)
1982
    if pid > 0 and alive:
1983
      if force or not acpi:
1984
        utils.KillProcess(pid)
1985
      else:
1986
        self._CallMonitorCommand(name, "system_powerdown")
1987

    
1988
  def CleanupInstance(self, instance_name):
1989
    """Cleanup after a stopped instance
1990

1991
    """
1992
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
1993
    if pid > 0 and alive:
1994
      raise errors.HypervisorError("Cannot cleanup a live instance")
1995
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1996

    
1997
  def RebootInstance(self, instance):
1998
    """Reboot an instance.
1999

2000
    """
2001
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2002
    # socket the instance will stop, but now power up again. So we'll resort
2003
    # to shutdown and restart.
2004
    _, _, alive = self._InstancePidAlive(instance.name)
2005
    if not alive:
2006
      raise errors.HypervisorError("Failed to reboot instance %s:"
2007
                                   " not running" % instance.name)
2008
    # StopInstance will delete the saved KVM runtime so:
2009
    # ...first load it...
2010
    kvm_runtime = self._LoadKVMRuntime(instance)
2011
    # ...now we can safely call StopInstance...
2012
    if not self.StopInstance(instance):
2013
      self.StopInstance(instance, force=True)
2014
    # ...and finally we can save it again, and execute it...
2015
    self._SaveKVMRuntime(instance, kvm_runtime)
2016
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2017
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2018
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2019

    
2020
  def MigrationInfo(self, instance):
2021
    """Get instance information to perform a migration.
2022

2023
    @type instance: L{objects.Instance}
2024
    @param instance: instance to be migrated
2025
    @rtype: string
2026
    @return: content of the KVM runtime file
2027

2028
    """
2029
    return self._ReadKVMRuntime(instance.name)
2030

    
2031
  def AcceptInstance(self, instance, info, target):
2032
    """Prepare to accept an instance.
2033

2034
    @type instance: L{objects.Instance}
2035
    @param instance: instance to be accepted
2036
    @type info: string
2037
    @param info: content of the KVM runtime file on the source node
2038
    @type target: string
2039
    @param target: target host (usually ip), on this node
2040

2041
    """
2042
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2043
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2044
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2045
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2046
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2047
                            incoming=incoming_address)
2048

    
2049
  def FinalizeMigrationDst(self, instance, info, success):
2050
    """Finalize the instance migration on the target node.
2051

2052
    Stop the incoming mode KVM.
2053

2054
    @type instance: L{objects.Instance}
2055
    @param instance: instance whose migration is being finalized
2056

2057
    """
2058
    if success:
2059
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2060
      kvm_nics = kvm_runtime[1]
2061

    
2062
      for nic_seq, nic in enumerate(kvm_nics):
2063
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2064
          # Bridged interfaces have already been configured
2065
          continue
2066
        try:
2067
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2068
        except EnvironmentError, err:
2069
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
2070
                          instance.name, nic_seq, str(err))
2071
          continue
2072
        try:
2073
          self._ConfigureNIC(instance, nic_seq, nic, tap)
2074
        except errors.HypervisorError, err:
2075
          logging.warning(str(err))
2076

    
2077
      self._WriteKVMRuntime(instance.name, info)
2078
    else:
2079
      self.StopInstance(instance, force=True)
2080

    
2081
  def MigrateInstance(self, cluster_name, instance, target, live):
2082
    """Migrate an instance to a target node.
2083

2084
    The migration will not be attempted if the instance is not
2085
    currently running.
2086

2087
    @type cluster_name: string
2088
    @param cluster_name: name of the cluster
2089
    @type instance: L{objects.Instance}
2090
    @param instance: the instance to be migrated
2091
    @type target: string
2092
    @param target: ip address of the target node
2093
    @type live: boolean
2094
    @param live: perform a live migration
2095

2096
    """
2097
    instance_name = instance.name
2098
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
2099
    _, _, alive = self._InstancePidAlive(instance_name)
2100
    if not alive:
2101
      raise errors.HypervisorError("Instance not running, cannot migrate")
2102

    
2103
    if not live:
2104
      self._CallMonitorCommand(instance_name, "stop")
2105

    
2106
    migrate_command = ("migrate_set_speed %dm" %
2107
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2108
    self._CallMonitorCommand(instance_name, migrate_command)
2109

    
2110
    migrate_command = ("migrate_set_downtime %dms" %
2111
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2112
    self._CallMonitorCommand(instance_name, migrate_command)
2113

    
2114
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2115
    self._CallMonitorCommand(instance_name, migrate_command)
2116

    
2117
  def FinalizeMigrationSource(self, instance, success, live):
2118
    """Finalize the instance migration on the source node.
2119

2120
    @type instance: L{objects.Instance}
2121
    @param instance: the instance that was migrated
2122
    @type success: bool
2123
    @param success: whether the migration succeeded or not
2124
    @type live: bool
2125
    @param live: whether the user requested a live migration or not
2126

2127
    """
2128
    if success:
2129
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2130
      utils.KillProcess(pid)
2131
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2132
    elif live:
2133
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2134

    
2135
  def GetMigrationStatus(self, instance):
2136
    """Get the migration status
2137

2138
    @type instance: L{objects.Instance}
2139
    @param instance: the instance that is being migrated
2140
    @rtype: L{objects.MigrationStatus}
2141
    @return: the status of the current migration (one of
2142
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2143
             progress info that can be retrieved from the hypervisor
2144

2145
    """
2146
    info_command = "info migrate"
2147
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2148
      result = self._CallMonitorCommand(instance.name, info_command)
2149
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
2150
      if not match:
2151
        if not result.stdout:
2152
          logging.info("KVM: empty 'info migrate' result")
2153
        else:
2154
          logging.warning("KVM: unknown 'info migrate' result: %s",
2155
                          result.stdout)
2156
      else:
2157
        status = match.group(1)
2158
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2159
          migration_status = objects.MigrationStatus(status=status)
2160
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2161
          if match:
2162
            migration_status.transferred_ram = match.group("transferred")
2163
            migration_status.total_ram = match.group("total")
2164

    
2165
          return migration_status
2166

    
2167
        logging.warning("KVM: unknown migration status '%s'", status)
2168

    
2169
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2170

    
2171
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2172

    
2173
  def BalloonInstanceMemory(self, instance, mem):
2174
    """Balloon an instance memory to a certain value.
2175

2176
    @type instance: L{objects.Instance}
2177
    @param instance: instance to be accepted
2178
    @type mem: int
2179
    @param mem: actual memory size to use for instance runtime
2180

2181
    """
2182
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2183

    
2184
  def GetNodeInfo(self, hvparams=None):
2185
    """Return information about the node.
2186

2187
    @type hvparams: dict of strings
2188
    @param hvparams: hypervisor parameters, not used in this class
2189

2190
    @return: a dict as returned by L{BaseHypervisor.GetLinuxNodeInfo} plus
2191
        the following keys:
2192
          - hv_version: the hypervisor version in the form (major, minor,
2193
                        revision)
2194

2195
    """
2196
    result = self.GetLinuxNodeInfo()
2197
    # FIXME: this is the global kvm version, but the actual version can be
2198
    # customized as an hv parameter. we should use the nodegroup's default kvm
2199
    # path parameter here.
2200
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2201
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2202
    return result
2203

    
2204
  @classmethod
2205
  def GetInstanceConsole(cls, instance, primary_node, hvparams, beparams):
2206
    """Return a command for connecting to the console of an instance.
2207

2208
    """
2209
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2210
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2211
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2212
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2213
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2214
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2215
      return objects.InstanceConsole(instance=instance.name,
2216
                                     kind=constants.CONS_SSH,
2217
                                     host=primary_node.name,
2218
                                     user=constants.SSH_CONSOLE_USER,
2219
                                     command=cmd)
2220

    
2221
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2222
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2223
      display = instance.network_port - constants.VNC_BASE_PORT
2224
      return objects.InstanceConsole(instance=instance.name,
2225
                                     kind=constants.CONS_VNC,
2226
                                     host=vnc_bind_address,
2227
                                     port=instance.network_port,
2228
                                     display=display)
2229

    
2230
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2231
    if spice_bind:
2232
      return objects.InstanceConsole(instance=instance.name,
2233
                                     kind=constants.CONS_SPICE,
2234
                                     host=spice_bind,
2235
                                     port=instance.network_port)
2236

    
2237
    return objects.InstanceConsole(instance=instance.name,
2238
                                   kind=constants.CONS_MESSAGE,
2239
                                   message=("No serial shell for instance %s" %
2240
                                            instance.name))
2241

    
2242
  def Verify(self, hvparams=None):
2243
    """Verify the hypervisor.
2244

2245
    Check that the required binaries exist.
2246

2247
    @type hvparams: dict of strings
2248
    @param hvparams: hypervisor parameters to be verified against, not used here
2249

2250
    @return: Problem description if something is wrong, C{None} otherwise
2251

2252
    """
2253
    msgs = []
2254
    # FIXME: this is the global kvm binary, but the actual path can be
2255
    # customized as an hv parameter; we should use the nodegroup's
2256
    # default kvm path parameter here.
2257
    if not os.path.exists(constants.KVM_PATH):
2258
      msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2259
    if not os.path.exists(constants.SOCAT_PATH):
2260
      msgs.append("The socat binary ('%s') does not exist" %
2261
                  constants.SOCAT_PATH)
2262

    
2263
    return self._FormatVerifyResults(msgs)
2264

    
2265
  @classmethod
2266
  def CheckParameterSyntax(cls, hvparams):
2267
    """Check the given parameters for validity.
2268

2269
    @type hvparams:  dict
2270
    @param hvparams: dictionary with parameter names/value
2271
    @raise errors.HypervisorError: when a parameter is not valid
2272

2273
    """
2274
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2275

    
2276
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2277
    if kernel_path:
2278
      if not hvparams[constants.HV_ROOT_PATH]:
2279
        raise errors.HypervisorError("Need a root partition for the instance,"
2280
                                     " if a kernel is defined")
2281

    
2282
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2283
        not hvparams[constants.HV_VNC_X509]):
2284
      raise errors.HypervisorError("%s must be defined, if %s is" %
2285
                                   (constants.HV_VNC_X509,
2286
                                    constants.HV_VNC_X509_VERIFY))
2287

    
2288
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2289
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2290
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2291
      if not serial_speed or serial_speed not in valid_speeds:
2292
        raise errors.HypervisorError("Invalid serial console speed, must be"
2293
                                     " one of: %s" %
2294
                                     utils.CommaJoin(valid_speeds))
2295

    
2296
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2297
    if (boot_order == constants.HT_BO_CDROM and
2298
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2299
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2300
                                   " ISO path")
2301

    
2302
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2303
    if security_model == constants.HT_SM_USER:
2304
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2305
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2306
                                     " must be specified")
2307
    elif (security_model == constants.HT_SM_NONE or
2308
          security_model == constants.HT_SM_POOL):
2309
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2310
        raise errors.HypervisorError("Cannot have a security domain when the"
2311
                                     " security model is 'none' or 'pool'")
2312

    
2313
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2314
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2315
    if spice_bind:
2316
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2317
        # if an IP version is specified, the spice_bind parameter must be an
2318
        # IP of that family
2319
        if (netutils.IP4Address.IsValid(spice_bind) and
2320
            spice_ip_version != constants.IP4_VERSION):
2321
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2322
                                       " the specified IP version is %s" %
2323
                                       (spice_bind, spice_ip_version))
2324

    
2325
        if (netutils.IP6Address.IsValid(spice_bind) and
2326
            spice_ip_version != constants.IP6_VERSION):
2327
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2328
                                       " the specified IP version is %s" %
2329
                                       (spice_bind, spice_ip_version))
2330
    else:
2331
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2332
      # error if any of them is set without it.
2333
      for param in _SPICE_ADDITIONAL_PARAMS:
2334
        if hvparams[param]:
2335
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2336
                                       (param, constants.HV_KVM_SPICE_BIND))
2337

    
2338
  @classmethod
2339
  def ValidateParameters(cls, hvparams):
2340
    """Check the given parameters for validity.
2341

2342
    @type hvparams:  dict
2343
    @param hvparams: dictionary with parameter names/value
2344
    @raise errors.HypervisorError: when a parameter is not valid
2345

2346
    """
2347
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2348

    
2349
    kvm_path = hvparams[constants.HV_KVM_PATH]
2350

    
2351
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2352
    if security_model == constants.HT_SM_USER:
2353
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2354
      try:
2355
        pwd.getpwnam(username)
2356
      except KeyError:
2357
        raise errors.HypervisorError("Unknown security domain user %s"
2358
                                     % username)
2359
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2360
    if vnc_bind_address:
2361
      bound_to_addr = netutils.IP4Address.IsValid(vnc_bind_address)
2362
      is_interface = netutils.IsValidInterface(vnc_bind_address)
2363
      is_path = utils.IsNormAbsPath(vnc_bind_address)
2364
      if not bound_to_addr and not is_interface and not is_path:
2365
        raise errors.HypervisorError("VNC: The %s parameter must be either"
2366
                                     " a valid IP address, an interface name,"
2367
                                     " or an absolute path" %
2368
                                     constants.HV_KVM_SPICE_BIND)
2369

    
2370
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2371
    if spice_bind:
2372
      # only one of VNC and SPICE can be used currently.
2373
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2374
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2375
                                     " only one of them can be used at a"
2376
                                     " given time")
2377

    
2378
      # check that KVM supports SPICE
2379
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2380
      if not cls._SPICE_RE.search(kvmhelp):
2381
        raise errors.HypervisorError("SPICE is configured, but it is not"
2382
                                     " supported according to 'kvm --help'")
2383

    
2384
      # if spice_bind is not an IP address, it must be a valid interface
2385
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2386
                       netutils.IP6Address.IsValid(spice_bind))
2387
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2388
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2389
                                     " a valid IP address or interface name" %
2390
                                     constants.HV_KVM_SPICE_BIND)
2391

    
2392
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2393
    if machine_version:
2394
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2395
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2396
        raise errors.HypervisorError("Unsupported machine version: %s" %
2397
                                     machine_version)
2398

    
2399
  @classmethod
2400
  def PowercycleNode(cls, hvparams=None):
2401
    """KVM powercycle, just a wrapper over Linux powercycle.
2402

2403
    @type hvparams: dict of strings
2404
    @param hvparams: hypervisor params to be used on this node
2405

2406
    """
2407
    cls.LinuxPowercycle()