Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm / __init__.py @ 744ff486

History | View | Annotate | Download (91.5 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-vif-bridge"
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
    """Open a QmpConnection, run the wrapped method and then close it"""
122
    conn_created = False
123
    if not getattr(self, "qmp", None):
124
      filename = self._InstanceQmpMonitor(instance.name)# pylint: disable=W0212
125
      self.qmp = QmpConnection(filename)
126
      conn_created = True
127

    
128
    self.qmp.connect()
129
    try:
130
      ret = fn(self, instance, *args, **kwargs)
131
    finally:
132
      if conn_created = True:
133
        self.qmp.close()
134
    return ret
135
  return wrapper
136

    
137

    
138
def _GetDriveURI(disk, link, uri, qmp=None):
139
  """Helper function to get the drive uri to be used in --drive kvm option
140

141
  Invoked during startup and hot-add. In latter case if kernelspace is used
142
  we get the fd of the disk, pass it to the instance via SCM rights and qmp
143
  monitor, and return the proper path (/dev/fdset/<fdset>)
144

145
  @type disk: L{objects.Disk}
146
  @param disk: A disk configuration object
147
  @type link: string
148
  @param link: The device link as returned by _SymlinkBlockDev()
149
  @type uri: string
150
  @param uri: The drive uri as returned by _CalculateDeviceURI()
151
  @type qmp: L{QmpConnection}
152
  @param qmp: The qmp connection used to pass the drive's fd
153

154
  @return: (the drive uri to use, the corresponing fdset if any) tuple
155

156
  """
157
  fdset = None
158
  access_mode = disk.params.get(constants.LDP_ACCESS,
159
                                constants.DISK_KERNELSPACE)
160
  # If uri is available, use it during startup/hot-add
161
  if (uri and access_mode == constants.DISK_USERSPACE):
162
    drive_uri = uri
163
  # During hot-add get the disk's fd and pass it to qemu via SCM rights
164
  elif qmp:
165
    try:
166
      fd = os.open(link, os.O_RDWR)
167
      fdset = qmp.AddFd([fd])
168
      os.close(fd)
169
    except OSError:
170
      logging.warning("Cannot open disk with link %s in order to"
171
                      " pass its fd to qmp monitor", link)
172
      fdset = None
173

    
174
    # fd passing succeeded
175
    if fdset is not None:
176
      drive_uri = "/dev/fdset/%s" % fdset
177
    else:
178
      drive_uri = link
179
  # Otherwise use the link previously created
180
  else:
181
    drive_uri = link
182

    
183
  return drive_uri, fdset
184

    
185

    
186
def _GenerateDeviceKVMId(dev_type, dev):
187
  """Helper function to generate a unique device name used by KVM
188

189
  QEMU monitor commands use names to identify devices. Here we use their pci
190
  slot and a part of their UUID to name them. dev.pci might be None for old
191
  devices in the cluster.
192

193
  @type dev_type: sting
194
  @param dev_type: device type of param dev
195
  @type dev: L{objects.Disk} or L{objects.NIC}
196
  @param dev: the device object for which we generate a kvm name
197
  @raise errors.HotplugError: in case a device has no pci slot (old devices)
198

199
  """
200

    
201
  if not dev.pci:
202
    raise errors.HotplugError("Hotplug is not supported for %s with UUID %s" %
203
                              (dev_type, dev.uuid))
204

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

    
207

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

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

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

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

    
231
  return found[0]
232

    
233

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

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

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

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

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

    
259
  return kvm_cmd, serialized_nics, hvparams, serialized_disks
260

    
261

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

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

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

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

    
279

    
280
class HeadRequest(urllib2.Request):
281
  def get_method(self):
282
    return "HEAD"
283

    
284

    
285
def _CheckUrl(url):
286
  """Check if a given URL exists on the server
287

288
  """
289
  try:
290
    urllib2.urlopen(HeadRequest(url))
291
    return True
292
  except urllib2.URLError:
293
    return False
294

    
295

    
296
class KVMHypervisor(hv_base.BaseHypervisor):
297
  """KVM hypervisor interface
298

299
  """
300
  CAN_MIGRATE = True
301

    
302
  _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
303
  _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
304
  _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
305
  _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
306
  _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
307
  _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
308
  _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
309
  # KVM instances with chroot enabled are started in empty chroot directories.
310
  _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
311
  # After an instance is stopped, its chroot directory is removed.
312
  # If the chroot directory is not empty, it can't be removed.
313
  # A non-empty chroot directory indicates a possible security incident.
314
  # To support forensics, the non-empty chroot directory is quarantined in
315
  # a separate directory, called 'chroot-quarantine'.
316
  _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
317
  _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
318
           _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
319

    
320
  PARAMETERS = {
321
    constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
322
    constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
323
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
324
    constants.HV_ROOT_PATH: hv_base.NO_CHECK,
325
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
326
    constants.HV_ACPI: hv_base.NO_CHECK,
327
    constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
328
    constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
329
    constants.HV_VNC_BIND_ADDRESS: hv_base.NO_CHECK, # will be checked later
330
    constants.HV_VNC_TLS: hv_base.NO_CHECK,
331
    constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
332
    constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
333
    constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
334
    constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
335
    constants.HV_KVM_SPICE_IP_VERSION:
336
      (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
337
                         x in constants.VALID_IP_VERSIONS),
338
       "The SPICE IP version should be 4 or 6",
339
       None, None),
340
    constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
341
    constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
342
      hv_base.ParamInSet(
343
        False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
344
    constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
345
      hv_base.ParamInSet(
346
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
347
    constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
348
      hv_base.ParamInSet(
349
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
350
    constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
351
      hv_base.ParamInSet(
352
        False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
353
    constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
354
    constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
355
    constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
356
    constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
357
    constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
358
    constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_OR_URL_CHECK,
359
    constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_OR_URL_CHECK,
360
    constants.HV_BOOT_ORDER:
361
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
362
    constants.HV_NIC_TYPE:
363
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
364
    constants.HV_DISK_TYPE:
365
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
366
    constants.HV_KVM_CDROM_DISK_TYPE:
367
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
368
    constants.HV_USB_MOUSE:
369
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
370
    constants.HV_KEYMAP: hv_base.NO_CHECK,
371
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
372
    constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
373
    constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
374
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
375
    constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
376
    constants.HV_DISK_CACHE:
377
      hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
378
    constants.HV_SECURITY_MODEL:
379
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
380
    constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
381
    constants.HV_KVM_FLAG:
382
      hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
383
    constants.HV_VHOST_NET: hv_base.NO_CHECK,
384
    constants.HV_VIRTIO_NET_QUEUES: hv_base.OPT_VIRTIO_NET_QUEUES_CHECK,
385
    constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
386
    constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
387
    constants.HV_REBOOT_BEHAVIOR:
388
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
389
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
390
    constants.HV_CPU_TYPE: hv_base.NO_CHECK,
391
    constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
392
    constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
393
    constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
394
    constants.HV_SOUNDHW: hv_base.NO_CHECK,
395
    constants.HV_USB_DEVICES: hv_base.NO_CHECK,
396
    constants.HV_VGA: hv_base.NO_CHECK,
397
    constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
398
    constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
399
    constants.HV_KVM_MIGRATION_CAPS: hv_base.NO_CHECK,
400
    constants.HV_VNET_HDR: hv_base.NO_CHECK,
401
    }
402

    
403
  _VIRTIO = "virtio"
404
  _VIRTIO_NET_PCI = "virtio-net-pci"
405
  _VIRTIO_BLK_PCI = "virtio-blk-pci"
406

    
407
  _MIGRATION_STATUS_RE = re.compile(r"Migration\s+status:\s+(\w+)",
408
                                    re.M | re.I)
409
  _MIGRATION_PROGRESS_RE = \
410
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
411
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
412
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
413

    
414
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
415
  _MIGRATION_INFO_RETRY_DELAY = 2
416

    
417
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
418

    
419
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
420
  _CPU_INFO_CMD = "info cpus"
421
  _CONT_CMD = "cont"
422

    
423
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
424
  _CHECK_MACHINE_VERSION_RE = \
425
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
426

    
427
  _QMP_RE = re.compile(r"^-qmp\s", re.M)
428
  _SPICE_RE = re.compile(r"^-spice\s", re.M)
429
  _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
430
  _VIRTIO_NET_QUEUES_RE = re.compile(r"^-net\s.*,fds=x:y:...:z", re.M)
431
  _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
432
  _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
433
  _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
434
  _DISPLAY_RE = re.compile(r"^-display\s", re.M)
435
  _MACHINE_RE = re.compile(r"^-machine\s", re.M)
436
  _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
437
  _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M)
438
  # match  -drive.*boot=on|off on different lines, but in between accept only
439
  # dashes not preceeded by a new line (which would mean another option
440
  # different than -drive is starting)
441
  _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
442
  _UUID_RE = re.compile(r"^-uuid\s", re.M)
443

    
444
  _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
445
  _INFO_PCI_CMD = "info pci"
446
  _FIND_PCI_DEVICE_RE = \
447
    staticmethod(
448
      lambda pci, devid: re.compile(r'Bus.*device[ ]*%d,(.*\n){5,6}.*id "%s"' %
449
                                    (pci, devid), re.M))
450

    
451
  _INFO_VERSION_RE = \
452
    re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
453
  _INFO_VERSION_CMD = "info version"
454

    
455
  # Slot 0 for Host bridge, Slot 1 for ISA bridge, Slot 2 for VGA controller
456
  _DEFAULT_PCI_RESERVATIONS = "11100000000000000000000000000000"
457
  _SOUNDHW_WITH_PCI_SLOT = ["ac97", "es1370", "hda"]
458

    
459
  ANCILLARY_FILES = [
460
    _KVM_NETWORK_SCRIPT,
461
    ]
462
  ANCILLARY_FILES_OPT = [
463
    _KVM_NETWORK_SCRIPT,
464
    ]
465

    
466
  # Supported kvm options to get output from
467
  _KVMOPT_HELP = "help"
468
  _KVMOPT_MLIST = "mlist"
469
  _KVMOPT_DEVICELIST = "devicelist"
470

    
471
  # Command to execute to get the output from kvm, and whether to
472
  # accept the output even on failure.
473
  _KVMOPTS_CMDS = {
474
    _KVMOPT_HELP: (["--help"], False),
475
    _KVMOPT_MLIST: (["-M", "?"], False),
476
    _KVMOPT_DEVICELIST: (["-device", "?"], True),
477
  }
478

    
479
  def __init__(self):
480
    hv_base.BaseHypervisor.__init__(self)
481
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
482
    # in a tmpfs filesystem or has been otherwise wiped out.
483
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
484
    utils.EnsureDirs(dirs)
485
    self.qmp = None
486

    
487
  @classmethod
488
  def _InstancePidFile(cls, instance_name):
489
    """Returns the instance pidfile.
490

491
    """
492
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
493

    
494
  @classmethod
495
  def _InstanceUidFile(cls, instance_name):
496
    """Returns the instance uidfile.
497

498
    """
499
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
500

    
501
  @classmethod
502
  def _InstancePidInfo(cls, pid):
503
    """Check pid file for instance information.
504

505
    Check that a pid file is associated with an instance, and retrieve
506
    information from its command line.
507

508
    @type pid: string or int
509
    @param pid: process id of the instance to check
510
    @rtype: tuple
511
    @return: (instance_name, memory, vcpus)
512
    @raise errors.HypervisorError: when an instance cannot be found
513

514
    """
515
    alive = utils.IsProcessAlive(pid)
516
    if not alive:
517
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
518

    
519
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
520
    try:
521
      cmdline = utils.ReadFile(cmdline_file)
522
    except EnvironmentError, err:
523
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
524
                                   (pid, err))
525

    
526
    instance = None
527
    memory = 0
528
    vcpus = 0
529

    
530
    arg_list = cmdline.split("\x00")
531
    while arg_list:
532
      arg = arg_list.pop(0)
533
      if arg == "-name":
534
        instance = arg_list.pop(0)
535
      elif arg == "-m":
536
        memory = int(arg_list.pop(0))
537
      elif arg == "-smp":
538
        vcpus = int(arg_list.pop(0).split(",")[0])
539

    
540
    if instance is None:
541
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
542
                                   " instance" % pid)
543

    
544
    return (instance, memory, vcpus)
545

    
546
  @classmethod
547
  def _InstancePidAlive(cls, instance_name):
548
    """Returns the instance pidfile, pid, and liveness.
549

550
    @type instance_name: string
551
    @param instance_name: instance name
552
    @rtype: tuple
553
    @return: (pid file name, pid, liveness)
554

555
    """
556
    pidfile = cls._InstancePidFile(instance_name)
557
    pid = utils.ReadPidFile(pidfile)
558

    
559
    alive = False
560
    try:
561
      cmd_instance = cls._InstancePidInfo(pid)[0]
562
      alive = (cmd_instance == instance_name)
563
    except errors.HypervisorError:
564
      pass
565

    
566
    return (pidfile, pid, alive)
567

    
568
  @classmethod
569
  def _CheckDown(cls, instance_name):
570
    """Raises an error unless the given instance is down.
571

572
    """
573
    alive = cls._InstancePidAlive(instance_name)[2]
574
    if alive:
575
      raise errors.HypervisorError("Failed to start instance %s: %s" %
576
                                   (instance_name, "already running"))
577

    
578
  @classmethod
579
  def _InstanceMonitor(cls, instance_name):
580
    """Returns the instance monitor socket name
581

582
    """
583
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
584

    
585
  @classmethod
586
  def _InstanceSerial(cls, instance_name):
587
    """Returns the instance serial socket name
588

589
    """
590
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
591

    
592
  @classmethod
593
  def _InstanceQmpMonitor(cls, instance_name):
594
    """Returns the instance serial QMP socket name
595

596
    """
597
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
598

    
599
  @staticmethod
600
  def _SocatUnixConsoleParams():
601
    """Returns the correct parameters for socat
602

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

605
    """
606
    if constants.SOCAT_USE_ESCAPE:
607
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
608
    else:
609
      return "echo=0,icanon=0"
610

    
611
  @classmethod
612
  def _InstanceKVMRuntime(cls, instance_name):
613
    """Returns the instance KVM runtime filename
614

615
    """
616
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
617

    
618
  @classmethod
619
  def _InstanceChrootDir(cls, instance_name):
620
    """Returns the name of the KVM chroot dir of the instance
621

622
    """
623
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
624

    
625
  @classmethod
626
  def _InstanceNICDir(cls, instance_name):
627
    """Returns the name of the directory holding the tap device files for a
628
    given instance.
629

630
    """
631
    return utils.PathJoin(cls._NICS_DIR, instance_name)
632

    
633
  @classmethod
634
  def _InstanceNICFile(cls, instance_name, seq):
635
    """Returns the name of the file containing the tap device for a given NIC
636

637
    """
638
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
639

    
640
  @classmethod
641
  def _InstanceKeymapFile(cls, instance_name):
642
    """Returns the name of the file containing the keymap for a given instance
643

644
    """
645
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
646

    
647
  @classmethod
648
  def _TryReadUidFile(cls, uid_file):
649
    """Try to read a uid file
650

651
    """
652
    if os.path.exists(uid_file):
653
      try:
654
        uid = int(utils.ReadOneLineFile(uid_file))
655
        return uid
656
      except EnvironmentError:
657
        logging.warning("Can't read uid file", exc_info=True)
658
      except (TypeError, ValueError):
659
        logging.warning("Can't parse uid file contents", exc_info=True)
660
    return None
661

    
662
  @classmethod
663
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
664
    """Removes an instance's rutime sockets/files/dirs.
665

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

    
702
  @staticmethod
703
  def _ConfigureNIC(instance, seq, nic, tap):
704
    """Run the network configuration script for a specified NIC
705

706
    See L{hv_base.ConfigureNIC}.
707

708
    @param instance: instance we're acting on
709
    @type instance: instance object
710
    @param seq: nic sequence number
711
    @type seq: int
712
    @param nic: nic we're acting on
713
    @type nic: nic object
714
    @param tap: the host's tap interface this NIC corresponds to
715
    @type tap: str
716

717
    """
718
    hv_base.ConfigureNIC([pathutils.KVM_IFUP, tap], instance, seq, nic, tap)
719

    
720
  @staticmethod
721
  def _VerifyAffinityPackage():
722
    if affinity is None:
723
      raise errors.HypervisorError("affinity Python package not"
724
                                   " found; cannot use CPU pinning under KVM")
725

    
726
  @staticmethod
727
  def _BuildAffinityCpuMask(cpu_list):
728
    """Create a CPU mask suitable for sched_setaffinity from a list of
729
    CPUs.
730

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

734
    @type cpu_list: list of int
735
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
736
    @rtype: int
737
    @return: a bit mask of CPU affinities
738

739
    """
740
    if cpu_list == constants.CPU_PINNING_OFF:
741
      return constants.CPU_PINNING_ALL_KVM
742
    else:
743
      return sum(2 ** cpu for cpu in cpu_list)
744

    
745
  @classmethod
746
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
747
    """Change CPU affinity for running VM according to given CPU mask.
748

749
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
750
    @type cpu_mask: string
751
    @param process_id: process ID of KVM process. Used to pin entire VM
752
                       to physical CPUs.
753
    @type process_id: int
754
    @param thread_dict: map of virtual CPUs to KVM thread IDs
755
    @type thread_dict: dict int:int
756

757
    """
758
    # Convert the string CPU mask to a list of list of int's
759
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
760

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

    
779
      # For each vCPU, map it to the proper list of physical CPUs
780
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
781
        affinity.set_process_affinity_mask(thread_dict[i],
782
                                           cls._BuildAffinityCpuMask(vcpu))
783

    
784
  def _GetVcpuThreadIds(self, instance_name):
785
    """Get a mapping of vCPU no. to thread IDs for the instance
786

787
    @type instance_name: string
788
    @param instance_name: instance in question
789
    @rtype: dictionary of int:int
790
    @return: a dictionary mapping vCPU numbers to thread IDs
791

792
    """
793
    result = {}
794
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
795
    for line in output.stdout.splitlines():
796
      match = self._CPU_INFO_RE.search(line)
797
      if not match:
798
        continue
799
      grp = map(int, match.groups())
800
      result[grp[0]] = grp[1]
801

    
802
    return result
803

    
804
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
805
    """Complete CPU pinning.
806

807
    @type instance_name: string
808
    @param instance_name: name of instance
809
    @type cpu_mask: string
810
    @param cpu_mask: CPU pinning mask as entered by user
811

812
    """
813
    # Get KVM process ID, to be used if need to pin entire VM
814
    _, pid, _ = self._InstancePidAlive(instance_name)
815
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
816
    thread_dict = self._GetVcpuThreadIds(instance_name)
817
    # Run CPU pinning, based on configured mask
818
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
819

    
820
  def ListInstances(self, hvparams=None):
821
    """Get the list of running instances.
822

823
    We can do this by listing our live instances directory and
824
    checking whether the associated kvm process is still alive.
825

826
    """
827
    result = []
828
    for name in os.listdir(self._PIDS_DIR):
829
      if self._InstancePidAlive(name)[2]:
830
        result.append(name)
831
    return result
832

    
833
  def GetInstanceInfo(self, instance_name, hvparams=None):
834
    """Get instance properties.
835

836
    @type instance_name: string
837
    @param instance_name: the instance name
838
    @type hvparams: dict of strings
839
    @param hvparams: hvparams to be used with this instance
840
    @rtype: tuple of strings
841
    @return: (name, id, memory, vcpus, stat, times)
842

843
    """
844
    _, pid, alive = self._InstancePidAlive(instance_name)
845
    if not alive:
846
      return None
847

    
848
    _, memory, vcpus = self._InstancePidInfo(pid)
849
    istat = "---b-"
850
    times = "0"
851

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

    
863
    return (instance_name, pid, memory, vcpus, istat, times)
864

    
865
  def GetAllInstancesInfo(self, hvparams=None):
866
    """Get properties of all instances.
867

868
    @type hvparams: dict of strings
869
    @param hvparams: hypervisor parameter
870
    @return: list of tuples (name, id, memory, vcpus, stat, times)
871

872
    """
873
    data = []
874
    for name in os.listdir(self._PIDS_DIR):
875
      try:
876
        info = self.GetInstanceInfo(name)
877
      except errors.HypervisorError:
878
        # Ignore exceptions due to instances being shut down
879
        continue
880
      if info:
881
        data.append(info)
882
    return data
883

    
884
  def _GenerateKVMBlockDevicesOptions(self, instance, up_hvp, kvm_disks,
885
                                      kvmhelp, devlist):
886
    """Generate KVM options regarding instance's block devices.
887

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

901
    """
902
    kernel_path = up_hvp[constants.HV_KERNEL_PATH]
903
    if kernel_path:
904
      boot_disk = False
905
    else:
906
      boot_disk = up_hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
907

    
908
    # whether this is an older KVM version that uses the boot=on flag
909
    # on devices
910
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
911

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

    
951
      drive_uri, _ = _GetDriveURI(cfdev, link_name, uri)
952

    
953
      drive_val = "file=%s,format=raw%s%s%s" % \
954
                  (drive_uri, if_val, boot_val, cache_val)
955

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

    
968
      dev_opts.extend(["-drive", drive_val])
969

    
970
    return dev_opts
971

    
972
  @staticmethod
973
  def _CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image, cdrom_boot,
974
                   needs_boot_flag):
975
    """Extends L{kvm_cmd} with the '-drive' option for a cdrom, and
976
    optionally the '-boot' option.
977

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

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

982
    Example: -drive file=http://hostname.com/cdrom.iso,media=cdrom
983

984
    @type kvm_cmd: string
985
    @param kvm_cmd: KVM command line
986

987
    @type cdrom_disk_type:
988
    @param cdrom_disk_type:
989

990
    @type cdrom_image:
991
    @param cdrom_image:
992

993
    @type cdrom_boot:
994
    @param cdrom_boot:
995

996
    @type needs_boot_flag:
997
    @param needs_boot_flag:
998

999
    """
1000
    # Check that the ISO image is accessible
1001
    # See https://bugs.launchpad.net/qemu/+bug/597575
1002
    if utils.IsUrl(cdrom_image) and not _CheckUrl(cdrom_image):
1003
      raise errors.HypervisorError("Cdrom ISO image '%s' is not accessible" %
1004
                                   cdrom_image)
1005

    
1006
    # set cdrom 'media' and 'format', if needed
1007
    if utils.IsUrl(cdrom_image):
1008
      options = ",media=cdrom"
1009
    else:
1010
      options = ",media=cdrom,format=raw"
1011

    
1012
    # set cdrom 'if' type
1013
    if cdrom_boot:
1014
      if_val = ",if=" + constants.HT_DISK_IDE
1015
    elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1016
      if_val = ",if=virtio"
1017
    else:
1018
      if_val = ",if=" + cdrom_disk_type
1019

    
1020
    # set boot flag, if needed
1021
    boot_val = ""
1022
    if cdrom_boot:
1023
      kvm_cmd.extend(["-boot", "d"])
1024

    
1025
      # whether this is an older KVM version that requires the 'boot=on' flag
1026
      # on devices
1027
      if needs_boot_flag:
1028
        boot_val = ",boot=on"
1029

    
1030
    # build '-drive' option
1031
    drive_val = "file=%s%s%s%s" % (cdrom_image, options, if_val, boot_val)
1032
    kvm_cmd.extend(["-drive", drive_val])
1033

    
1034
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1035
                          kvmhelp):
1036
    """Generate KVM information to start an instance.
1037

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

1047
    """
1048
    # pylint: disable=R0912,R0914,R0915
1049
    hvp = instance.hvparams
1050
    self.ValidateParameters(hvp)
1051

    
1052
    pidfile = self._InstancePidFile(instance.name)
1053
    kvm = hvp[constants.HV_KVM_PATH]
1054
    kvm_cmd = [kvm]
1055
    # used just by the vnc server, if enabled
1056
    kvm_cmd.extend(["-name", instance.name])
1057
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1058

    
1059
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1060
    if hvp[constants.HV_CPU_CORES]:
1061
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1062
    if hvp[constants.HV_CPU_THREADS]:
1063
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1064
    if hvp[constants.HV_CPU_SOCKETS]:
1065
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1066

    
1067
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1068

    
1069
    kvm_cmd.extend(["-pidfile", pidfile])
1070

    
1071
    pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1072

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

    
1083
    if hvp[constants.HV_DISK_TYPE] == constants.HT_DISK_SCSI:
1084
      # The SCSI controller requires another PCI slot.
1085
      _ = utils.GetFreeSlot(pci_reservations, reserve=True)
1086

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

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

    
1120
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1121
    if kernel_path:
1122
      boot_cdrom = boot_floppy = boot_network = False
1123
    else:
1124
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1125
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1126
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1127

    
1128
    if startup_paused:
1129
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1130

    
1131
    if boot_network:
1132
      kvm_cmd.extend(["-boot", "n"])
1133

    
1134
    disk_type = hvp[constants.HV_DISK_TYPE]
1135

    
1136
    # Now we can specify a different device type for CDROM devices.
1137
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1138
    if not cdrom_disk_type:
1139
      cdrom_disk_type = disk_type
1140

    
1141
    cdrom_image1 = hvp[constants.HV_CDROM_IMAGE_PATH]
1142
    if cdrom_image1:
1143
      needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1144
      self._CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image1, boot_cdrom,
1145
                        needs_boot_flag)
1146

    
1147
    cdrom_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1148
    if cdrom_image2:
1149
      self._CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image2, False, False)
1150

    
1151
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1152
    if floppy_image:
1153
      options = ",format=raw,media=disk"
1154
      if boot_floppy:
1155
        kvm_cmd.extend(["-boot", "a"])
1156
        options = "%s,boot=on" % options
1157
      if_val = ",if=floppy"
1158
      options = "%s%s" % (options, if_val)
1159
      drive_val = "file=%s%s" % (floppy_image, options)
1160
      kvm_cmd.extend(["-drive", drive_val])
1161

    
1162
    if kernel_path:
1163
      kvm_cmd.extend(["-kernel", kernel_path])
1164
      initrd_path = hvp[constants.HV_INITRD_PATH]
1165
      if initrd_path:
1166
        kvm_cmd.extend(["-initrd", initrd_path])
1167
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1168
                     hvp[constants.HV_KERNEL_ARGS]]
1169
      if hvp[constants.HV_SERIAL_CONSOLE]:
1170
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1171
        root_append.append("console=ttyS0,%s" % serial_speed)
1172
      kvm_cmd.extend(["-append", " ".join(root_append)])
1173

    
1174
    mem_path = hvp[constants.HV_MEM_PATH]
1175
    if mem_path:
1176
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1177

    
1178
    monitor_dev = ("unix:%s,server,nowait" %
1179
                   self._InstanceMonitor(instance.name))
1180
    kvm_cmd.extend(["-monitor", monitor_dev])
1181
    if hvp[constants.HV_SERIAL_CONSOLE]:
1182
      serial_dev = ("unix:%s,server,nowait" %
1183
                    self._InstanceSerial(instance.name))
1184
      kvm_cmd.extend(["-serial", serial_dev])
1185
    else:
1186
      kvm_cmd.extend(["-serial", "none"])
1187

    
1188
    mouse_type = hvp[constants.HV_USB_MOUSE]
1189
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1190
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1191
    spice_ip_version = None
1192

    
1193
    kvm_cmd.extend(["-usb"])
1194

    
1195
    if mouse_type:
1196
      kvm_cmd.extend(["-usbdevice", mouse_type])
1197
    elif vnc_bind_address:
1198
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1199

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

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

    
1236
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1237

    
1238
      else:
1239
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1240

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

    
1251
        # if the user specified an IP version and the interface does not
1252
        # have that kind of IP addresses, throw an exception
1253
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1254
          if not addresses[spice_ip_version]:
1255
            raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1256
                                         " for %s" % (spice_ip_version,
1257
                                                      spice_bind))
1258

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

    
1275
        spice_address = addresses[spice_ip_version][0]
1276

    
1277
      else:
1278
        # spice_bind is known to be a valid IP address, because
1279
        # ValidateParameters checked it.
1280
        spice_address = spice_bind
1281

    
1282
      spice_arg = "addr=%s" % spice_address
1283
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1284
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1285
                     (spice_arg, instance.network_port,
1286
                      pathutils.SPICE_CACERT_FILE))
1287
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1288
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1289
                      pathutils.SPICE_CERT_FILE))
1290
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1291
        if tls_ciphers:
1292
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1293
      else:
1294
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1295

    
1296
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1297
        spice_arg = "%s,disable-ticketing" % spice_arg
1298

    
1299
      if spice_ip_version:
1300
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1301

    
1302
      # Image compression options
1303
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1304
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1305
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1306
      if img_lossless:
1307
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1308
      if img_jpeg:
1309
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1310
      if img_zlib_glz:
1311
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1312

    
1313
      # Video stream detection
1314
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1315
      if video_streaming:
1316
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1317

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

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

    
1338
    else:
1339
      # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1340
      # also works in earlier versions though (tested with 1.1 and 1.3)
1341
      if self._DISPLAY_RE.search(kvmhelp):
1342
        kvm_cmd.extend(["-display", "none"])
1343
      else:
1344
        kvm_cmd.extend(["-nographic"])
1345

    
1346
    if hvp[constants.HV_USE_LOCALTIME]:
1347
      kvm_cmd.extend(["-localtime"])
1348

    
1349
    if hvp[constants.HV_KVM_USE_CHROOT]:
1350
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1351

    
1352
    # Add qemu-KVM -cpu param
1353
    if hvp[constants.HV_CPU_TYPE]:
1354
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1355

    
1356
    # Pass a -vga option if requested, or if spice is used, for backwards
1357
    # compatibility.
1358
    if hvp[constants.HV_VGA]:
1359
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1360
    elif spice_bind:
1361
      kvm_cmd.extend(["-vga", "qxl"])
1362

    
1363
    # Various types of usb devices, comma separated
1364
    if hvp[constants.HV_USB_DEVICES]:
1365
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1366
        kvm_cmd.extend(["-usbdevice", dev])
1367

    
1368
    # Set system UUID to instance UUID
1369
    if self._UUID_RE.search(kvmhelp):
1370
      kvm_cmd.extend(["-uuid", instance.uuid])
1371

    
1372
    if hvp[constants.HV_KVM_EXTRA]:
1373
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1374

    
1375
    kvm_disks = []
1376
    for disk, link_name, uri in block_devices:
1377
      disk.pci = utils.GetFreeSlot(pci_reservations, disk.pci, True)
1378
      kvm_disks.append((disk, link_name, uri))
1379

    
1380
    kvm_nics = []
1381
    for nic in instance.nics:
1382
      nic.pci = utils.GetFreeSlot(pci_reservations, nic.pci, True)
1383
      kvm_nics.append(nic)
1384

    
1385
    hvparams = hvp
1386

    
1387
    return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1388

    
1389
  def _WriteKVMRuntime(self, instance_name, data):
1390
    """Write an instance's KVM runtime
1391

1392
    """
1393
    try:
1394
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1395
                      data=data)
1396
    except EnvironmentError, err:
1397
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1398

    
1399
  def _ReadKVMRuntime(self, instance_name):
1400
    """Read an instance's KVM runtime
1401

1402
    """
1403
    try:
1404
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1405
    except EnvironmentError, err:
1406
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1407
    return file_content
1408

    
1409
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1410
    """Save an instance's KVM runtime
1411

1412
    """
1413
    kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1414

    
1415
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1416
    serialized_disks = [(blk.ToDict(), link, uri)
1417
                        for blk, link, uri in kvm_disks]
1418
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1419
                                      serialized_disks))
1420

    
1421
    self._WriteKVMRuntime(instance.name, serialized_form)
1422

    
1423
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1424
    """Load an instance's KVM runtime
1425

1426
    """
1427
    if not serialized_runtime:
1428
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1429

    
1430
    return _AnalyzeSerializedRuntime(serialized_runtime)
1431

    
1432
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1433
    """Run the KVM cmd and check for errors
1434

1435
    @type name: string
1436
    @param name: instance name
1437
    @type kvm_cmd: list of strings
1438
    @param kvm_cmd: runcmd input for kvm
1439
    @type tap_fds: list of int
1440
    @param tap_fds: fds of tap devices opened by Ganeti
1441

1442
    """
1443
    try:
1444
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1445
    finally:
1446
      for fd in tap_fds:
1447
        utils_wrapper.CloseFdNoError(fd)
1448

    
1449
    if result.failed:
1450
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1451
                                   (name, result.fail_reason, result.output))
1452
    if not self._InstancePidAlive(name)[2]:
1453
      raise errors.HypervisorError("Failed to start instance %s" % name)
1454

    
1455
  def _GetNetworkDeviceFeatures(self, up_hvp, devlist, kvmhelp):
1456
    """Get network device options to properly enable supported features.
1457

1458
    Return tuple of supported and enabled tap features with nic_model.
1459
    This function is called before opening a new tap device.
1460

1461
    @return: (nic_model, vnet_hdr, virtio_net_queues, tap_extra, nic_extra)
1462
    @rtype: tuple
1463

1464
    """
1465
    virtio_net_queues = 1
1466
    nic_extra = ""
1467
    nic_type = up_hvp[constants.HV_NIC_TYPE]
1468
    tap_extra = ""
1469
    vnet_hdr = False
1470
    if nic_type == constants.HT_NIC_PARAVIRTUAL:
1471
      nic_model = self._VIRTIO
1472
      try:
1473
        if self._VIRTIO_NET_RE.search(devlist):
1474
          nic_model = self._VIRTIO_NET_PCI
1475
          vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1476
      except errors.HypervisorError, _:
1477
        # Older versions of kvm don't support DEVICE_LIST, but they don't
1478
        # have new virtio syntax either.
1479
        pass
1480

    
1481
      if up_hvp[constants.HV_VHOST_NET]:
1482
        # Check for vhost_net support.
1483
        if self._VHOST_RE.search(kvmhelp):
1484
          tap_extra = ",vhost=on"
1485
        else:
1486
          raise errors.HypervisorError("vhost_net is configured"
1487
                                       " but it is not available")
1488
        if up_hvp[constants.HV_VIRTIO_NET_QUEUES] > 1:
1489
          # Check for multiqueue virtio-net support.
1490
          if self._VIRTIO_NET_QUEUES_RE.search(kvmhelp):
1491
            virtio_net_queues = up_hvp[constants.HV_VIRTIO_NET_QUEUES]
1492
            # As advised at http://www.linux-kvm.org/page/Multiqueue formula
1493
            # for calculating vector size is: vectors=2*N+1 where N is the
1494
            # number of queues (HV_VIRTIO_NET_QUEUES).
1495
            nic_extra = ",mq=on,vectors=%d" % (2 * virtio_net_queues + 1)
1496
          else:
1497
            raise errors.HypervisorError("virtio_net_queues is configured"
1498
                                         " but it is not available")
1499
    else:
1500
      nic_model = nic_type
1501

    
1502
    return (nic_model, vnet_hdr, virtio_net_queues, tap_extra, nic_extra)
1503

    
1504
  # too many local variables
1505
  # pylint: disable=R0914
1506
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1507
    """Execute a KVM cmd, after completing it with some last minute data.
1508

1509
    @type incoming: tuple of strings
1510
    @param incoming: (target_host_ip, port)
1511
    @type kvmhelp: string
1512
    @param kvmhelp: output of kvm --help
1513

1514
    """
1515
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1516
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1517
    #    have changed since the instance started; only use them if the change
1518
    #    won't affect the inside of the instance (which hasn't been rebooted).
1519
    #  - up_hvp contains the parameters as they were when the instance was
1520
    #    started, plus any new parameter which has been added between ganeti
1521
    #    versions: it is paramount that those default to a value which won't
1522
    #    affect the inside of the instance as well.
1523
    conf_hvp = instance.hvparams
1524
    name = instance.name
1525
    self._CheckDown(name)
1526

    
1527
    temp_files = []
1528

    
1529
    kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1530
    # the first element of kvm_cmd is always the path to the kvm binary
1531
    kvm_path = kvm_cmd[0]
1532
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1533

    
1534
    # We know it's safe to run as a different user upon migration, so we'll use
1535
    # the latest conf, from conf_hvp.
1536
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1537
    if security_model == constants.HT_SM_USER:
1538
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1539

    
1540
    keymap = conf_hvp[constants.HV_KEYMAP]
1541
    if keymap:
1542
      keymap_path = self._InstanceKeymapFile(name)
1543
      # If a keymap file is specified, KVM won't use its internal defaults. By
1544
      # first including the "en-us" layout, an error on loading the actual
1545
      # layout (e.g. because it can't be found) won't lead to a non-functional
1546
      # keyboard. A keyboard with incorrect keys is still better than none.
1547
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1548
      kvm_cmd.extend(["-k", keymap_path])
1549

    
1550
    # We have reasons to believe changing something like the nic driver/type
1551
    # upon migration won't exactly fly with the instance kernel, so for nic
1552
    # related parameters we'll use up_hvp
1553
    tapfds = []
1554
    taps = []
1555
    devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1556
    if not kvm_nics:
1557
      kvm_cmd.extend(["-net", "none"])
1558
    else:
1559
      (nic_model, vnet_hdr,
1560
       virtio_net_queues, tap_extra,
1561
       nic_extra) = self._GetNetworkDeviceFeatures(up_hvp, devlist, kvmhelp)
1562
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1563
      for nic_seq, nic in enumerate(kvm_nics):
1564
        tapname, nic_tapfds = OpenTap(vnet_hdr=vnet_hdr,
1565
                                      virtio_net_queues=virtio_net_queues)
1566
        tapfds.extend(nic_tapfds)
1567
        taps.append(tapname)
1568
        tapfd = "%s%s" % ("fds=" if len(nic_tapfds) > 1 else "fd=",
1569
                          ":".join(str(fd) for fd in nic_tapfds))
1570
        if kvm_supports_netdev:
1571
          nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1572
          try:
1573
            # kvm_nics already exist in old runtime files and thus there might
1574
            # be some entries without pci slot (therefore try: except:)
1575
            kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1576
            netdev = kvm_devid
1577
            nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1578
          except errors.HotplugError:
1579
            netdev = "netdev%d" % nic_seq
1580
          nic_val += (",netdev=%s%s" % (netdev, nic_extra))
1581
          tap_val = ("type=tap,id=%s,%s%s" %
1582
                     (netdev, tapfd, tap_extra))
1583
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1584
        else:
1585
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1586
                                                         nic.mac, nic_model)
1587
          tap_val = "tap,vlan=%s,%s" % (nic_seq, tapfd)
1588
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1589

    
1590
    if incoming:
1591
      target, port = incoming
1592
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1593

    
1594
    # Changing the vnc password doesn't bother the guest that much. At most it
1595
    # will surprise people who connect to it. Whether positively or negatively
1596
    # it's debatable.
1597
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1598
    vnc_pwd = None
1599
    if vnc_pwd_file:
1600
      try:
1601
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1602
      except EnvironmentError, err:
1603
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1604
                                     % (vnc_pwd_file, err))
1605

    
1606
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1607
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1608
                         constants.SECURE_DIR_MODE)])
1609

    
1610
    # Automatically enable QMP if version is >= 0.14
1611
    if self._QMP_RE.search(kvmhelp):
1612
      logging.debug("Enabling QMP")
1613
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1614
                      self._InstanceQmpMonitor(instance.name)])
1615

    
1616
    # Configure the network now for starting instances and bridged interfaces,
1617
    # during FinalizeMigration for incoming instances' routed interfaces
1618
    for nic_seq, nic in enumerate(kvm_nics):
1619
      if (incoming and
1620
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1621
        continue
1622
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1623

    
1624
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1625
                                                     up_hvp,
1626
                                                     kvm_disks,
1627
                                                     kvmhelp,
1628
                                                     devlist)
1629
    kvm_cmd.extend(bdev_opts)
1630
    # CPU affinity requires kvm to start paused, so we set this flag if the
1631
    # instance is not already paused and if we are not going to accept a
1632
    # migrating instance. In the latter case, pausing is not needed.
1633
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1634
    if start_kvm_paused:
1635
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1636

    
1637
    # Note: CPU pinning is using up_hvp since changes take effect
1638
    # during instance startup anyway, and to avoid problems when soft
1639
    # rebooting the instance.
1640
    cpu_pinning = False
1641
    if up_hvp.get(constants.HV_CPU_MASK, None):
1642
      cpu_pinning = True
1643

    
1644
    if security_model == constants.HT_SM_POOL:
1645
      ss = ssconf.SimpleStore()
1646
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1647
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1648
      uid = uidpool.RequestUnusedUid(all_uids)
1649
      try:
1650
        username = pwd.getpwuid(uid.GetUid()).pw_name
1651
        kvm_cmd.extend(["-runas", username])
1652
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1653
      except:
1654
        uidpool.ReleaseUid(uid)
1655
        raise
1656
      else:
1657
        uid.Unlock()
1658
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1659
    else:
1660
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1661

    
1662
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1663
                     constants.RUN_DIRS_MODE)])
1664
    for nic_seq, tap in enumerate(taps):
1665
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1666
                      data=tap)
1667

    
1668
    if vnc_pwd:
1669
      change_cmd = "change vnc password %s" % vnc_pwd
1670
      self._CallMonitorCommand(instance.name, change_cmd)
1671

    
1672
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1673
    # connection attempts because SPICE by default does not allow connections
1674
    # if neither a password nor the "disable_ticketing" options are specified.
1675
    # As soon as we send the password via QMP, that password is a valid ticket
1676
    # for connection.
1677
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1678
    if spice_password_file:
1679
      spice_pwd = ""
1680
      try:
1681
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1682
      except EnvironmentError, err:
1683
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1684
                                     % (spice_password_file, err))
1685

    
1686
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1687
      qmp.connect()
1688
      arguments = {
1689
          "protocol": "spice",
1690
          "password": spice_pwd,
1691
      }
1692
      qmp.Execute("set_password", arguments)
1693

    
1694
    for filename in temp_files:
1695
      utils.RemoveFile(filename)
1696

    
1697
    # If requested, set CPU affinity and resume instance execution
1698
    if cpu_pinning:
1699
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1700

    
1701
    start_memory = self._InstanceStartupMemory(instance)
1702
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1703
      self.BalloonInstanceMemory(instance, start_memory)
1704

    
1705
    if start_kvm_paused:
1706
      # To control CPU pinning, ballooning, and vnc/spice passwords
1707
      # the VM was started in a frozen state. If freezing was not
1708
      # explicitly requested resume the vm status.
1709
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1710

    
1711
  def StartInstance(self, instance, block_devices, startup_paused):
1712
    """Start an instance.
1713

1714
    """
1715
    self._CheckDown(instance.name)
1716
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1717
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1718
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1719
                                           startup_paused, kvmhelp)
1720
    self._SaveKVMRuntime(instance, kvm_runtime)
1721
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1722

    
1723
  @classmethod
1724
  def _CallMonitorCommand(cls, instance_name, command, timeout=None):
1725
    """Invoke a command on the instance monitor.
1726

1727
    """
1728
    if timeout is not None:
1729
      timeout_cmd = "timeout %s" % (timeout, )
1730
    else:
1731
      timeout_cmd = ""
1732

    
1733
    # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1734
    # version. The monitor protocol is designed for human consumption, whereas
1735
    # QMP is made for programmatic usage. In the worst case QMP can also
1736
    # execute monitor commands. As it is, all calls to socat take at least
1737
    # 500ms and likely more: socat can't detect the end of the reply and waits
1738
    # for 500ms of no data received before exiting (500 ms is the default for
1739
    # the "-t" parameter).
1740
    socat = ("echo %s | %s %s STDIO UNIX-CONNECT:%s" %
1741
             (utils.ShellQuote(command),
1742
              timeout_cmd,
1743
              constants.SOCAT_PATH,
1744
              utils.ShellQuote(cls._InstanceMonitor(instance_name))))
1745
    result = utils.RunCmd(socat)
1746
    if result.failed:
1747
      msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1748
             " output: %s" %
1749
             (command, instance_name, result.fail_reason, result.output))
1750
      raise errors.HypervisorError(msg)
1751

    
1752
    return result
1753

    
1754
  def _GetFreePCISlot(self, instance, dev):
1755
    """Get the first available pci slot of a runnung instance.
1756

1757
    """
1758
    slots = bitarray(32)
1759
    slots.setall(False) # pylint: disable=E1101
1760
    output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
1761
    for line in output.stdout.splitlines():
1762
      match = self._INFO_PCI_RE.search(line)
1763
      if match:
1764
        slot = int(match.group(1))
1765
        slots[slot] = True
1766

    
1767
    dev.pci = utils.GetFreeSlot(slots)
1768

    
1769
  @_with_qmp
1770
  def VerifyHotplugSupport(self, instance, action, dev_type):
1771
    """Verifies that hotplug is supported.
1772

1773
    @raise errors.HypervisorError: in one of the previous cases
1774

1775
    """
1776
    if dev_type == constants.HOTPLUG_TARGET_DISK:
1777
      if action == constants.HOTPLUG_ACTION_ADD:
1778
        self.qmp.CheckDiskHotAddSupport()
1779
    if dev_type == constants.HOTPLUG_TARGET_NIC:
1780
      if action == constants.HOTPLUG_ACTION_ADD:
1781
        self.qmp.CheckNicHotAddSupport()
1782

    
1783
  def HotplugSupported(self, instance):
1784
    """Checks if hotplug is generally supported.
1785

1786
    Hotplug is *not* supported in case of:
1787
     - qemu versions < 1.0
1788
     - for stopped instances
1789

1790
    @raise errors.HypervisorError: in one of the previous cases
1791

1792
    """
1793
    try:
1794
      output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
1795
    except errors.HypervisorError:
1796
      raise errors.HotplugError("Instance is probably down")
1797

    
1798
    # TODO: search for netdev_add, drive_add, device_add.....
1799
    match = self._INFO_VERSION_RE.search(output.stdout)
1800
    if not match:
1801
      raise errors.HotplugError("Cannot parse qemu version via monitor")
1802

    
1803
    v_major, v_min, _, _ = match.groups()
1804
    if (int(v_major), int(v_min)) < (1, 0):
1805
      raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
1806

    
1807
  @classmethod
1808
  def _CallHotplugCommands(cls, instance_name, cmds):
1809
    for c in cmds:
1810
      cls._CallMonitorCommand(instance_name, c)
1811
      time.sleep(1)
1812

    
1813
  def _VerifyHotplugCommand(self, instance_name, device, dev_type,
1814
                            should_exist):
1815
    """Checks if a previous hotplug command has succeeded.
1816

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

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

1822
    """
1823
    output = self._CallMonitorCommand(instance_name, self._INFO_PCI_CMD)
1824
    kvm_devid = _GenerateDeviceKVMId(dev_type, device)
1825
    match = \
1826
      self._FIND_PCI_DEVICE_RE(device.pci, kvm_devid).search(output.stdout)
1827
    if match and not should_exist:
1828
      msg = "Device %s should have been removed but is still there" % kvm_devid
1829
      raise errors.HypervisorError(msg)
1830

    
1831
    if not match and should_exist:
1832
      msg = "Device %s should have been added but is missing" % kvm_devid
1833
      raise errors.HypervisorError(msg)
1834

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

    
1837
  def HotAddDevice(self, instance, dev_type, device, extra, seq):
1838
    """ Helper method to hot-add a new device
1839

1840
    It gets free pci slot generates the device name and invokes the
1841
    device specific method.
1842

1843
    """
1844
    # in case of hot-mod this is given
1845
    if device.pci is None:
1846
      self._GetFreePCISlot(instance, device)
1847
    kvm_devid = _GenerateDeviceKVMId(dev_type, device)
1848
    runtime = self._LoadKVMRuntime(instance)
1849
    fdset = None
1850
    if dev_type == constants.HOTPLUG_TARGET_DISK:
1851
      # Create a shared qmp connection because
1852
      # fdsets get cleaned up on monitor disconnect
1853
      # See qemu commit efb87c1
1854
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1855
      qmp.connect()
1856
      drive_uri, fdset = _GetDriveURI(device, extra[0], extra[1], qmp)
1857
      cmds = ["drive_add dummy file=%s,if=none,id=%s,format=raw" %
1858
                (drive_uri, kvm_devid)]
1859
      cmds += ["device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
1860
                (hex(device.pci), kvm_devid, kvm_devid)]
1861
      self._CallHotplugCommands(instance.name, cmds)
1862
      if fdset is not None:
1863
        qmp.RemoveFdset(fdset)
1864
      qmp.close()
1865
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
1866
      kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1867
      kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1868
      devlist = self._GetKVMOutput(kvmpath, self._KVMOPT_DEVICELIST)
1869
      up_hvp = runtime[2]
1870
      (_, vnet_hdr,
1871
       virtio_net_queues, tap_extra,
1872
       nic_extra) = self._GetNetworkDeviceFeatures(up_hvp, devlist, kvmhelp)
1873
      (tap, fds) = OpenTap(vnet_hdr=vnet_hdr,
1874
                           virtio_net_queues=virtio_net_queues)
1875
      # netdev_add don't support "fds=" when multiple fds are
1876
      # requested, generate separate "fd=" string for every fd
1877
      tapfd = ",".join(["fd=%s" % fd for fd in fds])
1878
      self._ConfigureNIC(instance, seq, device, tap)
1879
      self._HMPPassFd(instance.name, fds, kvm_devid)
1880
      cmds = ["netdev_add tap,id=%s,%s%s" % (kvm_devid, tapfd, tap_extra)]
1881
      args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s%s" % \
1882
               (hex(device.pci), device.mac, kvm_devid, kvm_devid, nic_extra)
1883
      cmds += ["device_add %s" % args]
1884
      utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
1885
      self._CallHotplugCommands(instance.name, cmds)
1886

    
1887
    self._VerifyHotplugCommand(instance.name, device, dev_type, True)
1888
    # update relevant entries in runtime file
1889
    index = _DEVICE_RUNTIME_INDEX[dev_type]
1890
    entry = _RUNTIME_ENTRY[dev_type](device, extra)
1891
    runtime[index].append(entry)
1892
    self._SaveKVMRuntime(instance, runtime)
1893

    
1894
  def HotDelDevice(self, instance, dev_type, device, _, seq):
1895
    """ Helper method for hot-del device
1896

1897
    It gets device info from runtime file, generates the device name and
1898
    invokes the device specific method.
1899

1900
    """
1901
    runtime = self._LoadKVMRuntime(instance)
1902
    entry = _GetExistingDeviceInfo(dev_type, device, runtime)
1903
    kvm_device = _RUNTIME_DEVICE[dev_type](entry)
1904
    kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
1905
    if dev_type == constants.HOTPLUG_TARGET_DISK:
1906
      cmds = ["device_del %s" % kvm_devid]
1907
      cmds += ["drive_del %s" % kvm_devid]
1908
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
1909
      cmds = ["device_del %s" % kvm_devid]
1910
      cmds += ["netdev_del %s" % kvm_devid]
1911
      utils.RemoveFile(self._InstanceNICFile(instance.name, seq))
1912
    self._CallHotplugCommands(instance.name, cmds)
1913
    self._VerifyHotplugCommand(instance.name, kvm_device, dev_type, False)
1914
    index = _DEVICE_RUNTIME_INDEX[dev_type]
1915
    runtime[index].remove(entry)
1916
    self._SaveKVMRuntime(instance, runtime)
1917

    
1918
    return kvm_device.pci
1919

    
1920
  def HotModDevice(self, instance, dev_type, device, _, seq):
1921
    """ Helper method for hot-mod device
1922

1923
    It gets device info from runtime file, generates the device name and
1924
    invokes the device specific method. Currently only NICs support hot-mod
1925

1926
    """
1927
    if dev_type == constants.HOTPLUG_TARGET_NIC:
1928
      # putting it back in the same pci slot
1929
      device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
1930
      self.HotAddDevice(instance, dev_type, device, _, seq)
1931

    
1932
  @classmethod
1933
  def _HMPPassFd(cls, instance_name, fds, kvm_devid):
1934
    """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
1935

1936
    Wrapper of MonitorSocket.GetFd()
1937

1938
    """
1939
    mon = MonitorSocket(cls._InstanceMonitor(instance_name))
1940
    try:
1941
      mon.connect()
1942
      mon.GetFd(fds, kvm_devid)
1943
    finally:
1944
      mon.close()
1945

    
1946
  @classmethod
1947
  def _ParseKVMVersion(cls, text):
1948
    """Parse the KVM version from the --help output.
1949

1950
    @type text: string
1951
    @param text: output of kvm --help
1952
    @return: (version, v_maj, v_min, v_rev)
1953
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1954

1955
    """
1956
    match = cls._VERSION_RE.search(text.splitlines()[0])
1957
    if not match:
1958
      raise errors.HypervisorError("Unable to get KVM version")
1959

    
1960
    v_all = match.group(0)
1961
    v_maj = int(match.group(1))
1962
    v_min = int(match.group(2))
1963
    if match.group(4):
1964
      v_rev = int(match.group(4))
1965
    else:
1966
      v_rev = 0
1967
    return (v_all, v_maj, v_min, v_rev)
1968

    
1969
  @classmethod
1970
  def _GetKVMOutput(cls, kvm_path, option):
1971
    """Return the output of a kvm invocation
1972

1973
    @type kvm_path: string
1974
    @param kvm_path: path to the kvm executable
1975
    @type option: a key of _KVMOPTS_CMDS
1976
    @param option: kvm option to fetch the output from
1977
    @return: output a supported kvm invocation
1978
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1979

1980
    """
1981
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
1982

    
1983
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
1984

    
1985
    result = utils.RunCmd([kvm_path] + optlist)
1986
    if result.failed and not can_fail:
1987
      raise errors.HypervisorError("Unable to get KVM %s output" %
1988
                                    " ".join(optlist))
1989
    return result.output
1990

    
1991
  @classmethod
1992
  def _GetKVMVersion(cls, kvm_path):
1993
    """Return the installed KVM version.
1994

1995
    @return: (version, v_maj, v_min, v_rev)
1996
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1997

1998
    """
1999
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2000

    
2001
  @classmethod
2002
  def _GetDefaultMachineVersion(cls, kvm_path):
2003
    """Return the default hardware revision (e.g. pc-1.1)
2004

2005
    """
2006
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2007
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2008
    if match:
2009
      return match.group(1)
2010
    else:
2011
      return "pc"
2012

    
2013
  @classmethod
2014
  def _StopInstance(cls, instance, force=False, name=None, timeout=None):
2015
    """Stop an instance.
2016

2017
    """
2018
    assert(timeout is None or force is not None)
2019

    
2020
    if name is not None and not force:
2021
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2022
    if name is None:
2023
      name = instance.name
2024
      acpi = instance.hvparams[constants.HV_ACPI]
2025
    else:
2026
      acpi = False
2027
    _, pid, alive = cls._InstancePidAlive(name)
2028
    if pid > 0 and alive:
2029
      if force or not acpi:
2030
        utils.KillProcess(pid)
2031
      else:
2032
        cls._CallMonitorCommand(name, "system_powerdown", timeout)
2033

    
2034
  def StopInstance(self, instance, force=False, retry=False, name=None,
2035
                   timeout=None):
2036
    """Stop an instance.
2037

2038
    """
2039
    self._StopInstance(instance, force, name, timeout)
2040

    
2041
  def CleanupInstance(self, instance_name):
2042
    """Cleanup after a stopped instance
2043

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

    
2050
  def RebootInstance(self, instance):
2051
    """Reboot an instance.
2052

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

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

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

2081
    """
2082
    return self._ReadKVMRuntime(instance.name)
2083

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

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

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

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

2105
    Stop the incoming mode KVM.
2106

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

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

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

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

    
2134
  def MigrateInstance(self, cluster_name, instance, target, live):
2135
    """Migrate an instance to a target node.
2136

2137
    The migration will not be attempted if the instance is not
2138
    currently running.
2139

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

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

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

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

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

    
2167
    migration_caps = instance.hvparams[constants.HV_KVM_MIGRATION_CAPS]
2168
    if migration_caps:
2169
      for c in migration_caps.split(_MIGRATION_CAPS_DELIM):
2170
        migrate_command = ("migrate_set_capability %s on" % c)
2171
        self._CallMonitorCommand(instance_name, migrate_command)
2172

    
2173
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2174
    self._CallMonitorCommand(instance_name, migrate_command)
2175

    
2176
  def FinalizeMigrationSource(self, instance, success, live):
2177
    """Finalize the instance migration on the source node.
2178

2179
    @type instance: L{objects.Instance}
2180
    @param instance: the instance that was migrated
2181
    @type success: bool
2182
    @param success: whether the migration succeeded or not
2183
    @type live: bool
2184
    @param live: whether the user requested a live migration or not
2185

2186
    """
2187
    if success:
2188
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2189
      utils.KillProcess(pid)
2190
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2191
    elif live:
2192
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2193

    
2194
  def GetMigrationStatus(self, instance):
2195
    """Get the migration status
2196

2197
    @type instance: L{objects.Instance}
2198
    @param instance: the instance that is being migrated
2199
    @rtype: L{objects.MigrationStatus}
2200
    @return: the status of the current migration (one of
2201
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2202
             progress info that can be retrieved from the hypervisor
2203

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

    
2224
          return migration_status
2225

    
2226
        logging.warning("KVM: unknown migration status '%s'", status)
2227

    
2228
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2229

    
2230
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2231

    
2232
  def BalloonInstanceMemory(self, instance, mem):
2233
    """Balloon an instance memory to a certain value.
2234

2235
    @type instance: L{objects.Instance}
2236
    @param instance: instance to be accepted
2237
    @type mem: int
2238
    @param mem: actual memory size to use for instance runtime
2239

2240
    """
2241
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2242

    
2243
  def GetNodeInfo(self, hvparams=None):
2244
    """Return information about the node.
2245

2246
    @type hvparams: dict of strings
2247
    @param hvparams: hypervisor parameters, not used in this class
2248

2249
    @return: a dict as returned by L{BaseHypervisor.GetLinuxNodeInfo} plus
2250
        the following keys:
2251
          - hv_version: the hypervisor version in the form (major, minor,
2252
                        revision)
2253

2254
    """
2255
    result = self.GetLinuxNodeInfo()
2256
    kvmpath = constants.KVM_PATH
2257
    if hvparams is not None:
2258
      kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2259
    _, v_major, v_min, v_rev = self._GetKVMVersion(kvmpath)
2260
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2261
    return result
2262

    
2263
  @classmethod
2264
  def GetInstanceConsole(cls, instance, primary_node, hvparams, beparams):
2265
    """Return a command for connecting to the console of an instance.
2266

2267
    """
2268
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2269
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2270
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2271
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2272
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2273
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2274
      return objects.InstanceConsole(instance=instance.name,
2275
                                     kind=constants.CONS_SSH,
2276
                                     host=primary_node.name,
2277
                                     user=constants.SSH_CONSOLE_USER,
2278
                                     command=cmd)
2279

    
2280
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2281
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2282
      display = instance.network_port - constants.VNC_BASE_PORT
2283
      return objects.InstanceConsole(instance=instance.name,
2284
                                     kind=constants.CONS_VNC,
2285
                                     host=vnc_bind_address,
2286
                                     port=instance.network_port,
2287
                                     display=display)
2288

    
2289
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2290
    if spice_bind:
2291
      return objects.InstanceConsole(instance=instance.name,
2292
                                     kind=constants.CONS_SPICE,
2293
                                     host=spice_bind,
2294
                                     port=instance.network_port)
2295

    
2296
    return objects.InstanceConsole(instance=instance.name,
2297
                                   kind=constants.CONS_MESSAGE,
2298
                                   message=("No serial shell for instance %s" %
2299
                                            instance.name))
2300

    
2301
  def Verify(self, hvparams=None):
2302
    """Verify the hypervisor.
2303

2304
    Check that the required binaries exist.
2305

2306
    @type hvparams: dict of strings
2307
    @param hvparams: hypervisor parameters to be verified against, not used here
2308

2309
    @return: Problem description if something is wrong, C{None} otherwise
2310

2311
    """
2312
    msgs = []
2313
    kvmpath = constants.KVM_PATH
2314
    if hvparams is not None:
2315
      kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2316
    if not os.path.exists(kvmpath):
2317
      msgs.append("The KVM binary ('%s') does not exist" % kvmpath)
2318
    if not os.path.exists(constants.SOCAT_PATH):
2319
      msgs.append("The socat binary ('%s') does not exist" %
2320
                  constants.SOCAT_PATH)
2321

    
2322
    return self._FormatVerifyResults(msgs)
2323

    
2324
  @classmethod
2325
  def CheckParameterSyntax(cls, hvparams):
2326
    """Check the given parameters for validity.
2327

2328
    @type hvparams:  dict
2329
    @param hvparams: dictionary with parameter names/value
2330
    @raise errors.HypervisorError: when a parameter is not valid
2331

2332
    """
2333
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2334

    
2335
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2336
    if kernel_path:
2337
      if not hvparams[constants.HV_ROOT_PATH]:
2338
        raise errors.HypervisorError("Need a root partition for the instance,"
2339
                                     " if a kernel is defined")
2340

    
2341
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2342
        not hvparams[constants.HV_VNC_X509]):
2343
      raise errors.HypervisorError("%s must be defined, if %s is" %
2344
                                   (constants.HV_VNC_X509,
2345
                                    constants.HV_VNC_X509_VERIFY))
2346

    
2347
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2348
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2349
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2350
      if not serial_speed or serial_speed not in valid_speeds:
2351
        raise errors.HypervisorError("Invalid serial console speed, must be"
2352
                                     " one of: %s" %
2353
                                     utils.CommaJoin(valid_speeds))
2354

    
2355
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2356
    if (boot_order == constants.HT_BO_CDROM and
2357
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2358
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2359
                                   " ISO path")
2360

    
2361
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2362
    if security_model == constants.HT_SM_USER:
2363
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2364
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2365
                                     " must be specified")
2366
    elif (security_model == constants.HT_SM_NONE or
2367
          security_model == constants.HT_SM_POOL):
2368
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2369
        raise errors.HypervisorError("Cannot have a security domain when the"
2370
                                     " security model is 'none' or 'pool'")
2371

    
2372
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2373
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2374
    if spice_bind:
2375
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2376
        # if an IP version is specified, the spice_bind parameter must be an
2377
        # IP of that family
2378
        if (netutils.IP4Address.IsValid(spice_bind) and
2379
            spice_ip_version != constants.IP4_VERSION):
2380
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2381
                                       " the specified IP version is %s" %
2382
                                       (spice_bind, spice_ip_version))
2383

    
2384
        if (netutils.IP6Address.IsValid(spice_bind) and
2385
            spice_ip_version != constants.IP6_VERSION):
2386
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2387
                                       " the specified IP version is %s" %
2388
                                       (spice_bind, spice_ip_version))
2389
    else:
2390
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2391
      # error if any of them is set without it.
2392
      for param in _SPICE_ADDITIONAL_PARAMS:
2393
        if hvparams[param]:
2394
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2395
                                       (param, constants.HV_KVM_SPICE_BIND))
2396

    
2397
  @classmethod
2398
  def ValidateParameters(cls, hvparams):
2399
    """Check the given parameters for validity.
2400

2401
    @type hvparams:  dict
2402
    @param hvparams: dictionary with parameter names/value
2403
    @raise errors.HypervisorError: when a parameter is not valid
2404

2405
    """
2406
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2407

    
2408
    kvm_path = hvparams[constants.HV_KVM_PATH]
2409

    
2410
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2411
    if security_model == constants.HT_SM_USER:
2412
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2413
      try:
2414
        pwd.getpwnam(username)
2415
      except KeyError:
2416
        raise errors.HypervisorError("Unknown security domain user %s"
2417
                                     % username)
2418
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2419
    if vnc_bind_address:
2420
      bound_to_addr = netutils.IP4Address.IsValid(vnc_bind_address)
2421
      is_interface = netutils.IsValidInterface(vnc_bind_address)
2422
      is_path = utils.IsNormAbsPath(vnc_bind_address)
2423
      if not bound_to_addr and not is_interface and not is_path:
2424
        raise errors.HypervisorError("VNC: The %s parameter must be either"
2425
                                     " a valid IP address, an interface name,"
2426
                                     " or an absolute path" %
2427
                                     constants.HV_KVM_SPICE_BIND)
2428

    
2429
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2430
    if spice_bind:
2431
      # only one of VNC and SPICE can be used currently.
2432
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2433
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2434
                                     " only one of them can be used at a"
2435
                                     " given time")
2436

    
2437
      # check that KVM supports SPICE
2438
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2439
      if not cls._SPICE_RE.search(kvmhelp):
2440
        raise errors.HypervisorError("SPICE is configured, but it is not"
2441
                                     " supported according to 'kvm --help'")
2442

    
2443
      # if spice_bind is not an IP address, it must be a valid interface
2444
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2445
                       netutils.IP6Address.IsValid(spice_bind))
2446
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2447
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2448
                                     " a valid IP address or interface name" %
2449
                                     constants.HV_KVM_SPICE_BIND)
2450

    
2451
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2452
    if machine_version:
2453
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2454
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2455
        raise errors.HypervisorError("Unsupported machine version: %s" %
2456
                                     machine_version)
2457

    
2458
  @classmethod
2459
  def PowercycleNode(cls, hvparams=None):
2460
    """KVM powercycle, just a wrapper over Linux powercycle.
2461

2462
    @type hvparams: dict of strings
2463
    @param hvparams: hypervisor params to be used on this node
2464

2465
    """
2466
    cls.LinuxPowercycle()