__init__.py 90.7 KB
Newer Older
Guido Trotter's avatar
Guido Trotter committed
1
2
3
#
#

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


"""KVM hypervisor

"""

Balazs Lecz's avatar
Balazs Lecz committed
26
import errno
Guido Trotter's avatar
Guido Trotter committed
27
28
29
30
import os
import os.path
import re
import tempfile
31
import time
Guido Trotter's avatar
Guido Trotter committed
32
import logging
33
import pwd
34
import shutil
35
import urllib2
36
from bitarray import bitarray
37
try:
Andrea Spadaccini's avatar
Andrea Spadaccini committed
38
  import affinity   # pylint: disable=F0401
39
40
except ImportError:
  affinity = None
41
42
43
44
try:
  import fdsend   # pylint: disable=F0401
except ImportError:
  fdsend = None
Guido Trotter's avatar
Guido Trotter committed
45
46
47
48

from ganeti import utils
from ganeti import constants
from ganeti import errors
49
50
from ganeti import serializer
from ganeti import objects
51
52
from ganeti import uidpool
from ganeti import ssconf
53
from ganeti import netutils
54
55
from ganeti import pathutils
from ganeti.hypervisor import hv_base
56
from ganeti.utils import wrapper as utils_wrapper
Guido Trotter's avatar
Guido Trotter committed
57

58
59
from ganeti.hypervisor.hv_kvm.monitor import QmpConnection, QmpMessage, \
                                             MonitorSocket
60
from ganeti.hypervisor.hv_kvm.netdev import OpenTap
61

Guido Trotter's avatar
Guido Trotter committed
62

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

66
67
68
69
70
71
72
73
74
75
76
#: SPICE parameters which depend on L{constants.HV_KVM_SPICE_BIND}
_SPICE_ADDITIONAL_PARAMS = frozenset([
  constants.HV_KVM_SPICE_IP_VERSION,
  constants.HV_KVM_SPICE_PASSWORD_FILE,
  constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR,
  constants.HV_KVM_SPICE_JPEG_IMG_COMPR,
  constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR,
  constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION,
  constants.HV_KVM_SPICE_USE_TLS,
  ])

77
78
79
80
# Constant bitarray that reflects to a free pci slot
# Use it with bitarray.search()
_AVAILABLE_PCI_SLOT = bitarray("0")

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

107
108
_MIGRATION_CAPS_DELIM = ":"

109

110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
def _GenerateDeviceKVMId(dev_type, dev):
  """Helper function to generate a unique device name used by KVM

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

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

  """

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

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


132
133
134
135
136
137
138
139
140
141
142
143
def _GetFreeSlot(slots, slot=None, reserve=False):
  """Helper method to get first available slot in a bitarray

  @type slots: bitarray
  @param slots: the bitarray to operate on
  @type slot: integer
  @param slot: if given we check whether the slot is free
  @type reserve: boolean
  @param reserve: whether to reserve the first available slot or not
  @return: the idx of the (first) available slot
  @raise errors.HotplugError: If all slots in a bitarray are occupied
    or the given slot is not free.
144

145
146
147
148
149
  """
  if slot is not None:
    assert slot < len(slots)
    if slots[slot]:
      raise errors.HypervisorError("Slots %d occupied" % slot)
150

151
152
153
154
  else:
    avail = slots.search(_AVAILABLE_PCI_SLOT, 1)
    if not avail:
      raise errors.HypervisorError("All slots occupied")
155

156
    slot = int(avail[0])
157

158
159
  if reserve:
    slots[slot] = True
160

161
  return slot
162
163


164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
def _GetExistingDeviceInfo(dev_type, device, runtime):
  """Helper function to get an existing device inside the runtime file

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

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

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

  return found[0]


190
191
192
193
194
195
def _UpgradeSerializedRuntime(serialized_runtime):
  """Upgrade runtime data

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

  @type serialized_runtime: string
  @param serialized_runtime: raw text data read from actual runtime file
199
200
  @return: (cmd, nic dicts, hvparams, bdev dicts)
  @rtype: tuple
201
202
203

  """
  loaded_runtime = serializer.Load(serialized_runtime)
204
205
206
  kvm_cmd, serialized_nics, hvparams = loaded_runtime[:3]
  if len(loaded_runtime) >= 4:
    serialized_disks = loaded_runtime[3]
207
  else:
208
209
210
211
212
213
214
215
216
    serialized_disks = []

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

  return kvm_cmd, serialized_nics, hvparams, serialized_disks

217

218
219
def _AnalyzeSerializedRuntime(serialized_runtime):
  """Return runtime entries for a serialized runtime file
220

221
222
223
224
225
226
227
228
  @type serialized_runtime: string
  @param serialized_runtime: raw text data read from actual runtime file
  @return: (cmd, nics, hvparams, bdevs)
  @rtype: tuple

  """
  kvm_cmd, serialized_nics, hvparams, serialized_disks = \
    _UpgradeSerializedRuntime(serialized_runtime)
229
  kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
230
231
  kvm_disks = [(objects.Disk.FromDict(sdisk), link, uri)
               for sdisk, link, uri in serialized_disks]
232

233
  return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
234

235

236
237
238
239
240
class HeadRequest(urllib2.Request):
  def get_method(self):
    return "HEAD"


241
242
243
244
245
def _CheckUrl(url):
  """Check if a given URL exists on the server

  """
  try:
246
247
    urllib2.urlopen(HeadRequest(url))
    return True
248
249
250
251
  except urllib2.URLError:
    return False


Guido Trotter's avatar
Guido Trotter committed
252
class KVMHypervisor(hv_base.BaseHypervisor):
Michael Hanselmann's avatar
Michael Hanselmann committed
253
254
255
  """KVM hypervisor interface

  """
256
  CAN_MIGRATE = True
Guido Trotter's avatar
Guido Trotter committed
257

258
  _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
Guido Trotter's avatar
Guido Trotter committed
259
  _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
260
  _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
Guido Trotter's avatar
Guido Trotter committed
261
262
  _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
  _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
263
  _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
264
  _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
Balazs Lecz's avatar
Balazs Lecz committed
265
266
267
268
269
270
271
272
  # KVM instances with chroot enabled are started in empty chroot directories.
  _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
  # After an instance is stopped, its chroot directory is removed.
  # If the chroot directory is not empty, it can't be removed.
  # A non-empty chroot directory indicates a possible security incident.
  # To support forensics, the non-empty chroot directory is quarantined in
  # a separate directory, called 'chroot-quarantine'.
  _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
273
  _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
274
           _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
Guido Trotter's avatar
Guido Trotter committed
275

276
  PARAMETERS = {
277
    constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
278
279
280
281
282
283
    constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
    constants.HV_ROOT_PATH: hv_base.NO_CHECK,
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
    constants.HV_ACPI: hv_base.NO_CHECK,
    constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
Guido Trotter's avatar
Guido Trotter committed
284
    constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
285
    constants.HV_VNC_BIND_ADDRESS: hv_base.NO_CHECK, # will be checked later
286
287
288
    constants.HV_VNC_TLS: hv_base.NO_CHECK,
    constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
    constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
289
    constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
290
291
292
293
    constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
    constants.HV_KVM_SPICE_IP_VERSION:
      (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
                         x in constants.VALID_IP_VERSIONS),
294
       "The SPICE IP version should be 4 or 6",
295
       None, None),
296
    constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
297
    constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
Iustin Pop's avatar
Iustin Pop committed
298
299
      hv_base.ParamInSet(
        False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
300
    constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
Iustin Pop's avatar
Iustin Pop committed
301
302
      hv_base.ParamInSet(
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
303
    constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
Iustin Pop's avatar
Iustin Pop committed
304
305
      hv_base.ParamInSet(
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
306
    constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
Iustin Pop's avatar
Iustin Pop committed
307
308
      hv_base.ParamInSet(
        False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
309
    constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
310
    constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
311
312
    constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
    constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
313
    constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
Jose A. Lopes's avatar
Jose A. Lopes committed
314
    constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_OR_URL_CHECK,
315
    constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_OR_URL_CHECK,
Michael Hanselmann's avatar
Michael Hanselmann committed
316
317
318
319
320
321
    constants.HV_BOOT_ORDER:
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
    constants.HV_NIC_TYPE:
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
    constants.HV_DISK_TYPE:
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
322
323
    constants.HV_KVM_CDROM_DISK_TYPE:
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
Michael Hanselmann's avatar
Michael Hanselmann committed
324
325
    constants.HV_USB_MOUSE:
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
326
    constants.HV_KEYMAP: hv_base.NO_CHECK,
327
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
328
329
    constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
    constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
330
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
331
    constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
332
333
    constants.HV_DISK_CACHE:
      hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
334
335
    constants.HV_KVM_DISK_AIO:
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_AIO_TYPES),
336
337
338
    constants.HV_SECURITY_MODEL:
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
    constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
Guido Trotter's avatar
Guido Trotter committed
339
340
    constants.HV_KVM_FLAG:
      hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
341
    constants.HV_VHOST_NET: hv_base.NO_CHECK,
Balazs Lecz's avatar
Balazs Lecz committed
342
    constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
343
    constants.HV_KVM_USER_SHUTDOWN: hv_base.NO_CHECK,
344
    constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
345
    constants.HV_REBOOT_BEHAVIOR:
346
347
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
348
    constants.HV_CPU_TYPE: hv_base.NO_CHECK,
349
350
351
    constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
    constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
    constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
Guido Trotter's avatar
Guido Trotter committed
352
    constants.HV_SOUNDHW: hv_base.NO_CHECK,
Guido Trotter's avatar
Guido Trotter committed
353
    constants.HV_USB_DEVICES: hv_base.NO_CHECK,
Guido Trotter's avatar
Guido Trotter committed
354
    constants.HV_VGA: hv_base.NO_CHECK,
Guido Trotter's avatar
Guido Trotter committed
355
    constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
356
    constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
357
    constants.HV_KVM_MIGRATION_CAPS: hv_base.NO_CHECK,
358
    constants.HV_VNET_HDR: hv_base.NO_CHECK,
359
    }
360

361
362
  _VIRTIO = "virtio"
  _VIRTIO_NET_PCI = "virtio-net-pci"
363
  _VIRTIO_BLK_PCI = "virtio-blk-pci"
364

Michele Tartara's avatar
Michele Tartara committed
365
  _MIGRATION_STATUS_RE = re.compile(r"Migration\s+status:\s+(\w+)",
Guido Trotter's avatar
Guido Trotter committed
366
                                    re.M | re.I)
Michael Hanselmann's avatar
Michael Hanselmann committed
367
  _MIGRATION_PROGRESS_RE = \
368
369
370
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
371

372
373
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
  _MIGRATION_INFO_RETRY_DELAY = 2
Guido Trotter's avatar
Guido Trotter committed
374

375
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
376

377
378
379
380
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
  _CPU_INFO_CMD = "info cpus"
  _CONT_CMD = "cont"

381
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
382
383
  _CHECK_MACHINE_VERSION_RE = \
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
384

385
386
387
388
389
390
  _QMP_RE = re.compile(r"^-qmp\s", re.M)
  _SPICE_RE = re.compile(r"^-spice\s", re.M)
  _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
  _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
  _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
  _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
391
  _DISPLAY_RE = re.compile(r"^-display\s", re.M)
392
  _MACHINE_RE = re.compile(r"^-machine\s", re.M)
393
394
  _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
  _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M)
395
396
397
398
  # match  -drive.*boot=on|off on different lines, but in between accept only
  # dashes not preceeded by a new line (which would mean another option
  # different than -drive is starting)
  _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
399
  _UUID_RE = re.compile(r"^-uuid\s", re.M)
400

401
402
  _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
  _INFO_PCI_CMD = "info pci"
403
404
405
406
407
  _FIND_PCI_DEVICE_RE = \
    staticmethod(
      lambda pci, devid: re.compile(r'Bus.*device[ ]*%d,(.*\n){5,6}.*id "%s"' %
                                    (pci, devid), re.M))

408
409
410
411
  _INFO_VERSION_RE = \
    re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
  _INFO_VERSION_CMD = "info version"

412
413
414
  # Slot 0 for Host bridge, Slot 1 for ISA bridge, Slot 2 for VGA controller
  _DEFAULT_PCI_RESERVATIONS = "11100000000000000000000000000000"
  _SOUNDHW_WITH_PCI_SLOT = ["ac97", "es1370", "hda"]
415

416
417
418
  ANCILLARY_FILES = [
    _KVM_NETWORK_SCRIPT,
    ]
419
420
421
  ANCILLARY_FILES_OPT = [
    _KVM_NETWORK_SCRIPT,
    ]
422

423
424
425
  # Supported kvm options to get output from
  _KVMOPT_HELP = "help"
  _KVMOPT_MLIST = "mlist"
426
  _KVMOPT_DEVICELIST = "devicelist"
427
428
429

  # Command to execute to get the output from kvm, and whether to
  # accept the output even on failure.
430
  _KVMOPTS_CMDS = {
431
432
433
    _KVMOPT_HELP: (["--help"], False),
    _KVMOPT_MLIST: (["-M", "?"], False),
    _KVMOPT_DEVICELIST: (["-device", "?"], True),
434
435
  }

Guido Trotter's avatar
Guido Trotter committed
436
437
438
439
  def __init__(self):
    hv_base.BaseHypervisor.__init__(self)
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
    # in a tmpfs filesystem or has been otherwise wiped out.
Iustin Pop's avatar
Iustin Pop committed
440
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
Guido Trotter's avatar
Guido Trotter committed
441
    utils.EnsureDirs(dirs)
Guido Trotter's avatar
Guido Trotter committed
442

443
444
  @classmethod
  def _InstancePidFile(cls, instance_name):
445
446
447
    """Returns the instance pidfile.

    """
448
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
449

450
451
452
453
454
455
456
  @classmethod
  def _InstanceUidFile(cls, instance_name):
    """Returns the instance uidfile.

    """
    return utils.PathJoin(cls._UIDS_DIR, instance_name)

457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
  @classmethod
  def _InstancePidInfo(cls, pid):
    """Check pid file for instance information.

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

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

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

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

    instance = None
    memory = 0
    vcpus = 0

Iustin Pop's avatar
Iustin Pop committed
486
    arg_list = cmdline.split("\x00")
487
    while arg_list:
Michael Hanselmann's avatar
Michael Hanselmann committed
488
      arg = arg_list.pop(0)
489
490
491
492
493
      if arg == "-name":
        instance = arg_list.pop(0)
      elif arg == "-m":
        memory = int(arg_list.pop(0))
      elif arg == "-smp":
494
        vcpus = int(arg_list.pop(0).split(",")[0])
495
496
497
498
499
500
501

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

    return (instance, memory, vcpus)

502
503
  @classmethod
  def _InstancePidAlive(cls, instance_name):
504
505
506
507
508
509
    """Returns the instance pidfile, pid, and liveness.

    @type instance_name: string
    @param instance_name: instance name
    @rtype: tuple
    @return: (pid file name, pid, liveness)
510
511

    """
512
    pidfile = cls._InstancePidFile(instance_name)
513
    pid = utils.ReadPidFile(pidfile)
514
515
516

    alive = False
    try:
517
      cmd_instance = cls._InstancePidInfo(pid)[0]
518
519
520
      alive = (cmd_instance == instance_name)
    except errors.HypervisorError:
      pass
521
522
523

    return (pidfile, pid, alive)

524
525
  @classmethod
  def _CheckDown(cls, instance_name):
526
527
528
    """Raises an error unless the given instance is down.

    """
529
    alive = cls._InstancePidAlive(instance_name)[2]
530
531
532
533
    if alive:
      raise errors.HypervisorError("Failed to start instance %s: %s" %
                                   (instance_name, "already running"))

534
535
  @classmethod
  def _InstanceMonitor(cls, instance_name):
536
537
538
    """Returns the instance monitor socket name

    """
539
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
540

541
542
  @classmethod
  def _InstanceSerial(cls, instance_name):
543
544
545
    """Returns the instance serial socket name

    """
546
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
547

548
549
550
551
552
553
554
  @classmethod
  def _InstanceQmpMonitor(cls, instance_name):
    """Returns the instance serial QMP socket name

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

555
556
557
558
559
560
561
  @classmethod
  def _InstanceKvmdMonitor(cls, instance_name):
    """Returns the instance kvm daemon socket name

    """
    return utils.PathJoin(cls._CTRL_DIR, "%s.kvmd" % instance_name)

562
563
564
565
566
567
568
  @classmethod
  def _InstanceShutdownMonitor(cls, instance_name):
    """Returns the instance QMP output filename

    """
    return utils.PathJoin(cls._CTRL_DIR, "%s.shutdown" % instance_name)

569
570
571
572
573
574
575
  @staticmethod
  def _SocatUnixConsoleParams():
    """Returns the correct parameters for socat

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

    """
576
    if constants.SOCAT_USE_ESCAPE:
577
578
579
580
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
    else:
      return "echo=0,icanon=0"

581
582
  @classmethod
  def _InstanceKVMRuntime(cls, instance_name):
583
584
585
    """Returns the instance KVM runtime filename

    """
586
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
587

Balazs Lecz's avatar
Balazs Lecz committed
588
589
590
591
592
593
594
  @classmethod
  def _InstanceChrootDir(cls, instance_name):
    """Returns the name of the KVM chroot dir of the instance

    """
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)

595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
  @classmethod
  def _InstanceNICDir(cls, instance_name):
    """Returns the name of the directory holding the tap device files for a
    given instance.

    """
    return utils.PathJoin(cls._NICS_DIR, instance_name)

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

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

610
611
612
613
614
615
616
  @classmethod
  def _InstanceKeymapFile(cls, instance_name):
    """Returns the name of the file containing the keymap for a given instance

    """
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)

617
618
619
620
621
622
623
  @classmethod
  def _TryReadUidFile(cls, uid_file):
    """Try to read a uid file

    """
    if os.path.exists(uid_file):
      try:
624
        uid = int(utils.ReadOneLineFile(uid_file))
625
        return uid
626
627
628
629
      except EnvironmentError:
        logging.warning("Can't read uid file", exc_info=True)
      except (TypeError, ValueError):
        logging.warning("Can't parse uid file contents", exc_info=True)
630
    return None
631

632
633
  @classmethod
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
Balazs Lecz's avatar
Balazs Lecz committed
634
    """Removes an instance's rutime sockets/files/dirs.
635
636
637
638
639

    """
    utils.RemoveFile(pidfile)
    utils.RemoveFile(cls._InstanceMonitor(instance_name))
    utils.RemoveFile(cls._InstanceSerial(instance_name))
640
    utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
641
    utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
642
    utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
643
644
645
646
647
    uid_file = cls._InstanceUidFile(instance_name)
    uid = cls._TryReadUidFile(uid_file)
    utils.RemoveFile(uid_file)
    if uid is not None:
      uidpool.ReleaseUid(uid)
648
649
650
651
652
    try:
      shutil.rmtree(cls._InstanceNICDir(instance_name))
    except OSError, err:
      if err.errno != errno.ENOENT:
        raise
Balazs Lecz's avatar
Balazs Lecz committed
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
    try:
      chroot_dir = cls._InstanceChrootDir(instance_name)
      utils.RemoveDir(chroot_dir)
    except OSError, err:
      if err.errno == errno.ENOTEMPTY:
        # The chroot directory is expected to be empty, but it isn't.
        new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
                                          prefix="%s-%s-" %
                                          (instance_name,
                                           utils.TimestampForFilename()))
        logging.warning("The chroot directory of instance %s can not be"
                        " removed as it is not empty. Moving it to the"
                        " quarantine instead. Please investigate the"
                        " contents (%s) and clean up manually",
                        instance_name, new_chroot_dir)
        utils.RenameFile(chroot_dir, new_chroot_dir)
      else:
        raise
671

672
  @staticmethod
673
674
  def _ConfigureNIC(instance, seq, nic, tap):
    """Run the network configuration script for a specified NIC
Guido Trotter's avatar
Guido Trotter committed
675

676
677
    See L{hv_base.ConfigureNIC}.

Guido Trotter's avatar
Guido Trotter committed
678
679
680
681
682
683
    @param instance: instance we're acting on
    @type instance: instance object
    @param seq: nic sequence number
    @type seq: int
    @param nic: nic we're acting on
    @type nic: nic object
684
685
    @param tap: the host's tap interface this NIC corresponds to
    @type tap: str
Guido Trotter's avatar
Guido Trotter committed
686
687

    """
688
    hv_base.ConfigureNIC([pathutils.KVM_IFUP, tap], instance, seq, nic, tap)
Guido Trotter's avatar
Guido Trotter committed
689

690
691
692
693
  @staticmethod
  def _VerifyAffinityPackage():
    if affinity is None:
      raise errors.HypervisorError("affinity Python package not"
Iustin Pop's avatar
Iustin Pop committed
694
                                   " found; cannot use CPU pinning under KVM")
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739

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

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

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

    """
    if cpu_list == constants.CPU_PINNING_OFF:
      return constants.CPU_PINNING_ALL_KVM
    else:
      return sum(2 ** cpu for cpu in cpu_list)

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

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

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

    if len(cpu_list) == 1:
      all_cpu_mapping = cpu_list[0]
      if all_cpu_mapping == constants.CPU_PINNING_OFF:
        # If CPU pinning has 1 entry that's "all", then do nothing
        pass
      else:
        # If CPU pinning has one non-all entry, map the entire VM to
        # one set of physical CPUs
        cls._VerifyAffinityPackage()
Iustin Pop's avatar
Iustin Pop committed
740
741
        affinity.set_process_affinity_mask(
          process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
742
743
744
745
746
747
748
749
750
751
    else:
      # The number of vCPUs mapped should match the number of vCPUs
      # reported by KVM. This was already verified earlier, so
      # here only as a sanity check.
      assert len(thread_dict) == len(cpu_list)
      cls._VerifyAffinityPackage()

      # For each vCPU, map it to the proper list of physical CPUs
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
        affinity.set_process_affinity_mask(thread_dict[i],
Iustin Pop's avatar
Iustin Pop committed
752
                                           cls._BuildAffinityCpuMask(vcpu))
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773

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

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

    """
    result = {}
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
    for line in output.stdout.splitlines():
      match = self._CPU_INFO_RE.search(line)
      if not match:
        continue
      grp = map(int, match.groups())
      result[grp[0]] = grp[1]

    return result

774
775
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
    """Complete CPU pinning.
776
777
778
779
780
781
782

    @type instance_name: string
    @param instance_name: name of instance
    @type cpu_mask: string
    @param cpu_mask: CPU pinning mask as entered by user

    """
783
784
785
786
787
788
    # Get KVM process ID, to be used if need to pin entire VM
    _, pid, _ = self._InstancePidAlive(instance_name)
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
    thread_dict = self._GetVcpuThreadIds(instance_name)
    # Run CPU pinning, based on configured mask
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
789

790
  def ListInstances(self, hvparams=None):
Guido Trotter's avatar
Guido Trotter committed
791
792
    """Get the list of running instances.

Iustin Pop's avatar
Iustin Pop committed
793
794
    We can do this by listing our live instances directory and
    checking whether the associated kvm process is still alive.
Guido Trotter's avatar
Guido Trotter committed
795
796
797
798

    """
    result = []
    for name in os.listdir(self._PIDS_DIR):
799
      if self._InstancePidAlive(name)[2] or self._IsUserShutdown(name):
Guido Trotter's avatar
Guido Trotter committed
800
801
802
        result.append(name)
    return result

803
804
805
806
807
808
809
810
  @classmethod
  def _IsUserShutdown(cls, instance_name):
    return os.path.exists(cls._InstanceShutdownMonitor(instance_name))

  @classmethod
  def _ClearUserShutdown(cls, instance_name):
    utils.RemoveFile(cls._InstanceShutdownMonitor(instance_name))

811
  def GetInstanceInfo(self, instance_name, hvparams=None):
Guido Trotter's avatar
Guido Trotter committed
812
813
    """Get instance properties.

814
    @type instance_name: string
Iustin Pop's avatar
Iustin Pop committed
815
    @param instance_name: the instance name
816
817
    @type hvparams: dict of strings
    @param hvparams: hvparams to be used with this instance
818
819
    @rtype: tuple of strings
    @return: (name, id, memory, vcpus, stat, times)
Guido Trotter's avatar
Guido Trotter committed
820
821

    """
822
    _, pid, alive = self._InstancePidAlive(instance_name)
823
    if not alive:
824
825
826
827
      if self._IsUserShutdown(instance_name):
        return (instance_name, -1, 0, 0, hv_base.HvInstanceState.SHUTDOWN, 0)
      else:
        return None
Guido Trotter's avatar
Guido Trotter committed
828

829
    _, memory, vcpus = self._InstancePidInfo(pid)
830
    istat = hv_base.HvInstanceState.RUNNING
831
    times = 0
Guido Trotter's avatar
Guido Trotter committed
832

833
834
835
    try:
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
      qmp.connect()
836
      vcpus = len(qmp.Execute("query-cpus"))
837
838
      # Will fail if ballooning is not enabled, but we can then just resort to
      # the value above.
839
      mem_bytes = qmp.Execute("query-balloon")[qmp.ACTUAL_KEY]
840
841
842
843
      memory = mem_bytes / 1048576
    except errors.HypervisorError:
      pass

844
    return (instance_name, pid, memory, vcpus, istat, times)
Guido Trotter's avatar
Guido Trotter committed
845

846
  def GetAllInstancesInfo(self, hvparams=None):
Guido Trotter's avatar
Guido Trotter committed
847
848
    """Get properties of all instances.

849
850
    @type hvparams: dict of strings
    @param hvparams: hypervisor parameter
Iustin Pop's avatar
Iustin Pop committed
851
852
    @return: list of tuples (name, id, memory, vcpus, stat, times)

Guido Trotter's avatar
Guido Trotter committed
853
854
855
    """
    data = []
    for name in os.listdir(self._PIDS_DIR):
856
857
858
      try:
        info = self.GetInstanceInfo(name)
      except errors.HypervisorError:
859
        # Ignore exceptions due to instances being shut down
860
861
862
        continue
      if info:
        data.append(info)
Guido Trotter's avatar
Guido Trotter committed
863
864
    return data

865
  def _GenerateKVMBlockDevicesOptions(self, instance, up_hvp, kvm_disks,
866
867
868
869
870
                                      kvmhelp, devlist):
    """Generate KVM options regarding instance's block devices.

    @type instance: L{objects.Instance}
    @param instance: the instance object
871
872
    @type up_hvp: dict
    @param up_hvp: the instance's runtime hypervisor parameters
873
874
    @type kvm_disks: list of tuples
    @param kvm_disks: list of tuples [(disk, link_name, uri)..]
875
876
877
878
879
880
    @type kvmhelp: string
    @param kvmhelp: output of kvm --help
    @type devlist: string
    @param devlist: output of kvm -device ?
    @rtype: list
    @return: list of command line options eventually used by kvm executable
881

882
    """
883
    kernel_path = up_hvp[constants.HV_KERNEL_PATH]
884
885
886
    if kernel_path:
      boot_disk = False
    else:
887
      boot_disk = up_hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
888
889
890
891
892
893

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

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

      access_mode = cfdev.params.get(constants.LDP_ACCESS,
                                     constants.DISK_KERNELSPACE)
940
941
      if (uri and access_mode == constants.DISK_USERSPACE):
        drive_uri = uri
942
      else:
943
        drive_uri = link_name
944

945
946
      drive_val = "file=%s,format=raw%s%s%s%s" % \
                  (drive_uri, if_val, boot_val, cache_val, aio_val)
947

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

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

    return dev_opts

964
  @staticmethod
965
966
  def _CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image, cdrom_boot,
                   needs_boot_flag):
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
    """Extends L{kvm_cmd} with the '-drive' option for a cdrom, and
    optionally the '-boot' option.

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

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

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

    @type kvm_cmd: string
    @param kvm_cmd: KVM command line

    @type cdrom_disk_type:
    @param cdrom_disk_type:

    @type cdrom_image:
    @param cdrom_image:

    @type cdrom_boot:
    @param cdrom_boot:

    @type needs_boot_flag:
    @param needs_boot_flag:

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

    # set cdrom 'media' and 'format', if needed
    if utils.IsUrl(cdrom_image):
      options = ",media=cdrom"
    else:
      options = ",media=cdrom,format=raw"

    # set cdrom 'if' type
    if cdrom_boot:
      if_val = ",if=" + constants.HT_DISK_IDE
    elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
      if_val = ",if=virtio"
    else:
      if_val = ",if=" + cdrom_disk_type

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

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

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

1026
1027
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
                          kvmhelp):
1028
    """Generate KVM information to start an instance.
Guido Trotter's avatar
Guido Trotter committed
1029

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

Guido Trotter's avatar
Guido Trotter committed
1039
    """
1040
1041
    # pylint: disable=R0912,R0914,R0915
    hvp = instance.hvparams
1042
    self.ValidateParameters(hvp)
1043

Michael Hanselmann's avatar
Michael Hanselmann committed
1044
    pidfile = self._InstancePidFile(instance.name)
1045
    kvm = hvp[constants.HV_KVM_PATH]
Guido Trotter's avatar
Guido Trotter committed
1046
    kvm_cmd = [kvm]
1047
    # used just by the vnc server, if enabled
Iustin Pop's avatar
Iustin Pop committed
1048
    kvm_cmd.extend(["-name", instance.name])
1049
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060

    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
    if hvp[constants.HV_CPU_CORES]:
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
    if hvp[constants.HV_CPU_THREADS]:
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
    if hvp[constants.HV_CPU_SOCKETS]:
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])

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

Iustin Pop's avatar
Iustin Pop committed
1061
    kvm_cmd.extend(["-pidfile", pidfile])
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074

    pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)

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

1075
1076
1077
1078
    if hvp[constants.HV_DISK_TYPE] == constants.HT_DISK_SCSI:
      # The SCSI controller requires another PCI slot.
      _ = _GetFreeSlot(pci_reservations, reserve=True)

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

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

Iustin Pop's avatar
Iustin Pop committed
1112
1113
    kernel_path = hvp[constants.HV_KERNEL_PATH]
    if kernel_path:
1114
      boot_cdrom = boot_floppy = boot_network = False
Iustin Pop's avatar
Iustin Pop committed
1115
1116
1117
1118
    else:
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
Guido Trotter's avatar
Guido Trotter committed
1119

1120
1121
1122
    if startup_paused:
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])

Guido Trotter's avatar
Guido Trotter committed
1123
    if boot_network:
Iustin Pop's avatar
Iustin Pop committed
1124
      kvm_cmd.extend(["-boot", "n"])
1125

1126
    disk_type = hvp[constants.HV_DISK_TYPE]
Guido Trotter's avatar
Guido Trotter committed
1127

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

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

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

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

1154
    if kernel_path:
Iustin Pop's avatar
Iustin Pop committed
1155
      kvm_cmd.extend(["-kernel", kernel_path])
1156
      initrd_path = hvp[constants.HV_INITRD_PATH]
1157
      if initrd_path:
Iustin Pop's avatar
Iustin Pop committed
1158
1159
        kvm_cmd.extend(["-initrd", initrd_path])
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1160
1161
                     hvp[constants.HV_KERNEL_ARGS]]
      if hvp[constants.HV_SERIAL_CONSOLE]:
Guido Trotter's avatar
Guido Trotter committed
1162
1163
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
        root_append.append("console=ttyS0,%s" % serial_speed)
Iustin Pop's avatar
Iustin Pop committed
1164
      kvm_cmd.extend(["-append", " ".join(root_append)])
Guido Trotter's avatar
Guido Trotter committed
1165

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

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

1180
    mouse_type = hvp[constants.HV_USB_MOUSE]
1181
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1182
1183
    spice_bind