Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm / __init__.py @ 24d3d8da

History | View | Annotate | Download (91.9 kB)

1
#
2
#
3

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

    
21

    
22
"""KVM hypervisor
23

24
"""
25

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

    
46
from ganeti import utils
47
from ganeti import constants
48
from ganeti import errors
49
from ganeti import serializer
50
from ganeti import objects
51
from ganeti import uidpool
52
from ganeti import ssconf
53
from ganeti import netutils
54
from ganeti import pathutils
55
from ganeti.hypervisor import hv_base
56
from ganeti.utils import wrapper as utils_wrapper
57

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

    
62

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

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

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

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

    
107
_MIGRATION_CAPS_DELIM = ":"
108

    
109

    
110
def _GenerateDeviceKVMId(dev_type, dev):
111
  """Helper function to generate a unique device name used by KVM
112

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

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

123
  """
124

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

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

    
131

    
132
def _GetFreeSlot(slots, slot=None, reserve=False):
133
  """Helper method to get first available slot in a bitarray
134

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

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

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

    
156
    slot = int(avail[0])
157

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

    
161
  return slot
162

    
163

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

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

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

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

    
187
  return found[0]
188

    
189

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

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

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

202
  """
203
  loaded_runtime = serializer.Load(serialized_runtime)
204
  kvm_cmd, serialized_nics, hvparams = loaded_runtime[:3]
205
  if len(loaded_runtime) >= 4:
206
    serialized_disks = loaded_runtime[3]
207
  else:
208
    serialized_disks = []
209

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

    
215
  return kvm_cmd, serialized_nics, hvparams, serialized_disks
216

    
217

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

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

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

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

    
235

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

    
240

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

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

    
251

    
252
class KVMHypervisor(hv_base.BaseHypervisor):
253
  """KVM hypervisor interface
254

255
  """
256
  CAN_MIGRATE = True
257

    
258
  _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
259
  _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
260
  _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
261
  _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
262
  _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
265
  # KVM instances with chroot enabled are started in empty chroot directories.
266
  _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
267
  # After an instance is stopped, its chroot directory is removed.
268
  # If the chroot directory is not empty, it can't be removed.
269
  # A non-empty chroot directory indicates a possible security incident.
270
  # To support forensics, the non-empty chroot directory is quarantined in
271
  # a separate directory, called 'chroot-quarantine'.
272
  _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]
275

    
276
  PARAMETERS = {
277
    constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
278
    constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
279
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
280
    constants.HV_ROOT_PATH: hv_base.NO_CHECK,
281
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
282
    constants.HV_ACPI: hv_base.NO_CHECK,
283
    constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
284
    constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
285
    constants.HV_VNC_BIND_ADDRESS: hv_base.NO_CHECK, # will be checked later
286
    constants.HV_VNC_TLS: hv_base.NO_CHECK,
287
    constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
288
    constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
289
    constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
290
    constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
291
    constants.HV_KVM_SPICE_IP_VERSION:
292
      (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
293
                         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:
298
      hv_base.ParamInSet(
299
        False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
300
    constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
301
      hv_base.ParamInSet(
302
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
303
    constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
304
      hv_base.ParamInSet(
305
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
306
    constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
307
      hv_base.ParamInSet(
308
        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
    constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
312
    constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
313
    constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
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,
316
    constants.HV_BOOT_ORDER:
317
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
318
    constants.HV_NIC_TYPE:
319
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
320
    constants.HV_DISK_TYPE:
321
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
322
    constants.HV_KVM_CDROM_DISK_TYPE:
323
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
324
    constants.HV_USB_MOUSE:
325
      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
    constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
329
    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
    constants.HV_DISK_CACHE:
333
      hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
334
    constants.HV_SECURITY_MODEL:
335
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
336
    constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
337
    constants.HV_KVM_FLAG:
338
      hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
339
    constants.HV_VHOST_NET: hv_base.NO_CHECK,
340
    constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
341
    constants.HV_KVM_USER_SHUTDOWN: hv_base.NO_CHECK,
342
    constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
343
    constants.HV_REBOOT_BEHAVIOR:
344
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
345
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
346
    constants.HV_CPU_TYPE: hv_base.NO_CHECK,
347
    constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
348
    constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
349
    constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
350
    constants.HV_SOUNDHW: hv_base.NO_CHECK,
351
    constants.HV_USB_DEVICES: hv_base.NO_CHECK,
352
    constants.HV_VGA: hv_base.NO_CHECK,
353
    constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
354
    constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
355
    constants.HV_KVM_MIGRATION_CAPS: hv_base.NO_CHECK,
356
    constants.HV_VNET_HDR: hv_base.NO_CHECK,
357
    }
358

    
359
  _VIRTIO = "virtio"
360
  _VIRTIO_NET_PCI = "virtio-net-pci"
361
  _VIRTIO_BLK_PCI = "virtio-blk-pci"
362

    
363
  _MIGRATION_STATUS_RE = re.compile(r"Migration\s+status:\s+(\w+)",
364
                                    re.M | re.I)
365
  _MIGRATION_PROGRESS_RE = \
366
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
367
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
368
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
369

    
370
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
371
  _MIGRATION_INFO_RETRY_DELAY = 2
372

    
373
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
374

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

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

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

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

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

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

    
414
  ANCILLARY_FILES = [
415
    _KVM_NETWORK_SCRIPT,
416
    ]
417
  ANCILLARY_FILES_OPT = [
418
    _KVM_NETWORK_SCRIPT,
419
    ]
420

    
421
  # Supported kvm options to get output from
422
  _KVMOPT_HELP = "help"
423
  _KVMOPT_MLIST = "mlist"
424
  _KVMOPT_DEVICELIST = "devicelist"
425

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

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

    
441
  @classmethod
442
  def _InstancePidFile(cls, instance_name):
443
    """Returns the instance pidfile.
444

445
    """
446
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
447

    
448
  @classmethod
449
  def _InstanceUidFile(cls, instance_name):
450
    """Returns the instance uidfile.
451

452
    """
453
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
454

    
455
  @classmethod
456
  def _InstancePidInfo(cls, pid):
457
    """Check pid file for instance information.
458

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

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

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

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

    
480
    instance = None
481
    memory = 0
482
    vcpus = 0
483

    
484
    arg_list = cmdline.split("\x00")
485
    while arg_list:
486
      arg = arg_list.pop(0)
487
      if arg == "-name":
488
        instance = arg_list.pop(0)
489
      elif arg == "-m":
490
        memory = int(arg_list.pop(0))
491
      elif arg == "-smp":
492
        vcpus = int(arg_list.pop(0).split(",")[0])
493

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

    
498
    return (instance, memory, vcpus)
499

    
500
  @classmethod
501
  def _InstancePidAlive(cls, instance_name):
502
    """Returns the instance pidfile, pid, and liveness.
503

504
    @type instance_name: string
505
    @param instance_name: instance name
506
    @rtype: tuple
507
    @return: (pid file name, pid, liveness)
508

509
    """
510
    pidfile = cls._InstancePidFile(instance_name)
511
    pid = utils.ReadPidFile(pidfile)
512

    
513
    alive = False
514
    try:
515
      cmd_instance = cls._InstancePidInfo(pid)[0]
516
      alive = (cmd_instance == instance_name)
517
    except errors.HypervisorError:
518
      pass
519

    
520
    return (pidfile, pid, alive)
521

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

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

    
532
  @classmethod
533
  def _InstanceMonitor(cls, instance_name):
534
    """Returns the instance monitor socket name
535

536
    """
537
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
538

    
539
  @classmethod
540
  def _InstanceSerial(cls, instance_name):
541
    """Returns the instance serial socket name
542

543
    """
544
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
545

    
546
  @classmethod
547
  def _InstanceQmpMonitor(cls, instance_name):
548
    """Returns the instance serial QMP socket name
549

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

    
553
  @classmethod
554
  def _InstanceShutdownMonitor(cls, instance_name):
555
    """Returns the instance QMP output filename
556

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

    
560
  @staticmethod
561
  def _SocatUnixConsoleParams():
562
    """Returns the correct parameters for socat
563

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

566
    """
567
    if constants.SOCAT_USE_ESCAPE:
568
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
569
    else:
570
      return "echo=0,icanon=0"
571

    
572
  @classmethod
573
  def _InstanceKVMRuntime(cls, instance_name):
574
    """Returns the instance KVM runtime filename
575

576
    """
577
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
578

    
579
  @classmethod
580
  def _InstanceChrootDir(cls, instance_name):
581
    """Returns the name of the KVM chroot dir of the instance
582

583
    """
584
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
585

    
586
  @classmethod
587
  def _InstanceNICDir(cls, instance_name):
588
    """Returns the name of the directory holding the tap device files for a
589
    given instance.
590

591
    """
592
    return utils.PathJoin(cls._NICS_DIR, instance_name)
593

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

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

    
601
  @classmethod
602
  def _InstanceKeymapFile(cls, instance_name):
603
    """Returns the name of the file containing the keymap for a given instance
604

605
    """
606
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
607

    
608
  @classmethod
609
  def _TryReadUidFile(cls, uid_file):
610
    """Try to read a uid file
611

612
    """
613
    if os.path.exists(uid_file):
614
      try:
615
        uid = int(utils.ReadOneLineFile(uid_file))
616
        return uid
617
      except EnvironmentError:
618
        logging.warning("Can't read uid file", exc_info=True)
619
      except (TypeError, ValueError):
620
        logging.warning("Can't parse uid file contents", exc_info=True)
621
    return None
622

    
623
  @classmethod
624
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
625
    """Removes an instance's rutime sockets/files/dirs.
626

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

    
663
  @staticmethod
664
  def _ConfigureNIC(instance, seq, nic, tap):
665
    """Run the network configuration script for a specified NIC
666

667
    @param instance: instance we're acting on
668
    @type instance: instance object
669
    @param seq: nic sequence number
670
    @type seq: int
671
    @param nic: nic we're acting on
672
    @type nic: nic object
673
    @param tap: the host's tap interface this NIC corresponds to
674
    @type tap: str
675

676
    """
677
    env = {
678
      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
679
      "INSTANCE": instance.name,
680
      "MAC": nic.mac,
681
      "MODE": nic.nicparams[constants.NIC_MODE],
682
      "INTERFACE": tap,
683
      "INTERFACE_INDEX": str(seq),
684
      "INTERFACE_UUID": nic.uuid,
685
      "TAGS": " ".join(instance.GetTags()),
686
    }
687

    
688
    if nic.ip:
689
      env["IP"] = nic.ip
690

    
691
    if nic.name:
692
      env["INTERFACE_NAME"] = nic.name
693

    
694
    if nic.nicparams[constants.NIC_LINK]:
695
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
696

    
697
    if nic.nicparams[constants.NIC_VLAN]:
698
      env["VLAN"] = nic.nicparams[constants.NIC_VLAN]
699

    
700
    if nic.network:
701
      n = objects.Network.FromDict(nic.netinfo)
702
      env.update(n.HooksDict())
703

    
704
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
705
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
706

    
707
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
708
    if result.failed:
709
      raise errors.HypervisorError("Failed to configure interface %s: %s;"
710
                                   " network configuration script output: %s" %
711
                                   (tap, result.fail_reason, result.output))
712

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

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

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

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

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

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

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

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

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

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

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

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

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

    
795
    return result
796

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

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

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

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

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

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

    
826
  @classmethod
827
  def _IsUserShutdown(cls, instance_name):
828
    return os.path.exists(cls._InstanceShutdownMonitor(instance_name))
829

    
830
  @classmethod
831
  def _ClearUserShutdown(cls, instance_name):
832
    utils.RemoveFile(cls._InstanceShutdownMonitor(instance_name))
833

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

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

844
    """
845
    _, pid, alive = self._InstancePidAlive(instance_name)
846
    if not alive:
847
      if self._IsUserShutdown(instance_name):
848
        return (instance_name, -1, 0, 0, hv_base.HvInstanceState.SHUTDOWN, 0)
849
      else:
850
        return None
851

    
852
    _, memory, vcpus = self._InstancePidInfo(pid)
853
    istat = hv_base.HvInstanceState.RUNNING
854
    times = 0
855

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

    
867
    return (instance_name, pid, memory, vcpus, istat, times)
868

    
869
  def GetAllInstancesInfo(self, hvparams=None):
870
    """Get properties of all instances.
871

872
    @type hvparams: dict of strings
873
    @param hvparams: hypervisor parameter
874
    @return: list of tuples (name, id, memory, vcpus, stat, times)
875

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

    
888
  def _GenerateKVMBlockDevicesOptions(self, instance, up_hvp, kvm_disks,
889
                                      kvmhelp, devlist):
890
    """Generate KVM options regarding instance's block devices.
891

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

905
    """
906
    kernel_path = up_hvp[constants.HV_KERNEL_PATH]
907
    if kernel_path:
908
      boot_disk = False
909
    else:
910
      boot_disk = up_hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
911

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

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

    
955
      access_mode = cfdev.params.get(constants.LDP_ACCESS,
956
                                     constants.DISK_KERNELSPACE)
957
      if (uri and access_mode == constants.DISK_USERSPACE):
958
        drive_uri = uri
959
      else:
960
        drive_uri = link_name
961

    
962
      drive_val = "file=%s,format=raw%s%s%s" % \
963
                  (drive_uri, if_val, boot_val, cache_val)
964

    
965
      if device_driver:
966
        # kvm_disks are the 4th entry of runtime file that did not exist in
967
        # the past. That means that cfdev should always have pci slot and
968
        # _GenerateDeviceKVMId() will not raise a exception.
969
        kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_DISK, cfdev)
970
        drive_val += (",id=%s" % kvm_devid)
971
        drive_val += (",bus=0,unit=%d" % cfdev.pci)
972
        dev_val = ("%s,drive=%s,id=%s" %
973
                   (device_driver, kvm_devid, kvm_devid))
974
        dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci)
975
        dev_opts.extend(["-device", dev_val])
976

    
977
      dev_opts.extend(["-drive", drive_val])
978

    
979
    return dev_opts
980

    
981
  @staticmethod
982
  def _CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image, cdrom_boot,
983
                   needs_boot_flag):
984
    """Extends L{kvm_cmd} with the '-drive' option for a cdrom, and
985
    optionally the '-boot' option.
986

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

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

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

993
    @type kvm_cmd: string
994
    @param kvm_cmd: KVM command line
995

996
    @type cdrom_disk_type:
997
    @param cdrom_disk_type:
998

999
    @type cdrom_image:
1000
    @param cdrom_image:
1001

1002
    @type cdrom_boot:
1003
    @param cdrom_boot:
1004

1005
    @type needs_boot_flag:
1006
    @param needs_boot_flag:
1007

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

    
1015
    # set cdrom 'media' and 'format', if needed
1016
    if utils.IsUrl(cdrom_image):
1017
      options = ",media=cdrom"
1018
    else:
1019
      options = ",media=cdrom,format=raw"
1020

    
1021
    # set cdrom 'if' type
1022
    if cdrom_boot:
1023
      if_val = ",if=" + constants.HT_DISK_IDE
1024
    elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1025
      if_val = ",if=virtio"
1026
    else:
1027
      if_val = ",if=" + cdrom_disk_type
1028

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

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

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

    
1043
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1044
                          kvmhelp):
1045
    """Generate KVM information to start an instance.
1046

1047
    @type kvmhelp: string
1048
    @param kvmhelp: output of kvm --help
1049
    @attention: this function must not have any side-effects; for
1050
        example, it must not write to the filesystem, or read values
1051
        from the current system the are expected to differ between
1052
        nodes, since it is only run once at instance startup;
1053
        actions/kvm arguments that can vary between systems should be
1054
        done in L{_ExecuteKVMRuntime}
1055

1056
    """
1057
    # pylint: disable=R0912,R0914,R0915
1058
    hvp = instance.hvparams
1059
    self.ValidateParameters(hvp)
1060

    
1061
    pidfile = self._InstancePidFile(instance.name)
1062
    kvm = hvp[constants.HV_KVM_PATH]
1063
    kvm_cmd = [kvm]
1064
    # used just by the vnc server, if enabled
1065
    kvm_cmd.extend(["-name", instance.name])
1066
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1067

    
1068
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1069
    if hvp[constants.HV_CPU_CORES]:
1070
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1071
    if hvp[constants.HV_CPU_THREADS]:
1072
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1073
    if hvp[constants.HV_CPU_SOCKETS]:
1074
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1075

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

    
1078
    kvm_cmd.extend(["-pidfile", pidfile])
1079

    
1080
    pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1081

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

    
1092
    if hvp[constants.HV_DISK_TYPE] == constants.HT_DISK_SCSI:
1093
      # The SCSI controller requires another PCI slot.
1094
      _ = _GetFreeSlot(pci_reservations, reserve=True)
1095

    
1096
    # Add id to ballon and place to the first available slot (3 or 4)
1097
    addr = _GetFreeSlot(pci_reservations, reserve=True)
1098
    pci_info = ",bus=pci.0,addr=%s" % hex(addr)
1099
    kvm_cmd.extend(["-balloon", "virtio,id=balloon%s" % pci_info])
1100
    kvm_cmd.extend(["-daemonize"])
1101
    if not instance.hvparams[constants.HV_ACPI]:
1102
      kvm_cmd.extend(["-no-acpi"])
1103
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1104
        constants.INSTANCE_REBOOT_EXIT:
1105
      kvm_cmd.extend(["-no-reboot"])
1106

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

    
1129
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1130
    if kernel_path:
1131
      boot_cdrom = boot_floppy = boot_network = False
1132
    else:
1133
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1134
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1135
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1136

    
1137
    if startup_paused:
1138
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1139

    
1140
    if boot_network:
1141
      kvm_cmd.extend(["-boot", "n"])
1142

    
1143
    disk_type = hvp[constants.HV_DISK_TYPE]
1144

    
1145
    # Now we can specify a different device type for CDROM devices.
1146
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1147
    if not cdrom_disk_type:
1148
      cdrom_disk_type = disk_type
1149

    
1150
    cdrom_image1 = hvp[constants.HV_CDROM_IMAGE_PATH]
1151
    if cdrom_image1:
1152
      needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1153
      self._CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image1, boot_cdrom,
1154
                        needs_boot_flag)
1155

    
1156
    cdrom_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1157
    if cdrom_image2:
1158
      self._CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image2, False, False)
1159

    
1160
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1161
    if floppy_image:
1162
      options = ",format=raw,media=disk"
1163
      if boot_floppy:
1164
        kvm_cmd.extend(["-boot", "a"])
1165
        options = "%s,boot=on" % options
1166
      if_val = ",if=floppy"
1167
      options = "%s%s" % (options, if_val)
1168
      drive_val = "file=%s%s" % (floppy_image, options)
1169
      kvm_cmd.extend(["-drive", drive_val])
1170

    
1171
    if kernel_path:
1172
      kvm_cmd.extend(["-kernel", kernel_path])
1173
      initrd_path = hvp[constants.HV_INITRD_PATH]
1174
      if initrd_path:
1175
        kvm_cmd.extend(["-initrd", initrd_path])
1176
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1177
                     hvp[constants.HV_KERNEL_ARGS]]
1178
      if hvp[constants.HV_SERIAL_CONSOLE]:
1179
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1180
        root_append.append("console=ttyS0,%s" % serial_speed)
1181
      kvm_cmd.extend(["-append", " ".join(root_append)])
1182

    
1183
    mem_path = hvp[constants.HV_MEM_PATH]
1184
    if mem_path:
1185
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1186

    
1187
    monitor_dev = ("unix:%s,server,nowait" %
1188
                   self._InstanceMonitor(instance.name))
1189
    kvm_cmd.extend(["-monitor", monitor_dev])
1190
    if hvp[constants.HV_SERIAL_CONSOLE]:
1191
      serial_dev = ("unix:%s,server,nowait" %
1192
                    self._InstanceSerial(instance.name))
1193
      kvm_cmd.extend(["-serial", serial_dev])
1194
    else:
1195
      kvm_cmd.extend(["-serial", "none"])
1196

    
1197
    mouse_type = hvp[constants.HV_USB_MOUSE]
1198
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1199
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1200
    spice_ip_version = None
1201

    
1202
    kvm_cmd.extend(["-usb"])
1203

    
1204
    if mouse_type:
1205
      kvm_cmd.extend(["-usbdevice", mouse_type])
1206
    elif vnc_bind_address:
1207
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1208

    
1209
    if vnc_bind_address:
1210
      if netutils.IsValidInterface(vnc_bind_address):
1211
        if_addresses = netutils.GetInterfaceIpAddresses(vnc_bind_address)
1212
        if_ip4_addresses = if_addresses[constants.IP4_VERSION]
1213
        if len(if_ip4_addresses) < 1:
1214
          logging.error("Could not determine IPv4 address of interface %s",
1215
                        vnc_bind_address)
1216
        else:
1217
          vnc_bind_address = if_ip4_addresses[0]
1218
      if netutils.IP4Address.IsValid(vnc_bind_address):
1219
        if instance.network_port > constants.VNC_BASE_PORT:
1220
          display = instance.network_port - constants.VNC_BASE_PORT
1221
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1222
            vnc_arg = ":%d" % (display)
1223
          else:
1224
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1225
        else:
1226
          logging.error("Network port is not a valid VNC display (%d < %d),"
1227
                        " not starting VNC",
1228
                        instance.network_port, constants.VNC_BASE_PORT)
1229
          vnc_arg = "none"
1230

    
1231
        # Only allow tls and other option when not binding to a file, for now.
1232
        # kvm/qemu gets confused otherwise about the filename to use.
1233
        vnc_append = ""
1234
        if hvp[constants.HV_VNC_TLS]:
1235
          vnc_append = "%s,tls" % vnc_append
1236
          if hvp[constants.HV_VNC_X509_VERIFY]:
1237
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1238
                                               hvp[constants.HV_VNC_X509])
1239
          elif hvp[constants.HV_VNC_X509]:
1240
            vnc_append = "%s,x509=%s" % (vnc_append,
1241
                                         hvp[constants.HV_VNC_X509])
1242
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1243
          vnc_append = "%s,password" % vnc_append
1244

    
1245
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1246

    
1247
      else:
1248
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1249

    
1250
      kvm_cmd.extend(["-vnc", vnc_arg])
1251
    elif spice_bind:
1252
      # FIXME: this is wrong here; the iface ip address differs
1253
      # between systems, so it should be done in _ExecuteKVMRuntime
1254
      if netutils.IsValidInterface(spice_bind):
1255
        # The user specified a network interface, we have to figure out the IP
1256
        # address.
1257
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1258
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1259

    
1260
        # if the user specified an IP version and the interface does not
1261
        # have that kind of IP addresses, throw an exception
1262
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1263
          if not addresses[spice_ip_version]:
1264
            raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1265
                                         " for %s" % (spice_ip_version,
1266
                                                      spice_bind))
1267

    
1268
        # the user did not specify an IP version, we have to figure it out
1269
        elif (addresses[constants.IP4_VERSION] and
1270
              addresses[constants.IP6_VERSION]):
1271
          # we have both ipv4 and ipv6, let's use the cluster default IP
1272
          # version
1273
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1274
          spice_ip_version = \
1275
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1276
        elif addresses[constants.IP4_VERSION]:
1277
          spice_ip_version = constants.IP4_VERSION
1278
        elif addresses[constants.IP6_VERSION]:
1279
          spice_ip_version = constants.IP6_VERSION
1280
        else:
1281
          raise errors.HypervisorError("SPICE: Unable to get an IP address"
1282
                                       " for %s" % (spice_bind))
1283

    
1284
        spice_address = addresses[spice_ip_version][0]
1285

    
1286
      else:
1287
        # spice_bind is known to be a valid IP address, because
1288
        # ValidateParameters checked it.
1289
        spice_address = spice_bind
1290

    
1291
      spice_arg = "addr=%s" % spice_address
1292
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1293
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1294
                     (spice_arg, instance.network_port,
1295
                      pathutils.SPICE_CACERT_FILE))
1296
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1297
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1298
                      pathutils.SPICE_CERT_FILE))
1299
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1300
        if tls_ciphers:
1301
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1302
      else:
1303
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1304

    
1305
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1306
        spice_arg = "%s,disable-ticketing" % spice_arg
1307

    
1308
      if spice_ip_version:
1309
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1310

    
1311
      # Image compression options
1312
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1313
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1314
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1315
      if img_lossless:
1316
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1317
      if img_jpeg:
1318
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1319
      if img_zlib_glz:
1320
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1321

    
1322
      # Video stream detection
1323
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1324
      if video_streaming:
1325
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1326

    
1327
      # Audio compression, by default in qemu-kvm it is on
1328
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1329
        spice_arg = "%s,playback-compression=off" % spice_arg
1330
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1331
        spice_arg = "%s,agent-mouse=off" % spice_arg
1332
      else:
1333
        # Enable the spice agent communication channel between the host and the
1334
        # agent.
1335
        addr = _GetFreeSlot(pci_reservations, reserve=True)
1336
        pci_info = ",bus=pci.0,addr=%s" % hex(addr)
1337
        kvm_cmd.extend(["-device", "virtio-serial-pci,id=spice%s" % pci_info])
1338
        kvm_cmd.extend([
1339
          "-device",
1340
          "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1341
          ])
1342
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1343

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

    
1347
    else:
1348
      # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1349
      # also works in earlier versions though (tested with 1.1 and 1.3)
1350
      if self._DISPLAY_RE.search(kvmhelp):
1351
        kvm_cmd.extend(["-display", "none"])
1352
      else:
1353
        kvm_cmd.extend(["-nographic"])
1354

    
1355
    if hvp[constants.HV_USE_LOCALTIME]:
1356
      kvm_cmd.extend(["-localtime"])
1357

    
1358
    if hvp[constants.HV_KVM_USE_CHROOT]:
1359
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1360

    
1361
    # Add qemu-KVM -cpu param
1362
    if hvp[constants.HV_CPU_TYPE]:
1363
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1364

    
1365
    # Pass a -vga option if requested, or if spice is used, for backwards
1366
    # compatibility.
1367
    if hvp[constants.HV_VGA]:
1368
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1369
    elif spice_bind:
1370
      kvm_cmd.extend(["-vga", "qxl"])
1371

    
1372
    # Various types of usb devices, comma separated
1373
    if hvp[constants.HV_USB_DEVICES]:
1374
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1375
        kvm_cmd.extend(["-usbdevice", dev])
1376

    
1377
    # Set system UUID to instance UUID
1378
    if self._UUID_RE.search(kvmhelp):
1379
      kvm_cmd.extend(["-uuid", instance.uuid])
1380

    
1381
    if hvp[constants.HV_KVM_EXTRA]:
1382
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1383

    
1384
    kvm_disks = []
1385
    for disk, link_name, uri in block_devices:
1386
      disk.pci = _GetFreeSlot(pci_reservations, disk.pci, True)
1387
      kvm_disks.append((disk, link_name, uri))
1388

    
1389
    kvm_nics = []
1390
    for nic in instance.nics:
1391
      nic.pci = _GetFreeSlot(pci_reservations, nic.pci, True)
1392
      kvm_nics.append(nic)
1393

    
1394
    hvparams = hvp
1395

    
1396
    return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1397

    
1398
  def _WriteKVMRuntime(self, instance_name, data):
1399
    """Write an instance's KVM runtime
1400

1401
    """
1402
    try:
1403
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1404
                      data=data)
1405
    except EnvironmentError, err:
1406
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1407

    
1408
  def _ReadKVMRuntime(self, instance_name):
1409
    """Read an instance's KVM runtime
1410

1411
    """
1412
    try:
1413
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1414
    except EnvironmentError, err:
1415
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1416
    return file_content
1417

    
1418
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1419
    """Save an instance's KVM runtime
1420

1421
    """
1422
    kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1423

    
1424
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1425
    serialized_disks = [(blk.ToDict(), link, uri)
1426
                        for blk, link, uri in kvm_disks]
1427
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1428
                                      serialized_disks))
1429

    
1430
    self._WriteKVMRuntime(instance.name, serialized_form)
1431

    
1432
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1433
    """Load an instance's KVM runtime
1434

1435
    """
1436
    if not serialized_runtime:
1437
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1438

    
1439
    return _AnalyzeSerializedRuntime(serialized_runtime)
1440

    
1441
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1442
    """Run the KVM cmd and check for errors
1443

1444
    @type name: string
1445
    @param name: instance name
1446
    @type kvm_cmd: list of strings
1447
    @param kvm_cmd: runcmd input for kvm
1448
    @type tap_fds: list of int
1449
    @param tap_fds: fds of tap devices opened by Ganeti
1450

1451
    """
1452
    try:
1453
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1454
    finally:
1455
      for fd in tap_fds:
1456
        utils_wrapper.CloseFdNoError(fd)
1457

    
1458
    if result.failed:
1459
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1460
                                   (name, result.fail_reason, result.output))
1461
    if not self._InstancePidAlive(name)[2]:
1462
      raise errors.HypervisorError("Failed to start instance %s" % name)
1463

    
1464
  @staticmethod
1465
  def _GenerateTapName(nic):
1466
    """Generate a TAP network interface name for a NIC.
1467

1468
    This helper function generates a special TAP network interface
1469
    name for NICs that are meant to be used in instance communication.
1470
    This function checks the existing TAP interfaces in order to find
1471
    a unique name for the new TAP network interface.  The TAP network
1472
    interface names are of the form 'gnt.com.%d', where '%d' is a
1473
    unique number within the node.
1474

1475
    @type nic: ganeti.objects.NIC
1476
    @param nic: NIC object for the name should be generated
1477

1478
    @rtype: string
1479
    @return: TAP network interface name, or the empty string if the
1480
             NIC is not used in instance communication
1481

1482
    """
1483
    if nic.name is None or not \
1484
          nic.name.startswith(constants.INSTANCE_COMMUNICATION_NIC_PREFIX):
1485
      return ""
1486

    
1487
    result = utils.RunCmd(["ip", "tuntap", "list"])
1488

    
1489
    if result.failed:
1490
      raise errors.HypervisorError("Failed to list TUN/TAP interfaces")
1491

    
1492
    idxs = set()
1493

    
1494
    for line in result.output.splitlines():
1495
      parts = line.split(": ", 1)
1496

    
1497
      if len(parts) < 2:
1498
        raise errors.HypervisorError("Failed to parse TUN/TAP interfaces")
1499

    
1500
      r = re.match(r"gnt\.com\.([0-9]+)", parts[0])
1501

    
1502
      if r is not None:
1503
        idxs.add(int(r.group(1)))
1504

    
1505
    if idxs:
1506
      idx = max(idxs) + 1
1507
    else:
1508
      idx = 0
1509

    
1510
    return "gnt.com.%d" % idx
1511

    
1512
  # too many local variables
1513
  # pylint: disable=R0914
1514
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1515
    """Execute a KVM cmd, after completing it with some last minute data.
1516

1517
    @type incoming: tuple of strings
1518
    @param incoming: (target_host_ip, port)
1519
    @type kvmhelp: string
1520
    @param kvmhelp: output of kvm --help
1521

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

    
1535
    self._ClearUserShutdown(instance.name)
1536
    self._StartKvmd(instance.hvparams)
1537

    
1538
    temp_files = []
1539

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

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

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

    
1561
    # We have reasons to believe changing something like the nic driver/type
1562
    # upon migration won't exactly fly with the instance kernel, so for nic
1563
    # related parameters we'll use up_hvp
1564
    tapfds = []
1565
    taps = []
1566
    devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1567
    if not kvm_nics:
1568
      kvm_cmd.extend(["-net", "none"])
1569
    else:
1570
      vnet_hdr = False
1571
      tap_extra = ""
1572
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1573
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1574
        nic_model = self._VIRTIO
1575
        try:
1576
          if self._VIRTIO_NET_RE.search(devlist):
1577
            nic_model = self._VIRTIO_NET_PCI
1578
            vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1579
        except errors.HypervisorError, _:
1580
          # Older versions of kvm don't support DEVICE_LIST, but they don't
1581
          # have new virtio syntax either.
1582
          pass
1583

    
1584
        if up_hvp[constants.HV_VHOST_NET]:
1585
          # check for vhost_net support
1586
          if self._VHOST_RE.search(kvmhelp):
1587
            tap_extra = ",vhost=on"
1588
          else:
1589
            raise errors.HypervisorError("vhost_net is configured"
1590
                                         " but it is not available")
1591
      else:
1592
        nic_model = nic_type
1593

    
1594
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1595

    
1596
      for nic_seq, nic in enumerate(kvm_nics):
1597
        tapname, tapfd = OpenTap(vnet_hdr=vnet_hdr,
1598
                                 name=self._GenerateTapName(nic))
1599
        tapfds.append(tapfd)
1600
        taps.append(tapname)
1601
        if kvm_supports_netdev:
1602
          nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1603
          try:
1604
            # kvm_nics already exist in old runtime files and thus there might
1605
            # be some entries without pci slot (therefore try: except:)
1606
            kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1607
            netdev = kvm_devid
1608
            nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1609
          except errors.HotplugError:
1610
            netdev = "netdev%d" % nic_seq
1611
          nic_val += (",netdev=%s" % netdev)
1612
          tap_val = ("type=tap,id=%s,fd=%d%s" %
1613
                     (netdev, tapfd, tap_extra))
1614
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1615
        else:
1616
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1617
                                                         nic.mac, nic_model)
1618
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1619
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1620

    
1621
    if incoming:
1622
      target, port = incoming
1623
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1624

    
1625
    # Changing the vnc password doesn't bother the guest that much. At most it
1626
    # will surprise people who connect to it. Whether positively or negatively
1627
    # it's debatable.
1628
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1629
    vnc_pwd = None
1630
    if vnc_pwd_file:
1631
      try:
1632
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1633
      except EnvironmentError, err:
1634
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1635
                                     % (vnc_pwd_file, err))
1636

    
1637
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1638
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1639
                         constants.SECURE_DIR_MODE)])
1640

    
1641
    # Automatically enable QMP if version is >= 0.14
1642
    if self._QMP_RE.search(kvmhelp):
1643
      logging.debug("Enabling QMP")
1644
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1645
                      self._InstanceQmpMonitor(instance.name)])
1646

    
1647
    # Configure the network now for starting instances and bridged interfaces,
1648
    # during FinalizeMigration for incoming instances' routed interfaces
1649
    for nic_seq, nic in enumerate(kvm_nics):
1650
      if (incoming and
1651
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1652
        continue
1653
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1654

    
1655
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1656
                                                     up_hvp,
1657
                                                     kvm_disks,
1658
                                                     kvmhelp,
1659
                                                     devlist)
1660
    kvm_cmd.extend(bdev_opts)
1661
    # CPU affinity requires kvm to start paused, so we set this flag if the
1662
    # instance is not already paused and if we are not going to accept a
1663
    # migrating instance. In the latter case, pausing is not needed.
1664
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1665
    if start_kvm_paused:
1666
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1667

    
1668
    # Note: CPU pinning is using up_hvp since changes take effect
1669
    # during instance startup anyway, and to avoid problems when soft
1670
    # rebooting the instance.
1671
    cpu_pinning = False
1672
    if up_hvp.get(constants.HV_CPU_MASK, None):
1673
      cpu_pinning = True
1674

    
1675
    if security_model == constants.HT_SM_POOL:
1676
      ss = ssconf.SimpleStore()
1677
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1678
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1679
      uid = uidpool.RequestUnusedUid(all_uids)
1680
      try:
1681
        username = pwd.getpwuid(uid.GetUid()).pw_name
1682
        kvm_cmd.extend(["-runas", username])
1683
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1684
      except:
1685
        uidpool.ReleaseUid(uid)
1686
        raise
1687
      else:
1688
        uid.Unlock()
1689
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1690
    else:
1691
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1692

    
1693
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1694
                     constants.RUN_DIRS_MODE)])
1695
    for nic_seq, tap in enumerate(taps):
1696
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1697
                      data=tap)
1698

    
1699
    if vnc_pwd:
1700
      change_cmd = "change vnc password %s" % vnc_pwd
1701
      self._CallMonitorCommand(instance.name, change_cmd)
1702

    
1703
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1704
    # connection attempts because SPICE by default does not allow connections
1705
    # if neither a password nor the "disable_ticketing" options are specified.
1706
    # As soon as we send the password via QMP, that password is a valid ticket
1707
    # for connection.
1708
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1709
    if spice_password_file:
1710
      spice_pwd = ""
1711
      try:
1712
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1713
      except EnvironmentError, err:
1714
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1715
                                     % (spice_password_file, err))
1716

    
1717
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1718
      qmp.connect()
1719
      arguments = {
1720
          "protocol": "spice",
1721
          "password": spice_pwd,
1722
      }
1723
      qmp.Execute("set_password", arguments)
1724

    
1725
    for filename in temp_files:
1726
      utils.RemoveFile(filename)
1727

    
1728
    # If requested, set CPU affinity and resume instance execution
1729
    if cpu_pinning:
1730
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1731

    
1732
    start_memory = self._InstanceStartupMemory(instance)
1733
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1734
      self.BalloonInstanceMemory(instance, start_memory)
1735

    
1736
    if start_kvm_paused:
1737
      # To control CPU pinning, ballooning, and vnc/spice passwords
1738
      # the VM was started in a frozen state. If freezing was not
1739
      # explicitly requested resume the vm status.
1740
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1741

    
1742
  @staticmethod
1743
  def _StartKvmd(hvparams):
1744
    """Ensure that the Kvm daemon is running.
1745

1746
    """
1747
    if hvparams is None \
1748
          or not hvparams[constants.HV_KVM_USER_SHUTDOWN] \
1749
          or utils.IsDaemonAlive(constants.KVMD):
1750
      return
1751

    
1752
    result = utils.RunCmd(constants.KVMD)
1753

    
1754
    if result.failed:
1755
      raise errors.HypervisorError("Failed to start KVM daemon")
1756

    
1757
  def StartInstance(self, instance, block_devices, startup_paused):
1758
    """Start an instance.
1759

1760
    """
1761
    self._CheckDown(instance.name)
1762
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1763
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1764
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1765
                                           startup_paused, kvmhelp)
1766
    self._SaveKVMRuntime(instance, kvm_runtime)
1767
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1768

    
1769
  @classmethod
1770
  def _CallMonitorCommand(cls, instance_name, command, timeout=None):
1771
    """Invoke a command on the instance monitor.
1772

1773
    """
1774
    if timeout is not None:
1775
      timeout_cmd = "timeout %s" % (timeout, )
1776
    else:
1777
      timeout_cmd = ""
1778

    
1779
    # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1780
    # version. The monitor protocol is designed for human consumption, whereas
1781
    # QMP is made for programmatic usage. In the worst case QMP can also
1782
    # execute monitor commands. As it is, all calls to socat take at least
1783
    # 500ms and likely more: socat can't detect the end of the reply and waits
1784
    # for 500ms of no data received before exiting (500 ms is the default for
1785
    # the "-t" parameter).
1786
    socat = ("echo %s | %s %s STDIO UNIX-CONNECT:%s" %
1787
             (utils.ShellQuote(command),
1788
              timeout_cmd,
1789
              constants.SOCAT_PATH,
1790
              utils.ShellQuote(cls._InstanceMonitor(instance_name))))
1791
    result = utils.RunCmd(socat)
1792
    if result.failed:
1793
      msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1794
             " output: %s" %
1795
             (command, instance_name, result.fail_reason, result.output))
1796
      raise errors.HypervisorError(msg)
1797

    
1798
    return result
1799

    
1800
  def _GetFreePCISlot(self, instance, dev):
1801
    """Get the first available pci slot of a runnung instance.
1802

1803
    """
1804
    slots = bitarray(32)
1805
    slots.setall(False) # pylint: disable=E1101
1806
    output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
1807
    for line in output.stdout.splitlines():
1808
      match = self._INFO_PCI_RE.search(line)
1809
      if match:
1810
        slot = int(match.group(1))
1811
        slots[slot] = True
1812

    
1813
    dev.pci = _GetFreeSlot(slots)
1814

    
1815
  def VerifyHotplugSupport(self, instance, action, dev_type):
1816
    """Verifies that hotplug is supported.
1817

1818
    Hotplug is *not* supported in case of:
1819
     - security models and chroot (disk hotplug)
1820
     - fdsend module is missing (nic hot-add)
1821

1822
    @raise errors.HypervisorError: in one of the previous cases
1823

1824
    """
1825
    if dev_type == constants.HOTPLUG_TARGET_DISK:
1826
      hvp = instance.hvparams
1827
      security_model = hvp[constants.HV_SECURITY_MODEL]
1828
      use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
1829
      if use_chroot:
1830
        raise errors.HotplugError("Disk hotplug is not supported"
1831
                                  " in case of chroot.")
1832
      if security_model != constants.HT_SM_NONE:
1833
        raise errors.HotplugError("Disk Hotplug is not supported in case"
1834
                                  " security models are used.")
1835

    
1836
    if (dev_type == constants.HOTPLUG_TARGET_NIC and
1837
        action == constants.HOTPLUG_ACTION_ADD and not fdsend):
1838
      raise errors.HotplugError("Cannot hot-add NIC."
1839
                                " fdsend python module is missing.")
1840

    
1841
  def HotplugSupported(self, instance):
1842
    """Checks if hotplug is generally supported.
1843

1844
    Hotplug is *not* supported in case of:
1845
     - qemu versions < 1.0
1846
     - for stopped instances
1847

1848
    @raise errors.HypervisorError: in one of the previous cases
1849

1850
    """
1851
    try:
1852
      output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
1853
    except errors.HypervisorError:
1854
      raise errors.HotplugError("Instance is probably down")
1855

    
1856
    # TODO: search for netdev_add, drive_add, device_add.....
1857
    match = self._INFO_VERSION_RE.search(output.stdout)
1858
    if not match:
1859
      raise errors.HotplugError("Cannot parse qemu version via monitor")
1860

    
1861
    v_major, v_min, _, _ = match.groups()
1862
    if (int(v_major), int(v_min)) < (1, 0):
1863
      raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
1864

    
1865
  def _CallHotplugCommands(self, name, cmds):
1866
    for c in cmds:
1867
      self._CallMonitorCommand(name, c)
1868
      time.sleep(1)
1869

    
1870
  def _VerifyHotplugCommand(self, instance_name, device, dev_type,
1871
                            should_exist):
1872
    """Checks if a previous hotplug command has succeeded.
1873

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

1877
    @raise errors.HypervisorError: if result is not the expected one
1878

1879
    """
1880
    output = self._CallMonitorCommand(instance_name, self._INFO_PCI_CMD)
1881
    kvm_devid = _GenerateDeviceKVMId(dev_type, device)
1882
    match = \
1883
      self._FIND_PCI_DEVICE_RE(device.pci, kvm_devid).search(output.stdout)
1884
    if match and not should_exist:
1885
      msg = "Device %s should have been removed but is still there" % kvm_devid
1886
      raise errors.HypervisorError(msg)
1887

    
1888
    if not match and should_exist:
1889
      msg = "Device %s should have been added but is missing" % kvm_devid
1890
      raise errors.HypervisorError(msg)
1891

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

    
1894
  def HotAddDevice(self, instance, dev_type, device, extra, seq):
1895
    """ Helper method to hot-add a new device
1896

1897
    It gets free pci slot generates the device name and invokes the
1898
    device specific method.
1899

1900
    """
1901
    # in case of hot-mod this is given
1902
    if device.pci is None:
1903
      self._GetFreePCISlot(instance, device)
1904
    kvm_devid = _GenerateDeviceKVMId(dev_type, device)
1905
    runtime = self._LoadKVMRuntime(instance)
1906
    if dev_type == constants.HOTPLUG_TARGET_DISK:
1907
      cmds = ["drive_add dummy file=%s,if=none,id=%s,format=raw" %
1908
                (extra, kvm_devid)]
1909
      cmds += ["device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
1910
                (hex(device.pci), kvm_devid, kvm_devid)]
1911
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
1912
      (tap, fd) = OpenTap()
1913
      self._ConfigureNIC(instance, seq, device, tap)
1914
      self._PassTapFd(instance, fd, device)
1915
      cmds = ["netdev_add tap,id=%s,fd=%s" % (kvm_devid, kvm_devid)]
1916
      args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
1917
               (hex(device.pci), device.mac, kvm_devid, kvm_devid)
1918
      cmds += ["device_add %s" % args]
1919
      utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
1920

    
1921
    self._CallHotplugCommands(instance.name, cmds)
1922
    self._VerifyHotplugCommand(instance.name, device, dev_type, True)
1923
    # update relevant entries in runtime file
1924
    index = _DEVICE_RUNTIME_INDEX[dev_type]
1925
    entry = _RUNTIME_ENTRY[dev_type](device, extra)
1926
    runtime[index].append(entry)
1927
    self._SaveKVMRuntime(instance, runtime)
1928

    
1929
  def HotDelDevice(self, instance, dev_type, device, _, seq):
1930
    """ Helper method for hot-del device
1931

1932
    It gets device info from runtime file, generates the device name and
1933
    invokes the device specific method.
1934

1935
    """
1936
    runtime = self._LoadKVMRuntime(instance)
1937
    entry = _GetExistingDeviceInfo(dev_type, device, runtime)
1938
    kvm_device = _RUNTIME_DEVICE[dev_type](entry)
1939
    kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
1940
    if dev_type == constants.HOTPLUG_TARGET_DISK:
1941
      cmds = ["device_del %s" % kvm_devid]
1942
      cmds += ["drive_del %s" % kvm_devid]
1943
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
1944
      cmds = ["device_del %s" % kvm_devid]
1945
      cmds += ["netdev_del %s" % kvm_devid]
1946
      utils.RemoveFile(self._InstanceNICFile(instance.name, seq))
1947
    self._CallHotplugCommands(instance.name, cmds)
1948
    self._VerifyHotplugCommand(instance.name, kvm_device, dev_type, False)
1949
    index = _DEVICE_RUNTIME_INDEX[dev_type]
1950
    runtime[index].remove(entry)
1951
    self._SaveKVMRuntime(instance, runtime)
1952

    
1953
    return kvm_device.pci
1954

    
1955
  def HotModDevice(self, instance, dev_type, device, _, seq):
1956
    """ Helper method for hot-mod device
1957

1958
    It gets device info from runtime file, generates the device name and
1959
    invokes the device specific method. Currently only NICs support hot-mod
1960

1961
    """
1962
    if dev_type == constants.HOTPLUG_TARGET_NIC:
1963
      # putting it back in the same pci slot
1964
      device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
1965
      self.HotAddDevice(instance, dev_type, device, _, seq)
1966

    
1967
  def _PassTapFd(self, instance, fd, nic):
1968
    """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
1969

1970
    """
1971
    # TODO: factor out code related to unix sockets.
1972
    #       squash common parts between monitor and qmp
1973
    kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1974
    command = "getfd %s\n" % kvm_devid
1975
    fds = [fd]
1976
    logging.info("%s", fds)
1977
    try:
1978
      monsock = MonitorSocket(self._InstanceMonitor(instance.name))
1979
      monsock.connect()
1980
      fdsend.sendfds(monsock.sock, command, fds=fds)
1981
    finally:
1982
      monsock.close()
1983

    
1984
  @classmethod
1985
  def _ParseKVMVersion(cls, text):
1986
    """Parse the KVM version from the --help output.
1987

1988
    @type text: string
1989
    @param text: output of kvm --help
1990
    @return: (version, v_maj, v_min, v_rev)
1991
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1992

1993
    """
1994
    match = cls._VERSION_RE.search(text.splitlines()[0])
1995
    if not match:
1996
      raise errors.HypervisorError("Unable to get KVM version")
1997

    
1998
    v_all = match.group(0)
1999
    v_maj = int(match.group(1))
2000
    v_min = int(match.group(2))
2001
    if match.group(4):
2002
      v_rev = int(match.group(4))
2003
    else:
2004
      v_rev = 0
2005
    return (v_all, v_maj, v_min, v_rev)
2006

    
2007
  @classmethod
2008
  def _GetKVMOutput(cls, kvm_path, option):
2009
    """Return the output of a kvm invocation
2010

2011
    @type kvm_path: string
2012
    @param kvm_path: path to the kvm executable
2013
    @type option: a key of _KVMOPTS_CMDS
2014
    @param option: kvm option to fetch the output from
2015
    @return: output a supported kvm invocation
2016
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2017

2018
    """
2019
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2020

    
2021
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
2022

    
2023
    result = utils.RunCmd([kvm_path] + optlist)
2024
    if result.failed and not can_fail:
2025
      raise errors.HypervisorError("Unable to get KVM %s output" %
2026
                                    " ".join(optlist))
2027
    return result.output
2028

    
2029
  @classmethod
2030
  def _GetKVMVersion(cls, kvm_path):
2031
    """Return the installed KVM version.
2032

2033
    @return: (version, v_maj, v_min, v_rev)
2034
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2035

2036
    """
2037
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2038

    
2039
  @classmethod
2040
  def _GetDefaultMachineVersion(cls, kvm_path):
2041
    """Return the default hardware revision (e.g. pc-1.1)
2042

2043
    """
2044
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2045
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2046
    if match:
2047
      return match.group(1)
2048
    else:
2049
      return "pc"
2050

    
2051
  @classmethod
2052
  def _StopInstance(cls, instance, force=False, name=None, timeout=None):
2053
    """Stop an instance.
2054

2055
    """
2056
    assert(timeout is None or force is not None)
2057

    
2058
    if name is not None and not force:
2059
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2060
    if name is None:
2061
      name = instance.name
2062
      acpi = instance.hvparams[constants.HV_ACPI]
2063
    else:
2064
      acpi = False
2065
    _, pid, alive = cls._InstancePidAlive(name)
2066
    if pid > 0 and alive:
2067
      if force or not acpi:
2068
        utils.KillProcess(pid)
2069
      else:
2070
        cls._CallMonitorCommand(name, "system_powerdown", timeout)
2071
    cls._ClearUserShutdown(instance.name)
2072

    
2073
  def StopInstance(self, instance, force=False, retry=False, name=None,
2074
                   timeout=None):
2075
    """Stop an instance.
2076

2077
    """
2078
    self._StopInstance(instance, force, name=name, timeout=timeout)
2079

    
2080
  def CleanupInstance(self, instance_name):
2081
    """Cleanup after a stopped instance
2082

2083
    """
2084
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
2085
    if pid > 0 and alive:
2086
      raise errors.HypervisorError("Cannot cleanup a live instance")
2087
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2088
    self._ClearUserShutdown(instance_name)
2089

    
2090
  def RebootInstance(self, instance):
2091
    """Reboot an instance.
2092

2093
    """
2094
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2095
    # socket the instance will stop, but now power up again. So we'll resort
2096
    # to shutdown and restart.
2097
    _, _, alive = self._InstancePidAlive(instance.name)
2098
    if not alive:
2099
      raise errors.HypervisorError("Failed to reboot instance %s:"
2100
                                   " not running" % instance.name)
2101
    # StopInstance will delete the saved KVM runtime so:
2102
    # ...first load it...
2103
    kvm_runtime = self._LoadKVMRuntime(instance)
2104
    # ...now we can safely call StopInstance...
2105
    if not self.StopInstance(instance):
2106
      self.StopInstance(instance, force=True)
2107
    # ...and finally we can save it again, and execute it...
2108
    self._SaveKVMRuntime(instance, kvm_runtime)
2109
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2110
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2111
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2112

    
2113
  def MigrationInfo(self, instance):
2114
    """Get instance information to perform a migration.
2115

2116
    @type instance: L{objects.Instance}
2117
    @param instance: instance to be migrated
2118
    @rtype: string
2119
    @return: content of the KVM runtime file
2120

2121
    """
2122
    return self._ReadKVMRuntime(instance.name)
2123

    
2124
  def AcceptInstance(self, instance, info, target):
2125
    """Prepare to accept an instance.
2126

2127
    @type instance: L{objects.Instance}
2128
    @param instance: instance to be accepted
2129
    @type info: string
2130
    @param info: content of the KVM runtime file on the source node
2131
    @type target: string
2132
    @param target: target host (usually ip), on this node
2133

2134
    """
2135
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2136
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2137
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2138
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2139
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2140
                            incoming=incoming_address)
2141

    
2142
  def FinalizeMigrationDst(self, instance, info, success):
2143
    """Finalize the instance migration on the target node.
2144

2145
    Stop the incoming mode KVM.
2146

2147
    @type instance: L{objects.Instance}
2148
    @param instance: instance whose migration is being finalized
2149

2150
    """
2151
    if success:
2152
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2153
      kvm_nics = kvm_runtime[1]
2154

    
2155
      for nic_seq, nic in enumerate(kvm_nics):
2156
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2157
          # Bridged interfaces have already been configured
2158
          continue
2159
        try:
2160
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2161
        except EnvironmentError, err:
2162
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
2163
                          instance.name, nic_seq, str(err))
2164
          continue
2165
        try:
2166
          self._ConfigureNIC(instance, nic_seq, nic, tap)
2167
        except errors.HypervisorError, err:
2168
          logging.warning(str(err))
2169

    
2170
      self._WriteKVMRuntime(instance.name, info)
2171
    else:
2172
      self.StopInstance(instance, force=True)
2173

    
2174
  def MigrateInstance(self, cluster_name, instance, target, live):
2175
    """Migrate an instance to a target node.
2176

2177
    The migration will not be attempted if the instance is not
2178
    currently running.
2179

2180
    @type cluster_name: string
2181
    @param cluster_name: name of the cluster
2182
    @type instance: L{objects.Instance}
2183
    @param instance: the instance to be migrated
2184
    @type target: string
2185
    @param target: ip address of the target node
2186
    @type live: boolean
2187
    @param live: perform a live migration
2188

2189
    """
2190
    instance_name = instance.name
2191
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
2192
    _, _, alive = self._InstancePidAlive(instance_name)
2193
    if not alive:
2194
      raise errors.HypervisorError("Instance not running, cannot migrate")
2195

    
2196
    if not live:
2197
      self._CallMonitorCommand(instance_name, "stop")
2198

    
2199
    migrate_command = ("migrate_set_speed %dm" %
2200
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2201
    self._CallMonitorCommand(instance_name, migrate_command)
2202

    
2203
    migrate_command = ("migrate_set_downtime %dms" %
2204
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2205
    self._CallMonitorCommand(instance_name, migrate_command)
2206

    
2207
    migration_caps = instance.hvparams[constants.HV_KVM_MIGRATION_CAPS]
2208
    if migration_caps:
2209
      for c in migration_caps.split(_MIGRATION_CAPS_DELIM):
2210
        migrate_command = ("migrate_set_capability %s on" % c)
2211
        self._CallMonitorCommand(instance_name, migrate_command)
2212

    
2213
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2214
    self._CallMonitorCommand(instance_name, migrate_command)
2215

    
2216
  def FinalizeMigrationSource(self, instance, success, live):
2217
    """Finalize the instance migration on the source node.
2218

2219
    @type instance: L{objects.Instance}
2220
    @param instance: the instance that was migrated
2221
    @type success: bool
2222
    @param success: whether the migration succeeded or not
2223
    @type live: bool
2224
    @param live: whether the user requested a live migration or not
2225

2226
    """
2227
    if success:
2228
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2229
      utils.KillProcess(pid)
2230
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2231
    elif live:
2232
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2233
    self._ClearUserShutdown(instance.name)
2234

    
2235
  def GetMigrationStatus(self, instance):
2236
    """Get the migration status
2237

2238
    @type instance: L{objects.Instance}
2239
    @param instance: the instance that is being migrated
2240
    @rtype: L{objects.MigrationStatus}
2241
    @return: the status of the current migration (one of
2242
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2243
             progress info that can be retrieved from the hypervisor
2244

2245
    """
2246
    info_command = "info migrate"
2247
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2248
      result = self._CallMonitorCommand(instance.name, info_command)
2249
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
2250
      if not match:
2251
        if not result.stdout:
2252
          logging.info("KVM: empty 'info migrate' result")
2253
        else:
2254
          logging.warning("KVM: unknown 'info migrate' result: %s",
2255
                          result.stdout)
2256
      else:
2257
        status = match.group(1)
2258
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2259
          migration_status = objects.MigrationStatus(status=status)
2260
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2261
          if match:
2262
            migration_status.transferred_ram = match.group("transferred")
2263
            migration_status.total_ram = match.group("total")
2264

    
2265
          return migration_status
2266

    
2267
        logging.warning("KVM: unknown migration status '%s'", status)
2268

    
2269
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2270

    
2271
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2272

    
2273
  def BalloonInstanceMemory(self, instance, mem):
2274
    """Balloon an instance memory to a certain value.
2275

2276
    @type instance: L{objects.Instance}
2277
    @param instance: instance to be accepted
2278
    @type mem: int
2279
    @param mem: actual memory size to use for instance runtime
2280

2281
    """
2282
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2283

    
2284
  def GetNodeInfo(self, hvparams=None):
2285
    """Return information about the node.
2286

2287
    @type hvparams: dict of strings
2288
    @param hvparams: hypervisor parameters, not used in this class
2289

2290
    @return: a dict as returned by L{BaseHypervisor.GetLinuxNodeInfo} plus
2291
        the following keys:
2292
          - hv_version: the hypervisor version in the form (major, minor,
2293
                        revision)
2294

2295
    """
2296
    result = self.GetLinuxNodeInfo()
2297
    kvmpath = constants.KVM_PATH
2298
    if hvparams is not None:
2299
      kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2300
    _, v_major, v_min, v_rev = self._GetKVMVersion(kvmpath)
2301
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2302
    return result
2303

    
2304
  @classmethod
2305
  def GetInstanceConsole(cls, instance, primary_node, node_group,
2306
                         hvparams, beparams):
2307
    """Return a command for connecting to the console of an instance.
2308

2309
    """
2310
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2311
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2312
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2313
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2314
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2315
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2316
      ndparams = node_group.FillND(primary_node)
2317
      return objects.InstanceConsole(instance=instance.name,
2318
                                     kind=constants.CONS_SSH,
2319
                                     host=primary_node.name,
2320
                                     port=ndparams.get(constants.ND_SSH_PORT),
2321
                                     user=constants.SSH_CONSOLE_USER,
2322
                                     command=cmd)
2323

    
2324
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2325
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2326
      display = instance.network_port - constants.VNC_BASE_PORT
2327
      return objects.InstanceConsole(instance=instance.name,
2328
                                     kind=constants.CONS_VNC,
2329
                                     host=vnc_bind_address,
2330
                                     port=instance.network_port,
2331
                                     display=display)
2332

    
2333
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2334
    if spice_bind:
2335
      return objects.InstanceConsole(instance=instance.name,
2336
                                     kind=constants.CONS_SPICE,
2337
                                     host=spice_bind,
2338
                                     port=instance.network_port)
2339

    
2340
    return objects.InstanceConsole(instance=instance.name,
2341
                                   kind=constants.CONS_MESSAGE,
2342
                                   message=("No serial shell for instance %s" %
2343
                                            instance.name))
2344

    
2345
  def Verify(self, hvparams=None):
2346
    """Verify the hypervisor.
2347

2348
    Check that the required binaries exist.
2349

2350
    @type hvparams: dict of strings
2351
    @param hvparams: hypervisor parameters to be verified against, not used here
2352

2353
    @return: Problem description if something is wrong, C{None} otherwise
2354

2355
    """
2356
    msgs = []
2357
    kvmpath = constants.KVM_PATH
2358
    if hvparams is not None:
2359
      kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2360
    if not os.path.exists(kvmpath):
2361
      msgs.append("The KVM binary ('%s') does not exist" % kvmpath)
2362
    if not os.path.exists(constants.SOCAT_PATH):
2363
      msgs.append("The socat binary ('%s') does not exist" %
2364
                  constants.SOCAT_PATH)
2365

    
2366
    return self._FormatVerifyResults(msgs)
2367

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

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

2376
    """
2377
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2378

    
2379
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2380
    if kernel_path:
2381
      if not hvparams[constants.HV_ROOT_PATH]:
2382
        raise errors.HypervisorError("Need a root partition for the instance,"
2383
                                     " if a kernel is defined")
2384

    
2385
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2386
        not hvparams[constants.HV_VNC_X509]):
2387
      raise errors.HypervisorError("%s must be defined, if %s is" %
2388
                                   (constants.HV_VNC_X509,
2389
                                    constants.HV_VNC_X509_VERIFY))
2390

    
2391
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2392
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2393
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2394
      if not serial_speed or serial_speed not in valid_speeds:
2395
        raise errors.HypervisorError("Invalid serial console speed, must be"
2396
                                     " one of: %s" %
2397
                                     utils.CommaJoin(valid_speeds))
2398

    
2399
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2400
    if (boot_order == constants.HT_BO_CDROM and
2401
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2402
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2403
                                   " ISO path")
2404

    
2405
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2406
    if security_model == constants.HT_SM_USER:
2407
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2408
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2409
                                     " must be specified")
2410
    elif (security_model == constants.HT_SM_NONE or
2411
          security_model == constants.HT_SM_POOL):
2412
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2413
        raise errors.HypervisorError("Cannot have a security domain when the"
2414
                                     " security model is 'none' or 'pool'")
2415

    
2416
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2417
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2418
    if spice_bind:
2419
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2420
        # if an IP version is specified, the spice_bind parameter must be an
2421
        # IP of that family
2422
        if (netutils.IP4Address.IsValid(spice_bind) and
2423
            spice_ip_version != constants.IP4_VERSION):
2424
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2425
                                       " the specified IP version is %s" %
2426
                                       (spice_bind, spice_ip_version))
2427

    
2428
        if (netutils.IP6Address.IsValid(spice_bind) and
2429
            spice_ip_version != constants.IP6_VERSION):
2430
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2431
                                       " the specified IP version is %s" %
2432
                                       (spice_bind, spice_ip_version))
2433
    else:
2434
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2435
      # error if any of them is set without it.
2436
      for param in _SPICE_ADDITIONAL_PARAMS:
2437
        if hvparams[param]:
2438
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2439
                                       (param, constants.HV_KVM_SPICE_BIND))
2440

    
2441
  @classmethod
2442
  def ValidateParameters(cls, hvparams):
2443
    """Check the given parameters for validity.
2444

2445
    @type hvparams:  dict
2446
    @param hvparams: dictionary with parameter names/value
2447
    @raise errors.HypervisorError: when a parameter is not valid
2448

2449
    """
2450
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2451

    
2452
    kvm_path = hvparams[constants.HV_KVM_PATH]
2453

    
2454
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2455
    if security_model == constants.HT_SM_USER:
2456
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2457
      try:
2458
        pwd.getpwnam(username)
2459
      except KeyError:
2460
        raise errors.HypervisorError("Unknown security domain user %s"
2461
                                     % username)
2462
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2463
    if vnc_bind_address:
2464
      bound_to_addr = netutils.IP4Address.IsValid(vnc_bind_address)
2465
      is_interface = netutils.IsValidInterface(vnc_bind_address)
2466
      is_path = utils.IsNormAbsPath(vnc_bind_address)
2467
      if not bound_to_addr and not is_interface and not is_path:
2468
        raise errors.HypervisorError("VNC: The %s parameter must be either"
2469
                                     " a valid IP address, an interface name,"
2470
                                     " or an absolute path" %
2471
                                     constants.HV_KVM_SPICE_BIND)
2472

    
2473
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2474
    if spice_bind:
2475
      # only one of VNC and SPICE can be used currently.
2476
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2477
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2478
                                     " only one of them can be used at a"
2479
                                     " given time")
2480

    
2481
      # check that KVM supports SPICE
2482
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2483
      if not cls._SPICE_RE.search(kvmhelp):
2484
        raise errors.HypervisorError("SPICE is configured, but it is not"
2485
                                     " supported according to 'kvm --help'")
2486

    
2487
      # if spice_bind is not an IP address, it must be a valid interface
2488
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2489
                       netutils.IP6Address.IsValid(spice_bind))
2490
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2491
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2492
                                     " a valid IP address or interface name" %
2493
                                     constants.HV_KVM_SPICE_BIND)
2494

    
2495
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2496
    if machine_version:
2497
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2498
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2499
        raise errors.HypervisorError("Unsupported machine version: %s" %
2500
                                     machine_version)
2501

    
2502
  @classmethod
2503
  def PowercycleNode(cls, hvparams=None):
2504
    """KVM powercycle, just a wrapper over Linux powercycle.
2505

2506
    @type hvparams: dict of strings
2507
    @param hvparams: hypervisor params to be used on this node
2508

2509
    """
2510
    cls.LinuxPowercycle()