Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm / __init__.py @ 1f0ab629

History | View | Annotate | Download (90.2 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 shutil
44
import urllib2
45
import socket
46
import stat
47
import StringIO
48
from bitarray import bitarray
49
try:
50
  import affinity   # pylint: disable=F0401
51
except ImportError:
52
  affinity = None
53
try:
54
  import fdsend   # pylint: disable=F0401
55
except ImportError:
56
  fdsend = None
57

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

    
70
from ganeti.hypervisor.hv_kvm.monitor import QmpConnection, QmpMessage, \
71
                                             MonitorSocket
72
from ganeti.hypervisor.hv_kvm.netdev import OpenTap
73

    
74

    
75
_KVM_NETWORK_SCRIPT = pathutils.CONF_DIR + "/kvm-ifup-custom"
76
_KVM_START_PAUSED_FLAG = "-S"
77

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

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

    
115
_MIGRATION_CAPS_DELIM = ":"
116

    
117

    
118
def _with_qmp(fn):
119
  """Wrapper used on hotplug related methods"""
120
  def wrapper(self, instance, *args, **kwargs):
121
    """Create a QmpConnection and run the wrapped method"""
122
    if not getattr(self, "qmp", None):
123
      filename = self._InstanceQmpMonitor(instance.name)# pylint: disable=W0212
124
      self.qmp = QmpConnection(filename)
125
    return fn(self, instance, *args, **kwargs)
126
  return wrapper
127

    
128

    
129
def _GetDriveURI(disk, link, uri):
130
  """Helper function to get the drive uri to be used in --drive kvm option
131

132
  Invoked during startup and disk hot-add. In latter case and if no userspace
133
  access mode is used it will be overriden with /dev/fdset/<fdset-id> (see
134
  HotAddDisk() and AddFd() of QmpConnection).
135

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

143
  @return: The drive uri to use in kvm option
144

145
  """
146
  access_mode = disk.params.get(constants.LDP_ACCESS,
147
                                constants.DISK_KERNELSPACE)
148
  # If uri is available, use it during startup/hot-add
149
  if (uri and access_mode == constants.DISK_USERSPACE):
150
    drive_uri = uri
151
  # Otherwise use the link previously created
152
  else:
153
    drive_uri = link
154

    
155
  return drive_uri
156

    
157

    
158
def _GenerateDeviceKVMId(dev_type, dev):
159
  """Helper function to generate a unique device name used by KVM
160

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

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

171
  """
172

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

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

    
179

    
180
def _GetExistingDeviceInfo(dev_type, device, runtime):
181
  """Helper function to get an existing device inside the runtime file
182

183
  Used when an instance is running. Load kvm runtime file and search
184
  for a device based on its type and uuid.
185

186
  @type dev_type: sting
187
  @param dev_type: device type of param dev
188
  @type device: L{objects.Disk} or L{objects.NIC}
189
  @param device: the device object for which we generate a kvm name
190
  @type runtime: tuple (cmd, nics, hvparams, disks)
191
  @param runtime: the runtime data to search for the device
192
  @raise errors.HotplugError: in case the requested device does not
193
    exist (e.g. device has been added without --hotplug option) or
194
    device info has not pci slot (e.g. old devices in the cluster)
195

196
  """
197
  index = _DEVICE_RUNTIME_INDEX[dev_type]
198
  found = _FIND_RUNTIME_ENTRY[dev_type](device, runtime[index])
199
  if not found:
200
    raise errors.HotplugError("Cannot find runtime info for %s with UUID %s" %
201
                              (dev_type, device.uuid))
202

    
203
  return found[0]
204

    
205

    
206
def _UpgradeSerializedRuntime(serialized_runtime):
207
  """Upgrade runtime data
208

209
  Remove any deprecated fields or change the format of the data.
210
  The runtime files are not upgraded when Ganeti is upgraded, so the required
211
  modification have to be performed here.
212

213
  @type serialized_runtime: string
214
  @param serialized_runtime: raw text data read from actual runtime file
215
  @return: (cmd, nic dicts, hvparams, bdev dicts)
216
  @rtype: tuple
217

218
  """
219
  loaded_runtime = serializer.Load(serialized_runtime)
220
  kvm_cmd, serialized_nics, hvparams = loaded_runtime[:3]
221
  if len(loaded_runtime) >= 4:
222
    serialized_disks = loaded_runtime[3]
223
  else:
224
    serialized_disks = []
225

    
226
  for nic in serialized_nics:
227
    # Add a dummy uuid slot if an pre-2.8 NIC is found
228
    if "uuid" not in nic:
229
      nic["uuid"] = utils.NewUUID()
230

    
231
  return kvm_cmd, serialized_nics, hvparams, serialized_disks
232

    
233

    
234
def _AnalyzeSerializedRuntime(serialized_runtime):
235
  """Return runtime entries for a serialized runtime file
236

237
  @type serialized_runtime: string
238
  @param serialized_runtime: raw text data read from actual runtime file
239
  @return: (cmd, nics, hvparams, bdevs)
240
  @rtype: tuple
241

242
  """
243
  kvm_cmd, serialized_nics, hvparams, serialized_disks = \
244
    _UpgradeSerializedRuntime(serialized_runtime)
245
  kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
246
  kvm_disks = [(objects.Disk.FromDict(sdisk), link, uri)
247
               for sdisk, link, uri in serialized_disks]
248

    
249
  return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
250

    
251

    
252
class HeadRequest(urllib2.Request):
253
  def get_method(self):
254
    return "HEAD"
255

    
256

    
257
def _CheckUrl(url):
258
  """Check if a given URL exists on the server
259

260
  """
261
  try:
262
    urllib2.urlopen(HeadRequest(url))
263
    return True
264
  except urllib2.URLError:
265
    return False
266

    
267

    
268
class KVMHypervisor(hv_base.BaseHypervisor):
269
  """KVM hypervisor interface
270

271
  """
272
  CAN_MIGRATE = True
273

    
274
  _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
275
  _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
276
  _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
277
  _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
278
  _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
279
  _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
280
  _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
281
  # KVM instances with chroot enabled are started in empty chroot directories.
282
  _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
283
  # After an instance is stopped, its chroot directory is removed.
284
  # If the chroot directory is not empty, it can't be removed.
285
  # A non-empty chroot directory indicates a possible security incident.
286
  # To support forensics, the non-empty chroot directory is quarantined in
287
  # a separate directory, called 'chroot-quarantine'.
288
  _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
289
  _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
290
           _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
291

    
292
  PARAMETERS = {
293
    constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
294
    constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
295
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
296
    constants.HV_ROOT_PATH: hv_base.NO_CHECK,
297
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
298
    constants.HV_ACPI: hv_base.NO_CHECK,
299
    constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
300
    constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
301
    constants.HV_VNC_BIND_ADDRESS: hv_base.NO_CHECK, # will be checked later
302
    constants.HV_VNC_TLS: hv_base.NO_CHECK,
303
    constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
304
    constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
305
    constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
306
    constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
307
    constants.HV_KVM_SPICE_IP_VERSION:
308
      (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
309
                         x in constants.VALID_IP_VERSIONS),
310
       "The SPICE IP version should be 4 or 6",
311
       None, None),
312
    constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
313
    constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
314
      hv_base.ParamInSet(
315
        False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
316
    constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
317
      hv_base.ParamInSet(
318
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
319
    constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
320
      hv_base.ParamInSet(
321
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
322
    constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
323
      hv_base.ParamInSet(
324
        False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
325
    constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
326
    constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
327
    constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
328
    constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
329
    constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
330
    constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_OR_URL_CHECK,
331
    constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_OR_URL_CHECK,
332
    constants.HV_BOOT_ORDER:
333
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
334
    constants.HV_NIC_TYPE:
335
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
336
    constants.HV_DISK_TYPE:
337
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
338
    constants.HV_KVM_CDROM_DISK_TYPE:
339
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
340
    constants.HV_USB_MOUSE:
341
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
342
    constants.HV_KEYMAP: hv_base.NO_CHECK,
343
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
344
    constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
345
    constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
346
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
347
    constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
348
    constants.HV_DISK_CACHE:
349
      hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
350
    constants.HV_SECURITY_MODEL:
351
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
352
    constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
353
    constants.HV_KVM_FLAG:
354
      hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
355
    constants.HV_VHOST_NET: hv_base.NO_CHECK,
356
    constants.HV_VIRTIO_NET_QUEUES: hv_base.OPT_VIRTIO_NET_QUEUES_CHECK,
357
    constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
358
    constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
359
    constants.HV_REBOOT_BEHAVIOR:
360
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
361
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
362
    constants.HV_CPU_TYPE: hv_base.NO_CHECK,
363
    constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
364
    constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
365
    constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
366
    constants.HV_SOUNDHW: hv_base.NO_CHECK,
367
    constants.HV_USB_DEVICES: hv_base.NO_CHECK,
368
    constants.HV_VGA: hv_base.NO_CHECK,
369
    constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
370
    constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
371
    constants.HV_KVM_MIGRATION_CAPS: hv_base.NO_CHECK,
372
    constants.HV_VNET_HDR: hv_base.NO_CHECK,
373
    }
374

    
375
  _VIRTIO = "virtio"
376
  _VIRTIO_NET_PCI = "virtio-net-pci"
377
  _VIRTIO_BLK_PCI = "virtio-blk-pci"
378

    
379
  _MIGRATION_STATUS_RE = re.compile(r"Migration\s+status:\s+(\w+)",
380
                                    re.M | re.I)
381
  _MIGRATION_PROGRESS_RE = \
382
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
383
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
384
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
385

    
386
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
387
  _MIGRATION_INFO_RETRY_DELAY = 2
388

    
389
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
390

    
391
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
392
  _CPU_INFO_CMD = "info cpus"
393
  _CONT_CMD = "cont"
394

    
395
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
396
  _CHECK_MACHINE_VERSION_RE = \
397
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
398

    
399
  _QMP_RE = re.compile(r"^-qmp\s", re.M)
400
  _SPICE_RE = re.compile(r"^-spice\s", re.M)
401
  _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
402
  _VIRTIO_NET_QUEUES_RE = re.compile(r"^-net\s.*,fds=x:y:...:z", re.M)
403
  _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
404
  _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
405
  _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
406
  _DISPLAY_RE = re.compile(r"^-display\s", re.M)
407
  _MACHINE_RE = re.compile(r"^-machine\s", re.M)
408
  _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
409
  _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M)
410
  # match  -drive.*boot=on|off on different lines, but in between accept only
411
  # dashes not preceeded by a new line (which would mean another option
412
  # different than -drive is starting)
413
  _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
414
  _UUID_RE = re.compile(r"^-uuid\s", re.M)
415

    
416
  _INFO_VERSION_RE = \
417
    re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
418
  _INFO_VERSION_CMD = "info version"
419

    
420
  # Slot 0 for Host bridge, Slot 1 for ISA bridge, Slot 2 for VGA controller
421
  _DEFAULT_PCI_RESERVATIONS = "11100000000000000000000000000000"
422
  _SOUNDHW_WITH_PCI_SLOT = ["ac97", "es1370", "hda"]
423

    
424
  ANCILLARY_FILES = [
425
    _KVM_NETWORK_SCRIPT,
426
    ]
427
  ANCILLARY_FILES_OPT = [
428
    _KVM_NETWORK_SCRIPT,
429
    ]
430

    
431
  # Supported kvm options to get output from
432
  _KVMOPT_HELP = "help"
433
  _KVMOPT_MLIST = "mlist"
434
  _KVMOPT_DEVICELIST = "devicelist"
435

    
436
  # Command to execute to get the output from kvm, and whether to
437
  # accept the output even on failure.
438
  _KVMOPTS_CMDS = {
439
    _KVMOPT_HELP: (["--help"], False),
440
    _KVMOPT_MLIST: (["-M", "?"], False),
441
    _KVMOPT_DEVICELIST: (["-device", "?"], True),
442
  }
443

    
444
  def __init__(self):
445
    hv_base.BaseHypervisor.__init__(self)
446
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
447
    # in a tmpfs filesystem or has been otherwise wiped out.
448
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
449
    utils.EnsureDirs(dirs)
450
    self.qmp = None
451

    
452
  @classmethod
453
  def _InstancePidFile(cls, instance_name):
454
    """Returns the instance pidfile.
455

456
    """
457
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
458

    
459
  @classmethod
460
  def _InstanceUidFile(cls, instance_name):
461
    """Returns the instance uidfile.
462

463
    """
464
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
465

    
466
  @classmethod
467
  def _InstancePidInfo(cls, pid):
468
    """Check pid file for instance information.
469

470
    Check that a pid file is associated with an instance, and retrieve
471
    information from its command line.
472

473
    @type pid: string or int
474
    @param pid: process id of the instance to check
475
    @rtype: tuple
476
    @return: (instance_name, memory, vcpus)
477
    @raise errors.HypervisorError: when an instance cannot be found
478

479
    """
480
    alive = utils.IsProcessAlive(pid)
481
    if not alive:
482
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
483

    
484
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
485
    try:
486
      cmdline = utils.ReadFile(cmdline_file)
487
    except EnvironmentError, err:
488
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
489
                                   (pid, err))
490

    
491
    instance = None
492
    memory = 0
493
    vcpus = 0
494

    
495
    arg_list = cmdline.split("\x00")
496
    while arg_list:
497
      arg = arg_list.pop(0)
498
      if arg == "-name":
499
        instance = arg_list.pop(0)
500
      elif arg == "-m":
501
        memory = int(arg_list.pop(0))
502
      elif arg == "-smp":
503
        vcpus = int(arg_list.pop(0).split(",")[0])
504

    
505
    if instance is None:
506
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
507
                                   " instance" % pid)
508

    
509
    return (instance, memory, vcpus)
510

    
511
  @classmethod
512
  def _InstancePidAlive(cls, instance_name):
513
    """Returns the instance pidfile, pid, and liveness.
514

515
    @type instance_name: string
516
    @param instance_name: instance name
517
    @rtype: tuple
518
    @return: (pid file name, pid, liveness)
519

520
    """
521
    pidfile = cls._InstancePidFile(instance_name)
522
    pid = utils.ReadPidFile(pidfile)
523

    
524
    alive = False
525
    try:
526
      cmd_instance = cls._InstancePidInfo(pid)[0]
527
      alive = (cmd_instance == instance_name)
528
    except errors.HypervisorError:
529
      pass
530

    
531
    return (pidfile, pid, alive)
532

    
533
  @classmethod
534
  def _CheckDown(cls, instance_name):
535
    """Raises an error unless the given instance is down.
536

537
    """
538
    alive = cls._InstancePidAlive(instance_name)[2]
539
    if alive:
540
      raise errors.HypervisorError("Failed to start instance %s: %s" %
541
                                   (instance_name, "already running"))
542

    
543
  @classmethod
544
  def _InstanceMonitor(cls, instance_name):
545
    """Returns the instance monitor socket name
546

547
    """
548
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
549

    
550
  @classmethod
551
  def _InstanceSerial(cls, instance_name):
552
    """Returns the instance serial socket name
553

554
    """
555
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
556

    
557
  @classmethod
558
  def _InstanceQmpMonitor(cls, instance_name):
559
    """Returns the instance serial QMP socket name
560

561
    """
562
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
563

    
564
  @staticmethod
565
  def _SocatUnixConsoleParams():
566
    """Returns the correct parameters for socat
567

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

570
    """
571
    if constants.SOCAT_USE_ESCAPE:
572
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
573
    else:
574
      return "echo=0,icanon=0"
575

    
576
  @classmethod
577
  def _InstanceKVMRuntime(cls, instance_name):
578
    """Returns the instance KVM runtime filename
579

580
    """
581
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
582

    
583
  @classmethod
584
  def _InstanceChrootDir(cls, instance_name):
585
    """Returns the name of the KVM chroot dir of the instance
586

587
    """
588
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
589

    
590
  @classmethod
591
  def _InstanceNICDir(cls, instance_name):
592
    """Returns the name of the directory holding the tap device files for a
593
    given instance.
594

595
    """
596
    return utils.PathJoin(cls._NICS_DIR, instance_name)
597

    
598
  @classmethod
599
  def _InstanceNICFile(cls, instance_name, seq_or_uuid):
600
    """Returns the name of the file containing the tap device for a given NIC
601

602
    """
603
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq_or_uuid))
604

    
605
  @classmethod
606
  def _GetInstanceNICTap(cls, instance_name, nic):
607
    """Returns the tap for the corresponding nic
608

609
    Search for tap file named after NIC's uuid.
610
    For old instances without uuid indexed tap files returns nothing.
611

612
    """
613
    try:
614
      return utils.ReadFile(cls._InstanceNICFile(instance_name, nic.uuid))
615
    except EnvironmentError:
616
      pass
617

    
618
  @classmethod
619
  def _WriteInstanceNICFiles(cls, instance_name, seq, nic, tap):
620
    """Write tap name to both instance NIC files
621

622
    """
623
    for ident in [seq, nic.uuid]:
624
      utils.WriteFile(cls._InstanceNICFile(instance_name, ident), data=tap)
625

    
626
  @classmethod
627
  def _RemoveInstanceNICFiles(cls, instance_name, seq, nic):
628
    """Write tap name to both instance NIC files
629

630
    """
631
    for ident in [seq, nic.uuid]:
632
      utils.RemoveFile(cls._InstanceNICFile(instance_name, ident))
633

    
634
  @classmethod
635
  def _InstanceKeymapFile(cls, instance_name):
636
    """Returns the name of the file containing the keymap for a given instance
637

638
    """
639
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
640

    
641
  @classmethod
642
  def _TryReadUidFile(cls, uid_file):
643
    """Try to read a uid file
644

645
    """
646
    if os.path.exists(uid_file):
647
      try:
648
        uid = int(utils.ReadOneLineFile(uid_file))
649
        return uid
650
      except EnvironmentError:
651
        logging.warning("Can't read uid file", exc_info=True)
652
      except (TypeError, ValueError):
653
        logging.warning("Can't parse uid file contents", exc_info=True)
654
    return None
655

    
656
  @classmethod
657
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
658
    """Removes an instance's rutime sockets/files/dirs.
659

660
    """
661
    utils.RemoveFile(pidfile)
662
    utils.RemoveFile(cls._InstanceMonitor(instance_name))
663
    utils.RemoveFile(cls._InstanceSerial(instance_name))
664
    utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
665
    utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
666
    utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
667
    uid_file = cls._InstanceUidFile(instance_name)
668
    uid = cls._TryReadUidFile(uid_file)
669
    utils.RemoveFile(uid_file)
670
    if uid is not None:
671
      uidpool.ReleaseUid(uid)
672
    try:
673
      shutil.rmtree(cls._InstanceNICDir(instance_name))
674
    except OSError, err:
675
      if err.errno != errno.ENOENT:
676
        raise
677
    try:
678
      chroot_dir = cls._InstanceChrootDir(instance_name)
679
      utils.RemoveDir(chroot_dir)
680
    except OSError, err:
681
      if err.errno == errno.ENOTEMPTY:
682
        # The chroot directory is expected to be empty, but it isn't.
683
        new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
684
                                          prefix="%s-%s-" %
685
                                          (instance_name,
686
                                           utils.TimestampForFilename()))
687
        logging.warning("The chroot directory of instance %s can not be"
688
                        " removed as it is not empty. Moving it to the"
689
                        " quarantine instead. Please investigate the"
690
                        " contents (%s) and clean up manually",
691
                        instance_name, new_chroot_dir)
692
        utils.RenameFile(chroot_dir, new_chroot_dir)
693
      else:
694
        raise
695

    
696
  @staticmethod
697
  def _ConfigureNIC(instance, seq, nic, tap):
698
    """Run the network configuration script for a specified NIC
699

700
    See L{hv_base.ConfigureNIC}.
701

702
    @param instance: instance we're acting on
703
    @type instance: instance object
704
    @param seq: nic sequence number
705
    @type seq: int
706
    @param nic: nic we're acting on
707
    @type nic: nic object
708
    @param tap: the host's tap interface this NIC corresponds to
709
    @type tap: str
710

711
    """
712
    hv_base.ConfigureNIC([pathutils.KVM_IFUP, tap], instance, seq, nic, tap)
713

    
714
  @staticmethod
715
  def _VerifyAffinityPackage():
716
    if affinity is None:
717
      raise errors.HypervisorError("affinity Python package not"
718
                                   " found; cannot use CPU pinning under KVM")
719

    
720
  @staticmethod
721
  def _BuildAffinityCpuMask(cpu_list):
722
    """Create a CPU mask suitable for sched_setaffinity from a list of
723
    CPUs.
724

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

728
    @type cpu_list: list of int
729
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
730
    @rtype: int
731
    @return: a bit mask of CPU affinities
732

733
    """
734
    if cpu_list == constants.CPU_PINNING_OFF:
735
      return constants.CPU_PINNING_ALL_KVM
736
    else:
737
      return sum(2 ** cpu for cpu in cpu_list)
738

    
739
  @classmethod
740
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
741
    """Change CPU affinity for running VM according to given CPU mask.
742

743
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
744
    @type cpu_mask: string
745
    @param process_id: process ID of KVM process. Used to pin entire VM
746
                       to physical CPUs.
747
    @type process_id: int
748
    @param thread_dict: map of virtual CPUs to KVM thread IDs
749
    @type thread_dict: dict int:int
750

751
    """
752
    # Convert the string CPU mask to a list of list of int's
753
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
754

    
755
    if len(cpu_list) == 1:
756
      all_cpu_mapping = cpu_list[0]
757
      if all_cpu_mapping == constants.CPU_PINNING_OFF:
758
        # If CPU pinning has 1 entry that's "all", then do nothing
759
        pass
760
      else:
761
        # If CPU pinning has one non-all entry, map the entire VM to
762
        # one set of physical CPUs
763
        cls._VerifyAffinityPackage()
764
        affinity.set_process_affinity_mask(
765
          process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
766
    else:
767
      # The number of vCPUs mapped should match the number of vCPUs
768
      # reported by KVM. This was already verified earlier, so
769
      # here only as a sanity check.
770
      assert len(thread_dict) == len(cpu_list)
771
      cls._VerifyAffinityPackage()
772

    
773
      # For each vCPU, map it to the proper list of physical CPUs
774
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
775
        affinity.set_process_affinity_mask(thread_dict[i],
776
                                           cls._BuildAffinityCpuMask(vcpu))
777

    
778
  def _GetVcpuThreadIds(self, instance_name):
779
    """Get a mapping of vCPU no. to thread IDs for the instance
780

781
    @type instance_name: string
782
    @param instance_name: instance in question
783
    @rtype: dictionary of int:int
784
    @return: a dictionary mapping vCPU numbers to thread IDs
785

786
    """
787
    result = {}
788
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
789
    for line in output.stdout.splitlines():
790
      match = self._CPU_INFO_RE.search(line)
791
      if not match:
792
        continue
793
      grp = map(int, match.groups())
794
      result[grp[0]] = grp[1]
795

    
796
    return result
797

    
798
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
799
    """Complete CPU pinning.
800

801
    @type instance_name: string
802
    @param instance_name: name of instance
803
    @type cpu_mask: string
804
    @param cpu_mask: CPU pinning mask as entered by user
805

806
    """
807
    # Get KVM process ID, to be used if need to pin entire VM
808
    _, pid, _ = self._InstancePidAlive(instance_name)
809
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
810
    thread_dict = self._GetVcpuThreadIds(instance_name)
811
    # Run CPU pinning, based on configured mask
812
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
813

    
814
  def ListInstances(self, hvparams=None):
815
    """Get the list of running instances.
816

817
    We can do this by listing our live instances directory and
818
    checking whether the associated kvm process is still alive.
819

820
    """
821
    result = []
822
    for name in os.listdir(self._PIDS_DIR):
823
      if self._InstancePidAlive(name)[2]:
824
        result.append(name)
825
    return result
826

    
827
  def GetInstanceInfo(self, instance_name, hvparams=None):
828
    """Get instance properties.
829

830
    @type instance_name: string
831
    @param instance_name: the instance name
832
    @type hvparams: dict of strings
833
    @param hvparams: hvparams to be used with this instance
834
    @rtype: tuple of strings
835
    @return: (name, id, memory, vcpus, stat, times)
836

837
    """
838
    _, pid, alive = self._InstancePidAlive(instance_name)
839
    if not alive:
840
      return None
841

    
842
    _, memory, vcpus = self._InstancePidInfo(pid)
843
    istat = "---b-"
844
    times = "0"
845

    
846
    try:
847
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
848
      qmp.connect()
849
      vcpus = len(qmp.Execute("query-cpus"))
850
      # Will fail if ballooning is not enabled, but we can then just resort to
851
      # the value above.
852
      mem_bytes = qmp.Execute("query-balloon")[qmp.ACTUAL_KEY]
853
      memory = mem_bytes / 1048576
854
    except errors.HypervisorError:
855
      pass
856

    
857
    return (instance_name, pid, memory, vcpus, istat, times)
858

    
859
  def GetAllInstancesInfo(self, hvparams=None):
860
    """Get properties of all instances.
861

862
    @type hvparams: dict of strings
863
    @param hvparams: hypervisor parameter
864
    @return: list of tuples (name, id, memory, vcpus, stat, times)
865

866
    """
867
    data = []
868
    for name in os.listdir(self._PIDS_DIR):
869
      try:
870
        info = self.GetInstanceInfo(name)
871
      except errors.HypervisorError:
872
        # Ignore exceptions due to instances being shut down
873
        continue
874
      if info:
875
        data.append(info)
876
    return data
877

    
878
  def _GenerateKVMBlockDevicesOptions(self, instance, up_hvp, kvm_disks,
879
                                      kvmhelp, devlist):
880
    """Generate KVM options regarding instance's block devices.
881

882
    @type instance: L{objects.Instance}
883
    @param instance: the instance object
884
    @type up_hvp: dict
885
    @param up_hvp: the instance's runtime hypervisor parameters
886
    @type kvm_disks: list of tuples
887
    @param kvm_disks: list of tuples [(disk, link_name, uri)..]
888
    @type kvmhelp: string
889
    @param kvmhelp: output of kvm --help
890
    @type devlist: string
891
    @param devlist: output of kvm -device ?
892
    @rtype: list
893
    @return: list of command line options eventually used by kvm executable
894

895
    """
896
    kernel_path = up_hvp[constants.HV_KERNEL_PATH]
897
    if kernel_path:
898
      boot_disk = False
899
    else:
900
      boot_disk = up_hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
901

    
902
    # whether this is an older KVM version that uses the boot=on flag
903
    # on devices
904
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
905

    
906
    dev_opts = []
907
    device_driver = None
908
    disk_type = up_hvp[constants.HV_DISK_TYPE]
909
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
910
      if_val = ",if=%s" % self._VIRTIO
911
      try:
912
        if self._VIRTIO_BLK_RE.search(devlist):
913
          if_val = ",if=none"
914
          # will be passed in -device option as driver
915
          device_driver = self._VIRTIO_BLK_PCI
916
      except errors.HypervisorError, _:
917
        pass
918
    else:
919
      if_val = ",if=%s" % disk_type
920
    # Cache mode
921
    disk_cache = up_hvp[constants.HV_DISK_CACHE]
922
    if instance.disk_template in constants.DTS_EXT_MIRROR:
923
      if disk_cache != "none":
924
        # TODO: make this a hard error, instead of a silent overwrite
925
        logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
926
                        " to prevent shared storage corruption on migration",
927
                        disk_cache)
928
      cache_val = ",cache=none"
929
    elif disk_cache != constants.HT_CACHE_DEFAULT:
930
      cache_val = ",cache=%s" % disk_cache
931
    else:
932
      cache_val = ""
933
    for cfdev, link_name, uri in kvm_disks:
934
      if cfdev.mode != constants.DISK_RDWR:
935
        raise errors.HypervisorError("Instance has read-only disks which"
936
                                     " are not supported by KVM")
937
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
938
      boot_val = ""
939
      if boot_disk:
940
        dev_opts.extend(["-boot", "c"])
941
        boot_disk = False
942
        if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
943
          boot_val = ",boot=on"
944

    
945
      drive_uri = _GetDriveURI(cfdev, link_name, uri)
946

    
947
      drive_val = "file=%s,format=raw%s%s%s" % \
948
                  (drive_uri, if_val, boot_val, cache_val)
949

    
950
      if device_driver:
951
        # kvm_disks are the 4th entry of runtime file that did not exist in
952
        # the past. That means that cfdev should always have pci slot and
953
        # _GenerateDeviceKVMId() will not raise a exception.
954
        kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_DISK, cfdev)
955
        drive_val += (",id=%s" % kvm_devid)
956
        drive_val += (",bus=0,unit=%d" % cfdev.pci)
957
        dev_val = ("%s,drive=%s,id=%s" %
958
                   (device_driver, kvm_devid, kvm_devid))
959
        dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci)
960
        dev_opts.extend(["-device", dev_val])
961

    
962
      dev_opts.extend(["-drive", drive_val])
963

    
964
    return dev_opts
965

    
966
  @staticmethod
967
  def _CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image, cdrom_boot,
968
                   needs_boot_flag):
969
    """Extends L{kvm_cmd} with the '-drive' option for a cdrom, and
970
    optionally the '-boot' option.
971

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

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

976
    Example: -drive file=http://hostname.com/cdrom.iso,media=cdrom
977

978
    @type kvm_cmd: string
979
    @param kvm_cmd: KVM command line
980

981
    @type cdrom_disk_type:
982
    @param cdrom_disk_type:
983

984
    @type cdrom_image:
985
    @param cdrom_image:
986

987
    @type cdrom_boot:
988
    @param cdrom_boot:
989

990
    @type needs_boot_flag:
991
    @param needs_boot_flag:
992

993
    """
994
    # Check that the ISO image is accessible
995
    # See https://bugs.launchpad.net/qemu/+bug/597575
996
    if utils.IsUrl(cdrom_image) and not _CheckUrl(cdrom_image):
997
      raise errors.HypervisorError("Cdrom ISO image '%s' is not accessible" %
998
                                   cdrom_image)
999

    
1000
    # set cdrom 'media' and 'format', if needed
1001
    if utils.IsUrl(cdrom_image):
1002
      options = ",media=cdrom"
1003
    else:
1004
      options = ",media=cdrom,format=raw"
1005

    
1006
    # set cdrom 'if' type
1007
    if cdrom_boot:
1008
      if_val = ",if=" + constants.HT_DISK_IDE
1009
    elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1010
      if_val = ",if=virtio"
1011
    else:
1012
      if_val = ",if=" + cdrom_disk_type
1013

    
1014
    # set boot flag, if needed
1015
    boot_val = ""
1016
    if cdrom_boot:
1017
      kvm_cmd.extend(["-boot", "d"])
1018

    
1019
      # whether this is an older KVM version that requires the 'boot=on' flag
1020
      # on devices
1021
      if needs_boot_flag:
1022
        boot_val = ",boot=on"
1023

    
1024
    # build '-drive' option
1025
    drive_val = "file=%s%s%s%s" % (cdrom_image, options, if_val, boot_val)
1026
    kvm_cmd.extend(["-drive", drive_val])
1027

    
1028
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1029
                          kvmhelp):
1030
    """Generate KVM information to start an instance.
1031

1032
    @type kvmhelp: string
1033
    @param kvmhelp: output of kvm --help
1034
    @attention: this function must not have any side-effects; for
1035
        example, it must not write to the filesystem, or read values
1036
        from the current system the are expected to differ between
1037
        nodes, since it is only run once at instance startup;
1038
        actions/kvm arguments that can vary between systems should be
1039
        done in L{_ExecuteKVMRuntime}
1040

1041
    """
1042
    # pylint: disable=R0912,R0914,R0915
1043
    hvp = instance.hvparams
1044
    self.ValidateParameters(hvp)
1045

    
1046
    pidfile = self._InstancePidFile(instance.name)
1047
    kvm = hvp[constants.HV_KVM_PATH]
1048
    kvm_cmd = [kvm]
1049
    # used just by the vnc server, if enabled
1050
    kvm_cmd.extend(["-name", instance.name])
1051
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1052

    
1053
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1054
    if hvp[constants.HV_CPU_CORES]:
1055
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1056
    if hvp[constants.HV_CPU_THREADS]:
1057
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1058
    if hvp[constants.HV_CPU_SOCKETS]:
1059
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1060

    
1061
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1062

    
1063
    kvm_cmd.extend(["-pidfile", pidfile])
1064

    
1065
    pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1066

    
1067
    # As requested by music lovers
1068
    if hvp[constants.HV_SOUNDHW]:
1069
      soundhw = hvp[constants.HV_SOUNDHW]
1070
      # For some reason only few sound devices require a PCI slot
1071
      # while the Audio controller *must* be in slot 3.
1072
      # That's why we bridge this option early in command line
1073
      if soundhw in self._SOUNDHW_WITH_PCI_SLOT:
1074
        _ = utils.GetFreeSlot(pci_reservations, reserve=True)
1075
      kvm_cmd.extend(["-soundhw", soundhw])
1076

    
1077
    if hvp[constants.HV_DISK_TYPE] == constants.HT_DISK_SCSI:
1078
      # The SCSI controller requires another PCI slot.
1079
      _ = utils.GetFreeSlot(pci_reservations, reserve=True)
1080

    
1081
    # Add id to ballon and place to the first available slot (3 or 4)
1082
    addr = utils.GetFreeSlot(pci_reservations, reserve=True)
1083
    pci_info = ",bus=pci.0,addr=%s" % hex(addr)
1084
    kvm_cmd.extend(["-balloon", "virtio,id=balloon%s" % pci_info])
1085
    kvm_cmd.extend(["-daemonize"])
1086
    if not instance.hvparams[constants.HV_ACPI]:
1087
      kvm_cmd.extend(["-no-acpi"])
1088
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1089
        constants.INSTANCE_REBOOT_EXIT:
1090
      kvm_cmd.extend(["-no-reboot"])
1091

    
1092
    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1093
    if not mversion:
1094
      mversion = self._GetDefaultMachineVersion(kvm)
1095
    if self._MACHINE_RE.search(kvmhelp):
1096
      # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1097
      # extra hypervisor parameters. We should also investigate whether and how
1098
      # shadow_mem should be considered for the resource model.
1099
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1100
        specprop = ",accel=kvm"
1101
      else:
1102
        specprop = ""
1103
      machinespec = "%s%s" % (mversion, specprop)
1104
      kvm_cmd.extend(["-machine", machinespec])
1105
    else:
1106
      kvm_cmd.extend(["-M", mversion])
1107
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1108
          self._ENABLE_KVM_RE.search(kvmhelp)):
1109
        kvm_cmd.extend(["-enable-kvm"])
1110
      elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1111
            self._DISABLE_KVM_RE.search(kvmhelp)):
1112
        kvm_cmd.extend(["-disable-kvm"])
1113

    
1114
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1115
    if kernel_path:
1116
      boot_cdrom = boot_floppy = boot_network = False
1117
    else:
1118
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1119
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1120
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1121

    
1122
    if startup_paused:
1123
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1124

    
1125
    if boot_network:
1126
      kvm_cmd.extend(["-boot", "n"])
1127

    
1128
    disk_type = hvp[constants.HV_DISK_TYPE]
1129

    
1130
    # Now we can specify a different device type for CDROM devices.
1131
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1132
    if not cdrom_disk_type:
1133
      cdrom_disk_type = disk_type
1134

    
1135
    cdrom_image1 = hvp[constants.HV_CDROM_IMAGE_PATH]
1136
    if cdrom_image1:
1137
      needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1138
      self._CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image1, boot_cdrom,
1139
                        needs_boot_flag)
1140

    
1141
    cdrom_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1142
    if cdrom_image2:
1143
      self._CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image2, False, False)
1144

    
1145
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1146
    if floppy_image:
1147
      options = ",format=raw,media=disk"
1148
      if boot_floppy:
1149
        kvm_cmd.extend(["-boot", "a"])
1150
        options = "%s,boot=on" % options
1151
      if_val = ",if=floppy"
1152
      options = "%s%s" % (options, if_val)
1153
      drive_val = "file=%s%s" % (floppy_image, options)
1154
      kvm_cmd.extend(["-drive", drive_val])
1155

    
1156
    if kernel_path:
1157
      kvm_cmd.extend(["-kernel", kernel_path])
1158
      initrd_path = hvp[constants.HV_INITRD_PATH]
1159
      if initrd_path:
1160
        kvm_cmd.extend(["-initrd", initrd_path])
1161
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1162
                     hvp[constants.HV_KERNEL_ARGS]]
1163
      if hvp[constants.HV_SERIAL_CONSOLE]:
1164
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1165
        root_append.append("console=ttyS0,%s" % serial_speed)
1166
      kvm_cmd.extend(["-append", " ".join(root_append)])
1167

    
1168
    mem_path = hvp[constants.HV_MEM_PATH]
1169
    if mem_path:
1170
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1171

    
1172
    monitor_dev = ("unix:%s,server,nowait" %
1173
                   self._InstanceMonitor(instance.name))
1174
    kvm_cmd.extend(["-monitor", monitor_dev])
1175
    if hvp[constants.HV_SERIAL_CONSOLE]:
1176
      serial_dev = ("unix:%s,server,nowait" %
1177
                    self._InstanceSerial(instance.name))
1178
      kvm_cmd.extend(["-serial", serial_dev])
1179
    else:
1180
      kvm_cmd.extend(["-serial", "none"])
1181

    
1182
    mouse_type = hvp[constants.HV_USB_MOUSE]
1183
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1184
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1185
    spice_ip_version = None
1186

    
1187
    kvm_cmd.extend(["-usb"])
1188

    
1189
    if mouse_type:
1190
      kvm_cmd.extend(["-usbdevice", mouse_type])
1191
    elif vnc_bind_address:
1192
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1193

    
1194
    if vnc_bind_address:
1195
      if netutils.IsValidInterface(vnc_bind_address):
1196
        if_addresses = netutils.GetInterfaceIpAddresses(vnc_bind_address)
1197
        if_ip4_addresses = if_addresses[constants.IP4_VERSION]
1198
        if len(if_ip4_addresses) < 1:
1199
          logging.error("Could not determine IPv4 address of interface %s",
1200
                        vnc_bind_address)
1201
        else:
1202
          vnc_bind_address = if_ip4_addresses[0]
1203
      if netutils.IP4Address.IsValid(vnc_bind_address):
1204
        if instance.network_port > constants.VNC_BASE_PORT:
1205
          display = instance.network_port - constants.VNC_BASE_PORT
1206
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1207
            vnc_arg = ":%d" % (display)
1208
          else:
1209
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1210
        else:
1211
          logging.error("Network port is not a valid VNC display (%d < %d),"
1212
                        " not starting VNC",
1213
                        instance.network_port, constants.VNC_BASE_PORT)
1214
          vnc_arg = "none"
1215

    
1216
        # Only allow tls and other option when not binding to a file, for now.
1217
        # kvm/qemu gets confused otherwise about the filename to use.
1218
        vnc_append = ""
1219
        if hvp[constants.HV_VNC_TLS]:
1220
          vnc_append = "%s,tls" % vnc_append
1221
          if hvp[constants.HV_VNC_X509_VERIFY]:
1222
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1223
                                               hvp[constants.HV_VNC_X509])
1224
          elif hvp[constants.HV_VNC_X509]:
1225
            vnc_append = "%s,x509=%s" % (vnc_append,
1226
                                         hvp[constants.HV_VNC_X509])
1227
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1228
          vnc_append = "%s,password" % vnc_append
1229

    
1230
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1231

    
1232
      else:
1233
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1234

    
1235
      kvm_cmd.extend(["-vnc", vnc_arg])
1236
    elif spice_bind:
1237
      # FIXME: this is wrong here; the iface ip address differs
1238
      # between systems, so it should be done in _ExecuteKVMRuntime
1239
      if netutils.IsValidInterface(spice_bind):
1240
        # The user specified a network interface, we have to figure out the IP
1241
        # address.
1242
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1243
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1244

    
1245
        # if the user specified an IP version and the interface does not
1246
        # have that kind of IP addresses, throw an exception
1247
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1248
          if not addresses[spice_ip_version]:
1249
            raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1250
                                         " for %s" % (spice_ip_version,
1251
                                                      spice_bind))
1252

    
1253
        # the user did not specify an IP version, we have to figure it out
1254
        elif (addresses[constants.IP4_VERSION] and
1255
              addresses[constants.IP6_VERSION]):
1256
          # we have both ipv4 and ipv6, let's use the cluster default IP
1257
          # version
1258
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1259
          spice_ip_version = \
1260
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1261
        elif addresses[constants.IP4_VERSION]:
1262
          spice_ip_version = constants.IP4_VERSION
1263
        elif addresses[constants.IP6_VERSION]:
1264
          spice_ip_version = constants.IP6_VERSION
1265
        else:
1266
          raise errors.HypervisorError("SPICE: Unable to get an IP address"
1267
                                       " for %s" % (spice_bind))
1268

    
1269
        spice_address = addresses[spice_ip_version][0]
1270

    
1271
      else:
1272
        # spice_bind is known to be a valid IP address, because
1273
        # ValidateParameters checked it.
1274
        spice_address = spice_bind
1275

    
1276
      spice_arg = "addr=%s" % spice_address
1277
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1278
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1279
                     (spice_arg, instance.network_port,
1280
                      pathutils.SPICE_CACERT_FILE))
1281
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1282
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1283
                      pathutils.SPICE_CERT_FILE))
1284
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1285
        if tls_ciphers:
1286
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1287
      else:
1288
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1289

    
1290
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1291
        spice_arg = "%s,disable-ticketing" % spice_arg
1292

    
1293
      if spice_ip_version:
1294
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1295

    
1296
      # Image compression options
1297
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1298
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1299
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1300
      if img_lossless:
1301
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1302
      if img_jpeg:
1303
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1304
      if img_zlib_glz:
1305
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1306

    
1307
      # Video stream detection
1308
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1309
      if video_streaming:
1310
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1311

    
1312
      # Audio compression, by default in qemu-kvm it is on
1313
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1314
        spice_arg = "%s,playback-compression=off" % spice_arg
1315
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1316
        spice_arg = "%s,agent-mouse=off" % spice_arg
1317
      else:
1318
        # Enable the spice agent communication channel between the host and the
1319
        # agent.
1320
        addr = utils.GetFreeSlot(pci_reservations, reserve=True)
1321
        pci_info = ",bus=pci.0,addr=%s" % hex(addr)
1322
        kvm_cmd.extend(["-device", "virtio-serial-pci,id=spice%s" % pci_info])
1323
        kvm_cmd.extend([
1324
          "-device",
1325
          "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1326
          ])
1327
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1328

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

    
1332
    else:
1333
      # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1334
      # also works in earlier versions though (tested with 1.1 and 1.3)
1335
      if self._DISPLAY_RE.search(kvmhelp):
1336
        kvm_cmd.extend(["-display", "none"])
1337
      else:
1338
        kvm_cmd.extend(["-nographic"])
1339

    
1340
    if hvp[constants.HV_USE_LOCALTIME]:
1341
      kvm_cmd.extend(["-localtime"])
1342

    
1343
    if hvp[constants.HV_KVM_USE_CHROOT]:
1344
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1345

    
1346
    # Add qemu-KVM -cpu param
1347
    if hvp[constants.HV_CPU_TYPE]:
1348
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1349

    
1350
    # Pass a -vga option if requested, or if spice is used, for backwards
1351
    # compatibility.
1352
    if hvp[constants.HV_VGA]:
1353
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1354
    elif spice_bind:
1355
      kvm_cmd.extend(["-vga", "qxl"])
1356

    
1357
    # Various types of usb devices, comma separated
1358
    if hvp[constants.HV_USB_DEVICES]:
1359
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1360
        kvm_cmd.extend(["-usbdevice", dev])
1361

    
1362
    # Set system UUID to instance UUID
1363
    if self._UUID_RE.search(kvmhelp):
1364
      kvm_cmd.extend(["-uuid", instance.uuid])
1365

    
1366
    if hvp[constants.HV_KVM_EXTRA]:
1367
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1368

    
1369
    kvm_disks = []
1370
    for disk, link_name, uri in block_devices:
1371
      disk.pci = utils.GetFreeSlot(pci_reservations, disk.pci, True)
1372
      kvm_disks.append((disk, link_name, uri))
1373

    
1374
    kvm_nics = []
1375
    for nic in instance.nics:
1376
      nic.pci = utils.GetFreeSlot(pci_reservations, nic.pci, True)
1377
      kvm_nics.append(nic)
1378

    
1379
    hvparams = hvp
1380

    
1381
    return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1382

    
1383
  def _WriteKVMRuntime(self, instance_name, data):
1384
    """Write an instance's KVM runtime
1385

1386
    """
1387
    try:
1388
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1389
                      data=data)
1390
    except EnvironmentError, err:
1391
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1392

    
1393
  @classmethod
1394
  def _ReadKVMRuntime(cls, instance_name):
1395
    """Read an instance's KVM runtime
1396

1397
    """
1398
    try:
1399
      file_content = utils.ReadFile(cls._InstanceKVMRuntime(instance_name))
1400
    except EnvironmentError, err:
1401
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1402
    return file_content
1403

    
1404
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1405
    """Save an instance's KVM runtime
1406

1407
    """
1408
    kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1409

    
1410
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1411
    serialized_disks = [(blk.ToDict(), link, uri)
1412
                        for blk, link, uri in kvm_disks]
1413
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1414
                                      serialized_disks))
1415

    
1416
    self._WriteKVMRuntime(instance.name, serialized_form)
1417

    
1418
  @classmethod
1419
  def _LoadKVMRuntime(cls, instance_name, serialized_runtime=None):
1420
    """Load an instance's KVM runtime
1421

1422
    """
1423
    if not serialized_runtime:
1424
      serialized_runtime = cls._ReadKVMRuntime(instance_name)
1425

    
1426
    return _AnalyzeSerializedRuntime(serialized_runtime)
1427

    
1428
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1429
    """Run the KVM cmd and check for errors
1430

1431
    @type name: string
1432
    @param name: instance name
1433
    @type kvm_cmd: list of strings
1434
    @param kvm_cmd: runcmd input for kvm
1435
    @type tap_fds: list of int
1436
    @param tap_fds: fds of tap devices opened by Ganeti
1437

1438
    """
1439
    try:
1440
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1441
    finally:
1442
      for fd in tap_fds:
1443
        utils_wrapper.CloseFdNoError(fd)
1444

    
1445
    if result.failed:
1446
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1447
                                   (name, result.fail_reason, result.output))
1448
    if not self._InstancePidAlive(name)[2]:
1449
      raise errors.HypervisorError("Failed to start instance %s" % name)
1450

    
1451
  def _GetNetworkDeviceFeatures(self, up_hvp, devlist, kvmhelp):
1452
    """Get network device options to properly enable supported features.
1453

1454
    Return a dict of supported and enabled tap features with nic_model along
1455
    with the extra strings to be appended to the --netdev and --device options.
1456
    This function is called before opening a new tap device.
1457

1458
    Currently the features_dict includes the following attributes:
1459
      - vhost (boolean)
1460
      - vnet_hdr (boolean)
1461
      - mq (boolean, int)
1462

1463
    @rtype: (dict, str, str) tuple
1464
    @return: The supported features,
1465
             the string to be appended to the --netdev option,
1466
             the string to be appended to the --device option
1467

1468
    """
1469
    nic_type = up_hvp[constants.HV_NIC_TYPE]
1470
    nic_extra_str = ""
1471
    tap_extra_str = ""
1472
    features = {
1473
      "vhost": False,
1474
      "vnet_hdr": False,
1475
      "mq": (False, 1)
1476
      }
1477
    update_features = {}
1478
    if nic_type == constants.HT_NIC_PARAVIRTUAL:
1479
      nic_model = self._VIRTIO
1480
      try:
1481
        if self._VIRTIO_NET_RE.search(devlist):
1482
          nic_model = self._VIRTIO_NET_PCI
1483
          update_features["vnet_hdr"] = up_hvp[constants.HV_VNET_HDR]
1484
      except errors.HypervisorError, _:
1485
        # Older versions of kvm don't support DEVICE_LIST, but they don't
1486
        # have new virtio syntax either.
1487
        pass
1488

    
1489
      if up_hvp[constants.HV_VHOST_NET]:
1490
        # Check for vhost_net support.
1491
        if self._VHOST_RE.search(kvmhelp):
1492
          update_features["vhost"] = True
1493
          tap_extra_str = ",vhost=on"
1494
        else:
1495
          raise errors.HypervisorError("vhost_net is configured"
1496
                                       " but it is not available")
1497
        virtio_net_queues = up_hvp.get(constants.HV_VIRTIO_NET_QUEUES, 1)
1498
        if virtio_net_queues > 1:
1499
          # Check for multiqueue virtio-net support.
1500
          if self._VIRTIO_NET_QUEUES_RE.search(kvmhelp):
1501
            # As advised at http://www.linux-kvm.org/page/Multiqueue formula
1502
            # for calculating vector size is: vectors=2*N+1 where N is the
1503
            # number of queues (HV_VIRTIO_NET_QUEUES).
1504
            nic_extra_str = ",mq=on,vectors=%d" % (2 * virtio_net_queues + 1)
1505
            update_features["mq"] = (True, virtio_net_queues)
1506
          else:
1507
            raise errors.HypervisorError("virtio_net_queues is configured"
1508
                                         " but it is not available")
1509
    else:
1510
      nic_model = nic_type
1511

    
1512
    update_features["driver"] = nic_model
1513
    features.update(update_features)
1514

    
1515
    return features, tap_extra_str, nic_extra_str
1516

    
1517
  # too many local variables
1518
  # pylint: disable=R0914
1519
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1520
    """Execute a KVM cmd, after completing it with some last minute data.
1521

1522
    @type incoming: tuple of strings
1523
    @param incoming: (target_host_ip, port)
1524
    @type kvmhelp: string
1525
    @param kvmhelp: output of kvm --help
1526

1527
    """
1528
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1529
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1530
    #    have changed since the instance started; only use them if the change
1531
    #    won't affect the inside of the instance (which hasn't been rebooted).
1532
    #  - up_hvp contains the parameters as they were when the instance was
1533
    #    started, plus any new parameter which has been added between ganeti
1534
    #    versions: it is paramount that those default to a value which won't
1535
    #    affect the inside of the instance as well.
1536
    conf_hvp = instance.hvparams
1537
    name = instance.name
1538
    self._CheckDown(name)
1539

    
1540
    temp_files = []
1541

    
1542
    kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1543
    # the first element of kvm_cmd is always the path to the kvm binary
1544
    kvm_path = kvm_cmd[0]
1545
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1546

    
1547
    # We know it's safe to run as a different user upon migration, so we'll use
1548
    # the latest conf, from conf_hvp.
1549
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1550
    if security_model == constants.HT_SM_USER:
1551
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1552

    
1553
    keymap = conf_hvp[constants.HV_KEYMAP]
1554
    if keymap:
1555
      keymap_path = self._InstanceKeymapFile(name)
1556
      # If a keymap file is specified, KVM won't use its internal defaults. By
1557
      # first including the "en-us" layout, an error on loading the actual
1558
      # layout (e.g. because it can't be found) won't lead to a non-functional
1559
      # keyboard. A keyboard with incorrect keys is still better than none.
1560
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1561
      kvm_cmd.extend(["-k", keymap_path])
1562

    
1563
    # We have reasons to believe changing something like the nic driver/type
1564
    # upon migration won't exactly fly with the instance kernel, so for nic
1565
    # related parameters we'll use up_hvp
1566
    tapfds = []
1567
    taps = []
1568
    devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1569
    if not kvm_nics:
1570
      kvm_cmd.extend(["-net", "none"])
1571
    else:
1572
      features, tap_extra, nic_extra = \
1573
          self._GetNetworkDeviceFeatures(up_hvp, devlist, kvmhelp)
1574
      nic_model = features["driver"]
1575
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1576
      for nic_seq, nic in enumerate(kvm_nics):
1577
        tapname, nic_tapfds, nic_vhostfds = OpenTap(features=features)
1578
        tapfds.extend(nic_tapfds)
1579
        tapfds.extend(nic_vhostfds)
1580
        taps.append(tapname)
1581
        tapfd = "%s%s" % ("fds=" if len(nic_tapfds) > 1 else "fd=",
1582
                          ":".join(str(fd) for fd in nic_tapfds))
1583

    
1584
        if nic_vhostfds:
1585
          vhostfd = "%s%s" % (",vhostfds="
1586
                              if len(nic_vhostfds) > 1 else ",vhostfd=",
1587
                              ":".join(str(fd) for fd in nic_vhostfds))
1588
        else:
1589
          vhostfd = ""
1590

    
1591
        if kvm_supports_netdev:
1592
          nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1593
          try:
1594
            # kvm_nics already exist in old runtime files and thus there might
1595
            # be some entries without pci slot (therefore try: except:)
1596
            kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1597
            netdev = kvm_devid
1598
            nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1599
          except errors.HotplugError:
1600
            netdev = "netdev%d" % nic_seq
1601
          nic_val += (",netdev=%s%s" % (netdev, nic_extra))
1602
          tap_val = ("type=tap,id=%s,%s%s%s" %
1603
                     (netdev, tapfd, vhostfd, tap_extra))
1604
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1605
        else:
1606
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1607
                                                         nic.mac, nic_model)
1608
          tap_val = "tap,vlan=%s,%s" % (nic_seq, tapfd)
1609
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1610

    
1611
    if incoming:
1612
      target, port = incoming
1613
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1614

    
1615
    # Changing the vnc password doesn't bother the guest that much. At most it
1616
    # will surprise people who connect to it. Whether positively or negatively
1617
    # it's debatable.
1618
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1619
    vnc_pwd = None
1620
    if vnc_pwd_file:
1621
      try:
1622
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1623
      except EnvironmentError, err:
1624
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1625
                                     % (vnc_pwd_file, err))
1626

    
1627
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1628
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1629
                         constants.SECURE_DIR_MODE)])
1630

    
1631
    # Automatically enable QMP if version is >= 0.14
1632
    if self._QMP_RE.search(kvmhelp):
1633
      logging.debug("Enabling QMP")
1634
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1635
                      self._InstanceQmpMonitor(instance.name)])
1636

    
1637
    # Configure the network now for starting instances and bridged interfaces,
1638
    # during FinalizeMigration for incoming instances' routed interfaces
1639
    for nic_seq, nic in enumerate(kvm_nics):
1640
      if (incoming and
1641
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1642
        continue
1643
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1644

    
1645
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1646
                                                     up_hvp,
1647
                                                     kvm_disks,
1648
                                                     kvmhelp,
1649
                                                     devlist)
1650
    kvm_cmd.extend(bdev_opts)
1651
    # CPU affinity requires kvm to start paused, so we set this flag if the
1652
    # instance is not already paused and if we are not going to accept a
1653
    # migrating instance. In the latter case, pausing is not needed.
1654
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1655
    if start_kvm_paused:
1656
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1657

    
1658
    # Note: CPU pinning is using up_hvp since changes take effect
1659
    # during instance startup anyway, and to avoid problems when soft
1660
    # rebooting the instance.
1661
    cpu_pinning = False
1662
    if up_hvp.get(constants.HV_CPU_MASK, None):
1663
      cpu_pinning = True
1664

    
1665
    if security_model == constants.HT_SM_POOL:
1666
      ss = ssconf.SimpleStore()
1667
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1668
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1669
      uid = uidpool.RequestUnusedUid(all_uids)
1670
      try:
1671
        username = pwd.getpwuid(uid.GetUid()).pw_name
1672
        kvm_cmd.extend(["-runas", username])
1673
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1674
      except:
1675
        uidpool.ReleaseUid(uid)
1676
        raise
1677
      else:
1678
        uid.Unlock()
1679
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1680
    else:
1681
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1682

    
1683
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1684
                     constants.RUN_DIRS_MODE)])
1685
    for nic_seq, tap in enumerate(taps):
1686
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1687
                      data=tap)
1688

    
1689
    if vnc_pwd:
1690
      change_cmd = "change vnc password %s" % vnc_pwd
1691
      self._CallMonitorCommand(instance.name, change_cmd)
1692

    
1693
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1694
    # connection attempts because SPICE by default does not allow connections
1695
    # if neither a password nor the "disable_ticketing" options are specified.
1696
    # As soon as we send the password via QMP, that password is a valid ticket
1697
    # for connection.
1698
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1699
    if spice_password_file:
1700
      spice_pwd = ""
1701
      try:
1702
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1703
      except EnvironmentError, err:
1704
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1705
                                     % (spice_password_file, err))
1706

    
1707
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1708
      qmp.connect()
1709
      arguments = {
1710
          "protocol": "spice",
1711
          "password": spice_pwd,
1712
      }
1713
      qmp.Execute("set_password", arguments)
1714

    
1715
    for filename in temp_files:
1716
      utils.RemoveFile(filename)
1717

    
1718
    # If requested, set CPU affinity and resume instance execution
1719
    if cpu_pinning:
1720
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1721

    
1722
    start_memory = self._InstanceStartupMemory(instance)
1723
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1724
      self.BalloonInstanceMemory(instance, start_memory)
1725

    
1726
    if start_kvm_paused:
1727
      # To control CPU pinning, ballooning, and vnc/spice passwords
1728
      # the VM was started in a frozen state. If freezing was not
1729
      # explicitly requested resume the vm status.
1730
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1731

    
1732
  def StartInstance(self, instance, block_devices, startup_paused):
1733
    """Start an instance.
1734

1735
    """
1736
    self._CheckDown(instance.name)
1737
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1738
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1739
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1740
                                           startup_paused, kvmhelp)
1741
    self._SaveKVMRuntime(instance, kvm_runtime)
1742
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1743

    
1744
  @classmethod
1745
  def _CallMonitorCommand(cls, instance_name, command, timeout=None):
1746
    """Invoke a command on the instance monitor.
1747

1748
    """
1749
    if timeout is not None:
1750
      timeout_cmd = "timeout %s" % (timeout, )
1751
    else:
1752
      timeout_cmd = ""
1753

    
1754
    # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1755
    # version. The monitor protocol is designed for human consumption, whereas
1756
    # QMP is made for programmatic usage. In the worst case QMP can also
1757
    # execute monitor commands. As it is, all calls to socat take at least
1758
    # 500ms and likely more: socat can't detect the end of the reply and waits
1759
    # for 500ms of no data received before exiting (500 ms is the default for
1760
    # the "-t" parameter).
1761
    socat = ("echo %s | %s %s STDIO UNIX-CONNECT:%s" %
1762
             (utils.ShellQuote(command),
1763
              timeout_cmd,
1764
              constants.SOCAT_PATH,
1765
              utils.ShellQuote(cls._InstanceMonitor(instance_name))))
1766
    result = utils.RunCmd(socat)
1767
    if result.failed:
1768
      msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1769
             " output: %s" %
1770
             (command, instance_name, result.fail_reason, result.output))
1771
      raise errors.HypervisorError(msg)
1772

    
1773
    return result
1774

    
1775
  @_with_qmp
1776
  def VerifyHotplugSupport(self, instance, action, dev_type):
1777
    """Verifies that hotplug is supported.
1778

1779
    @raise errors.HypervisorError: in one of the previous cases
1780

1781
    """
1782
    if dev_type == constants.HOTPLUG_TARGET_DISK:
1783
      if action == constants.HOTPLUG_ACTION_ADD:
1784
        self.qmp.CheckDiskHotAddSupport()
1785
    if dev_type == constants.HOTPLUG_TARGET_NIC:
1786
      if action == constants.HOTPLUG_ACTION_ADD:
1787
        self.qmp.CheckNicHotAddSupport()
1788

    
1789
  def HotplugSupported(self, instance):
1790
    """Checks if hotplug is generally supported.
1791

1792
    Hotplug is *not* supported in case of:
1793
     - qemu versions < 1.7 (where all qmp related commands are supported)
1794
     - for stopped instances
1795

1796
    @raise errors.HypervisorError: in one of the previous cases
1797

1798
    """
1799
    try:
1800
      output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
1801
    except errors.HypervisorError:
1802
      raise errors.HotplugError("Instance is probably down")
1803

    
1804
    match = self._INFO_VERSION_RE.search(output.stdout)
1805
    if not match:
1806
      raise errors.HotplugError("Cannot parse qemu version via monitor")
1807

    
1808
    #TODO: delegate more fine-grained checks to VerifyHotplugSupport
1809
    v_major, v_min, _, _ = match.groups()
1810
    if (int(v_major), int(v_min)) < (1, 7):
1811
      raise errors.HotplugError("Hotplug not supported for qemu versions < 1.7")
1812

    
1813
  @_with_qmp
1814
  def _VerifyHotplugCommand(self, _instance,
1815
                            device, kvm_devid, should_exist):
1816
    """Checks if a previous hotplug command has succeeded.
1817

1818
    Depending on the should_exist value, verifies that an entry identified by
1819
    the PCI slot and device ID is present or not.
1820

1821
    @raise errors.HypervisorError: if result is not the expected one
1822

1823
    """
1824
    for i in range(5):
1825
      found = self.qmp.HasPCIDevice(device, kvm_devid)
1826
      logging.info("Verifying hotplug command (retry %s): %s", i, found)
1827
      if found and should_exist:
1828
        break
1829
      if not found and not should_exist:
1830
        break
1831
      time.sleep(1)
1832

    
1833
    if found and not should_exist:
1834
      msg = "Device %s should have been removed but is still there" % kvm_devid
1835
      raise errors.HypervisorError(msg)
1836

    
1837
    if not found and should_exist:
1838
      msg = "Device %s should have been added but is missing" % kvm_devid
1839
      raise errors.HypervisorError(msg)
1840

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

    
1843
  @_with_qmp
1844
  def HotAddDevice(self, instance, dev_type, device, extra, seq):
1845
    """ Helper method to hot-add a new device
1846

1847
    It gets free pci slot generates the device name and invokes the
1848
    device specific method.
1849

1850
    """
1851
    # in case of hot-mod this is given
1852
    if device.pci is None:
1853
      device.pci = self.qmp.GetFreePCISlot()
1854
    kvm_devid = _GenerateDeviceKVMId(dev_type, device)
1855
    runtime = self._LoadKVMRuntime(instance.name)
1856
    if dev_type == constants.HOTPLUG_TARGET_DISK:
1857
      uri = _GetDriveURI(device, extra[0], extra[1])
1858
      self.qmp.HotAddDisk(device, kvm_devid, uri)
1859
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
1860
      kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1861
      kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1862
      devlist = self._GetKVMOutput(kvmpath, self._KVMOPT_DEVICELIST)
1863
      up_hvp = runtime[2]
1864
      features, _, _ = self._GetNetworkDeviceFeatures(up_hvp, devlist, kvmhelp)
1865
      (tap, tapfds, vhostfds) = OpenTap(features=features)
1866
      self._ConfigureNIC(instance, seq, device, tap)
1867
      self.qmp.HotAddNic(device, kvm_devid, tapfds, vhostfds, features)
1868
      utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
1869

    
1870
    self._VerifyHotplugCommand(instance, device, kvm_devid, True)
1871
    # update relevant entries in runtime file
1872
    index = _DEVICE_RUNTIME_INDEX[dev_type]
1873
    entry = _RUNTIME_ENTRY[dev_type](device, extra)
1874
    runtime[index].append(entry)
1875
    self._SaveKVMRuntime(instance, runtime)
1876

    
1877
  @_with_qmp
1878
  def HotDelDevice(self, instance, dev_type, device, _, seq):
1879
    """ Helper method for hot-del device
1880

1881
    It gets device info from runtime file, generates the device name and
1882
    invokes the device specific method.
1883

1884
    """
1885
    runtime = self._LoadKVMRuntime(instance.name)
1886
    entry = _GetExistingDeviceInfo(dev_type, device, runtime)
1887
    kvm_device = _RUNTIME_DEVICE[dev_type](entry)
1888
    kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
1889
    if dev_type == constants.HOTPLUG_TARGET_DISK:
1890
      self.qmp.HotDelDisk(kvm_devid)
1891
      # drive_del is not implemented yet in qmp
1892
      command = "drive_del %s\n" % kvm_devid
1893
      self._CallMonitorCommand(instance.name, command)
1894
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
1895
      self.qmp.HotDelNic(kvm_devid)
1896
      utils.RemoveFile(self._InstanceNICFile(instance.name, seq))
1897
    self._VerifyHotplugCommand(instance, kvm_device, kvm_devid, False)
1898
    index = _DEVICE_RUNTIME_INDEX[dev_type]
1899
    runtime[index].remove(entry)
1900
    self._SaveKVMRuntime(instance, runtime)
1901

    
1902
    return kvm_device.pci
1903

    
1904
  def HotModDevice(self, instance, dev_type, device, _, seq):
1905
    """ Helper method for hot-mod device
1906

1907
    It gets device info from runtime file, generates the device name and
1908
    invokes the device specific method. Currently only NICs support hot-mod
1909

1910
    """
1911
    if dev_type == constants.HOTPLUG_TARGET_NIC:
1912
      # putting it back in the same pci slot
1913
      device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
1914
      self.HotAddDevice(instance, dev_type, device, _, seq)
1915

    
1916
  @classmethod
1917
  def _ParseKVMVersion(cls, text):
1918
    """Parse the KVM version from the --help output.
1919

1920
    @type text: string
1921
    @param text: output of kvm --help
1922
    @return: (version, v_maj, v_min, v_rev)
1923
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1924

1925
    """
1926
    match = cls._VERSION_RE.search(text.splitlines()[0])
1927
    if not match:
1928
      raise errors.HypervisorError("Unable to get KVM version")
1929

    
1930
    v_all = match.group(0)
1931
    v_maj = int(match.group(1))
1932
    v_min = int(match.group(2))
1933
    if match.group(4):
1934
      v_rev = int(match.group(4))
1935
    else:
1936
      v_rev = 0
1937
    return (v_all, v_maj, v_min, v_rev)
1938

    
1939
  @classmethod
1940
  def _GetKVMOutput(cls, kvm_path, option):
1941
    """Return the output of a kvm invocation
1942

1943
    @type kvm_path: string
1944
    @param kvm_path: path to the kvm executable
1945
    @type option: a key of _KVMOPTS_CMDS
1946
    @param option: kvm option to fetch the output from
1947
    @return: output a supported kvm invocation
1948
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1949

1950
    """
1951
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
1952

    
1953
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
1954

    
1955
    result = utils.RunCmd([kvm_path] + optlist)
1956
    if result.failed and not can_fail:
1957
      raise errors.HypervisorError("Unable to get KVM %s output" %
1958
                                    " ".join(optlist))
1959
    return result.output
1960

    
1961
  @classmethod
1962
  def _GetKVMVersion(cls, kvm_path):
1963
    """Return the installed KVM version.
1964

1965
    @return: (version, v_maj, v_min, v_rev)
1966
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1967

1968
    """
1969
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
1970

    
1971
  @classmethod
1972
  def _GetDefaultMachineVersion(cls, kvm_path):
1973
    """Return the default hardware revision (e.g. pc-1.1)
1974

1975
    """
1976
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
1977
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
1978
    if match:
1979
      return match.group(1)
1980
    else:
1981
      return "pc"
1982

    
1983
  @classmethod
1984
  def _StopInstance(cls, instance, force=False, name=None, timeout=None):
1985
    """Stop an instance.
1986

1987
    """
1988
    assert(timeout is None or force is not None)
1989

    
1990
    if name is not None and not force:
1991
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1992
    if name is None:
1993
      name = instance.name
1994
      acpi = instance.hvparams[constants.HV_ACPI]
1995
    else:
1996
      acpi = False
1997
    _, pid, alive = cls._InstancePidAlive(name)
1998
    if pid > 0 and alive:
1999
      if force or not acpi:
2000
        utils.KillProcess(pid)
2001
      else:
2002
        cls._CallMonitorCommand(name, "system_powerdown", timeout)
2003

    
2004
  def StopInstance(self, instance, force=False, retry=False, name=None,
2005
                   timeout=None):
2006
    """Stop an instance.
2007

2008
    """
2009
    self._StopInstance(instance, force, name, timeout)
2010

    
2011
  def CleanupInstance(self, instance_name):
2012
    """Cleanup after a stopped instance
2013

2014
    """
2015
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
2016
    if pid > 0 and alive:
2017
      raise errors.HypervisorError("Cannot cleanup a live instance")
2018
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2019

    
2020
  def RebootInstance(self, instance):
2021
    """Reboot an instance.
2022

2023
    """
2024
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2025
    # socket the instance will stop, but now power up again. So we'll resort
2026
    # to shutdown and restart.
2027
    _, _, alive = self._InstancePidAlive(instance.name)
2028
    if not alive:
2029
      raise errors.HypervisorError("Failed to reboot instance %s:"
2030
                                   " not running" % instance.name)
2031
    # StopInstance will delete the saved KVM runtime so:
2032
    # ...first load it...
2033
    kvm_runtime = self._LoadKVMRuntime(instance.name)
2034
    # ...now we can safely call StopInstance...
2035
    if not self.StopInstance(instance):
2036
      self.StopInstance(instance, force=True)
2037
    # ...and finally we can save it again, and execute it...
2038
    self._SaveKVMRuntime(instance, kvm_runtime)
2039
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2040
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2041
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2042

    
2043
  def MigrationInfo(self, instance):
2044
    """Get instance information to perform a migration.
2045

2046
    @type instance: L{objects.Instance}
2047
    @param instance: instance to be migrated
2048
    @rtype: string
2049
    @return: content of the KVM runtime file
2050

2051
    """
2052
    return self._ReadKVMRuntime(instance.name)
2053

    
2054
  def AcceptInstance(self, instance, info, target):
2055
    """Prepare to accept an instance.
2056

2057
    @type instance: L{objects.Instance}
2058
    @param instance: instance to be accepted
2059
    @type info: string
2060
    @param info: content of the KVM runtime file on the source node
2061
    @type target: string
2062
    @param target: target host (usually ip), on this node
2063

2064
    """
2065
    kvm_runtime = self._LoadKVMRuntime(instance.name, serialized_runtime=info)
2066
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2067
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2068
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2069
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2070
                            incoming=incoming_address)
2071

    
2072
  def FinalizeMigrationDst(self, instance, info, success):
2073
    """Finalize the instance migration on the target node.
2074

2075
    Stop the incoming mode KVM.
2076

2077
    @type instance: L{objects.Instance}
2078
    @param instance: instance whose migration is being finalized
2079

2080
    """
2081
    if success:
2082
      kvm_runtime = self._LoadKVMRuntime(instance.name, serialized_runtime=info)
2083
      kvm_nics = kvm_runtime[1]
2084

    
2085
      for nic_seq, nic in enumerate(kvm_nics):
2086
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2087
          # Bridged interfaces have already been configured
2088
          continue
2089
        try:
2090
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2091
        except EnvironmentError, err:
2092
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
2093
                          instance.name, nic_seq, str(err))
2094
          continue
2095
        try:
2096
          self._ConfigureNIC(instance, nic_seq, nic, tap)
2097
        except errors.HypervisorError, err:
2098
          logging.warning(str(err))
2099

    
2100
      self._WriteKVMRuntime(instance.name, info)
2101
    else:
2102
      self.StopInstance(instance, force=True)
2103

    
2104
  def MigrateInstance(self, cluster_name, instance, target, live):
2105
    """Migrate an instance to a target node.
2106

2107
    The migration will not be attempted if the instance is not
2108
    currently running.
2109

2110
    @type cluster_name: string
2111
    @param cluster_name: name of the cluster
2112
    @type instance: L{objects.Instance}
2113
    @param instance: the instance to be migrated
2114
    @type target: string
2115
    @param target: ip address of the target node
2116
    @type live: boolean
2117
    @param live: perform a live migration
2118

2119
    """
2120
    instance_name = instance.name
2121
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
2122
    _, _, alive = self._InstancePidAlive(instance_name)
2123
    if not alive:
2124
      raise errors.HypervisorError("Instance not running, cannot migrate")
2125

    
2126
    if not live:
2127
      self._CallMonitorCommand(instance_name, "stop")
2128

    
2129
    migrate_command = ("migrate_set_speed %dm" %
2130
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2131
    self._CallMonitorCommand(instance_name, migrate_command)
2132

    
2133
    migrate_command = ("migrate_set_downtime %dms" %
2134
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2135
    self._CallMonitorCommand(instance_name, migrate_command)
2136

    
2137
    migration_caps = instance.hvparams[constants.HV_KVM_MIGRATION_CAPS]
2138
    if migration_caps:
2139
      for c in migration_caps.split(_MIGRATION_CAPS_DELIM):
2140
        migrate_command = ("migrate_set_capability %s on" % c)
2141
        self._CallMonitorCommand(instance_name, migrate_command)
2142

    
2143
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2144
    self._CallMonitorCommand(instance_name, migrate_command)
2145

    
2146
  def FinalizeMigrationSource(self, instance, success, live):
2147
    """Finalize the instance migration on the source node.
2148

2149
    @type instance: L{objects.Instance}
2150
    @param instance: the instance that was migrated
2151
    @type success: bool
2152
    @param success: whether the migration succeeded or not
2153
    @type live: bool
2154
    @param live: whether the user requested a live migration or not
2155

2156
    """
2157
    if success:
2158
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2159
      utils.KillProcess(pid)
2160
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2161
    elif live:
2162
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2163

    
2164
  def GetMigrationStatus(self, instance):
2165
    """Get the migration status
2166

2167
    @type instance: L{objects.Instance}
2168
    @param instance: the instance that is being migrated
2169
    @rtype: L{objects.MigrationStatus}
2170
    @return: the status of the current migration (one of
2171
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2172
             progress info that can be retrieved from the hypervisor
2173

2174
    """
2175
    info_command = "info migrate"
2176
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2177
      result = self._CallMonitorCommand(instance.name, info_command)
2178
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
2179
      if not match:
2180
        if not result.stdout:
2181
          logging.info("KVM: empty 'info migrate' result")
2182
        else:
2183
          logging.warning("KVM: unknown 'info migrate' result: %s",
2184
                          result.stdout)
2185
      else:
2186
        status = match.group(1)
2187
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2188
          migration_status = objects.MigrationStatus(status=status)
2189
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2190
          if match:
2191
            migration_status.transferred_ram = match.group("transferred")
2192
            migration_status.total_ram = match.group("total")
2193

    
2194
          return migration_status
2195

    
2196
        logging.warning("KVM: unknown migration status '%s'", status)
2197

    
2198
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2199

    
2200
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2201

    
2202
  def BalloonInstanceMemory(self, instance, mem):
2203
    """Balloon an instance memory to a certain value.
2204

2205
    @type instance: L{objects.Instance}
2206
    @param instance: instance to be accepted
2207
    @type mem: int
2208
    @param mem: actual memory size to use for instance runtime
2209

2210
    """
2211
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2212

    
2213
  def GetNodeInfo(self, hvparams=None):
2214
    """Return information about the node.
2215

2216
    @type hvparams: dict of strings
2217
    @param hvparams: hypervisor parameters, not used in this class
2218

2219
    @return: a dict as returned by L{BaseHypervisor.GetLinuxNodeInfo} plus
2220
        the following keys:
2221
          - hv_version: the hypervisor version in the form (major, minor,
2222
                        revision)
2223

2224
    """
2225
    result = self.GetLinuxNodeInfo()
2226
    kvmpath = constants.KVM_PATH
2227
    if hvparams is not None:
2228
      kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2229
    _, v_major, v_min, v_rev = self._GetKVMVersion(kvmpath)
2230
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2231
    return result
2232

    
2233
  @classmethod
2234
  def GetInstanceConsole(cls, instance, primary_node, hvparams, beparams):
2235
    """Return a command for connecting to the console of an instance.
2236

2237
    """
2238
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2239
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2240
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2241
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2242
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2243
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2244
      return objects.InstanceConsole(instance=instance.name,
2245
                                     kind=constants.CONS_SSH,
2246
                                     host=primary_node.name,
2247
                                     user=constants.SSH_CONSOLE_USER,
2248
                                     command=cmd)
2249

    
2250
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2251
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2252
      display = instance.network_port - constants.VNC_BASE_PORT
2253
      return objects.InstanceConsole(instance=instance.name,
2254
                                     kind=constants.CONS_VNC,
2255
                                     host=vnc_bind_address,
2256
                                     port=instance.network_port,
2257
                                     display=display)
2258

    
2259
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2260
    if spice_bind:
2261
      return objects.InstanceConsole(instance=instance.name,
2262
                                     kind=constants.CONS_SPICE,
2263
                                     host=spice_bind,
2264
                                     port=instance.network_port)
2265

    
2266
    return objects.InstanceConsole(instance=instance.name,
2267
                                   kind=constants.CONS_MESSAGE,
2268
                                   message=("No serial shell for instance %s" %
2269
                                            instance.name))
2270

    
2271
  def Verify(self, hvparams=None):
2272
    """Verify the hypervisor.
2273

2274
    Check that the required binaries exist.
2275

2276
    @type hvparams: dict of strings
2277
    @param hvparams: hypervisor parameters to be verified against, not used here
2278

2279
    @return: Problem description if something is wrong, C{None} otherwise
2280

2281
    """
2282
    msgs = []
2283
    kvmpath = constants.KVM_PATH
2284
    if hvparams is not None:
2285
      kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2286
    if not os.path.exists(kvmpath):
2287
      msgs.append("The KVM binary ('%s') does not exist" % kvmpath)
2288
    if not os.path.exists(constants.SOCAT_PATH):
2289
      msgs.append("The socat binary ('%s') does not exist" %
2290
                  constants.SOCAT_PATH)
2291

    
2292
    return self._FormatVerifyResults(msgs)
2293

    
2294
  @classmethod
2295
  def CheckParameterSyntax(cls, hvparams):
2296
    """Check the given parameters for validity.
2297

2298
    @type hvparams:  dict
2299
    @param hvparams: dictionary with parameter names/value
2300
    @raise errors.HypervisorError: when a parameter is not valid
2301

2302
    """
2303
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2304

    
2305
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2306
    if kernel_path:
2307
      if not hvparams[constants.HV_ROOT_PATH]:
2308
        raise errors.HypervisorError("Need a root partition for the instance,"
2309
                                     " if a kernel is defined")
2310

    
2311
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2312
        not hvparams[constants.HV_VNC_X509]):
2313
      raise errors.HypervisorError("%s must be defined, if %s is" %
2314
                                   (constants.HV_VNC_X509,
2315
                                    constants.HV_VNC_X509_VERIFY))
2316

    
2317
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2318
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2319
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2320
      if not serial_speed or serial_speed not in valid_speeds:
2321
        raise errors.HypervisorError("Invalid serial console speed, must be"
2322
                                     " one of: %s" %
2323
                                     utils.CommaJoin(valid_speeds))
2324

    
2325
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2326
    if (boot_order == constants.HT_BO_CDROM and
2327
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2328
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2329
                                   " ISO path")
2330

    
2331
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2332
    if security_model == constants.HT_SM_USER:
2333
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2334
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2335
                                     " must be specified")
2336
    elif (security_model == constants.HT_SM_NONE or
2337
          security_model == constants.HT_SM_POOL):
2338
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2339
        raise errors.HypervisorError("Cannot have a security domain when the"
2340
                                     " security model is 'none' or 'pool'")
2341

    
2342
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2343
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2344
    if spice_bind:
2345
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2346
        # if an IP version is specified, the spice_bind parameter must be an
2347
        # IP of that family
2348
        if (netutils.IP4Address.IsValid(spice_bind) and
2349
            spice_ip_version != constants.IP4_VERSION):
2350
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2351
                                       " the specified IP version is %s" %
2352
                                       (spice_bind, spice_ip_version))
2353

    
2354
        if (netutils.IP6Address.IsValid(spice_bind) and
2355
            spice_ip_version != constants.IP6_VERSION):
2356
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2357
                                       " the specified IP version is %s" %
2358
                                       (spice_bind, spice_ip_version))
2359
    else:
2360
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2361
      # error if any of them is set without it.
2362
      for param in _SPICE_ADDITIONAL_PARAMS:
2363
        if hvparams[param]:
2364
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2365
                                       (param, constants.HV_KVM_SPICE_BIND))
2366

    
2367
  @classmethod
2368
  def ValidateParameters(cls, hvparams):
2369
    """Check the given parameters for validity.
2370

2371
    @type hvparams:  dict
2372
    @param hvparams: dictionary with parameter names/value
2373
    @raise errors.HypervisorError: when a parameter is not valid
2374

2375
    """
2376
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2377

    
2378
    kvm_path = hvparams[constants.HV_KVM_PATH]
2379

    
2380
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2381
    if security_model == constants.HT_SM_USER:
2382
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2383
      try:
2384
        pwd.getpwnam(username)
2385
      except KeyError:
2386
        raise errors.HypervisorError("Unknown security domain user %s"
2387
                                     % username)
2388
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2389
    if vnc_bind_address:
2390
      bound_to_addr = netutils.IP4Address.IsValid(vnc_bind_address)
2391
      is_interface = netutils.IsValidInterface(vnc_bind_address)
2392
      is_path = utils.IsNormAbsPath(vnc_bind_address)
2393
      if not bound_to_addr and not is_interface and not is_path:
2394
        raise errors.HypervisorError("VNC: The %s parameter must be either"
2395
                                     " a valid IP address, an interface name,"
2396
                                     " or an absolute path" %
2397
                                     constants.HV_KVM_SPICE_BIND)
2398

    
2399
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2400
    if spice_bind:
2401
      # only one of VNC and SPICE can be used currently.
2402
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2403
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2404
                                     " only one of them can be used at a"
2405
                                     " given time")
2406

    
2407
      # check that KVM supports SPICE
2408
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2409
      if not cls._SPICE_RE.search(kvmhelp):
2410
        raise errors.HypervisorError("SPICE is configured, but it is not"
2411
                                     " supported according to 'kvm --help'")
2412

    
2413
      # if spice_bind is not an IP address, it must be a valid interface
2414
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2415
                       netutils.IP6Address.IsValid(spice_bind))
2416
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2417
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2418
                                     " a valid IP address or interface name" %
2419
                                     constants.HV_KVM_SPICE_BIND)
2420

    
2421
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2422
    if machine_version:
2423
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2424
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2425
        raise errors.HypervisorError("Unsupported machine version: %s" %
2426
                                     machine_version)
2427

    
2428
  @classmethod
2429
  def PowercycleNode(cls, hvparams=None):
2430
    """KVM powercycle, just a wrapper over Linux powercycle.
2431

2432
    @type hvparams: dict of strings
2433
    @param hvparams: hypervisor params to be used on this node
2434

2435
    """
2436
    cls.LinuxPowercycle()