Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm / __init__.py @ 904d32bc

History | View | Annotate | Download (93.1 kB)

1
#
2
#
3

    
4
# Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Google Inc.
5
# All rights reserved.
6
#
7
# Redistribution and use in source and binary forms, with or without
8
# modification, are permitted provided that the following conditions are
9
# met:
10
#
11
# 1. Redistributions of source code must retain the above copyright notice,
12
# this list of conditions and the following disclaimer.
13
#
14
# 2. Redistributions in binary form must reproduce the above copyright
15
# notice, this list of conditions and the following disclaimer in the
16
# documentation and/or other materials provided with the distribution.
17
#
18
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
19
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29

    
30

    
31
"""KVM hypervisor
32

33
"""
34

    
35
import errno
36
import os
37
import os.path
38
import re
39
import tempfile
40
import time
41
import logging
42
import pwd
43
import struct
44
import fcntl
45
import shutil
46
import urllib2
47
import socket
48
import stat
49
import StringIO
50
from bitarray import bitarray
51
try:
52
  import affinity   # pylint: disable=F0401
53
except ImportError:
54
  affinity = None
55
try:
56
  import fdsend   # pylint: disable=F0401
57
except ImportError:
58
  fdsend = None
59

    
60
from ganeti import utils
61
from ganeti import constants
62
from ganeti import errors
63
from ganeti import serializer
64
from ganeti import objects
65
from ganeti import uidpool
66
from ganeti import ssconf
67
from ganeti import netutils
68
from ganeti import pathutils
69
from ganeti.hypervisor import hv_base
70
from ganeti.utils import wrapper as utils_wrapper
71

    
72
from ganeti.hypervisor.hv_kvm.monitor import QmpConnection, QmpMessage, \
73
                                             MonitorSocket
74

    
75

    
76
_KVM_NETWORK_SCRIPT = pathutils.CONF_DIR + "/kvm-vif-bridge"
77
_KVM_START_PAUSED_FLAG = "-S"
78

    
79
# TUN/TAP driver constants, taken from <linux/if_tun.h>
80
# They are architecture-independent and already hardcoded in qemu-kvm source,
81
# so we can safely include them here.
82
TUNSETIFF = 0x400454ca
83
TUNGETIFF = 0x800454d2
84
TUNGETFEATURES = 0x800454cf
85
IFF_TAP = 0x0002
86
IFF_NO_PI = 0x1000
87
IFF_ONE_QUEUE = 0x2000
88
IFF_VNET_HDR = 0x4000
89

    
90
#: SPICE parameters which depend on L{constants.HV_KVM_SPICE_BIND}
91
_SPICE_ADDITIONAL_PARAMS = frozenset([
92
  constants.HV_KVM_SPICE_IP_VERSION,
93
  constants.HV_KVM_SPICE_PASSWORD_FILE,
94
  constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR,
95
  constants.HV_KVM_SPICE_JPEG_IMG_COMPR,
96
  constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR,
97
  constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION,
98
  constants.HV_KVM_SPICE_USE_TLS,
99
  ])
100

    
101
# Constant bitarray that reflects to a free pci slot
102
# Use it with bitarray.search()
103
_AVAILABLE_PCI_SLOT = bitarray("0")
104

    
105
# below constants show the format of runtime file
106
# the nics are in second possition, while the disks in 4th (last)
107
# moreover disk entries are stored as a list of in tuples
108
# (L{objects.Disk}, link_name, uri)
109
_KVM_NICS_RUNTIME_INDEX = 1
110
_KVM_DISKS_RUNTIME_INDEX = 3
111
_DEVICE_RUNTIME_INDEX = {
112
  constants.HOTPLUG_TARGET_DISK: _KVM_DISKS_RUNTIME_INDEX,
113
  constants.HOTPLUG_TARGET_NIC: _KVM_NICS_RUNTIME_INDEX
114
  }
115
_FIND_RUNTIME_ENTRY = {
116
  constants.HOTPLUG_TARGET_NIC:
117
    lambda nic, kvm_nics: [n for n in kvm_nics if n.uuid == nic.uuid],
118
  constants.HOTPLUG_TARGET_DISK:
119
    lambda disk, kvm_disks: [(d, l, u) for (d, l, u) in kvm_disks
120
                             if d.uuid == disk.uuid]
121
  }
122
_RUNTIME_DEVICE = {
123
  constants.HOTPLUG_TARGET_NIC: lambda d: d,
124
  constants.HOTPLUG_TARGET_DISK: lambda (d, e, _): d
125
  }
126
_RUNTIME_ENTRY = {
127
  constants.HOTPLUG_TARGET_NIC: lambda d, e: d,
128
  constants.HOTPLUG_TARGET_DISK: lambda d, e: (d, e[0], e[1])
129
  }
130

    
131
_MIGRATION_CAPS_DELIM = ":"
132

    
133

    
134
def _GetDriveURI(disk, link, uri):
135
  """Helper function to get the drive uri to be used in --drive kvm option
136

137
  @type disk: L{objects.Disk}
138
  @param disk: A disk configuration object
139
  @type link: string
140
  @param link: The device link as returned by _SymlinkBlockDev()
141
  @type uri: string
142
  @param uri: The drive uri as returned by _CalculateDeviceURI()
143

144
  """
145
  access_mode = disk.params.get(constants.LDP_ACCESS,
146
                                constants.DISK_KERNELSPACE)
147
  if (uri and access_mode == constants.DISK_USERSPACE):
148
    drive_uri = uri
149
  else:
150
    drive_uri = link
151

    
152
  return drive_uri
153

    
154

    
155
def _GenerateDeviceKVMId(dev_type, dev):
156
  """Helper function to generate a unique device name used by KVM
157

158
  QEMU monitor commands use names to identify devices. Here we use their pci
159
  slot and a part of their UUID to name them. dev.pci might be None for old
160
  devices in the cluster.
161

162
  @type dev_type: sting
163
  @param dev_type: device type of param dev
164
  @type dev: L{objects.Disk} or L{objects.NIC}
165
  @param dev: the device object for which we generate a kvm name
166
  @raise errors.HotplugError: in case a device has no pci slot (old devices)
167

168
  """
169

    
170
  if not dev.pci:
171
    raise errors.HotplugError("Hotplug is not supported for %s with UUID %s" %
172
                              (dev_type, dev.uuid))
173

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

    
176

    
177
def _GetFreeSlot(slots, slot=None, reserve=False):
178
  """Helper method to get first available slot in a bitarray
179

180
  @type slots: bitarray
181
  @param slots: the bitarray to operate on
182
  @type slot: integer
183
  @param slot: if given we check whether the slot is free
184
  @type reserve: boolean
185
  @param reserve: whether to reserve the first available slot or not
186
  @return: the idx of the (first) available slot
187
  @raise errors.HotplugError: If all slots in a bitarray are occupied
188
    or the given slot is not free.
189

190
  """
191
  if slot is not None:
192
    assert slot < len(slots)
193
    if slots[slot]:
194
      raise errors.HypervisorError("Slots %d occupied" % slot)
195

    
196
  else:
197
    avail = slots.search(_AVAILABLE_PCI_SLOT, 1)
198
    if not avail:
199
      raise errors.HypervisorError("All slots occupied")
200

    
201
    slot = int(avail[0])
202

    
203
  if reserve:
204
    slots[slot] = True
205

    
206
  return slot
207

    
208

    
209
def _GetExistingDeviceInfo(dev_type, device, runtime):
210
  """Helper function to get an existing device inside the runtime file
211

212
  Used when an instance is running. Load kvm runtime file and search
213
  for a device based on its type and uuid.
214

215
  @type dev_type: sting
216
  @param dev_type: device type of param dev
217
  @type device: L{objects.Disk} or L{objects.NIC}
218
  @param device: the device object for which we generate a kvm name
219
  @type runtime: tuple (cmd, nics, hvparams, disks)
220
  @param runtime: the runtime data to search for the device
221
  @raise errors.HotplugError: in case the requested device does not
222
    exist (e.g. device has been added without --hotplug option) or
223
    device info has not pci slot (e.g. old devices in the cluster)
224

225
  """
226
  index = _DEVICE_RUNTIME_INDEX[dev_type]
227
  found = _FIND_RUNTIME_ENTRY[dev_type](device, runtime[index])
228
  if not found:
229
    raise errors.HotplugError("Cannot find runtime info for %s with UUID %s" %
230
                              (dev_type, device.uuid))
231

    
232
  return found[0]
233

    
234

    
235
def _UpgradeSerializedRuntime(serialized_runtime):
236
  """Upgrade runtime data
237

238
  Remove any deprecated fields or change the format of the data.
239
  The runtime files are not upgraded when Ganeti is upgraded, so the required
240
  modification have to be performed here.
241

242
  @type serialized_runtime: string
243
  @param serialized_runtime: raw text data read from actual runtime file
244
  @return: (cmd, nic dicts, hvparams, bdev dicts)
245
  @rtype: tuple
246

247
  """
248
  loaded_runtime = serializer.Load(serialized_runtime)
249
  kvm_cmd, serialized_nics, hvparams = loaded_runtime[:3]
250
  if len(loaded_runtime) >= 4:
251
    serialized_disks = loaded_runtime[3]
252
  else:
253
    serialized_disks = []
254

    
255
  for nic in serialized_nics:
256
    # Add a dummy uuid slot if an pre-2.8 NIC is found
257
    if "uuid" not in nic:
258
      nic["uuid"] = utils.NewUUID()
259

    
260
  return kvm_cmd, serialized_nics, hvparams, serialized_disks
261

    
262

    
263
def _AnalyzeSerializedRuntime(serialized_runtime):
264
  """Return runtime entries for a serialized runtime file
265

266
  @type serialized_runtime: string
267
  @param serialized_runtime: raw text data read from actual runtime file
268
  @return: (cmd, nics, hvparams, bdevs)
269
  @rtype: tuple
270

271
  """
272
  kvm_cmd, serialized_nics, hvparams, serialized_disks = \
273
    _UpgradeSerializedRuntime(serialized_runtime)
274
  kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
275
  kvm_disks = [(objects.Disk.FromDict(sdisk), link, uri)
276
               for sdisk, link, uri in serialized_disks]
277

    
278
  return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
279

    
280

    
281
def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
282
  """Retrieves supported TUN features from file descriptor.
283

284
  @see: L{_ProbeTapVnetHdr}
285

286
  """
287
  req = struct.pack("I", 0)
288
  try:
289
    buf = _ioctl(fd, TUNGETFEATURES, req)
290
  except EnvironmentError, err:
291
    logging.warning("ioctl(TUNGETFEATURES) failed: %s", err)
292
    return None
293
  else:
294
    (flags, ) = struct.unpack("I", buf)
295
    return flags
296

    
297

    
298
def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
299
  """Check whether to enable the IFF_VNET_HDR flag.
300

301
  To do this, _all_ of the following conditions must be met:
302
   1. TUNGETFEATURES ioctl() *must* be implemented
303
   2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
304
   3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
305
      drivers/net/tun.c there is no way to test this until after the tap device
306
      has been created using TUNSETIFF, and there is no way to change the
307
      IFF_VNET_HDR flag after creating the interface, catch-22! However both
308
      TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
309
      thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
310

311
   @type fd: int
312
   @param fd: the file descriptor of /dev/net/tun
313

314
  """
315
  flags = _features_fn(fd)
316

    
317
  if flags is None:
318
    # Not supported
319
    return False
320

    
321
  result = bool(flags & IFF_VNET_HDR)
322

    
323
  if not result:
324
    logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
325

    
326
  return result
327

    
328

    
329
def _OpenTap(vnet_hdr=True, name=""):
330
  """Open a new tap device and return its file descriptor.
331

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

335
  @type vnet_hdr: boolean
336
  @param vnet_hdr: Enable the VNET Header
337

338
  @type name: string
339
  @param name: name for the TAP interface being created; if an empty
340
               string is passed, the OS will generate a unique name
341

342
  @return: (ifname, tapfd)
343
  @rtype: tuple
344

345
  """
346
  try:
347
    tapfd = os.open("/dev/net/tun", os.O_RDWR)
348
  except EnvironmentError:
349
    raise errors.HypervisorError("Failed to open /dev/net/tun")
350

    
351
  flags = IFF_TAP | IFF_NO_PI | IFF_ONE_QUEUE
352

    
353
  if vnet_hdr and _ProbeTapVnetHdr(tapfd):
354
    flags |= IFF_VNET_HDR
355

    
356
  # The struct ifreq ioctl request (see netdevice(7))
357
  ifr = struct.pack("16sh", name, flags)
358

    
359
  try:
360
    res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
361
  except EnvironmentError, err:
362
    raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
363
                                 err)
364

    
365
  # Get the interface name from the ioctl
366
  ifname = struct.unpack("16sh", res)[0].strip("\x00")
367
  return (ifname, tapfd)
368

    
369

    
370
class HeadRequest(urllib2.Request):
371
  def get_method(self):
372
    return "HEAD"
373

    
374

    
375
def _CheckUrl(url):
376
  """Check if a given URL exists on the server
377

378
  """
379
  try:
380
    urllib2.urlopen(HeadRequest(url))
381
    return True
382
  except urllib2.URLError:
383
    return False
384

    
385

    
386
class KVMHypervisor(hv_base.BaseHypervisor):
387
  """KVM hypervisor interface
388

389
  """
390
  CAN_MIGRATE = True
391

    
392
  _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
393
  _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
394
  _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
395
  _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
396
  _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
397
  _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
398
  _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
399
  # KVM instances with chroot enabled are started in empty chroot directories.
400
  _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
401
  # After an instance is stopped, its chroot directory is removed.
402
  # If the chroot directory is not empty, it can't be removed.
403
  # A non-empty chroot directory indicates a possible security incident.
404
  # To support forensics, the non-empty chroot directory is quarantined in
405
  # a separate directory, called 'chroot-quarantine'.
406
  _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
407
  _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
408
           _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
409

    
410
  PARAMETERS = {
411
    constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
412
    constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
413
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
414
    constants.HV_ROOT_PATH: hv_base.NO_CHECK,
415
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
416
    constants.HV_ACPI: hv_base.NO_CHECK,
417
    constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
418
    constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
419
    constants.HV_VNC_BIND_ADDRESS: hv_base.NO_CHECK, # will be checked later
420
    constants.HV_VNC_TLS: hv_base.NO_CHECK,
421
    constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
422
    constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
423
    constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
424
    constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
425
    constants.HV_KVM_SPICE_IP_VERSION:
426
      (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
427
                         x in constants.VALID_IP_VERSIONS),
428
       "The SPICE IP version should be 4 or 6",
429
       None, None),
430
    constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
431
    constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
432
      hv_base.ParamInSet(
433
        False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
434
    constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
435
      hv_base.ParamInSet(
436
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
437
    constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
438
      hv_base.ParamInSet(
439
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
440
    constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
441
      hv_base.ParamInSet(
442
        False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
443
    constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
444
    constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
445
    constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
446
    constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
447
    constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
448
    constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_OR_URL_CHECK,
449
    constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_OR_URL_CHECK,
450
    constants.HV_BOOT_ORDER:
451
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
452
    constants.HV_NIC_TYPE:
453
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
454
    constants.HV_DISK_TYPE:
455
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
456
    constants.HV_KVM_CDROM_DISK_TYPE:
457
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
458
    constants.HV_USB_MOUSE:
459
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
460
    constants.HV_KEYMAP: hv_base.NO_CHECK,
461
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
462
    constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
463
    constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
464
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
465
    constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
466
    constants.HV_DISK_CACHE:
467
      hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
468
    constants.HV_SECURITY_MODEL:
469
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
470
    constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
471
    constants.HV_KVM_FLAG:
472
      hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
473
    constants.HV_VHOST_NET: hv_base.NO_CHECK,
474
    constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
475
    constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
476
    constants.HV_REBOOT_BEHAVIOR:
477
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
478
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
479
    constants.HV_CPU_TYPE: hv_base.NO_CHECK,
480
    constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
481
    constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
482
    constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
483
    constants.HV_SOUNDHW: hv_base.NO_CHECK,
484
    constants.HV_USB_DEVICES: hv_base.NO_CHECK,
485
    constants.HV_VGA: hv_base.NO_CHECK,
486
    constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
487
    constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
488
    constants.HV_KVM_MIGRATION_CAPS: hv_base.NO_CHECK,
489
    constants.HV_VNET_HDR: hv_base.NO_CHECK,
490
    }
491

    
492
  _VIRTIO = "virtio"
493
  _VIRTIO_NET_PCI = "virtio-net-pci"
494
  _VIRTIO_BLK_PCI = "virtio-blk-pci"
495

    
496
  _MIGRATION_STATUS_RE = re.compile(r"Migration\s+status:\s+(\w+)",
497
                                    re.M | re.I)
498
  _MIGRATION_PROGRESS_RE = \
499
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
500
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
501
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
502

    
503
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
504
  _MIGRATION_INFO_RETRY_DELAY = 2
505

    
506
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
507

    
508
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
509
  _CPU_INFO_CMD = "info cpus"
510
  _CONT_CMD = "cont"
511

    
512
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
513
  _CHECK_MACHINE_VERSION_RE = \
514
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
515

    
516
  _QMP_RE = re.compile(r"^-qmp\s", re.M)
517
  _SPICE_RE = re.compile(r"^-spice\s", re.M)
518
  _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
519
  _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
520
  _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
521
  _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
522
  _DISPLAY_RE = re.compile(r"^-display\s", re.M)
523
  _MACHINE_RE = re.compile(r"^-machine\s", re.M)
524
  _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
525
  _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M)
526
  # match  -drive.*boot=on|off on different lines, but in between accept only
527
  # dashes not preceeded by a new line (which would mean another option
528
  # different than -drive is starting)
529
  _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
530
  _UUID_RE = re.compile(r"^-uuid\s", re.M)
531

    
532
  _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
533
  _INFO_PCI_CMD = "info pci"
534
  _FIND_PCI_DEVICE_RE = \
535
    staticmethod(
536
      lambda pci, devid: re.compile(r'Bus.*device[ ]*%d,(.*\n){5,6}.*id "%s"' %
537
                                    (pci, devid), re.M))
538

    
539
  _INFO_VERSION_RE = \
540
    re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
541
  _INFO_VERSION_CMD = "info version"
542

    
543
  # Slot 0 for Host bridge, Slot 1 for ISA bridge, Slot 2 for VGA controller
544
  _DEFAULT_PCI_RESERVATIONS = "11100000000000000000000000000000"
545
  _SOUNDHW_WITH_PCI_SLOT = ["ac97", "es1370", "hda"]
546

    
547
  ANCILLARY_FILES = [
548
    _KVM_NETWORK_SCRIPT,
549
    ]
550
  ANCILLARY_FILES_OPT = [
551
    _KVM_NETWORK_SCRIPT,
552
    ]
553

    
554
  # Supported kvm options to get output from
555
  _KVMOPT_HELP = "help"
556
  _KVMOPT_MLIST = "mlist"
557
  _KVMOPT_DEVICELIST = "devicelist"
558

    
559
  # Command to execute to get the output from kvm, and whether to
560
  # accept the output even on failure.
561
  _KVMOPTS_CMDS = {
562
    _KVMOPT_HELP: (["--help"], False),
563
    _KVMOPT_MLIST: (["-M", "?"], False),
564
    _KVMOPT_DEVICELIST: (["-device", "?"], True),
565
  }
566

    
567
  def __init__(self):
568
    hv_base.BaseHypervisor.__init__(self)
569
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
570
    # in a tmpfs filesystem or has been otherwise wiped out.
571
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
572
    utils.EnsureDirs(dirs)
573

    
574
  @classmethod
575
  def _InstancePidFile(cls, instance_name):
576
    """Returns the instance pidfile.
577

578
    """
579
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
580

    
581
  @classmethod
582
  def _InstanceUidFile(cls, instance_name):
583
    """Returns the instance uidfile.
584

585
    """
586
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
587

    
588
  @classmethod
589
  def _InstancePidInfo(cls, pid):
590
    """Check pid file for instance information.
591

592
    Check that a pid file is associated with an instance, and retrieve
593
    information from its command line.
594

595
    @type pid: string or int
596
    @param pid: process id of the instance to check
597
    @rtype: tuple
598
    @return: (instance_name, memory, vcpus)
599
    @raise errors.HypervisorError: when an instance cannot be found
600

601
    """
602
    alive = utils.IsProcessAlive(pid)
603
    if not alive:
604
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
605

    
606
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
607
    try:
608
      cmdline = utils.ReadFile(cmdline_file)
609
    except EnvironmentError, err:
610
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
611
                                   (pid, err))
612

    
613
    instance = None
614
    memory = 0
615
    vcpus = 0
616

    
617
    arg_list = cmdline.split("\x00")
618
    while arg_list:
619
      arg = arg_list.pop(0)
620
      if arg == "-name":
621
        instance = arg_list.pop(0)
622
      elif arg == "-m":
623
        memory = int(arg_list.pop(0))
624
      elif arg == "-smp":
625
        vcpus = int(arg_list.pop(0).split(",")[0])
626

    
627
    if instance is None:
628
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
629
                                   " instance" % pid)
630

    
631
    return (instance, memory, vcpus)
632

    
633
  @classmethod
634
  def _InstancePidAlive(cls, instance_name):
635
    """Returns the instance pidfile, pid, and liveness.
636

637
    @type instance_name: string
638
    @param instance_name: instance name
639
    @rtype: tuple
640
    @return: (pid file name, pid, liveness)
641

642
    """
643
    pidfile = cls._InstancePidFile(instance_name)
644
    pid = utils.ReadPidFile(pidfile)
645

    
646
    alive = False
647
    try:
648
      cmd_instance = cls._InstancePidInfo(pid)[0]
649
      alive = (cmd_instance == instance_name)
650
    except errors.HypervisorError:
651
      pass
652

    
653
    return (pidfile, pid, alive)
654

    
655
  @classmethod
656
  def _CheckDown(cls, instance_name):
657
    """Raises an error unless the given instance is down.
658

659
    """
660
    alive = cls._InstancePidAlive(instance_name)[2]
661
    if alive:
662
      raise errors.HypervisorError("Failed to start instance %s: %s" %
663
                                   (instance_name, "already running"))
664

    
665
  @classmethod
666
  def _InstanceMonitor(cls, instance_name):
667
    """Returns the instance monitor socket name
668

669
    """
670
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
671

    
672
  @classmethod
673
  def _InstanceSerial(cls, instance_name):
674
    """Returns the instance serial socket name
675

676
    """
677
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
678

    
679
  @classmethod
680
  def _InstanceQmpMonitor(cls, instance_name):
681
    """Returns the instance serial QMP socket name
682

683
    """
684
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
685

    
686
  @staticmethod
687
  def _SocatUnixConsoleParams():
688
    """Returns the correct parameters for socat
689

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

692
    """
693
    if constants.SOCAT_USE_ESCAPE:
694
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
695
    else:
696
      return "echo=0,icanon=0"
697

    
698
  @classmethod
699
  def _InstanceKVMRuntime(cls, instance_name):
700
    """Returns the instance KVM runtime filename
701

702
    """
703
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
704

    
705
  @classmethod
706
  def _InstanceChrootDir(cls, instance_name):
707
    """Returns the name of the KVM chroot dir of the instance
708

709
    """
710
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
711

    
712
  @classmethod
713
  def _InstanceNICDir(cls, instance_name):
714
    """Returns the name of the directory holding the tap device files for a
715
    given instance.
716

717
    """
718
    return utils.PathJoin(cls._NICS_DIR, instance_name)
719

    
720
  @classmethod
721
  def _InstanceNICFile(cls, instance_name, seq):
722
    """Returns the name of the file containing the tap device for a given NIC
723

724
    """
725
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
726

    
727
  @classmethod
728
  def _InstanceKeymapFile(cls, instance_name):
729
    """Returns the name of the file containing the keymap for a given instance
730

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

    
734
  @classmethod
735
  def _TryReadUidFile(cls, uid_file):
736
    """Try to read a uid file
737

738
    """
739
    if os.path.exists(uid_file):
740
      try:
741
        uid = int(utils.ReadOneLineFile(uid_file))
742
        return uid
743
      except EnvironmentError:
744
        logging.warning("Can't read uid file", exc_info=True)
745
      except (TypeError, ValueError):
746
        logging.warning("Can't parse uid file contents", exc_info=True)
747
    return None
748

    
749
  @classmethod
750
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
751
    """Removes an instance's rutime sockets/files/dirs.
752

753
    """
754
    utils.RemoveFile(pidfile)
755
    utils.RemoveFile(cls._InstanceMonitor(instance_name))
756
    utils.RemoveFile(cls._InstanceSerial(instance_name))
757
    utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
758
    utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
759
    utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
760
    uid_file = cls._InstanceUidFile(instance_name)
761
    uid = cls._TryReadUidFile(uid_file)
762
    utils.RemoveFile(uid_file)
763
    if uid is not None:
764
      uidpool.ReleaseUid(uid)
765
    try:
766
      shutil.rmtree(cls._InstanceNICDir(instance_name))
767
    except OSError, err:
768
      if err.errno != errno.ENOENT:
769
        raise
770
    try:
771
      chroot_dir = cls._InstanceChrootDir(instance_name)
772
      utils.RemoveDir(chroot_dir)
773
    except OSError, err:
774
      if err.errno == errno.ENOTEMPTY:
775
        # The chroot directory is expected to be empty, but it isn't.
776
        new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
777
                                          prefix="%s-%s-" %
778
                                          (instance_name,
779
                                           utils.TimestampForFilename()))
780
        logging.warning("The chroot directory of instance %s can not be"
781
                        " removed as it is not empty. Moving it to the"
782
                        " quarantine instead. Please investigate the"
783
                        " contents (%s) and clean up manually",
784
                        instance_name, new_chroot_dir)
785
        utils.RenameFile(chroot_dir, new_chroot_dir)
786
      else:
787
        raise
788

    
789
  @staticmethod
790
  def _ConfigureNIC(instance, seq, nic, tap):
791
    """Run the network configuration script for a specified NIC
792

793
    @param instance: instance we're acting on
794
    @type instance: instance object
795
    @param seq: nic sequence number
796
    @type seq: int
797
    @param nic: nic we're acting on
798
    @type nic: nic object
799
    @param tap: the host's tap interface this NIC corresponds to
800
    @type tap: str
801

802
    """
803
    env = {
804
      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
805
      "INSTANCE": instance.name,
806
      "MAC": nic.mac,
807
      "MODE": nic.nicparams[constants.NIC_MODE],
808
      "INTERFACE": tap,
809
      "INTERFACE_INDEX": str(seq),
810
      "INTERFACE_UUID": nic.uuid,
811
      "TAGS": " ".join(instance.GetTags()),
812
    }
813

    
814
    if nic.ip:
815
      env["IP"] = nic.ip
816

    
817
    if nic.name:
818
      env["INTERFACE_NAME"] = nic.name
819

    
820
    if nic.nicparams[constants.NIC_LINK]:
821
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
822

    
823
    if constants.NIC_VLAN in nic.nicparams:
824
      env["VLAN"] = nic.nicparams[constants.NIC_VLAN]
825

    
826
    if nic.network:
827
      n = objects.Network.FromDict(nic.netinfo)
828
      env.update(n.HooksDict())
829

    
830
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
831
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
832

    
833
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
834
    if result.failed:
835
      raise errors.HypervisorError("Failed to configure interface %s: %s;"
836
                                   " network configuration script output: %s" %
837
                                   (tap, result.fail_reason, result.output))
838

    
839
  @staticmethod
840
  def _VerifyAffinityPackage():
841
    if affinity is None:
842
      raise errors.HypervisorError("affinity Python package not"
843
                                   " found; cannot use CPU pinning under KVM")
844

    
845
  @staticmethod
846
  def _BuildAffinityCpuMask(cpu_list):
847
    """Create a CPU mask suitable for sched_setaffinity from a list of
848
    CPUs.
849

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

853
    @type cpu_list: list of int
854
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
855
    @rtype: int
856
    @return: a bit mask of CPU affinities
857

858
    """
859
    if cpu_list == constants.CPU_PINNING_OFF:
860
      return constants.CPU_PINNING_ALL_KVM
861
    else:
862
      return sum(2 ** cpu for cpu in cpu_list)
863

    
864
  @classmethod
865
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
866
    """Change CPU affinity for running VM according to given CPU mask.
867

868
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
869
    @type cpu_mask: string
870
    @param process_id: process ID of KVM process. Used to pin entire VM
871
                       to physical CPUs.
872
    @type process_id: int
873
    @param thread_dict: map of virtual CPUs to KVM thread IDs
874
    @type thread_dict: dict int:int
875

876
    """
877
    # Convert the string CPU mask to a list of list of int's
878
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
879

    
880
    if len(cpu_list) == 1:
881
      all_cpu_mapping = cpu_list[0]
882
      if all_cpu_mapping == constants.CPU_PINNING_OFF:
883
        # If CPU pinning has 1 entry that's "all", then do nothing
884
        pass
885
      else:
886
        # If CPU pinning has one non-all entry, map the entire VM to
887
        # one set of physical CPUs
888
        cls._VerifyAffinityPackage()
889
        affinity.set_process_affinity_mask(
890
          process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
891
    else:
892
      # The number of vCPUs mapped should match the number of vCPUs
893
      # reported by KVM. This was already verified earlier, so
894
      # here only as a sanity check.
895
      assert len(thread_dict) == len(cpu_list)
896
      cls._VerifyAffinityPackage()
897

    
898
      # For each vCPU, map it to the proper list of physical CPUs
899
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
900
        affinity.set_process_affinity_mask(thread_dict[i],
901
                                           cls._BuildAffinityCpuMask(vcpu))
902

    
903
  def _GetVcpuThreadIds(self, instance_name):
904
    """Get a mapping of vCPU no. to thread IDs for the instance
905

906
    @type instance_name: string
907
    @param instance_name: instance in question
908
    @rtype: dictionary of int:int
909
    @return: a dictionary mapping vCPU numbers to thread IDs
910

911
    """
912
    result = {}
913
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
914
    for line in output.stdout.splitlines():
915
      match = self._CPU_INFO_RE.search(line)
916
      if not match:
917
        continue
918
      grp = map(int, match.groups())
919
      result[grp[0]] = grp[1]
920

    
921
    return result
922

    
923
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
924
    """Complete CPU pinning.
925

926
    @type instance_name: string
927
    @param instance_name: name of instance
928
    @type cpu_mask: string
929
    @param cpu_mask: CPU pinning mask as entered by user
930

931
    """
932
    # Get KVM process ID, to be used if need to pin entire VM
933
    _, pid, _ = self._InstancePidAlive(instance_name)
934
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
935
    thread_dict = self._GetVcpuThreadIds(instance_name)
936
    # Run CPU pinning, based on configured mask
937
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
938

    
939
  def ListInstances(self, hvparams=None):
940
    """Get the list of running instances.
941

942
    We can do this by listing our live instances directory and
943
    checking whether the associated kvm process is still alive.
944

945
    """
946
    result = []
947
    for name in os.listdir(self._PIDS_DIR):
948
      if self._InstancePidAlive(name)[2]:
949
        result.append(name)
950
    return result
951

    
952
  def GetInstanceInfo(self, instance_name, hvparams=None):
953
    """Get instance properties.
954

955
    @type instance_name: string
956
    @param instance_name: the instance name
957
    @type hvparams: dict of strings
958
    @param hvparams: hvparams to be used with this instance
959
    @rtype: tuple of strings
960
    @return: (name, id, memory, vcpus, stat, times)
961

962
    """
963
    _, pid, alive = self._InstancePidAlive(instance_name)
964
    if not alive:
965
      return None
966

    
967
    _, memory, vcpus = self._InstancePidInfo(pid)
968
    istat = "---b-"
969
    times = "0"
970

    
971
    try:
972
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
973
      qmp.connect()
974
      vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
975
      # Will fail if ballooning is not enabled, but we can then just resort to
976
      # the value above.
977
      mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
978
      memory = mem_bytes / 1048576
979
    except errors.HypervisorError:
980
      pass
981

    
982
    return (instance_name, pid, memory, vcpus, istat, times)
983

    
984
  def GetAllInstancesInfo(self, hvparams=None):
985
    """Get properties of all instances.
986

987
    @type hvparams: dict of strings
988
    @param hvparams: hypervisor parameter
989
    @return: list of tuples (name, id, memory, vcpus, stat, times)
990

991
    """
992
    data = []
993
    for name in os.listdir(self._PIDS_DIR):
994
      try:
995
        info = self.GetInstanceInfo(name)
996
      except errors.HypervisorError:
997
        # Ignore exceptions due to instances being shut down
998
        continue
999
      if info:
1000
        data.append(info)
1001
    return data
1002

    
1003
  def _GenerateKVMBlockDevicesOptions(self, instance, up_hvp, kvm_disks,
1004
                                      kvmhelp, devlist):
1005
    """Generate KVM options regarding instance's block devices.
1006

1007
    @type instance: L{objects.Instance}
1008
    @param instance: the instance object
1009
    @type up_hvp: dict
1010
    @param up_hvp: the instance's runtime hypervisor parameters
1011
    @type kvm_disks: list of tuples
1012
    @param kvm_disks: list of tuples [(disk, link_name, uri)..]
1013
    @type kvmhelp: string
1014
    @param kvmhelp: output of kvm --help
1015
    @type devlist: string
1016
    @param devlist: output of kvm -device ?
1017
    @rtype: list
1018
    @return: list of command line options eventually used by kvm executable
1019

1020
    """
1021
    kernel_path = up_hvp[constants.HV_KERNEL_PATH]
1022
    if kernel_path:
1023
      boot_disk = False
1024
    else:
1025
      boot_disk = up_hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1026

    
1027
    # whether this is an older KVM version that uses the boot=on flag
1028
    # on devices
1029
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1030

    
1031
    dev_opts = []
1032
    device_driver = None
1033
    disk_type = up_hvp[constants.HV_DISK_TYPE]
1034
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
1035
      if_val = ",if=%s" % self._VIRTIO
1036
      try:
1037
        if self._VIRTIO_BLK_RE.search(devlist):
1038
          if_val = ",if=none"
1039
          # will be passed in -device option as driver
1040
          device_driver = self._VIRTIO_BLK_PCI
1041
      except errors.HypervisorError, _:
1042
        pass
1043
    else:
1044
      if_val = ",if=%s" % disk_type
1045
    # Cache mode
1046
    disk_cache = up_hvp[constants.HV_DISK_CACHE]
1047
    if instance.disk_template in constants.DTS_EXT_MIRROR:
1048
      if disk_cache != "none":
1049
        # TODO: make this a hard error, instead of a silent overwrite
1050
        logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1051
                        " to prevent shared storage corruption on migration",
1052
                        disk_cache)
1053
      cache_val = ",cache=none"
1054
    elif disk_cache != constants.HT_CACHE_DEFAULT:
1055
      cache_val = ",cache=%s" % disk_cache
1056
    else:
1057
      cache_val = ""
1058
    for cfdev, link_name, uri in kvm_disks:
1059
      if cfdev.mode != constants.DISK_RDWR:
1060
        raise errors.HypervisorError("Instance has read-only disks which"
1061
                                     " are not supported by KVM")
1062
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
1063
      boot_val = ""
1064
      if boot_disk:
1065
        dev_opts.extend(["-boot", "c"])
1066
        boot_disk = False
1067
        if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1068
          boot_val = ",boot=on"
1069

    
1070
      drive_uri = _GetDriveURI(cfdev, link_name, uri)
1071

    
1072
      drive_val = "file=%s,format=raw%s%s%s" % \
1073
                  (drive_uri, if_val, boot_val, cache_val)
1074

    
1075
      if device_driver:
1076
        # kvm_disks are the 4th entry of runtime file that did not exist in
1077
        # the past. That means that cfdev should always have pci slot and
1078
        # _GenerateDeviceKVMId() will not raise a exception.
1079
        kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_DISK, cfdev)
1080
        drive_val += (",id=%s" % kvm_devid)
1081
        drive_val += (",bus=0,unit=%d" % cfdev.pci)
1082
        dev_val = ("%s,drive=%s,id=%s" %
1083
                   (device_driver, kvm_devid, kvm_devid))
1084
        dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci)
1085
        dev_opts.extend(["-device", dev_val])
1086

    
1087
      dev_opts.extend(["-drive", drive_val])
1088

    
1089
    return dev_opts
1090

    
1091
  @staticmethod
1092
  def _CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image, cdrom_boot,
1093
                   needs_boot_flag):
1094
    """Extends L{kvm_cmd} with the '-drive' option for a cdrom, and
1095
    optionally the '-boot' option.
1096

1097
    Example: -drive file=cdrom.iso,media=cdrom,format=raw,if=ide -boot d
1098

1099
    Example: -drive file=cdrom.iso,media=cdrom,format=raw,if=ide,boot=on
1100

1101
    Example: -drive file=http://hostname.com/cdrom.iso,media=cdrom
1102

1103
    @type kvm_cmd: string
1104
    @param kvm_cmd: KVM command line
1105

1106
    @type cdrom_disk_type:
1107
    @param cdrom_disk_type:
1108

1109
    @type cdrom_image:
1110
    @param cdrom_image:
1111

1112
    @type cdrom_boot:
1113
    @param cdrom_boot:
1114

1115
    @type needs_boot_flag:
1116
    @param needs_boot_flag:
1117

1118
    """
1119
    # Check that the ISO image is accessible
1120
    # See https://bugs.launchpad.net/qemu/+bug/597575
1121
    if utils.IsUrl(cdrom_image) and not _CheckUrl(cdrom_image):
1122
      raise errors.HypervisorError("Cdrom ISO image '%s' is not accessible" %
1123
                                   cdrom_image)
1124

    
1125
    # set cdrom 'media' and 'format', if needed
1126
    if utils.IsUrl(cdrom_image):
1127
      options = ",media=cdrom"
1128
    else:
1129
      options = ",media=cdrom,format=raw"
1130

    
1131
    # set cdrom 'if' type
1132
    if cdrom_boot:
1133
      if_val = ",if=" + constants.HT_DISK_IDE
1134
    elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1135
      if_val = ",if=virtio"
1136
    else:
1137
      if_val = ",if=" + cdrom_disk_type
1138

    
1139
    # set boot flag, if needed
1140
    boot_val = ""
1141
    if cdrom_boot:
1142
      kvm_cmd.extend(["-boot", "d"])
1143

    
1144
      # whether this is an older KVM version that requires the 'boot=on' flag
1145
      # on devices
1146
      if needs_boot_flag:
1147
        boot_val = ",boot=on"
1148

    
1149
    # build '-drive' option
1150
    drive_val = "file=%s%s%s%s" % (cdrom_image, options, if_val, boot_val)
1151
    kvm_cmd.extend(["-drive", drive_val])
1152

    
1153
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1154
                          kvmhelp):
1155
    """Generate KVM information to start an instance.
1156

1157
    @type kvmhelp: string
1158
    @param kvmhelp: output of kvm --help
1159
    @attention: this function must not have any side-effects; for
1160
        example, it must not write to the filesystem, or read values
1161
        from the current system the are expected to differ between
1162
        nodes, since it is only run once at instance startup;
1163
        actions/kvm arguments that can vary between systems should be
1164
        done in L{_ExecuteKVMRuntime}
1165

1166
    """
1167
    # pylint: disable=R0912,R0914,R0915
1168
    hvp = instance.hvparams
1169
    self.ValidateParameters(hvp)
1170

    
1171
    pidfile = self._InstancePidFile(instance.name)
1172
    kvm = hvp[constants.HV_KVM_PATH]
1173
    kvm_cmd = [kvm]
1174
    # used just by the vnc server, if enabled
1175
    kvm_cmd.extend(["-name", instance.name])
1176
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1177

    
1178
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1179
    if hvp[constants.HV_CPU_CORES]:
1180
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1181
    if hvp[constants.HV_CPU_THREADS]:
1182
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1183
    if hvp[constants.HV_CPU_SOCKETS]:
1184
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1185

    
1186
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1187

    
1188
    kvm_cmd.extend(["-pidfile", pidfile])
1189

    
1190
    pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1191

    
1192
    # As requested by music lovers
1193
    if hvp[constants.HV_SOUNDHW]:
1194
      soundhw = hvp[constants.HV_SOUNDHW]
1195
      # For some reason only few sound devices require a PCI slot
1196
      # while the Audio controller *must* be in slot 3.
1197
      # That's why we bridge this option early in command line
1198
      if soundhw in self._SOUNDHW_WITH_PCI_SLOT:
1199
        _ = _GetFreeSlot(pci_reservations, reserve=True)
1200
      kvm_cmd.extend(["-soundhw", soundhw])
1201

    
1202
    if hvp[constants.HV_DISK_TYPE] == constants.HT_DISK_SCSI:
1203
      # The SCSI controller requires another PCI slot.
1204
      _ = _GetFreeSlot(pci_reservations, reserve=True)
1205

    
1206
    # Add id to ballon and place to the first available slot (3 or 4)
1207
    addr = _GetFreeSlot(pci_reservations, reserve=True)
1208
    pci_info = ",bus=pci.0,addr=%s" % hex(addr)
1209
    kvm_cmd.extend(["-balloon", "virtio,id=balloon%s" % pci_info])
1210
    kvm_cmd.extend(["-daemonize"])
1211
    if not instance.hvparams[constants.HV_ACPI]:
1212
      kvm_cmd.extend(["-no-acpi"])
1213
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1214
        constants.INSTANCE_REBOOT_EXIT:
1215
      kvm_cmd.extend(["-no-reboot"])
1216

    
1217
    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1218
    if not mversion:
1219
      mversion = self._GetDefaultMachineVersion(kvm)
1220
    if self._MACHINE_RE.search(kvmhelp):
1221
      # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1222
      # extra hypervisor parameters. We should also investigate whether and how
1223
      # shadow_mem should be considered for the resource model.
1224
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1225
        specprop = ",accel=kvm"
1226
      else:
1227
        specprop = ""
1228
      machinespec = "%s%s" % (mversion, specprop)
1229
      kvm_cmd.extend(["-machine", machinespec])
1230
    else:
1231
      kvm_cmd.extend(["-M", mversion])
1232
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1233
          self._ENABLE_KVM_RE.search(kvmhelp)):
1234
        kvm_cmd.extend(["-enable-kvm"])
1235
      elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1236
            self._DISABLE_KVM_RE.search(kvmhelp)):
1237
        kvm_cmd.extend(["-disable-kvm"])
1238

    
1239
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1240
    if kernel_path:
1241
      boot_cdrom = boot_floppy = boot_network = False
1242
    else:
1243
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1244
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1245
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1246

    
1247
    if startup_paused:
1248
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1249

    
1250
    if boot_network:
1251
      kvm_cmd.extend(["-boot", "n"])
1252

    
1253
    disk_type = hvp[constants.HV_DISK_TYPE]
1254

    
1255
    # Now we can specify a different device type for CDROM devices.
1256
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1257
    if not cdrom_disk_type:
1258
      cdrom_disk_type = disk_type
1259

    
1260
    cdrom_image1 = hvp[constants.HV_CDROM_IMAGE_PATH]
1261
    if cdrom_image1:
1262
      needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1263
      self._CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image1, boot_cdrom,
1264
                        needs_boot_flag)
1265

    
1266
    cdrom_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1267
    if cdrom_image2:
1268
      self._CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image2, False, False)
1269

    
1270
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1271
    if floppy_image:
1272
      options = ",format=raw,media=disk"
1273
      if boot_floppy:
1274
        kvm_cmd.extend(["-boot", "a"])
1275
        options = "%s,boot=on" % options
1276
      if_val = ",if=floppy"
1277
      options = "%s%s" % (options, if_val)
1278
      drive_val = "file=%s%s" % (floppy_image, options)
1279
      kvm_cmd.extend(["-drive", drive_val])
1280

    
1281
    if kernel_path:
1282
      kvm_cmd.extend(["-kernel", kernel_path])
1283
      initrd_path = hvp[constants.HV_INITRD_PATH]
1284
      if initrd_path:
1285
        kvm_cmd.extend(["-initrd", initrd_path])
1286
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1287
                     hvp[constants.HV_KERNEL_ARGS]]
1288
      if hvp[constants.HV_SERIAL_CONSOLE]:
1289
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1290
        root_append.append("console=ttyS0,%s" % serial_speed)
1291
      kvm_cmd.extend(["-append", " ".join(root_append)])
1292

    
1293
    mem_path = hvp[constants.HV_MEM_PATH]
1294
    if mem_path:
1295
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1296

    
1297
    monitor_dev = ("unix:%s,server,nowait" %
1298
                   self._InstanceMonitor(instance.name))
1299
    kvm_cmd.extend(["-monitor", monitor_dev])
1300
    if hvp[constants.HV_SERIAL_CONSOLE]:
1301
      serial_dev = ("unix:%s,server,nowait" %
1302
                    self._InstanceSerial(instance.name))
1303
      kvm_cmd.extend(["-serial", serial_dev])
1304
    else:
1305
      kvm_cmd.extend(["-serial", "none"])
1306

    
1307
    mouse_type = hvp[constants.HV_USB_MOUSE]
1308
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1309
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1310
    spice_ip_version = None
1311

    
1312
    kvm_cmd.extend(["-usb"])
1313

    
1314
    if mouse_type:
1315
      kvm_cmd.extend(["-usbdevice", mouse_type])
1316
    elif vnc_bind_address:
1317
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1318

    
1319
    if vnc_bind_address:
1320
      if netutils.IsValidInterface(vnc_bind_address):
1321
        if_addresses = netutils.GetInterfaceIpAddresses(vnc_bind_address)
1322
        if_ip4_addresses = if_addresses[constants.IP4_VERSION]
1323
        if len(if_ip4_addresses) < 1:
1324
          logging.error("Could not determine IPv4 address of interface %s",
1325
                        vnc_bind_address)
1326
        else:
1327
          vnc_bind_address = if_ip4_addresses[0]
1328
      if netutils.IP4Address.IsValid(vnc_bind_address):
1329
        if instance.network_port > constants.VNC_BASE_PORT:
1330
          display = instance.network_port - constants.VNC_BASE_PORT
1331
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1332
            vnc_arg = ":%d" % (display)
1333
          else:
1334
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1335
        else:
1336
          logging.error("Network port is not a valid VNC display (%d < %d),"
1337
                        " not starting VNC",
1338
                        instance.network_port, constants.VNC_BASE_PORT)
1339
          vnc_arg = "none"
1340

    
1341
        # Only allow tls and other option when not binding to a file, for now.
1342
        # kvm/qemu gets confused otherwise about the filename to use.
1343
        vnc_append = ""
1344
        if hvp[constants.HV_VNC_TLS]:
1345
          vnc_append = "%s,tls" % vnc_append
1346
          if hvp[constants.HV_VNC_X509_VERIFY]:
1347
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1348
                                               hvp[constants.HV_VNC_X509])
1349
          elif hvp[constants.HV_VNC_X509]:
1350
            vnc_append = "%s,x509=%s" % (vnc_append,
1351
                                         hvp[constants.HV_VNC_X509])
1352
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1353
          vnc_append = "%s,password" % vnc_append
1354

    
1355
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1356

    
1357
      else:
1358
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1359

    
1360
      kvm_cmd.extend(["-vnc", vnc_arg])
1361
    elif spice_bind:
1362
      # FIXME: this is wrong here; the iface ip address differs
1363
      # between systems, so it should be done in _ExecuteKVMRuntime
1364
      if netutils.IsValidInterface(spice_bind):
1365
        # The user specified a network interface, we have to figure out the IP
1366
        # address.
1367
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1368
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1369

    
1370
        # if the user specified an IP version and the interface does not
1371
        # have that kind of IP addresses, throw an exception
1372
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1373
          if not addresses[spice_ip_version]:
1374
            raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1375
                                         " for %s" % (spice_ip_version,
1376
                                                      spice_bind))
1377

    
1378
        # the user did not specify an IP version, we have to figure it out
1379
        elif (addresses[constants.IP4_VERSION] and
1380
              addresses[constants.IP6_VERSION]):
1381
          # we have both ipv4 and ipv6, let's use the cluster default IP
1382
          # version
1383
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1384
          spice_ip_version = \
1385
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1386
        elif addresses[constants.IP4_VERSION]:
1387
          spice_ip_version = constants.IP4_VERSION
1388
        elif addresses[constants.IP6_VERSION]:
1389
          spice_ip_version = constants.IP6_VERSION
1390
        else:
1391
          raise errors.HypervisorError("SPICE: Unable to get an IP address"
1392
                                       " for %s" % (spice_bind))
1393

    
1394
        spice_address = addresses[spice_ip_version][0]
1395

    
1396
      else:
1397
        # spice_bind is known to be a valid IP address, because
1398
        # ValidateParameters checked it.
1399
        spice_address = spice_bind
1400

    
1401
      spice_arg = "addr=%s" % spice_address
1402
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1403
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1404
                     (spice_arg, instance.network_port,
1405
                      pathutils.SPICE_CACERT_FILE))
1406
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1407
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1408
                      pathutils.SPICE_CERT_FILE))
1409
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1410
        if tls_ciphers:
1411
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1412
      else:
1413
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1414

    
1415
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1416
        spice_arg = "%s,disable-ticketing" % spice_arg
1417

    
1418
      if spice_ip_version:
1419
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1420

    
1421
      # Image compression options
1422
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1423
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1424
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1425
      if img_lossless:
1426
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1427
      if img_jpeg:
1428
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1429
      if img_zlib_glz:
1430
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1431

    
1432
      # Video stream detection
1433
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1434
      if video_streaming:
1435
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1436

    
1437
      # Audio compression, by default in qemu-kvm it is on
1438
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1439
        spice_arg = "%s,playback-compression=off" % spice_arg
1440
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1441
        spice_arg = "%s,agent-mouse=off" % spice_arg
1442
      else:
1443
        # Enable the spice agent communication channel between the host and the
1444
        # agent.
1445
        addr = _GetFreeSlot(pci_reservations, reserve=True)
1446
        pci_info = ",bus=pci.0,addr=%s" % hex(addr)
1447
        kvm_cmd.extend(["-device", "virtio-serial-pci,id=spice%s" % pci_info])
1448
        kvm_cmd.extend([
1449
          "-device",
1450
          "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1451
          ])
1452
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1453

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

    
1457
    else:
1458
      # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1459
      # also works in earlier versions though (tested with 1.1 and 1.3)
1460
      if self._DISPLAY_RE.search(kvmhelp):
1461
        kvm_cmd.extend(["-display", "none"])
1462
      else:
1463
        kvm_cmd.extend(["-nographic"])
1464

    
1465
    if hvp[constants.HV_USE_LOCALTIME]:
1466
      kvm_cmd.extend(["-localtime"])
1467

    
1468
    if hvp[constants.HV_KVM_USE_CHROOT]:
1469
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1470

    
1471
    # Add qemu-KVM -cpu param
1472
    if hvp[constants.HV_CPU_TYPE]:
1473
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1474

    
1475
    # Pass a -vga option if requested, or if spice is used, for backwards
1476
    # compatibility.
1477
    if hvp[constants.HV_VGA]:
1478
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1479
    elif spice_bind:
1480
      kvm_cmd.extend(["-vga", "qxl"])
1481

    
1482
    # Various types of usb devices, comma separated
1483
    if hvp[constants.HV_USB_DEVICES]:
1484
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1485
        kvm_cmd.extend(["-usbdevice", dev])
1486

    
1487
    # Set system UUID to instance UUID
1488
    if self._UUID_RE.search(kvmhelp):
1489
      kvm_cmd.extend(["-uuid", instance.uuid])
1490

    
1491
    if hvp[constants.HV_KVM_EXTRA]:
1492
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1493

    
1494
    kvm_disks = []
1495
    for disk, link_name, uri in block_devices:
1496
      disk.pci = _GetFreeSlot(pci_reservations, disk.pci, True)
1497
      kvm_disks.append((disk, link_name, uri))
1498

    
1499
    kvm_nics = []
1500
    for nic in instance.nics:
1501
      nic.pci = _GetFreeSlot(pci_reservations, nic.pci, True)
1502
      kvm_nics.append(nic)
1503

    
1504
    hvparams = hvp
1505

    
1506
    return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1507

    
1508
  def _WriteKVMRuntime(self, instance_name, data):
1509
    """Write an instance's KVM runtime
1510

1511
    """
1512
    try:
1513
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1514
                      data=data)
1515
    except EnvironmentError, err:
1516
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1517

    
1518
  def _ReadKVMRuntime(self, instance_name):
1519
    """Read an instance's KVM runtime
1520

1521
    """
1522
    try:
1523
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1524
    except EnvironmentError, err:
1525
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1526
    return file_content
1527

    
1528
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1529
    """Save an instance's KVM runtime
1530

1531
    """
1532
    kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1533

    
1534
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1535
    serialized_disks = [(blk.ToDict(), link, uri)
1536
                        for blk, link, uri in kvm_disks]
1537
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1538
                                      serialized_disks))
1539

    
1540
    self._WriteKVMRuntime(instance.name, serialized_form)
1541

    
1542
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1543
    """Load an instance's KVM runtime
1544

1545
    """
1546
    if not serialized_runtime:
1547
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1548

    
1549
    return _AnalyzeSerializedRuntime(serialized_runtime)
1550

    
1551
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1552
    """Run the KVM cmd and check for errors
1553

1554
    @type name: string
1555
    @param name: instance name
1556
    @type kvm_cmd: list of strings
1557
    @param kvm_cmd: runcmd input for kvm
1558
    @type tap_fds: list of int
1559
    @param tap_fds: fds of tap devices opened by Ganeti
1560

1561
    """
1562
    try:
1563
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1564
    finally:
1565
      for fd in tap_fds:
1566
        utils_wrapper.CloseFdNoError(fd)
1567

    
1568
    if result.failed:
1569
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1570
                                   (name, result.fail_reason, result.output))
1571
    if not self._InstancePidAlive(name)[2]:
1572
      raise errors.HypervisorError("Failed to start instance %s" % name)
1573

    
1574
  # too many local variables
1575
  # pylint: disable=R0914
1576
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1577
    """Execute a KVM cmd, after completing it with some last minute data.
1578

1579
    @type incoming: tuple of strings
1580
    @param incoming: (target_host_ip, port)
1581
    @type kvmhelp: string
1582
    @param kvmhelp: output of kvm --help
1583

1584
    """
1585
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1586
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1587
    #    have changed since the instance started; only use them if the change
1588
    #    won't affect the inside of the instance (which hasn't been rebooted).
1589
    #  - up_hvp contains the parameters as they were when the instance was
1590
    #    started, plus any new parameter which has been added between ganeti
1591
    #    versions: it is paramount that those default to a value which won't
1592
    #    affect the inside of the instance as well.
1593
    conf_hvp = instance.hvparams
1594
    name = instance.name
1595
    self._CheckDown(name)
1596

    
1597
    temp_files = []
1598

    
1599
    kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1600
    # the first element of kvm_cmd is always the path to the kvm binary
1601
    kvm_path = kvm_cmd[0]
1602
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1603

    
1604
    # We know it's safe to run as a different user upon migration, so we'll use
1605
    # the latest conf, from conf_hvp.
1606
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1607
    if security_model == constants.HT_SM_USER:
1608
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1609

    
1610
    keymap = conf_hvp[constants.HV_KEYMAP]
1611
    if keymap:
1612
      keymap_path = self._InstanceKeymapFile(name)
1613
      # If a keymap file is specified, KVM won't use its internal defaults. By
1614
      # first including the "en-us" layout, an error on loading the actual
1615
      # layout (e.g. because it can't be found) won't lead to a non-functional
1616
      # keyboard. A keyboard with incorrect keys is still better than none.
1617
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1618
      kvm_cmd.extend(["-k", keymap_path])
1619

    
1620
    # We have reasons to believe changing something like the nic driver/type
1621
    # upon migration won't exactly fly with the instance kernel, so for nic
1622
    # related parameters we'll use up_hvp
1623
    tapfds = []
1624
    taps = []
1625
    devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1626
    if not kvm_nics:
1627
      kvm_cmd.extend(["-net", "none"])
1628
    else:
1629
      vnet_hdr = False
1630
      tap_extra = ""
1631
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1632
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1633
        nic_model = self._VIRTIO
1634
        try:
1635
          if self._VIRTIO_NET_RE.search(devlist):
1636
            nic_model = self._VIRTIO_NET_PCI
1637
            vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1638
        except errors.HypervisorError, _:
1639
          # Older versions of kvm don't support DEVICE_LIST, but they don't
1640
          # have new virtio syntax either.
1641
          pass
1642

    
1643
        if up_hvp[constants.HV_VHOST_NET]:
1644
          # check for vhost_net support
1645
          if self._VHOST_RE.search(kvmhelp):
1646
            tap_extra = ",vhost=on"
1647
          else:
1648
            raise errors.HypervisorError("vhost_net is configured"
1649
                                         " but it is not available")
1650
      else:
1651
        nic_model = nic_type
1652

    
1653
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1654

    
1655
      for nic_seq, nic in enumerate(kvm_nics):
1656
        tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1657
        tapfds.append(tapfd)
1658
        taps.append(tapname)
1659
        if kvm_supports_netdev:
1660
          nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1661
          try:
1662
            # kvm_nics already exist in old runtime files and thus there might
1663
            # be some entries without pci slot (therefore try: except:)
1664
            kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1665
            netdev = kvm_devid
1666
            nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1667
          except errors.HotplugError:
1668
            netdev = "netdev%d" % nic_seq
1669
          nic_val += (",netdev=%s" % netdev)
1670
          tap_val = ("type=tap,id=%s,fd=%d%s" %
1671
                     (netdev, tapfd, tap_extra))
1672
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1673
        else:
1674
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1675
                                                         nic.mac, nic_model)
1676
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1677
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1678

    
1679
    if incoming:
1680
      target, port = incoming
1681
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1682

    
1683
    # Changing the vnc password doesn't bother the guest that much. At most it
1684
    # will surprise people who connect to it. Whether positively or negatively
1685
    # it's debatable.
1686
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1687
    vnc_pwd = None
1688
    if vnc_pwd_file:
1689
      try:
1690
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1691
      except EnvironmentError, err:
1692
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1693
                                     % (vnc_pwd_file, err))
1694

    
1695
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1696
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1697
                         constants.SECURE_DIR_MODE)])
1698

    
1699
    # Automatically enable QMP if version is >= 0.14
1700
    if self._QMP_RE.search(kvmhelp):
1701
      logging.debug("Enabling QMP")
1702
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1703
                      self._InstanceQmpMonitor(instance.name)])
1704

    
1705
    # Configure the network now for starting instances and bridged interfaces,
1706
    # during FinalizeMigration for incoming instances' routed interfaces
1707
    for nic_seq, nic in enumerate(kvm_nics):
1708
      if (incoming and
1709
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1710
        continue
1711
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1712

    
1713
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1714
                                                     up_hvp,
1715
                                                     kvm_disks,
1716
                                                     kvmhelp,
1717
                                                     devlist)
1718
    kvm_cmd.extend(bdev_opts)
1719
    # CPU affinity requires kvm to start paused, so we set this flag if the
1720
    # instance is not already paused and if we are not going to accept a
1721
    # migrating instance. In the latter case, pausing is not needed.
1722
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1723
    if start_kvm_paused:
1724
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1725

    
1726
    # Note: CPU pinning is using up_hvp since changes take effect
1727
    # during instance startup anyway, and to avoid problems when soft
1728
    # rebooting the instance.
1729
    cpu_pinning = False
1730
    if up_hvp.get(constants.HV_CPU_MASK, None):
1731
      cpu_pinning = True
1732

    
1733
    if security_model == constants.HT_SM_POOL:
1734
      ss = ssconf.SimpleStore()
1735
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1736
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1737
      uid = uidpool.RequestUnusedUid(all_uids)
1738
      try:
1739
        username = pwd.getpwuid(uid.GetUid()).pw_name
1740
        kvm_cmd.extend(["-runas", username])
1741
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1742
      except:
1743
        uidpool.ReleaseUid(uid)
1744
        raise
1745
      else:
1746
        uid.Unlock()
1747
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1748
    else:
1749
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1750

    
1751
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1752
                     constants.RUN_DIRS_MODE)])
1753
    for nic_seq, tap in enumerate(taps):
1754
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1755
                      data=tap)
1756

    
1757
    if vnc_pwd:
1758
      change_cmd = "change vnc password %s" % vnc_pwd
1759
      self._CallMonitorCommand(instance.name, change_cmd)
1760

    
1761
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1762
    # connection attempts because SPICE by default does not allow connections
1763
    # if neither a password nor the "disable_ticketing" options are specified.
1764
    # As soon as we send the password via QMP, that password is a valid ticket
1765
    # for connection.
1766
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1767
    if spice_password_file:
1768
      spice_pwd = ""
1769
      try:
1770
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1771
      except EnvironmentError, err:
1772
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1773
                                     % (spice_password_file, err))
1774

    
1775
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1776
      qmp.connect()
1777
      arguments = {
1778
          "protocol": "spice",
1779
          "password": spice_pwd,
1780
      }
1781
      qmp.Execute("set_password", arguments)
1782

    
1783
    for filename in temp_files:
1784
      utils.RemoveFile(filename)
1785

    
1786
    # If requested, set CPU affinity and resume instance execution
1787
    if cpu_pinning:
1788
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1789

    
1790
    start_memory = self._InstanceStartupMemory(instance)
1791
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1792
      self.BalloonInstanceMemory(instance, start_memory)
1793

    
1794
    if start_kvm_paused:
1795
      # To control CPU pinning, ballooning, and vnc/spice passwords
1796
      # the VM was started in a frozen state. If freezing was not
1797
      # explicitly requested resume the vm status.
1798
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1799

    
1800
  def StartInstance(self, instance, block_devices, startup_paused):
1801
    """Start an instance.
1802

1803
    """
1804
    self._CheckDown(instance.name)
1805
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1806
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1807
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1808
                                           startup_paused, kvmhelp)
1809
    self._SaveKVMRuntime(instance, kvm_runtime)
1810
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1811

    
1812
  @classmethod
1813
  def _CallMonitorCommand(cls, instance_name, command, timeout=None):
1814
    """Invoke a command on the instance monitor.
1815

1816
    """
1817
    if timeout is not None:
1818
      timeout_cmd = "timeout %s" % (timeout, )
1819
    else:
1820
      timeout_cmd = ""
1821

    
1822
    # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1823
    # version. The monitor protocol is designed for human consumption, whereas
1824
    # QMP is made for programmatic usage. In the worst case QMP can also
1825
    # execute monitor commands. As it is, all calls to socat take at least
1826
    # 500ms and likely more: socat can't detect the end of the reply and waits
1827
    # for 500ms of no data received before exiting (500 ms is the default for
1828
    # the "-t" parameter).
1829
    socat = ("echo %s | %s %s STDIO UNIX-CONNECT:%s" %
1830
             (utils.ShellQuote(command),
1831
              timeout_cmd,
1832
              constants.SOCAT_PATH,
1833
              utils.ShellQuote(cls._InstanceMonitor(instance_name))))
1834
    result = utils.RunCmd(socat)
1835
    if result.failed:
1836
      msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1837
             " output: %s" %
1838
             (command, instance_name, result.fail_reason, result.output))
1839
      raise errors.HypervisorError(msg)
1840

    
1841
    return result
1842

    
1843
  def _GetFreePCISlot(self, instance, dev):
1844
    """Get the first available pci slot of a runnung instance.
1845

1846
    """
1847
    slots = bitarray(32)
1848
    slots.setall(False) # pylint: disable=E1101
1849
    output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
1850
    for line in output.stdout.splitlines():
1851
      match = self._INFO_PCI_RE.search(line)
1852
      if match:
1853
        slot = int(match.group(1))
1854
        slots[slot] = True
1855

    
1856
    dev.pci = _GetFreeSlot(slots)
1857

    
1858
  def VerifyHotplugSupport(self, instance, action, dev_type):
1859
    """Verifies that hotplug is supported.
1860

1861
    Hotplug is *not* supported in case of:
1862
     - security models and chroot (disk hotplug)
1863
     - fdsend module is missing (nic hot-add)
1864

1865
    @raise errors.HypervisorError: in one of the previous cases
1866

1867
    """
1868
    if dev_type == constants.HOTPLUG_TARGET_DISK:
1869
      hvp = instance.hvparams
1870
      security_model = hvp[constants.HV_SECURITY_MODEL]
1871
      use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
1872
      if action == constants.HOTPLUG_ACTION_ADD:
1873
        if use_chroot:
1874
          raise errors.HotplugError("Disk hotplug is not supported"
1875
                                    " in case of chroot.")
1876
        if security_model != constants.HT_SM_NONE:
1877
          raise errors.HotplugError("Disk Hotplug is not supported in case"
1878
                                    " security models are used.")
1879

    
1880
    if (dev_type == constants.HOTPLUG_TARGET_NIC and
1881
        action == constants.HOTPLUG_ACTION_ADD and not fdsend):
1882
      raise errors.HotplugError("Cannot hot-add NIC."
1883
                                " fdsend python module is missing.")
1884

    
1885
  def HotplugSupported(self, instance):
1886
    """Checks if hotplug is generally supported.
1887

1888
    Hotplug is *not* supported in case of:
1889
     - qemu versions < 1.0
1890
     - for stopped instances
1891

1892
    @raise errors.HypervisorError: in one of the previous cases
1893

1894
    """
1895
    try:
1896
      output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
1897
    except errors.HypervisorError:
1898
      raise errors.HotplugError("Instance is probably down")
1899

    
1900
    # TODO: search for netdev_add, drive_add, device_add.....
1901
    match = self._INFO_VERSION_RE.search(output.stdout)
1902
    if not match:
1903
      raise errors.HotplugError("Cannot parse qemu version via monitor")
1904

    
1905
    v_major, v_min, _, _ = match.groups()
1906
    if (int(v_major), int(v_min)) < (1, 0):
1907
      raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
1908

    
1909
  def _CallHotplugCommands(self, name, cmds):
1910
    for c in cmds:
1911
      self._CallMonitorCommand(name, c)
1912
      time.sleep(1)
1913

    
1914
  def _VerifyHotplugCommand(self, instance_name, device, dev_type,
1915
                            should_exist):
1916
    """Checks if a previous hotplug command has succeeded.
1917

1918
    It issues info pci monitor command and checks depending on should_exist
1919
    value if an entry with PCI slot and device ID is found or not.
1920

1921
    @raise errors.HypervisorError: if result is not the expected one
1922

1923
    """
1924
    output = self._CallMonitorCommand(instance_name, self._INFO_PCI_CMD)
1925
    kvm_devid = _GenerateDeviceKVMId(dev_type, device)
1926
    match = \
1927
      self._FIND_PCI_DEVICE_RE(device.pci, kvm_devid).search(output.stdout)
1928
    if match and not should_exist:
1929
      msg = "Device %s should have been removed but is still there" % kvm_devid
1930
      raise errors.HypervisorError(msg)
1931

    
1932
    if not match and should_exist:
1933
      msg = "Device %s should have been added but is missing" % kvm_devid
1934
      raise errors.HypervisorError(msg)
1935

    
1936
    logging.info("Device %s has been correctly hot-plugged", kvm_devid)
1937

    
1938
  def HotAddDevice(self, instance, dev_type, device, extra, seq):
1939
    """ Helper method to hot-add a new device
1940

1941
    It gets free pci slot generates the device name and invokes the
1942
    device specific method.
1943

1944
    """
1945
    # in case of hot-mod this is given
1946
    if device.pci is None:
1947
      self._GetFreePCISlot(instance, device)
1948
    kvm_devid = _GenerateDeviceKVMId(dev_type, device)
1949
    runtime = self._LoadKVMRuntime(instance)
1950
    if dev_type == constants.HOTPLUG_TARGET_DISK:
1951
      drive_uri = _GetDriveURI(device, extra[0], extra[1])
1952
      cmds = ["drive_add dummy file=%s,if=none,id=%s,format=raw" %
1953
                (drive_uri, kvm_devid)]
1954
      cmds += ["device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
1955
                (hex(device.pci), kvm_devid, kvm_devid)]
1956
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
1957
      (tap, fd) = _OpenTap()
1958
      self._ConfigureNIC(instance, seq, device, tap)
1959
      self._PassTapFd(instance, fd, device)
1960
      cmds = ["netdev_add tap,id=%s,fd=%s" % (kvm_devid, kvm_devid)]
1961
      args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
1962
               (hex(device.pci), device.mac, kvm_devid, kvm_devid)
1963
      cmds += ["device_add %s" % args]
1964
      utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
1965

    
1966
    self._CallHotplugCommands(instance.name, cmds)
1967
    self._VerifyHotplugCommand(instance.name, device, dev_type, True)
1968
    # update relevant entries in runtime file
1969
    index = _DEVICE_RUNTIME_INDEX[dev_type]
1970
    entry = _RUNTIME_ENTRY[dev_type](device, extra)
1971
    runtime[index].append(entry)
1972
    self._SaveKVMRuntime(instance, runtime)
1973

    
1974
  def HotDelDevice(self, instance, dev_type, device, _, seq):
1975
    """ Helper method for hot-del device
1976

1977
    It gets device info from runtime file, generates the device name and
1978
    invokes the device specific method.
1979

1980
    """
1981
    runtime = self._LoadKVMRuntime(instance)
1982
    entry = _GetExistingDeviceInfo(dev_type, device, runtime)
1983
    kvm_device = _RUNTIME_DEVICE[dev_type](entry)
1984
    kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
1985
    if dev_type == constants.HOTPLUG_TARGET_DISK:
1986
      cmds = ["device_del %s" % kvm_devid]
1987
      cmds += ["drive_del %s" % kvm_devid]
1988
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
1989
      cmds = ["device_del %s" % kvm_devid]
1990
      cmds += ["netdev_del %s" % kvm_devid]
1991
      utils.RemoveFile(self._InstanceNICFile(instance.name, seq))
1992
    self._CallHotplugCommands(instance.name, cmds)
1993
    self._VerifyHotplugCommand(instance.name, kvm_device, dev_type, False)
1994
    index = _DEVICE_RUNTIME_INDEX[dev_type]
1995
    runtime[index].remove(entry)
1996
    self._SaveKVMRuntime(instance, runtime)
1997

    
1998
    return kvm_device.pci
1999

    
2000
  def HotModDevice(self, instance, dev_type, device, _, seq):
2001
    """ Helper method for hot-mod device
2002

2003
    It gets device info from runtime file, generates the device name and
2004
    invokes the device specific method. Currently only NICs support hot-mod
2005

2006
    """
2007
    if dev_type == constants.HOTPLUG_TARGET_NIC:
2008
      # putting it back in the same pci slot
2009
      device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2010
      self.HotAddDevice(instance, dev_type, device, _, seq)
2011

    
2012
  def _PassTapFd(self, instance, fd, nic):
2013
    """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2014

2015
    """
2016
    # TODO: factor out code related to unix sockets.
2017
    #       squash common parts between monitor and qmp
2018
    kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2019
    command = "getfd %s\n" % kvm_devid
2020
    fds = [fd]
2021
    logging.info("%s", fds)
2022
    try:
2023
      monsock = MonitorSocket(self._InstanceMonitor(instance.name))
2024
      monsock.connect()
2025
      fdsend.sendfds(monsock.sock, command, fds=fds)
2026
    finally:
2027
      monsock.close()
2028

    
2029
  @classmethod
2030
  def _ParseKVMVersion(cls, text):
2031
    """Parse the KVM version from the --help output.
2032

2033
    @type text: string
2034
    @param text: output of kvm --help
2035
    @return: (version, v_maj, v_min, v_rev)
2036
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2037

2038
    """
2039
    match = cls._VERSION_RE.search(text.splitlines()[0])
2040
    if not match:
2041
      raise errors.HypervisorError("Unable to get KVM version")
2042

    
2043
    v_all = match.group(0)
2044
    v_maj = int(match.group(1))
2045
    v_min = int(match.group(2))
2046
    if match.group(4):
2047
      v_rev = int(match.group(4))
2048
    else:
2049
      v_rev = 0
2050
    return (v_all, v_maj, v_min, v_rev)
2051

    
2052
  @classmethod
2053
  def _GetKVMOutput(cls, kvm_path, option):
2054
    """Return the output of a kvm invocation
2055

2056
    @type kvm_path: string
2057
    @param kvm_path: path to the kvm executable
2058
    @type option: a key of _KVMOPTS_CMDS
2059
    @param option: kvm option to fetch the output from
2060
    @return: output a supported kvm invocation
2061
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2062

2063
    """
2064
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2065

    
2066
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
2067

    
2068
    result = utils.RunCmd([kvm_path] + optlist)
2069
    if result.failed and not can_fail:
2070
      raise errors.HypervisorError("Unable to get KVM %s output" %
2071
                                    " ".join(optlist))
2072
    return result.output
2073

    
2074
  @classmethod
2075
  def _GetKVMVersion(cls, kvm_path):
2076
    """Return the installed KVM version.
2077

2078
    @return: (version, v_maj, v_min, v_rev)
2079
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2080

2081
    """
2082
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2083

    
2084
  @classmethod
2085
  def _GetDefaultMachineVersion(cls, kvm_path):
2086
    """Return the default hardware revision (e.g. pc-1.1)
2087

2088
    """
2089
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2090
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2091
    if match:
2092
      return match.group(1)
2093
    else:
2094
      return "pc"
2095

    
2096
  @classmethod
2097
  def _StopInstance(cls, instance, force=False, name=None, timeout=None):
2098
    """Stop an instance.
2099

2100
    """
2101
    assert(timeout is None or force is not None)
2102

    
2103
    if name is not None and not force:
2104
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2105
    if name is None:
2106
      name = instance.name
2107
      acpi = instance.hvparams[constants.HV_ACPI]
2108
    else:
2109
      acpi = False
2110
    _, pid, alive = cls._InstancePidAlive(name)
2111
    if pid > 0 and alive:
2112
      if force or not acpi:
2113
        utils.KillProcess(pid)
2114
      else:
2115
        cls._CallMonitorCommand(name, "system_powerdown", timeout)
2116

    
2117
  def StopInstance(self, instance, force=False, retry=False, name=None,
2118
                   timeout=None):
2119
    """Stop an instance.
2120

2121
    """
2122
    self._StopInstance(instance, force, name, timeout)
2123

    
2124
  def CleanupInstance(self, instance_name):
2125
    """Cleanup after a stopped instance
2126

2127
    """
2128
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
2129
    if pid > 0 and alive:
2130
      raise errors.HypervisorError("Cannot cleanup a live instance")
2131
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2132

    
2133
  def RebootInstance(self, instance):
2134
    """Reboot an instance.
2135

2136
    """
2137
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2138
    # socket the instance will stop, but now power up again. So we'll resort
2139
    # to shutdown and restart.
2140
    _, _, alive = self._InstancePidAlive(instance.name)
2141
    if not alive:
2142
      raise errors.HypervisorError("Failed to reboot instance %s:"
2143
                                   " not running" % instance.name)
2144
    # StopInstance will delete the saved KVM runtime so:
2145
    # ...first load it...
2146
    kvm_runtime = self._LoadKVMRuntime(instance)
2147
    # ...now we can safely call StopInstance...
2148
    if not self.StopInstance(instance):
2149
      self.StopInstance(instance, force=True)
2150
    # ...and finally we can save it again, and execute it...
2151
    self._SaveKVMRuntime(instance, kvm_runtime)
2152
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2153
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2154
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2155

    
2156
  def MigrationInfo(self, instance):
2157
    """Get instance information to perform a migration.
2158

2159
    @type instance: L{objects.Instance}
2160
    @param instance: instance to be migrated
2161
    @rtype: string
2162
    @return: content of the KVM runtime file
2163

2164
    """
2165
    return self._ReadKVMRuntime(instance.name)
2166

    
2167
  def AcceptInstance(self, instance, info, target):
2168
    """Prepare to accept an instance.
2169

2170
    @type instance: L{objects.Instance}
2171
    @param instance: instance to be accepted
2172
    @type info: string
2173
    @param info: content of the KVM runtime file on the source node
2174
    @type target: string
2175
    @param target: target host (usually ip), on this node
2176

2177
    """
2178
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2179
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2180
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2181
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2182
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2183
                            incoming=incoming_address)
2184

    
2185
  def FinalizeMigrationDst(self, instance, info, success):
2186
    """Finalize the instance migration on the target node.
2187

2188
    Stop the incoming mode KVM.
2189

2190
    @type instance: L{objects.Instance}
2191
    @param instance: instance whose migration is being finalized
2192

2193
    """
2194
    if success:
2195
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2196
      kvm_nics = kvm_runtime[1]
2197

    
2198
      for nic_seq, nic in enumerate(kvm_nics):
2199
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2200
          # Bridged interfaces have already been configured
2201
          continue
2202
        try:
2203
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2204
        except EnvironmentError, err:
2205
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
2206
                          instance.name, nic_seq, str(err))
2207
          continue
2208
        try:
2209
          self._ConfigureNIC(instance, nic_seq, nic, tap)
2210
        except errors.HypervisorError, err:
2211
          logging.warning(str(err))
2212

    
2213
      self._WriteKVMRuntime(instance.name, info)
2214
    else:
2215
      self.StopInstance(instance, force=True)
2216

    
2217
  def MigrateInstance(self, cluster_name, instance, target, live):
2218
    """Migrate an instance to a target node.
2219

2220
    The migration will not be attempted if the instance is not
2221
    currently running.
2222

2223
    @type cluster_name: string
2224
    @param cluster_name: name of the cluster
2225
    @type instance: L{objects.Instance}
2226
    @param instance: the instance to be migrated
2227
    @type target: string
2228
    @param target: ip address of the target node
2229
    @type live: boolean
2230
    @param live: perform a live migration
2231

2232
    """
2233
    instance_name = instance.name
2234
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
2235
    _, _, alive = self._InstancePidAlive(instance_name)
2236
    if not alive:
2237
      raise errors.HypervisorError("Instance not running, cannot migrate")
2238

    
2239
    if not live:
2240
      self._CallMonitorCommand(instance_name, "stop")
2241

    
2242
    migrate_command = ("migrate_set_speed %dm" %
2243
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2244
    self._CallMonitorCommand(instance_name, migrate_command)
2245

    
2246
    migrate_command = ("migrate_set_downtime %dms" %
2247
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2248
    self._CallMonitorCommand(instance_name, migrate_command)
2249

    
2250
    migration_caps = instance.hvparams[constants.HV_KVM_MIGRATION_CAPS]
2251
    if migration_caps:
2252
      for c in migration_caps.split(_MIGRATION_CAPS_DELIM):
2253
        migrate_command = ("migrate_set_capability %s on" % c)
2254
        self._CallMonitorCommand(instance_name, migrate_command)
2255

    
2256
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2257
    self._CallMonitorCommand(instance_name, migrate_command)
2258

    
2259
  def FinalizeMigrationSource(self, instance, success, live):
2260
    """Finalize the instance migration on the source node.
2261

2262
    @type instance: L{objects.Instance}
2263
    @param instance: the instance that was migrated
2264
    @type success: bool
2265
    @param success: whether the migration succeeded or not
2266
    @type live: bool
2267
    @param live: whether the user requested a live migration or not
2268

2269
    """
2270
    if success:
2271
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2272
      utils.KillProcess(pid)
2273
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2274
    elif live:
2275
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2276

    
2277
  def GetMigrationStatus(self, instance):
2278
    """Get the migration status
2279

2280
    @type instance: L{objects.Instance}
2281
    @param instance: the instance that is being migrated
2282
    @rtype: L{objects.MigrationStatus}
2283
    @return: the status of the current migration (one of
2284
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2285
             progress info that can be retrieved from the hypervisor
2286

2287
    """
2288
    info_command = "info migrate"
2289
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2290
      result = self._CallMonitorCommand(instance.name, info_command)
2291
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
2292
      if not match:
2293
        if not result.stdout:
2294
          logging.info("KVM: empty 'info migrate' result")
2295
        else:
2296
          logging.warning("KVM: unknown 'info migrate' result: %s",
2297
                          result.stdout)
2298
      else:
2299
        status = match.group(1)
2300
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2301
          migration_status = objects.MigrationStatus(status=status)
2302
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2303
          if match:
2304
            migration_status.transferred_ram = match.group("transferred")
2305
            migration_status.total_ram = match.group("total")
2306

    
2307
          return migration_status
2308

    
2309
        logging.warning("KVM: unknown migration status '%s'", status)
2310

    
2311
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2312

    
2313
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2314

    
2315
  def BalloonInstanceMemory(self, instance, mem):
2316
    """Balloon an instance memory to a certain value.
2317

2318
    @type instance: L{objects.Instance}
2319
    @param instance: instance to be accepted
2320
    @type mem: int
2321
    @param mem: actual memory size to use for instance runtime
2322

2323
    """
2324
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2325

    
2326
  def GetNodeInfo(self, hvparams=None):
2327
    """Return information about the node.
2328

2329
    @type hvparams: dict of strings
2330
    @param hvparams: hypervisor parameters, not used in this class
2331

2332
    @return: a dict as returned by L{BaseHypervisor.GetLinuxNodeInfo} plus
2333
        the following keys:
2334
          - hv_version: the hypervisor version in the form (major, minor,
2335
                        revision)
2336

2337
    """
2338
    result = self.GetLinuxNodeInfo()
2339
    kvmpath = constants.KVM_PATH
2340
    if hvparams is not None:
2341
      kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2342
    _, v_major, v_min, v_rev = self._GetKVMVersion(kvmpath)
2343
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2344
    return result
2345

    
2346
  @classmethod
2347
  def GetInstanceConsole(cls, instance, primary_node, hvparams, beparams):
2348
    """Return a command for connecting to the console of an instance.
2349

2350
    """
2351
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2352
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2353
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2354
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2355
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2356
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2357
      return objects.InstanceConsole(instance=instance.name,
2358
                                     kind=constants.CONS_SSH,
2359
                                     host=primary_node.name,
2360
                                     user=constants.SSH_CONSOLE_USER,
2361
                                     command=cmd)
2362

    
2363
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2364
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2365
      display = instance.network_port - constants.VNC_BASE_PORT
2366
      return objects.InstanceConsole(instance=instance.name,
2367
                                     kind=constants.CONS_VNC,
2368
                                     host=vnc_bind_address,
2369
                                     port=instance.network_port,
2370
                                     display=display)
2371

    
2372
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2373
    if spice_bind:
2374
      return objects.InstanceConsole(instance=instance.name,
2375
                                     kind=constants.CONS_SPICE,
2376
                                     host=spice_bind,
2377
                                     port=instance.network_port)
2378

    
2379
    return objects.InstanceConsole(instance=instance.name,
2380
                                   kind=constants.CONS_MESSAGE,
2381
                                   message=("No serial shell for instance %s" %
2382
                                            instance.name))
2383

    
2384
  def Verify(self, hvparams=None):
2385
    """Verify the hypervisor.
2386

2387
    Check that the required binaries exist.
2388

2389
    @type hvparams: dict of strings
2390
    @param hvparams: hypervisor parameters to be verified against, not used here
2391

2392
    @return: Problem description if something is wrong, C{None} otherwise
2393

2394
    """
2395
    msgs = []
2396
    kvmpath = constants.KVM_PATH
2397
    if hvparams is not None:
2398
      kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2399
    if not os.path.exists(kvmpath):
2400
      msgs.append("The KVM binary ('%s') does not exist" % kvmpath)
2401
    if not os.path.exists(constants.SOCAT_PATH):
2402
      msgs.append("The socat binary ('%s') does not exist" %
2403
                  constants.SOCAT_PATH)
2404

    
2405
    return self._FormatVerifyResults(msgs)
2406

    
2407
  @classmethod
2408
  def CheckParameterSyntax(cls, hvparams):
2409
    """Check the given parameters for validity.
2410

2411
    @type hvparams:  dict
2412
    @param hvparams: dictionary with parameter names/value
2413
    @raise errors.HypervisorError: when a parameter is not valid
2414

2415
    """
2416
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2417

    
2418
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2419
    if kernel_path:
2420
      if not hvparams[constants.HV_ROOT_PATH]:
2421
        raise errors.HypervisorError("Need a root partition for the instance,"
2422
                                     " if a kernel is defined")
2423

    
2424
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2425
        not hvparams[constants.HV_VNC_X509]):
2426
      raise errors.HypervisorError("%s must be defined, if %s is" %
2427
                                   (constants.HV_VNC_X509,
2428
                                    constants.HV_VNC_X509_VERIFY))
2429

    
2430
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2431
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2432
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2433
      if not serial_speed or serial_speed not in valid_speeds:
2434
        raise errors.HypervisorError("Invalid serial console speed, must be"
2435
                                     " one of: %s" %
2436
                                     utils.CommaJoin(valid_speeds))
2437

    
2438
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2439
    if (boot_order == constants.HT_BO_CDROM and
2440
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2441
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2442
                                   " ISO path")
2443

    
2444
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2445
    if security_model == constants.HT_SM_USER:
2446
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2447
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2448
                                     " must be specified")
2449
    elif (security_model == constants.HT_SM_NONE or
2450
          security_model == constants.HT_SM_POOL):
2451
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2452
        raise errors.HypervisorError("Cannot have a security domain when the"
2453
                                     " security model is 'none' or 'pool'")
2454

    
2455
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2456
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2457
    if spice_bind:
2458
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2459
        # if an IP version is specified, the spice_bind parameter must be an
2460
        # IP of that family
2461
        if (netutils.IP4Address.IsValid(spice_bind) and
2462
            spice_ip_version != constants.IP4_VERSION):
2463
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2464
                                       " the specified IP version is %s" %
2465
                                       (spice_bind, spice_ip_version))
2466

    
2467
        if (netutils.IP6Address.IsValid(spice_bind) and
2468
            spice_ip_version != constants.IP6_VERSION):
2469
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2470
                                       " the specified IP version is %s" %
2471
                                       (spice_bind, spice_ip_version))
2472
    else:
2473
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2474
      # error if any of them is set without it.
2475
      for param in _SPICE_ADDITIONAL_PARAMS:
2476
        if hvparams[param]:
2477
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2478
                                       (param, constants.HV_KVM_SPICE_BIND))
2479

    
2480
  @classmethod
2481
  def ValidateParameters(cls, hvparams):
2482
    """Check the given parameters for validity.
2483

2484
    @type hvparams:  dict
2485
    @param hvparams: dictionary with parameter names/value
2486
    @raise errors.HypervisorError: when a parameter is not valid
2487

2488
    """
2489
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2490

    
2491
    kvm_path = hvparams[constants.HV_KVM_PATH]
2492

    
2493
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2494
    if security_model == constants.HT_SM_USER:
2495
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2496
      try:
2497
        pwd.getpwnam(username)
2498
      except KeyError:
2499
        raise errors.HypervisorError("Unknown security domain user %s"
2500
                                     % username)
2501
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2502
    if vnc_bind_address:
2503
      bound_to_addr = netutils.IP4Address.IsValid(vnc_bind_address)
2504
      is_interface = netutils.IsValidInterface(vnc_bind_address)
2505
      is_path = utils.IsNormAbsPath(vnc_bind_address)
2506
      if not bound_to_addr and not is_interface and not is_path:
2507
        raise errors.HypervisorError("VNC: The %s parameter must be either"
2508
                                     " a valid IP address, an interface name,"
2509
                                     " or an absolute path" %
2510
                                     constants.HV_KVM_SPICE_BIND)
2511

    
2512
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2513
    if spice_bind:
2514
      # only one of VNC and SPICE can be used currently.
2515
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2516
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2517
                                     " only one of them can be used at a"
2518
                                     " given time")
2519

    
2520
      # check that KVM supports SPICE
2521
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2522
      if not cls._SPICE_RE.search(kvmhelp):
2523
        raise errors.HypervisorError("SPICE is configured, but it is not"
2524
                                     " supported according to 'kvm --help'")
2525

    
2526
      # if spice_bind is not an IP address, it must be a valid interface
2527
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2528
                       netutils.IP6Address.IsValid(spice_bind))
2529
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2530
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2531
                                     " a valid IP address or interface name" %
2532
                                     constants.HV_KVM_SPICE_BIND)
2533

    
2534
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2535
    if machine_version:
2536
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2537
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2538
        raise errors.HypervisorError("Unsupported machine version: %s" %
2539
                                     machine_version)
2540

    
2541
  @classmethod
2542
  def PowercycleNode(cls, hvparams=None):
2543
    """KVM powercycle, just a wrapper over Linux powercycle.
2544

2545
    @type hvparams: dict of strings
2546
    @param hvparams: hypervisor params to be used on this node
2547

2548
    """
2549
    cls.LinuxPowercycle()