Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ e506cce0

History | View | Annotate | Download (88.9 kB)

1
#
2
#
3

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

    
21

    
22
"""KVM hypervisor
23

24
"""
25

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

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

    
62

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

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

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

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

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

    
116

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

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

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

130
  """
131

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

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

    
138

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

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

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

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

    
161
  pci_reservations[free] = True
162

    
163

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

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

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

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

    
187
  return found[0]
188

    
189

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

193
  @see: L{_ProbeTapVnetHdr}
194

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

    
206

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

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

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

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

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

    
230
  result = bool(flags & IFF_VNET_HDR)
231

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

    
235
  return result
236

    
237

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

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

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

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

    
255
  flags = IFF_TAP | IFF_NO_PI
256

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

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

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

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

    
273

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

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

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

    
285
    self.data = data
286

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

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

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

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

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

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

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

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

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

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

    
327

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

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

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

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

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

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

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

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

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

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

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

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

    
396
    self._check_socket()
397

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

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

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

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

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

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

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

    
439
    return (message, buf)
440

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

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

449
    """
450
    self._check_connection()
451

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

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

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

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

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

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

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

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

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

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

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

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

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

    
536

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

540
  """
541
  CAN_MIGRATE = True
542

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

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

    
646
  _VIRTIO = "virtio"
647
  _VIRTIO_NET_PCI = "virtio-net-pci"
648
  _VIRTIO_BLK_PCI = "virtio-blk-pci"
649

    
650
  _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
651
                                    re.M | re.I)
652
  _MIGRATION_PROGRESS_RE = \
653
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
654
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
655
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
656

    
657
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
658
  _MIGRATION_INFO_RETRY_DELAY = 2
659

    
660
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
661

    
662
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
663
  _CPU_INFO_CMD = "info cpus"
664
  _CONT_CMD = "cont"
665

    
666
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
667
  _CHECK_MACHINE_VERSION_RE = \
668
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
669

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

    
685
  _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
686
  _INFO_PCI_CMD = "info pci"
687
  _INFO_VERSION_RE = \
688
    re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
689
  _INFO_VERSION_CMD = "info version"
690

    
691
  _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
692

    
693
  ANCILLARY_FILES = [
694
    _KVM_NETWORK_SCRIPT,
695
    ]
696
  ANCILLARY_FILES_OPT = [
697
    _KVM_NETWORK_SCRIPT,
698
    ]
699

    
700
  # Supported kvm options to get output from
701
  _KVMOPT_HELP = "help"
702
  _KVMOPT_MLIST = "mlist"
703
  _KVMOPT_DEVICELIST = "devicelist"
704

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

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

    
720
  @classmethod
721
  def _InstancePidFile(cls, instance_name):
722
    """Returns the instance pidfile.
723

724
    """
725
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
726

    
727
  @classmethod
728
  def _InstanceUidFile(cls, instance_name):
729
    """Returns the instance uidfile.
730

731
    """
732
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
733

    
734
  @classmethod
735
  def _InstancePidInfo(cls, pid):
736
    """Check pid file for instance information.
737

738
    Check that a pid file is associated with an instance, and retrieve
739
    information from its command line.
740

741
    @type pid: string or int
742
    @param pid: process id of the instance to check
743
    @rtype: tuple
744
    @return: (instance_name, memory, vcpus)
745
    @raise errors.HypervisorError: when an instance cannot be found
746

747
    """
748
    alive = utils.IsProcessAlive(pid)
749
    if not alive:
750
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
751

    
752
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
753
    try:
754
      cmdline = utils.ReadFile(cmdline_file)
755
    except EnvironmentError, err:
756
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
757
                                   (pid, err))
758

    
759
    instance = None
760
    memory = 0
761
    vcpus = 0
762

    
763
    arg_list = cmdline.split("\x00")
764
    while arg_list:
765
      arg = arg_list.pop(0)
766
      if arg == "-name":
767
        instance = arg_list.pop(0)
768
      elif arg == "-m":
769
        memory = int(arg_list.pop(0))
770
      elif arg == "-smp":
771
        vcpus = int(arg_list.pop(0).split(",")[0])
772

    
773
    if instance is None:
774
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
775
                                   " instance" % pid)
776

    
777
    return (instance, memory, vcpus)
778

    
779
  def _InstancePidAlive(self, instance_name):
780
    """Returns the instance pidfile, pid, and liveness.
781

782
    @type instance_name: string
783
    @param instance_name: instance name
784
    @rtype: tuple
785
    @return: (pid file name, pid, liveness)
786

787
    """
788
    pidfile = self._InstancePidFile(instance_name)
789
    pid = utils.ReadPidFile(pidfile)
790

    
791
    alive = False
792
    try:
793
      cmd_instance = self._InstancePidInfo(pid)[0]
794
      alive = (cmd_instance == instance_name)
795
    except errors.HypervisorError:
796
      pass
797

    
798
    return (pidfile, pid, alive)
799

    
800
  def _CheckDown(self, instance_name):
801
    """Raises an error unless the given instance is down.
802

803
    """
804
    alive = self._InstancePidAlive(instance_name)[2]
805
    if alive:
806
      raise errors.HypervisorError("Failed to start instance %s: %s" %
807
                                   (instance_name, "already running"))
808

    
809
  @classmethod
810
  def _InstanceMonitor(cls, instance_name):
811
    """Returns the instance monitor socket name
812

813
    """
814
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
815

    
816
  @classmethod
817
  def _InstanceSerial(cls, instance_name):
818
    """Returns the instance serial socket name
819

820
    """
821
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
822

    
823
  @classmethod
824
  def _InstanceQmpMonitor(cls, instance_name):
825
    """Returns the instance serial QMP socket name
826

827
    """
828
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
829

    
830
  @staticmethod
831
  def _SocatUnixConsoleParams():
832
    """Returns the correct parameters for socat
833

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

836
    """
837
    if constants.SOCAT_USE_ESCAPE:
838
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
839
    else:
840
      return "echo=0,icanon=0"
841

    
842
  @classmethod
843
  def _InstanceKVMRuntime(cls, instance_name):
844
    """Returns the instance KVM runtime filename
845

846
    """
847
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
848

    
849
  @classmethod
850
  def _InstanceChrootDir(cls, instance_name):
851
    """Returns the name of the KVM chroot dir of the instance
852

853
    """
854
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
855

    
856
  @classmethod
857
  def _InstanceNICDir(cls, instance_name):
858
    """Returns the name of the directory holding the tap device files for a
859
    given instance.
860

861
    """
862
    return utils.PathJoin(cls._NICS_DIR, instance_name)
863

    
864
  @classmethod
865
  def _InstanceNICFile(cls, instance_name, seq):
866
    """Returns the name of the file containing the tap device for a given NIC
867

868
    """
869
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
870

    
871
  @classmethod
872
  def _InstanceKeymapFile(cls, instance_name):
873
    """Returns the name of the file containing the keymap for a given instance
874

875
    """
876
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
877

    
878
  @classmethod
879
  def _TryReadUidFile(cls, uid_file):
880
    """Try to read a uid file
881

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

    
893
  @classmethod
894
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
895
    """Removes an instance's rutime sockets/files/dirs.
896

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

    
933
  @staticmethod
934
  def _ConfigureNIC(instance, seq, nic, tap):
935
    """Run the network configuration script for a specified NIC
936

937
    @param instance: instance we're acting on
938
    @type instance: instance object
939
    @param seq: nic sequence number
940
    @type seq: int
941
    @param nic: nic we're acting on
942
    @type nic: nic object
943
    @param tap: the host's tap interface this NIC corresponds to
944
    @type tap: str
945

946
    """
947
    if instance.tags:
948
      tags = " ".join(instance.tags)
949
    else:
950
      tags = ""
951

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

    
962
    if nic.ip:
963
      env["IP"] = nic.ip
964

    
965
    if nic.nicparams[constants.NIC_LINK]:
966
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
967

    
968
    if nic.network:
969
      n = objects.Network.FromDict(nic.netinfo)
970
      env.update(n.HooksDict())
971

    
972
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
973
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
974

    
975
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
976
    if result.failed:
977
      raise errors.HypervisorError("Failed to configure interface %s: %s;"
978
                                   " network configuration script output: %s" %
979
                                   (tap, result.fail_reason, result.output))
980

    
981
  @staticmethod
982
  def _VerifyAffinityPackage():
983
    if affinity is None:
984
      raise errors.HypervisorError("affinity Python package not"
985
                                   " found; cannot use CPU pinning under KVM")
986

    
987
  @staticmethod
988
  def _BuildAffinityCpuMask(cpu_list):
989
    """Create a CPU mask suitable for sched_setaffinity from a list of
990
    CPUs.
991

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

995
    @type cpu_list: list of int
996
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
997
    @rtype: int
998
    @return: a bit mask of CPU affinities
999

1000
    """
1001
    if cpu_list == constants.CPU_PINNING_OFF:
1002
      return constants.CPU_PINNING_ALL_KVM
1003
    else:
1004
      return sum(2 ** cpu for cpu in cpu_list)
1005

    
1006
  @classmethod
1007
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
1008
    """Change CPU affinity for running VM according to given CPU mask.
1009

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

1018
    """
1019
    # Convert the string CPU mask to a list of list of int's
1020
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
1021

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

    
1040
      # For each vCPU, map it to the proper list of physical CPUs
1041
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1042
        affinity.set_process_affinity_mask(thread_dict[i],
1043
                                           cls._BuildAffinityCpuMask(vcpu))
1044

    
1045
  def _GetVcpuThreadIds(self, instance_name):
1046
    """Get a mapping of vCPU no. to thread IDs for the instance
1047

1048
    @type instance_name: string
1049
    @param instance_name: instance in question
1050
    @rtype: dictionary of int:int
1051
    @return: a dictionary mapping vCPU numbers to thread IDs
1052

1053
    """
1054
    result = {}
1055
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1056
    for line in output.stdout.splitlines():
1057
      match = self._CPU_INFO_RE.search(line)
1058
      if not match:
1059
        continue
1060
      grp = map(int, match.groups())
1061
      result[grp[0]] = grp[1]
1062

    
1063
    return result
1064

    
1065
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1066
    """Complete CPU pinning.
1067

1068
    @type instance_name: string
1069
    @param instance_name: name of instance
1070
    @type cpu_mask: string
1071
    @param cpu_mask: CPU pinning mask as entered by user
1072

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

    
1081
  def ListInstances(self):
1082
    """Get the list of running instances.
1083

1084
    We can do this by listing our live instances directory and
1085
    checking whether the associated kvm process is still alive.
1086

1087
    """
1088
    result = []
1089
    for name in os.listdir(self._PIDS_DIR):
1090
      if self._InstancePidAlive(name)[2]:
1091
        result.append(name)
1092
    return result
1093

    
1094
  def GetInstanceInfo(self, instance_name):
1095
    """Get instance properties.
1096

1097
    @type instance_name: string
1098
    @param instance_name: the instance name
1099
    @rtype: tuple of strings
1100
    @return: (name, id, memory, vcpus, stat, times)
1101

1102
    """
1103
    _, pid, alive = self._InstancePidAlive(instance_name)
1104
    if not alive:
1105
      return None
1106

    
1107
    _, memory, vcpus = self._InstancePidInfo(pid)
1108
    istat = "---b-"
1109
    times = "0"
1110

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

    
1122
    return (instance_name, pid, memory, vcpus, istat, times)
1123

    
1124
  def GetAllInstancesInfo(self):
1125
    """Get properties of all instances.
1126

1127
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1128

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

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

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

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

    
1151
    dev_opts = []
1152
    device_driver = None
1153
    disk_type = hvp[constants.HV_DISK_TYPE]
1154
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
1155
      if_val = ",if=%s" % self._VIRTIO
1156
      try:
1157
        devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1158
        if self._VIRTIO_BLK_RE.search(devlist):
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
        # block_devices are the 4th entry of runtime file that did not exist in
1195
        # the past. That means that cfdev should always have pci slot and
1196
        # _GenerateDeviceKVMId() will not raise a exception.
1197
        kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_DISK, cfdev)
1198
        drive_val += (",id=%s" % kvm_devid)
1199
        drive_val += (",bus=0,unit=%d" % cfdev.pci)
1200
        dev_val = ("%s,drive=%s,id=%s" %
1201
                   (device_driver, kvm_devid, kvm_devid))
1202
        dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci)
1203
        dev_opts.extend(["-device", dev_val])
1204

    
1205
      dev_opts.extend(["-drive", drive_val])
1206

    
1207
    return dev_opts
1208

    
1209
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1210
                          kvmhelp):
1211
    """Generate KVM information to start an instance.
1212

1213
    @type kvmhelp: string
1214
    @param kvmhelp: output of kvm --help
1215
    @attention: this function must not have any side-effects; for
1216
        example, it must not write to the filesystem, or read values
1217
        from the current system the are expected to differ between
1218
        nodes, since it is only run once at instance startup;
1219
        actions/kvm arguments that can vary between systems should be
1220
        done in L{_ExecuteKVMRuntime}
1221

1222
    """
1223
    # pylint: disable=R0912,R0914,R0915
1224
    hvp = instance.hvparams
1225
    self.ValidateParameters(hvp)
1226

    
1227
    pidfile = self._InstancePidFile(instance.name)
1228
    kvm = hvp[constants.HV_KVM_PATH]
1229
    kvm_cmd = [kvm]
1230
    # used just by the vnc server, if enabled
1231
    kvm_cmd.extend(["-name", instance.name])
1232
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1233

    
1234
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1235
    if hvp[constants.HV_CPU_CORES]:
1236
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1237
    if hvp[constants.HV_CPU_THREADS]:
1238
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1239
    if hvp[constants.HV_CPU_SOCKETS]:
1240
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1241

    
1242
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1243

    
1244
    kvm_cmd.extend(["-pidfile", pidfile])
1245
    kvm_cmd.extend(["-balloon", "virtio"])
1246
    kvm_cmd.extend(["-daemonize"])
1247
    if not instance.hvparams[constants.HV_ACPI]:
1248
      kvm_cmd.extend(["-no-acpi"])
1249
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1250
        constants.INSTANCE_REBOOT_EXIT:
1251
      kvm_cmd.extend(["-no-reboot"])
1252

    
1253
    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1254
    if not mversion:
1255
      mversion = self._GetDefaultMachineVersion(kvm)
1256
    if self._MACHINE_RE.search(kvmhelp):
1257
      # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1258
      # extra hypervisor parameters. We should also investigate whether and how
1259
      # shadow_mem should be considered for the resource model.
1260
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1261
        specprop = ",accel=kvm"
1262
      else:
1263
        specprop = ""
1264
      machinespec = "%s%s" % (mversion, specprop)
1265
      kvm_cmd.extend(["-machine", machinespec])
1266
    else:
1267
      kvm_cmd.extend(["-M", mversion])
1268
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1269
          self._ENABLE_KVM_RE.search(kvmhelp)):
1270
        kvm_cmd.extend(["-enable-kvm"])
1271
      elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1272
            self._DISABLE_KVM_RE.search(kvmhelp)):
1273
        kvm_cmd.extend(["-disable-kvm"])
1274

    
1275
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1276
    if kernel_path:
1277
      boot_cdrom = boot_floppy = boot_network = False
1278
    else:
1279
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1280
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1281
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1282

    
1283
    if startup_paused:
1284
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1285

    
1286
    if boot_network:
1287
      kvm_cmd.extend(["-boot", "n"])
1288

    
1289
    # whether this is an older KVM version that uses the boot=on flag
1290
    # on devices
1291
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1292

    
1293
    disk_type = hvp[constants.HV_DISK_TYPE]
1294

    
1295
    #Now we can specify a different device type for CDROM devices.
1296
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1297
    if not cdrom_disk_type:
1298
      cdrom_disk_type = disk_type
1299

    
1300
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1301
    if iso_image:
1302
      options = ",format=raw,media=cdrom"
1303
      # set cdrom 'if' type
1304
      if boot_cdrom:
1305
        actual_cdrom_type = constants.HT_DISK_IDE
1306
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1307
        actual_cdrom_type = "virtio"
1308
      else:
1309
        actual_cdrom_type = cdrom_disk_type
1310
      if_val = ",if=%s" % actual_cdrom_type
1311
      # set boot flag, if needed
1312
      boot_val = ""
1313
      if boot_cdrom:
1314
        kvm_cmd.extend(["-boot", "d"])
1315
        if needs_boot_flag:
1316
          boot_val = ",boot=on"
1317
      # and finally build the entire '-drive' value
1318
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1319
      kvm_cmd.extend(["-drive", drive_val])
1320

    
1321
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1322
    if iso_image2:
1323
      options = ",format=raw,media=cdrom"
1324
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1325
        if_val = ",if=virtio"
1326
      else:
1327
        if_val = ",if=%s" % cdrom_disk_type
1328
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1329
      kvm_cmd.extend(["-drive", drive_val])
1330

    
1331
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1332
    if floppy_image:
1333
      options = ",format=raw,media=disk"
1334
      if boot_floppy:
1335
        kvm_cmd.extend(["-boot", "a"])
1336
        options = "%s,boot=on" % options
1337
      if_val = ",if=floppy"
1338
      options = "%s%s" % (options, if_val)
1339
      drive_val = "file=%s%s" % (floppy_image, options)
1340
      kvm_cmd.extend(["-drive", drive_val])
1341

    
1342
    if kernel_path:
1343
      kvm_cmd.extend(["-kernel", kernel_path])
1344
      initrd_path = hvp[constants.HV_INITRD_PATH]
1345
      if initrd_path:
1346
        kvm_cmd.extend(["-initrd", initrd_path])
1347
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1348
                     hvp[constants.HV_KERNEL_ARGS]]
1349
      if hvp[constants.HV_SERIAL_CONSOLE]:
1350
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1351
        root_append.append("console=ttyS0,%s" % serial_speed)
1352
      kvm_cmd.extend(["-append", " ".join(root_append)])
1353

    
1354
    mem_path = hvp[constants.HV_MEM_PATH]
1355
    if mem_path:
1356
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1357

    
1358
    monitor_dev = ("unix:%s,server,nowait" %
1359
                   self._InstanceMonitor(instance.name))
1360
    kvm_cmd.extend(["-monitor", monitor_dev])
1361
    if hvp[constants.HV_SERIAL_CONSOLE]:
1362
      serial_dev = ("unix:%s,server,nowait" %
1363
                    self._InstanceSerial(instance.name))
1364
      kvm_cmd.extend(["-serial", serial_dev])
1365
    else:
1366
      kvm_cmd.extend(["-serial", "none"])
1367

    
1368
    mouse_type = hvp[constants.HV_USB_MOUSE]
1369
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1370
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1371
    spice_ip_version = None
1372

    
1373
    kvm_cmd.extend(["-usb"])
1374

    
1375
    if mouse_type:
1376
      kvm_cmd.extend(["-usbdevice", mouse_type])
1377
    elif vnc_bind_address:
1378
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1379

    
1380
    if vnc_bind_address:
1381
      if netutils.IP4Address.IsValid(vnc_bind_address):
1382
        if instance.network_port > constants.VNC_BASE_PORT:
1383
          display = instance.network_port - constants.VNC_BASE_PORT
1384
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1385
            vnc_arg = ":%d" % (display)
1386
          else:
1387
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1388
        else:
1389
          logging.error("Network port is not a valid VNC display (%d < %d),"
1390
                        " not starting VNC",
1391
                        instance.network_port, constants.VNC_BASE_PORT)
1392
          vnc_arg = "none"
1393

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

    
1408
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1409

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

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

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

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

    
1447
        spice_address = addresses[spice_ip_version][0]
1448

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

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

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

    
1471
      if spice_ip_version:
1472
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1473

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

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

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

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

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

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

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

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

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

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

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

    
1542
    if hvp[constants.HV_KVM_EXTRA]:
1543
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1544

    
1545
    pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1546
    kvm_disks = []
1547
    for disk, dev_path in block_devices:
1548
      _UpdatePCISlots(disk, pci_reservations)
1549
      kvm_disks.append((disk, dev_path))
1550

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

    
1556
    hvparams = hvp
1557

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1636
  # 52/50 local variables
1637
  # pylint: disable=R0914
1638
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1639
    """Execute a KVM cmd, after completing it with some last minute data.
1640

1641
    @type incoming: tuple of strings
1642
    @param incoming: (target_host_ip, port)
1643
    @type kvmhelp: string
1644
    @param kvmhelp: output of kvm --help
1645

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

    
1659
    temp_files = []
1660

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

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

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

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

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

    
1715
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1716

    
1717
      for nic_seq, nic in enumerate(kvm_nics):
1718
        tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1719
        tapfds.append(tapfd)
1720
        taps.append(tapname)
1721
        if kvm_supports_netdev:
1722
          nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1723
          try:
1724
            # kvm_nics already exist in old runtime files and thus there might
1725
            # be some entries without pci slot (therefore try: except:)
1726
            kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1727
            netdev = kvm_devid
1728
            nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1729
          except errors.HotplugError:
1730
            netdev = "netdev%d" % nic_seq
1731
          nic_val += (",netdev=%s" % netdev)
1732
          tap_val = ("type=tap,id=%s,fd=%d%s" %
1733
                     (netdev, tapfd, tap_extra))
1734
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1735
        else:
1736
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1737
                                                         nic.mac, nic_model)
1738
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1739
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1740

    
1741
    if incoming:
1742
      target, port = incoming
1743
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1744

    
1745
    # Changing the vnc password doesn't bother the guest that much. At most it
1746
    # will surprise people who connect to it. Whether positively or negatively
1747
    # it's debatable.
1748
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1749
    vnc_pwd = None
1750
    if vnc_pwd_file:
1751
      try:
1752
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1753
      except EnvironmentError, err:
1754
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1755
                                     % (vnc_pwd_file, err))
1756

    
1757
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1758
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1759
                         constants.SECURE_DIR_MODE)])
1760

    
1761
    # Automatically enable QMP if version is >= 0.14
1762
    if self._QMP_RE.search(kvmhelp):
1763
      logging.debug("Enabling QMP")
1764
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1765
                      self._InstanceQmpMonitor(instance.name)])
1766

    
1767
    # Configure the network now for starting instances and bridged interfaces,
1768
    # during FinalizeMigration for incoming instances' routed interfaces
1769
    for nic_seq, nic in enumerate(kvm_nics):
1770
      if (incoming and
1771
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1772
        continue
1773
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1774

    
1775
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1776
                                                     block_devices,
1777
                                                     kvmhelp)
1778
    kvm_cmd.extend(bdev_opts)
1779
    # CPU affinity requires kvm to start paused, so we set this flag if the
1780
    # instance is not already paused and if we are not going to accept a
1781
    # migrating instance. In the latter case, pausing is not needed.
1782
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1783
    if start_kvm_paused:
1784
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1785

    
1786
    # Note: CPU pinning is using up_hvp since changes take effect
1787
    # during instance startup anyway, and to avoid problems when soft
1788
    # rebooting the instance.
1789
    cpu_pinning = False
1790
    if up_hvp.get(constants.HV_CPU_MASK, None):
1791
      cpu_pinning = True
1792

    
1793
    if security_model == constants.HT_SM_POOL:
1794
      ss = ssconf.SimpleStore()
1795
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1796
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1797
      uid = uidpool.RequestUnusedUid(all_uids)
1798
      try:
1799
        username = pwd.getpwuid(uid.GetUid()).pw_name
1800
        kvm_cmd.extend(["-runas", username])
1801
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1802
      except:
1803
        uidpool.ReleaseUid(uid)
1804
        raise
1805
      else:
1806
        uid.Unlock()
1807
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1808
    else:
1809
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1810

    
1811
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1812
                     constants.RUN_DIRS_MODE)])
1813
    for nic_seq, tap in enumerate(taps):
1814
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1815
                      data=tap)
1816

    
1817
    if vnc_pwd:
1818
      change_cmd = "change vnc password %s" % vnc_pwd
1819
      self._CallMonitorCommand(instance.name, change_cmd)
1820

    
1821
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1822
    # connection attempts because SPICE by default does not allow connections
1823
    # if neither a password nor the "disable_ticketing" options are specified.
1824
    # As soon as we send the password via QMP, that password is a valid ticket
1825
    # for connection.
1826
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1827
    if spice_password_file:
1828
      spice_pwd = ""
1829
      try:
1830
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1831
      except EnvironmentError, err:
1832
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1833
                                     % (spice_password_file, err))
1834

    
1835
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1836
      qmp.connect()
1837
      arguments = {
1838
          "protocol": "spice",
1839
          "password": spice_pwd,
1840
      }
1841
      qmp.Execute("set_password", arguments)
1842

    
1843
    for filename in temp_files:
1844
      utils.RemoveFile(filename)
1845

    
1846
    # If requested, set CPU affinity and resume instance execution
1847
    if cpu_pinning:
1848
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1849

    
1850
    start_memory = self._InstanceStartupMemory(instance)
1851
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1852
      self.BalloonInstanceMemory(instance, start_memory)
1853

    
1854
    if start_kvm_paused:
1855
      # To control CPU pinning, ballooning, and vnc/spice passwords
1856
      # the VM was started in a frozen state. If freezing was not
1857
      # explicitly requested resume the vm status.
1858
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1859

    
1860
  def StartInstance(self, instance, block_devices, startup_paused):
1861
    """Start an instance.
1862

1863
    """
1864
    self._CheckDown(instance.name)
1865
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1866
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1867
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1868
                                           startup_paused, kvmhelp)
1869
    self._SaveKVMRuntime(instance, kvm_runtime)
1870
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1871

    
1872
  def _CallMonitorCommand(self, instance_name, command):
1873
    """Invoke a command on the instance monitor.
1874

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

    
1894
    return result
1895

    
1896
  def _GetFreePCISlot(self, instance, dev):
1897
    """Get the first available pci slot of a runnung instance.
1898

1899
    """
1900
    slots = bitarray(32)
1901
    slots.setall(False) # pylint: disable=E1101
1902
    output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
1903
    for line in output.stdout.splitlines():
1904
      match = self._INFO_PCI_RE.search(line)
1905
      if match:
1906
        slot = int(match.group(1))
1907
        slots[slot] = True
1908

    
1909
    [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
1910
    if not free:
1911
      raise errors.HypervisorError("All PCI slots occupied")
1912

    
1913
    dev.pci = int(free)
1914

    
1915
  def HotplugSupported(self, instance, action, dev_type):
1916
    """Check if hotplug is supported.
1917

1918
    Hotplug is *not* supported in case of:
1919
     - qemu versions < 1.0
1920
     - security models and chroot (disk hotplug)
1921
     - fdsend module is missing (nic hot-add)
1922

1923
    @raise errors.HypervisorError: in previous cases
1924

1925
    """
1926
    output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
1927
    # TODO: search for netdev_add, drive_add, device_add.....
1928
    match = self._INFO_VERSION_RE.search(output.stdout)
1929
    if not match:
1930
      raise errors.HotplugError("Try hotplug only in running instances.")
1931
    v_major, v_min, _, _ = match.groups()
1932
    if (v_major, v_min) <= (1, 0):
1933
      raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
1934

    
1935
    if dev_type == constants.HOTPLUG_TARGET_DISK:
1936
      hvp = instance.hvparams
1937
      security_model = hvp[constants.HV_SECURITY_MODEL]
1938
      use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
1939
      if use_chroot:
1940
        raise errors.HotplugError("Disk hotplug is not supported"
1941
                                  " in case of chroot.")
1942
      if security_model != constants.HT_SM_NONE:
1943
        raise errors.HotplugError("Disk Hotplug is not supported in case"
1944
                                  " security models are used.")
1945

    
1946
    if (dev_type == constants.HOTPLUG_TARGET_NIC and
1947
        action == constants.HOTPLUG_ACTION_ADD and not fdsend):
1948
      raise errors.HotplugError("Cannot hot-add NIC."
1949
                                " fdsend python module is missing.")
1950
    return True
1951

    
1952
  def _CallHotplugCommand(self, name, cmd):
1953
    output = self._CallMonitorCommand(name, cmd)
1954
    # TODO: parse output and check if succeeded
1955
    for line in output.stdout.splitlines():
1956
      logging.info("%s", line)
1957

    
1958
  @classmethod
1959
  def _ParseKVMVersion(cls, text):
1960
    """Parse the KVM version from the --help output.
1961

1962
    @type text: string
1963
    @param text: output of kvm --help
1964
    @return: (version, v_maj, v_min, v_rev)
1965
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1966

1967
    """
1968
    match = cls._VERSION_RE.search(text.splitlines()[0])
1969
    if not match:
1970
      raise errors.HypervisorError("Unable to get KVM version")
1971

    
1972
    v_all = match.group(0)
1973
    v_maj = int(match.group(1))
1974
    v_min = int(match.group(2))
1975
    if match.group(4):
1976
      v_rev = int(match.group(4))
1977
    else:
1978
      v_rev = 0
1979
    return (v_all, v_maj, v_min, v_rev)
1980

    
1981
  @classmethod
1982
  def _GetKVMOutput(cls, kvm_path, option):
1983
    """Return the output of a kvm invocation
1984

1985
    @type kvm_path: string
1986
    @param kvm_path: path to the kvm executable
1987
    @type option: a key of _KVMOPTS_CMDS
1988
    @param option: kvm option to fetch the output from
1989
    @return: output a supported kvm invocation
1990
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1991

1992
    """
1993
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
1994

    
1995
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
1996

    
1997
    result = utils.RunCmd([kvm_path] + optlist)
1998
    if result.failed and not can_fail:
1999
      raise errors.HypervisorError("Unable to get KVM %s output" %
2000
                                    " ".join(cls._KVMOPTS_CMDS[option]))
2001
    return result.output
2002

    
2003
  @classmethod
2004
  def _GetKVMVersion(cls, kvm_path):
2005
    """Return the installed KVM version.
2006

2007
    @return: (version, v_maj, v_min, v_rev)
2008
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2009

2010
    """
2011
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2012

    
2013
  @classmethod
2014
  def _GetDefaultMachineVersion(cls, kvm_path):
2015
    """Return the default hardware revision (e.g. pc-1.1)
2016

2017
    """
2018
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2019
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2020
    if match:
2021
      return match.group(1)
2022
    else:
2023
      return "pc"
2024

    
2025
  def StopInstance(self, instance, force=False, retry=False, name=None):
2026
    """Stop an instance.
2027

2028
    """
2029
    if name is not None and not force:
2030
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2031
    if name is None:
2032
      name = instance.name
2033
      acpi = instance.hvparams[constants.HV_ACPI]
2034
    else:
2035
      acpi = False
2036
    _, pid, alive = self._InstancePidAlive(name)
2037
    if pid > 0 and alive:
2038
      if force or not acpi:
2039
        utils.KillProcess(pid)
2040
      else:
2041
        self._CallMonitorCommand(name, "system_powerdown")
2042

    
2043
  def CleanupInstance(self, instance_name):
2044
    """Cleanup after a stopped instance
2045

2046
    """
2047
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
2048
    if pid > 0 and alive:
2049
      raise errors.HypervisorError("Cannot cleanup a live instance")
2050
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2051

    
2052
  def RebootInstance(self, instance):
2053
    """Reboot an instance.
2054

2055
    """
2056
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2057
    # socket the instance will stop, but now power up again. So we'll resort
2058
    # to shutdown and restart.
2059
    _, _, alive = self._InstancePidAlive(instance.name)
2060
    if not alive:
2061
      raise errors.HypervisorError("Failed to reboot instance %s:"
2062
                                   " not running" % instance.name)
2063
    # StopInstance will delete the saved KVM runtime so:
2064
    # ...first load it...
2065
    kvm_runtime = self._LoadKVMRuntime(instance)
2066
    # ...now we can safely call StopInstance...
2067
    if not self.StopInstance(instance):
2068
      self.StopInstance(instance, force=True)
2069
    # ...and finally we can save it again, and execute it...
2070
    self._SaveKVMRuntime(instance, kvm_runtime)
2071
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2072
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2073
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2074

    
2075
  def MigrationInfo(self, instance):
2076
    """Get instance information to perform a migration.
2077

2078
    @type instance: L{objects.Instance}
2079
    @param instance: instance to be migrated
2080
    @rtype: string
2081
    @return: content of the KVM runtime file
2082

2083
    """
2084
    return self._ReadKVMRuntime(instance.name)
2085

    
2086
  def AcceptInstance(self, instance, info, target):
2087
    """Prepare to accept an instance.
2088

2089
    @type instance: L{objects.Instance}
2090
    @param instance: instance to be accepted
2091
    @type info: string
2092
    @param info: content of the KVM runtime file on the source node
2093
    @type target: string
2094
    @param target: target host (usually ip), on this node
2095

2096
    """
2097
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2098
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2099
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2100
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2101
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2102
                            incoming=incoming_address)
2103

    
2104
  def FinalizeMigrationDst(self, instance, info, success):
2105
    """Finalize the instance migration on the target node.
2106

2107
    Stop the incoming mode KVM.
2108

2109
    @type instance: L{objects.Instance}
2110
    @param instance: instance whose migration is being finalized
2111

2112
    """
2113
    if success:
2114
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2115
      kvm_nics = kvm_runtime[1]
2116

    
2117
      for nic_seq, nic in enumerate(kvm_nics):
2118
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2119
          # Bridged interfaces have already been configured
2120
          continue
2121
        try:
2122
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2123
        except EnvironmentError, err:
2124
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
2125
                          instance.name, nic_seq, str(err))
2126
          continue
2127
        try:
2128
          self._ConfigureNIC(instance, nic_seq, nic, tap)
2129
        except errors.HypervisorError, err:
2130
          logging.warning(str(err))
2131

    
2132
      self._WriteKVMRuntime(instance.name, info)
2133
    else:
2134
      self.StopInstance(instance, force=True)
2135

    
2136
  def MigrateInstance(self, instance, target, live):
2137
    """Migrate an instance to a target node.
2138

2139
    The migration will not be attempted if the instance is not
2140
    currently running.
2141

2142
    @type instance: L{objects.Instance}
2143
    @param instance: the instance to be migrated
2144
    @type target: string
2145
    @param target: ip address of the target node
2146
    @type live: boolean
2147
    @param live: perform a live migration
2148

2149
    """
2150
    instance_name = instance.name
2151
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
2152
    _, _, alive = self._InstancePidAlive(instance_name)
2153
    if not alive:
2154
      raise errors.HypervisorError("Instance not running, cannot migrate")
2155

    
2156
    if not live:
2157
      self._CallMonitorCommand(instance_name, "stop")
2158

    
2159
    migrate_command = ("migrate_set_speed %dm" %
2160
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2161
    self._CallMonitorCommand(instance_name, migrate_command)
2162

    
2163
    migrate_command = ("migrate_set_downtime %dms" %
2164
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2165
    self._CallMonitorCommand(instance_name, migrate_command)
2166

    
2167
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2168
    self._CallMonitorCommand(instance_name, migrate_command)
2169

    
2170
  def FinalizeMigrationSource(self, instance, success, live):
2171
    """Finalize the instance migration on the source node.
2172

2173
    @type instance: L{objects.Instance}
2174
    @param instance: the instance that was migrated
2175
    @type success: bool
2176
    @param success: whether the migration succeeded or not
2177
    @type live: bool
2178
    @param live: whether the user requested a live migration or not
2179

2180
    """
2181
    if success:
2182
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2183
      utils.KillProcess(pid)
2184
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2185
    elif live:
2186
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2187

    
2188
  def GetMigrationStatus(self, instance):
2189
    """Get the migration status
2190

2191
    @type instance: L{objects.Instance}
2192
    @param instance: the instance that is being migrated
2193
    @rtype: L{objects.MigrationStatus}
2194
    @return: the status of the current migration (one of
2195
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2196
             progress info that can be retrieved from the hypervisor
2197

2198
    """
2199
    info_command = "info migrate"
2200
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2201
      result = self._CallMonitorCommand(instance.name, info_command)
2202
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
2203
      if not match:
2204
        if not result.stdout:
2205
          logging.info("KVM: empty 'info migrate' result")
2206
        else:
2207
          logging.warning("KVM: unknown 'info migrate' result: %s",
2208
                          result.stdout)
2209
      else:
2210
        status = match.group(1)
2211
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2212
          migration_status = objects.MigrationStatus(status=status)
2213
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2214
          if match:
2215
            migration_status.transferred_ram = match.group("transferred")
2216
            migration_status.total_ram = match.group("total")
2217

    
2218
          return migration_status
2219

    
2220
        logging.warning("KVM: unknown migration status '%s'", status)
2221

    
2222
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2223

    
2224
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2225

    
2226
  def BalloonInstanceMemory(self, instance, mem):
2227
    """Balloon an instance memory to a certain value.
2228

2229
    @type instance: L{objects.Instance}
2230
    @param instance: instance to be accepted
2231
    @type mem: int
2232
    @param mem: actual memory size to use for instance runtime
2233

2234
    """
2235
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2236

    
2237
  def GetNodeInfo(self):
2238
    """Return information about the node.
2239

2240
    @return: a dict with the following keys (values in MiB):
2241
          - memory_total: the total memory size on the node
2242
          - memory_free: the available memory on the node for instances
2243
          - memory_dom0: the memory used by the node itself, if available
2244
          - hv_version: the hypervisor version in the form (major, minor,
2245
                        revision)
2246

2247
    """
2248
    result = self.GetLinuxNodeInfo()
2249
    # FIXME: this is the global kvm version, but the actual version can be
2250
    # customized as an hv parameter. we should use the nodegroup's default kvm
2251
    # path parameter here.
2252
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2253
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2254
    return result
2255

    
2256
  @classmethod
2257
  def GetInstanceConsole(cls, instance, hvparams, beparams):
2258
    """Return a command for connecting to the console of an instance.
2259

2260
    """
2261
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2262
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2263
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2264
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2265
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2266
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2267
      return objects.InstanceConsole(instance=instance.name,
2268
                                     kind=constants.CONS_SSH,
2269
                                     host=instance.primary_node,
2270
                                     user=constants.SSH_CONSOLE_USER,
2271
                                     command=cmd)
2272

    
2273
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2274
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2275
      display = instance.network_port - constants.VNC_BASE_PORT
2276
      return objects.InstanceConsole(instance=instance.name,
2277
                                     kind=constants.CONS_VNC,
2278
                                     host=vnc_bind_address,
2279
                                     port=instance.network_port,
2280
                                     display=display)
2281

    
2282
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2283
    if spice_bind:
2284
      return objects.InstanceConsole(instance=instance.name,
2285
                                     kind=constants.CONS_SPICE,
2286
                                     host=spice_bind,
2287
                                     port=instance.network_port)
2288

    
2289
    return objects.InstanceConsole(instance=instance.name,
2290
                                   kind=constants.CONS_MESSAGE,
2291
                                   message=("No serial shell for instance %s" %
2292
                                            instance.name))
2293

    
2294
  def Verify(self):
2295
    """Verify the hypervisor.
2296

2297
    Check that the required binaries exist.
2298

2299
    @return: Problem description if something is wrong, C{None} otherwise
2300

2301
    """
2302
    msgs = []
2303
    # FIXME: this is the global kvm binary, but the actual path can be
2304
    # customized as an hv parameter; we should use the nodegroup's
2305
    # default kvm path parameter here.
2306
    if not os.path.exists(constants.KVM_PATH):
2307
      msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2308
    if not os.path.exists(constants.SOCAT_PATH):
2309
      msgs.append("The socat binary ('%s') does not exist" %
2310
                  constants.SOCAT_PATH)
2311

    
2312
    return self._FormatVerifyResults(msgs)
2313

    
2314
  @classmethod
2315
  def CheckParameterSyntax(cls, hvparams):
2316
    """Check the given parameters for validity.
2317

2318
    @type hvparams:  dict
2319
    @param hvparams: dictionary with parameter names/value
2320
    @raise errors.HypervisorError: when a parameter is not valid
2321

2322
    """
2323
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2324

    
2325
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2326
    if kernel_path:
2327
      if not hvparams[constants.HV_ROOT_PATH]:
2328
        raise errors.HypervisorError("Need a root partition for the instance,"
2329
                                     " if a kernel is defined")
2330

    
2331
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2332
        not hvparams[constants.HV_VNC_X509]):
2333
      raise errors.HypervisorError("%s must be defined, if %s is" %
2334
                                   (constants.HV_VNC_X509,
2335
                                    constants.HV_VNC_X509_VERIFY))
2336

    
2337
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2338
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2339
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2340
      if not serial_speed or serial_speed not in valid_speeds:
2341
        raise errors.HypervisorError("Invalid serial console speed, must be"
2342
                                     " one of: %s" %
2343
                                     utils.CommaJoin(valid_speeds))
2344

    
2345
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2346
    if (boot_order == constants.HT_BO_CDROM and
2347
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2348
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2349
                                   " ISO path")
2350

    
2351
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2352
    if security_model == constants.HT_SM_USER:
2353
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2354
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2355
                                     " must be specified")
2356
    elif (security_model == constants.HT_SM_NONE or
2357
          security_model == constants.HT_SM_POOL):
2358
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2359
        raise errors.HypervisorError("Cannot have a security domain when the"
2360
                                     " security model is 'none' or 'pool'")
2361

    
2362
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2363
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2364
    if spice_bind:
2365
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2366
        # if an IP version is specified, the spice_bind parameter must be an
2367
        # IP of that family
2368
        if (netutils.IP4Address.IsValid(spice_bind) and
2369
            spice_ip_version != constants.IP4_VERSION):
2370
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2371
                                       " the specified IP version is %s" %
2372
                                       (spice_bind, spice_ip_version))
2373

    
2374
        if (netutils.IP6Address.IsValid(spice_bind) and
2375
            spice_ip_version != constants.IP6_VERSION):
2376
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2377
                                       " the specified IP version is %s" %
2378
                                       (spice_bind, spice_ip_version))
2379
    else:
2380
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2381
      # error if any of them is set without it.
2382
      for param in _SPICE_ADDITIONAL_PARAMS:
2383
        if hvparams[param]:
2384
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2385
                                       (param, constants.HV_KVM_SPICE_BIND))
2386

    
2387
  @classmethod
2388
  def ValidateParameters(cls, hvparams):
2389
    """Check the given parameters for validity.
2390

2391
    @type hvparams:  dict
2392
    @param hvparams: dictionary with parameter names/value
2393
    @raise errors.HypervisorError: when a parameter is not valid
2394

2395
    """
2396
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2397

    
2398
    kvm_path = hvparams[constants.HV_KVM_PATH]
2399

    
2400
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2401
    if security_model == constants.HT_SM_USER:
2402
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2403
      try:
2404
        pwd.getpwnam(username)
2405
      except KeyError:
2406
        raise errors.HypervisorError("Unknown security domain user %s"
2407
                                     % username)
2408

    
2409
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2410
    if spice_bind:
2411
      # only one of VNC and SPICE can be used currently.
2412
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2413
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2414
                                     " only one of them can be used at a"
2415
                                     " given time")
2416

    
2417
      # check that KVM supports SPICE
2418
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2419
      if not cls._SPICE_RE.search(kvmhelp):
2420
        raise errors.HypervisorError("SPICE is configured, but it is not"
2421
                                     " supported according to 'kvm --help'")
2422

    
2423
      # if spice_bind is not an IP address, it must be a valid interface
2424
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2425
                       netutils.IP6Address.IsValid(spice_bind))
2426
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2427
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2428
                                     " a valid IP address or interface name" %
2429
                                     constants.HV_KVM_SPICE_BIND)
2430

    
2431
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2432
    if machine_version:
2433
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2434
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2435
        raise errors.HypervisorError("Unsupported machine version: %s" %
2436
                                     machine_version)
2437

    
2438
  @classmethod
2439
  def PowercycleNode(cls):
2440
    """KVM powercycle, just a wrapper over Linux powercycle.
2441

2442
    """
2443
    cls.LinuxPowercycle()