Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 1902c213

History | View | Annotate | Download (96.8 kB)

1
#
2
#
3

    
4
# Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 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 struct
35
import fcntl
36
import shutil
37
import socket
38
import stat
39
import StringIO
40
from bitarray import bitarray
41
try:
42
  import affinity   # pylint: disable=F0401
43
except ImportError:
44
  affinity = None
45
try:
46
  import fdsend   # pylint: disable=F0401
47
except ImportError:
48
  fdsend = None
49

    
50
from ganeti import utils
51
from ganeti import constants
52
from ganeti import errors
53
from ganeti import serializer
54
from ganeti import objects
55
from ganeti import uidpool
56
from ganeti import ssconf
57
from ganeti import netutils
58
from ganeti import pathutils
59
from ganeti.hypervisor import hv_base
60
from ganeti.utils import wrapper as utils_wrapper
61

    
62

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

    
66
# TUN/TAP driver constants, taken from <linux/if_tun.h>
67
# They are architecture-independent and already hardcoded in qemu-kvm source,
68
# so we can safely include them here.
69
TUNSETIFF = 0x400454ca
70
TUNGETIFF = 0x800454d2
71
TUNGETFEATURES = 0x800454cf
72
IFF_TAP = 0x0002
73
IFF_NO_PI = 0x1000
74
IFF_VNET_HDR = 0x4000
75

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

    
87
# Constant bitarray that reflects to a free pci slot
88
# Use it with bitarray.search()
89
_AVAILABLE_PCI_SLOT = bitarray("0")
90

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

    
117

    
118
def _GenerateDeviceKVMId(dev_type, dev, idx=None):
119
  """Helper function to generate a unique device name used by KVM
120

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

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

131
  """
132

    
133
  # proper device id - available in latest Ganeti versions
134
  if dev.pci and dev.uuid:
135
    return "%s-%s-pci-%d" % (dev_type.lower(), dev.uuid.split("-")[0], dev.pci)
136

    
137
  # dummy device id - returned only to _GenerateKVMBlockDevicesOptions
138
  # This enables -device option for paravirtual disk_type
139
  if idx is not None:
140
    return "%s-%d" % (dev_type.lower(), idx)
141

    
142
  raise errors.HotplugError("Hotplug is not supported for devices"
143
                            " without UUID or PCI info")
144

    
145

    
146
def _UpdatePCISlots(dev, pci_reservations):
147
  """Update pci configuration for a stopped instance
148

149
  If dev has a pci slot then reserve it, else find first available
150
  in pci_reservations bitarray. It acts on the same objects passed
151
  as params so there is no need to return anything.
152

153
  @type dev: L{objects.Disk} or L{objects.NIC}
154
  @param dev: the device object for which we update its pci slot
155
  @type pci_reservations: bitarray
156
  @param pci_reservations: existing pci reservations for an instance
157
  @raise errors.HotplugError: in case an instance has all its slot occupied
158

159
  """
160
  if dev.pci:
161
    free = dev.pci
162
  else: # pylint: disable=E1103
163
    [free] = pci_reservations.search(_AVAILABLE_PCI_SLOT, 1)
164
    if not free:
165
      raise errors.HypervisorError("All PCI slots occupied")
166
    dev.pci = int(free)
167

    
168
  pci_reservations[free] = True
169

    
170

    
171
def _GetExistingDeviceInfo(dev_type, device, runtime):
172
  """Helper function to get an existing device inside the runtime file
173

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

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

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

    
194
  return found[0]
195

    
196

    
197
def _UpgradeSerializedRuntime(serialized_runtime):
198
  """Upgrade runtime data
199

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

204
  @type serialized_runtime: string
205
  @param serialized_runtime: raw text data read from actual runtime file
206
  @return: (cmd, nic dicts, hvparams, bdev dicts)
207
  @rtype: tuple
208

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

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

    
222
  return kvm_cmd, serialized_nics, hvparams, serialized_disks
223

    
224

    
225
def _AnalyzeSerializedRuntime(serialized_runtime):
226
  """Return runtime entries for a serialized runtime file
227

228
  @type serialized_runtime: string
229
  @param serialized_runtime: raw text data read from actual runtime file
230
  @return: (cmd, nics, hvparams, bdevs)
231
  @rtype: tuple
232

233
  """
234
  kvm_cmd, serialized_nics, hvparams, serialized_disks = \
235
    _UpgradeSerializedRuntime(serialized_runtime)
236
  kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
237
  kvm_disks = [(objects.Disk.FromDict(sdisk), link)
238
               for sdisk, link in serialized_disks]
239

    
240
  return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
241

    
242

    
243
def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
244
  """Retrieves supported TUN features from file descriptor.
245

246
  @see: L{_ProbeTapVnetHdr}
247

248
  """
249
  req = struct.pack("I", 0)
250
  try:
251
    buf = _ioctl(fd, TUNGETFEATURES, req)
252
  except EnvironmentError, err:
253
    logging.warning("ioctl(TUNGETFEATURES) failed: %s", err)
254
    return None
255
  else:
256
    (flags, ) = struct.unpack("I", buf)
257
    return flags
258

    
259

    
260
def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
261
  """Check whether to enable the IFF_VNET_HDR flag.
262

263
  To do this, _all_ of the following conditions must be met:
264
   1. TUNGETFEATURES ioctl() *must* be implemented
265
   2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
266
   3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
267
      drivers/net/tun.c there is no way to test this until after the tap device
268
      has been created using TUNSETIFF, and there is no way to change the
269
      IFF_VNET_HDR flag after creating the interface, catch-22! However both
270
      TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
271
      thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
272

273
   @type fd: int
274
   @param fd: the file descriptor of /dev/net/tun
275

276
  """
277
  flags = _features_fn(fd)
278

    
279
  if flags is None:
280
    # Not supported
281
    return False
282

    
283
  result = bool(flags & IFF_VNET_HDR)
284

    
285
  if not result:
286
    logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
287

    
288
  return result
289

    
290

    
291
def _OpenTap(vnet_hdr=True):
292
  """Open a new tap device and return its file descriptor.
293

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

297
  @type vnet_hdr: boolean
298
  @param vnet_hdr: Enable the VNET Header
299
  @return: (ifname, tapfd)
300
  @rtype: tuple
301

302
  """
303
  try:
304
    tapfd = os.open("/dev/net/tun", os.O_RDWR)
305
  except EnvironmentError:
306
    raise errors.HypervisorError("Failed to open /dev/net/tun")
307

    
308
  flags = IFF_TAP | IFF_NO_PI
309

    
310
  if vnet_hdr and _ProbeTapVnetHdr(tapfd):
311
    flags |= IFF_VNET_HDR
312

    
313
  # The struct ifreq ioctl request (see netdevice(7))
314
  ifr = struct.pack("16sh", "", flags)
315

    
316
  try:
317
    res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
318
  except EnvironmentError, err:
319
    raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
320
                                 err)
321

    
322
  # Get the interface name from the ioctl
323
  ifname = struct.unpack("16sh", res)[0].strip("\x00")
324
  return (ifname, tapfd)
325

    
326

    
327
class QmpMessage:
328
  """QEMU Messaging Protocol (QMP) message.
329

330
  """
331
  def __init__(self, data):
332
    """Creates a new QMP message based on the passed data.
333

334
    """
335
    if not isinstance(data, dict):
336
      raise TypeError("QmpMessage must be initialized with a dict")
337

    
338
    self.data = data
339

    
340
  def __getitem__(self, field_name):
341
    """Get the value of the required field if present, or None.
342

343
    Overrides the [] operator to provide access to the message data,
344
    returning None if the required item is not in the message
345
    @return: the value of the field_name field, or None if field_name
346
             is not contained in the message
347

348
    """
349
    return self.data.get(field_name, None)
350

    
351
  def __setitem__(self, field_name, field_value):
352
    """Set the value of the required field_name to field_value.
353

354
    """
355
    self.data[field_name] = field_value
356

    
357
  @staticmethod
358
  def BuildFromJsonString(json_string):
359
    """Build a QmpMessage from a JSON encoded string.
360

361
    @type json_string: str
362
    @param json_string: JSON string representing the message
363
    @rtype: L{QmpMessage}
364
    @return: a L{QmpMessage} built from json_string
365

366
    """
367
    # Parse the string
368
    data = serializer.LoadJson(json_string)
369
    return QmpMessage(data)
370

    
371
  def __str__(self):
372
    # The protocol expects the JSON object to be sent as a single line.
373
    return serializer.DumpJson(self.data)
374

    
375
  def __eq__(self, other):
376
    # When comparing two QmpMessages, we are interested in comparing
377
    # their internal representation of the message data
378
    return self.data == other.data
379

    
380

    
381
class MonitorSocket(object):
382
  _SOCKET_TIMEOUT = 5
383

    
384
  def __init__(self, monitor_filename):
385
    """Instantiates the MonitorSocket object.
386

387
    @type monitor_filename: string
388
    @param monitor_filename: the filename of the UNIX raw socket on which the
389
                             monitor (QMP or simple one) is listening
390

391
    """
392
    self.monitor_filename = monitor_filename
393
    self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
394
    # We want to fail if the server doesn't send a complete message
395
    # in a reasonable amount of time
396
    self.sock.settimeout(self._SOCKET_TIMEOUT)
397
    self._connected = False
398

    
399
  def _check_socket(self):
400
    sock_stat = None
401
    try:
402
      sock_stat = os.stat(self.monitor_filename)
403
    except EnvironmentError, err:
404
      if err.errno == errno.ENOENT:
405
        raise errors.HypervisorError("No monitor socket found")
406
      else:
407
        raise errors.HypervisorError("Error checking monitor socket: %s",
408
                                     utils.ErrnoOrStr(err))
409
    if not stat.S_ISSOCK(sock_stat.st_mode):
410
      raise errors.HypervisorError("Monitor socket is not a socket")
411

    
412
  def _check_connection(self):
413
    """Make sure that the connection is established.
414

415
    """
416
    if not self._connected:
417
      raise errors.ProgrammerError("To use a MonitorSocket you need to first"
418
                                   " invoke connect() on it")
419

    
420
  def connect(self):
421
    """Connects to the monitor.
422

423
    Connects to the UNIX socket
424

425
    @raise errors.HypervisorError: when there are communication errors
426

427
    """
428
    if self._connected:
429
      raise errors.ProgrammerError("Cannot connect twice")
430

    
431
    self._check_socket()
432

    
433
    # Check file existance/stuff
434
    try:
435
      self.sock.connect(self.monitor_filename)
436
    except EnvironmentError:
437
      raise errors.HypervisorError("Can't connect to qmp socket")
438
    self._connected = True
439

    
440
  def close(self):
441
    """Closes the socket
442

443
    It cannot be used after this call.
444

445
    """
446
    self.sock.close()
447

    
448

    
449
class QmpConnection(MonitorSocket):
450
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
451

452
  """
453
  _FIRST_MESSAGE_KEY = "QMP"
454
  _EVENT_KEY = "event"
455
  _ERROR_KEY = "error"
456
  _RETURN_KEY = RETURN_KEY = "return"
457
  _ACTUAL_KEY = ACTUAL_KEY = "actual"
458
  _ERROR_CLASS_KEY = "class"
459
  _ERROR_DESC_KEY = "desc"
460
  _EXECUTE_KEY = "execute"
461
  _ARGUMENTS_KEY = "arguments"
462
  _CAPABILITIES_COMMAND = "qmp_capabilities"
463
  _MESSAGE_END_TOKEN = "\r\n"
464

    
465
  def __init__(self, monitor_filename):
466
    super(QmpConnection, self).__init__(monitor_filename)
467
    self._buf = ""
468

    
469
  def connect(self):
470
    """Connects to the QMP monitor.
471

472
    Connects to the UNIX socket and makes sure that we can actually send and
473
    receive data to the kvm instance via QMP.
474

475
    @raise errors.HypervisorError: when there are communication errors
476
    @raise errors.ProgrammerError: when there are data serialization errors
477

478
    """
479
    super(QmpConnection, self).connect()
480
    # Check if we receive a correct greeting message from the server
481
    # (As per the QEMU Protocol Specification 0.1 - section 2.2)
482
    greeting = self._Recv()
483
    if not greeting[self._FIRST_MESSAGE_KEY]:
484
      self._connected = False
485
      raise errors.HypervisorError("kvm: QMP communication error (wrong"
486
                                   " server greeting")
487

    
488
    # Let's put the monitor in command mode using the qmp_capabilities
489
    # command, or else no command will be executable.
490
    # (As per the QEMU Protocol Specification 0.1 - section 4)
491
    self.Execute(self._CAPABILITIES_COMMAND)
492

    
493
  def _ParseMessage(self, buf):
494
    """Extract and parse a QMP message from the given buffer.
495

496
    Seeks for a QMP message in the given buf. If found, it parses it and
497
    returns it together with the rest of the characters in the buf.
498
    If no message is found, returns None and the whole buffer.
499

500
    @raise errors.ProgrammerError: when there are data serialization errors
501

502
    """
503
    message = None
504
    # Check if we got the message end token (CRLF, as per the QEMU Protocol
505
    # Specification 0.1 - Section 2.1.1)
506
    pos = buf.find(self._MESSAGE_END_TOKEN)
507
    if pos >= 0:
508
      try:
509
        message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
510
      except Exception, err:
511
        raise errors.ProgrammerError("QMP data serialization error: %s" % err)
512
      buf = buf[pos + 1:]
513

    
514
    return (message, buf)
515

    
516
  def _Recv(self):
517
    """Receives a message from QMP and decodes the received JSON object.
518

519
    @rtype: QmpMessage
520
    @return: the received message
521
    @raise errors.HypervisorError: when there are communication errors
522
    @raise errors.ProgrammerError: when there are data serialization errors
523

524
    """
525
    self._check_connection()
526

    
527
    # Check if there is already a message in the buffer
528
    (message, self._buf) = self._ParseMessage(self._buf)
529
    if message:
530
      logging.warning("Message already in the buffer: %s", message)
531
      return message
532

    
533
    recv_buffer = StringIO.StringIO(self._buf)
534
    recv_buffer.seek(len(self._buf))
535
    try:
536
      while True:
537
        data = self.sock.recv(4096)
538
        if not data:
539
          break
540
        recv_buffer.write(data)
541

    
542
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
543
        if message:
544
          logging.warning("New message in the buffer: %s", message)
545
          return message
546

    
547
    except socket.timeout, err:
548
      raise errors.HypervisorError("Timeout while receiving a QMP message: "
549
                                   "%s" % (err))
550
    except socket.error, err:
551
      raise errors.HypervisorError("Unable to receive data from KVM using the"
552
                                   " QMP protocol: %s" % err)
553

    
554
  def _Send(self, message):
555
    """Encodes and sends a message to KVM using QMP.
556

557
    @type message: QmpMessage
558
    @param message: message to send to KVM
559
    @raise errors.HypervisorError: when there are communication errors
560
    @raise errors.ProgrammerError: when there are data serialization errors
561

562
    """
563
    self._check_connection()
564
    try:
565
      message_str = str(message)
566
    except Exception, err:
567
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
568

    
569
    try:
570
      self.sock.sendall(message_str)
571
    except socket.timeout, err:
572
      raise errors.HypervisorError("Timeout while sending a QMP message: "
573
                                   "%s (%s)" % (err.string, err.errno))
574
    except socket.error, err:
575
      raise errors.HypervisorError("Unable to send data from KVM using the"
576
                                   " QMP protocol: %s" % err)
577

    
578
  def Execute(self, command, arguments=None):
579
    """Executes a QMP command and returns the response of the server.
580

581
    @type command: str
582
    @param command: the command to execute
583
    @type arguments: dict
584
    @param arguments: dictionary of arguments to be passed to the command
585
    @rtype: dict
586
    @return: dictionary representing the received JSON object
587
    @raise errors.HypervisorError: when there are communication errors
588
    @raise errors.ProgrammerError: when there are data serialization errors
589

590
    """
591
    self._check_connection()
592
    message = QmpMessage({self._EXECUTE_KEY: command})
593
    if arguments:
594
      message[self._ARGUMENTS_KEY] = arguments
595
    self._Send(message)
596

    
597
    # Events can occur between the sending of the command and the reception
598
    # of the response, so we need to filter out messages with the event key.
599
    while True:
600
      response = self._Recv()
601
      err = response[self._ERROR_KEY]
602
      if err:
603
        raise errors.HypervisorError("kvm: error executing the %s"
604
                                     " command: %s (%s):" %
605
                                     (command,
606
                                      err[self._ERROR_DESC_KEY],
607
                                      err[self._ERROR_CLASS_KEY]))
608

    
609
      elif not response[self._EVENT_KEY]:
610
        return response
611

    
612

    
613
class KVMHypervisor(hv_base.BaseHypervisor):
614
  """KVM hypervisor interface
615

616
  """
617
  CAN_MIGRATE = True
618

    
619
  _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
620
  _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
621
  _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
622
  _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
623
  _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
624
  _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
625
  _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
626
  # KVM instances with chroot enabled are started in empty chroot directories.
627
  _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
628
  # After an instance is stopped, its chroot directory is removed.
629
  # If the chroot directory is not empty, it can't be removed.
630
  # A non-empty chroot directory indicates a possible security incident.
631
  # To support forensics, the non-empty chroot directory is quarantined in
632
  # a separate directory, called 'chroot-quarantine'.
633
  _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
634
  _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
635
           _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
636

    
637
  PARAMETERS = {
638
    constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
639
    constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
640
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
641
    constants.HV_ROOT_PATH: hv_base.NO_CHECK,
642
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
643
    constants.HV_ACPI: hv_base.NO_CHECK,
644
    constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
645
    constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
646
    constants.HV_VNC_BIND_ADDRESS:
647
      (False, lambda x: (netutils.IP4Address.IsValid(x) or
648
                         utils.IsNormAbsPath(x)),
649
       "The VNC bind address must be either a valid IP address or an absolute"
650
       " pathname", None, None),
651
    constants.HV_VNC_TLS: hv_base.NO_CHECK,
652
    constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
653
    constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
654
    constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
655
    constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
656
    constants.HV_KVM_SPICE_IP_VERSION:
657
      (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
658
                         x in constants.VALID_IP_VERSIONS),
659
       "The SPICE IP version should be 4 or 6",
660
       None, None),
661
    constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
662
    constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
663
      hv_base.ParamInSet(
664
        False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
665
    constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
666
      hv_base.ParamInSet(
667
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
668
    constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
669
      hv_base.ParamInSet(
670
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
671
    constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
672
      hv_base.ParamInSet(
673
        False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
674
    constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
675
    constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
676
    constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
677
    constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
678
    constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
679
    constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
680
    constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
681
    constants.HV_BOOT_ORDER:
682
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
683
    constants.HV_NIC_TYPE:
684
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
685
    constants.HV_DISK_TYPE:
686
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
687
    constants.HV_KVM_CDROM_DISK_TYPE:
688
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
689
    constants.HV_USB_MOUSE:
690
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
691
    constants.HV_KEYMAP: hv_base.NO_CHECK,
692
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
693
    constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
694
    constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
695
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
696
    constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
697
    constants.HV_DISK_CACHE:
698
      hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
699
    constants.HV_SECURITY_MODEL:
700
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
701
    constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
702
    constants.HV_KVM_FLAG:
703
      hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
704
    constants.HV_VHOST_NET: hv_base.NO_CHECK,
705
    constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
706
    constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
707
    constants.HV_REBOOT_BEHAVIOR:
708
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
709
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
710
    constants.HV_CPU_TYPE: hv_base.NO_CHECK,
711
    constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
712
    constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
713
    constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
714
    constants.HV_SOUNDHW: hv_base.NO_CHECK,
715
    constants.HV_USB_DEVICES: hv_base.NO_CHECK,
716
    constants.HV_VGA: hv_base.NO_CHECK,
717
    constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
718
    constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
719
    constants.HV_VNET_HDR: hv_base.NO_CHECK,
720
    }
721

    
722
  _VIRTIO = "virtio"
723
  _VIRTIO_NET_PCI = "virtio-net-pci"
724
  _VIRTIO_BLK_PCI = "virtio-blk-pci"
725

    
726
  _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
727
                                    re.M | re.I)
728
  _MIGRATION_PROGRESS_RE = \
729
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
730
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
731
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
732

    
733
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
734
  _MIGRATION_INFO_RETRY_DELAY = 2
735

    
736
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
737

    
738
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
739
  _CPU_INFO_CMD = "info cpus"
740
  _CONT_CMD = "cont"
741

    
742
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
743
  _CHECK_MACHINE_VERSION_RE = \
744
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
745

    
746
  _QMP_RE = re.compile(r"^-qmp\s", re.M)
747
  _SPICE_RE = re.compile(r"^-spice\s", re.M)
748
  _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
749
  _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
750
  _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
751
  _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
752
  _DISPLAY_RE = re.compile(r"^-display\s", re.M)
753
  _MACHINE_RE = re.compile(r"^-machine\s", re.M)
754
  _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
755
  _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M)
756
  # match  -drive.*boot=on|off on different lines, but in between accept only
757
  # dashes not preceeded by a new line (which would mean another option
758
  # different than -drive is starting)
759
  _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
760

    
761
  _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
762
  _INFO_PCI_CMD = "info pci"
763
  _INFO_VERSION_RE = \
764
    re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
765
  _INFO_VERSION_CMD = "info version"
766

    
767
  _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
768

    
769
  ANCILLARY_FILES = [
770
    _KVM_NETWORK_SCRIPT,
771
    ]
772
  ANCILLARY_FILES_OPT = [
773
    _KVM_NETWORK_SCRIPT,
774
    ]
775

    
776
  # Supported kvm options to get output from
777
  _KVMOPT_HELP = "help"
778
  _KVMOPT_MLIST = "mlist"
779
  _KVMOPT_DEVICELIST = "devicelist"
780

    
781
  # Command to execute to get the output from kvm, and whether to
782
  # accept the output even on failure.
783
  _KVMOPTS_CMDS = {
784
    _KVMOPT_HELP: (["--help"], False),
785
    _KVMOPT_MLIST: (["-M", "?"], False),
786
    _KVMOPT_DEVICELIST: (["-device", "?"], True),
787
  }
788

    
789
  def __init__(self):
790
    hv_base.BaseHypervisor.__init__(self)
791
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
792
    # in a tmpfs filesystem or has been otherwise wiped out.
793
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
794
    utils.EnsureDirs(dirs)
795

    
796
  @classmethod
797
  def _InstancePidFile(cls, instance_name):
798
    """Returns the instance pidfile.
799

800
    """
801
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
802

    
803
  @classmethod
804
  def _InstanceUidFile(cls, instance_name):
805
    """Returns the instance uidfile.
806

807
    """
808
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
809

    
810
  @classmethod
811
  def _InstancePidInfo(cls, pid):
812
    """Check pid file for instance information.
813

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

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

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

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

    
835
    instance = None
836
    memory = 0
837
    vcpus = 0
838

    
839
    arg_list = cmdline.split("\x00")
840
    while arg_list:
841
      arg = arg_list.pop(0)
842
      if arg == "-name":
843
        instance = arg_list.pop(0)
844
      elif arg == "-m":
845
        memory = int(arg_list.pop(0))
846
      elif arg == "-smp":
847
        vcpus = int(arg_list.pop(0).split(",")[0])
848

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

    
853
    return (instance, memory, vcpus)
854

    
855
  def _InstancePidAlive(self, instance_name):
856
    """Returns the instance pidfile, pid, and liveness.
857

858
    @type instance_name: string
859
    @param instance_name: instance name
860
    @rtype: tuple
861
    @return: (pid file name, pid, liveness)
862

863
    """
864
    pidfile = self._InstancePidFile(instance_name)
865
    pid = utils.ReadPidFile(pidfile)
866

    
867
    alive = False
868
    try:
869
      cmd_instance = self._InstancePidInfo(pid)[0]
870
      alive = (cmd_instance == instance_name)
871
    except errors.HypervisorError:
872
      pass
873

    
874
    return (pidfile, pid, alive)
875

    
876
  def _CheckDown(self, instance_name):
877
    """Raises an error unless the given instance is down.
878

879
    """
880
    alive = self._InstancePidAlive(instance_name)[2]
881
    if alive:
882
      raise errors.HypervisorError("Failed to start instance %s: %s" %
883
                                   (instance_name, "already running"))
884

    
885
  @classmethod
886
  def _InstanceMonitor(cls, instance_name):
887
    """Returns the instance monitor socket name
888

889
    """
890
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
891

    
892
  @classmethod
893
  def _InstanceSerial(cls, instance_name):
894
    """Returns the instance serial socket name
895

896
    """
897
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
898

    
899
  @classmethod
900
  def _InstanceQmpMonitor(cls, instance_name):
901
    """Returns the instance serial QMP socket name
902

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

    
906
  @staticmethod
907
  def _SocatUnixConsoleParams():
908
    """Returns the correct parameters for socat
909

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

912
    """
913
    if constants.SOCAT_USE_ESCAPE:
914
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
915
    else:
916
      return "echo=0,icanon=0"
917

    
918
  @classmethod
919
  def _InstanceKVMRuntime(cls, instance_name):
920
    """Returns the instance KVM runtime filename
921

922
    """
923
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
924

    
925
  @classmethod
926
  def _InstanceChrootDir(cls, instance_name):
927
    """Returns the name of the KVM chroot dir of the instance
928

929
    """
930
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
931

    
932
  @classmethod
933
  def _InstanceNICDir(cls, instance_name):
934
    """Returns the name of the directory holding the tap device files for a
935
    given instance.
936

937
    """
938
    return utils.PathJoin(cls._NICS_DIR, instance_name)
939

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

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

    
947
  @classmethod
948
  def _InstanceKeymapFile(cls, instance_name):
949
    """Returns the name of the file containing the keymap for a given instance
950

951
    """
952
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
953

    
954
  @classmethod
955
  def _TryReadUidFile(cls, uid_file):
956
    """Try to read a uid file
957

958
    """
959
    if os.path.exists(uid_file):
960
      try:
961
        uid = int(utils.ReadOneLineFile(uid_file))
962
        return uid
963
      except EnvironmentError:
964
        logging.warning("Can't read uid file", exc_info=True)
965
      except (TypeError, ValueError):
966
        logging.warning("Can't parse uid file contents", exc_info=True)
967
    return None
968

    
969
  @classmethod
970
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
971
    """Removes an instance's rutime sockets/files/dirs.
972

973
    """
974
    utils.RemoveFile(pidfile)
975
    utils.RemoveFile(cls._InstanceMonitor(instance_name))
976
    utils.RemoveFile(cls._InstanceSerial(instance_name))
977
    utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
978
    utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
979
    utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
980
    uid_file = cls._InstanceUidFile(instance_name)
981
    uid = cls._TryReadUidFile(uid_file)
982
    utils.RemoveFile(uid_file)
983
    if uid is not None:
984
      uidpool.ReleaseUid(uid)
985
    try:
986
      shutil.rmtree(cls._InstanceNICDir(instance_name))
987
    except OSError, err:
988
      if err.errno != errno.ENOENT:
989
        raise
990
    try:
991
      chroot_dir = cls._InstanceChrootDir(instance_name)
992
      utils.RemoveDir(chroot_dir)
993
    except OSError, err:
994
      if err.errno == errno.ENOTEMPTY:
995
        # The chroot directory is expected to be empty, but it isn't.
996
        new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
997
                                          prefix="%s-%s-" %
998
                                          (instance_name,
999
                                           utils.TimestampForFilename()))
1000
        logging.warning("The chroot directory of instance %s can not be"
1001
                        " removed as it is not empty. Moving it to the"
1002
                        " quarantine instead. Please investigate the"
1003
                        " contents (%s) and clean up manually",
1004
                        instance_name, new_chroot_dir)
1005
        utils.RenameFile(chroot_dir, new_chroot_dir)
1006
      else:
1007
        raise
1008

    
1009
  @staticmethod
1010
  def _ConfigureNIC(instance, seq, nic, tap):
1011
    """Run the network configuration script for a specified NIC
1012

1013
    @param instance: instance we're acting on
1014
    @type instance: instance object
1015
    @param seq: nic sequence number
1016
    @type seq: int
1017
    @param nic: nic we're acting on
1018
    @type nic: nic object
1019
    @param tap: the host's tap interface this NIC corresponds to
1020
    @type tap: str
1021

1022
    """
1023
    env = {
1024
      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
1025
      "INSTANCE": instance.name,
1026
      "MAC": nic.mac,
1027
      "MODE": nic.nicparams[constants.NIC_MODE],
1028
      "INTERFACE": tap,
1029
      "INTERFACE_INDEX": str(seq),
1030
      "INTERFACE_UUID": nic.uuid,
1031
      "TAGS": " ".join(instance.GetTags()),
1032
    }
1033

    
1034
    if nic.ip:
1035
      env["IP"] = nic.ip
1036

    
1037
    if nic.name:
1038
      env["INTERFACE_NAME"] = nic.name
1039

    
1040
    if nic.nicparams[constants.NIC_LINK]:
1041
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
1042

    
1043
    if nic.network:
1044
      n = objects.Network.FromDict(nic.netinfo)
1045
      env.update(n.HooksDict())
1046

    
1047
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1048
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
1049

    
1050
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
1051
    if result.failed:
1052
      raise errors.HypervisorError("Failed to configure interface %s: %s;"
1053
                                   " network configuration script output: %s" %
1054
                                   (tap, result.fail_reason, result.output))
1055

    
1056
  @staticmethod
1057
  def _VerifyAffinityPackage():
1058
    if affinity is None:
1059
      raise errors.HypervisorError("affinity Python package not"
1060
                                   " found; cannot use CPU pinning under KVM")
1061

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

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

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

1075
    """
1076
    if cpu_list == constants.CPU_PINNING_OFF:
1077
      return constants.CPU_PINNING_ALL_KVM
1078
    else:
1079
      return sum(2 ** cpu for cpu in cpu_list)
1080

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

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

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

    
1097
    if len(cpu_list) == 1:
1098
      all_cpu_mapping = cpu_list[0]
1099
      if all_cpu_mapping == constants.CPU_PINNING_OFF:
1100
        # If CPU pinning has 1 entry that's "all", then do nothing
1101
        pass
1102
      else:
1103
        # If CPU pinning has one non-all entry, map the entire VM to
1104
        # one set of physical CPUs
1105
        cls._VerifyAffinityPackage()
1106
        affinity.set_process_affinity_mask(
1107
          process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
1108
    else:
1109
      # The number of vCPUs mapped should match the number of vCPUs
1110
      # reported by KVM. This was already verified earlier, so
1111
      # here only as a sanity check.
1112
      assert len(thread_dict) == len(cpu_list)
1113
      cls._VerifyAffinityPackage()
1114

    
1115
      # For each vCPU, map it to the proper list of physical CPUs
1116
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1117
        affinity.set_process_affinity_mask(thread_dict[i],
1118
                                           cls._BuildAffinityCpuMask(vcpu))
1119

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

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

1128
    """
1129
    result = {}
1130
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1131
    for line in output.stdout.splitlines():
1132
      match = self._CPU_INFO_RE.search(line)
1133
      if not match:
1134
        continue
1135
      grp = map(int, match.groups())
1136
      result[grp[0]] = grp[1]
1137

    
1138
    return result
1139

    
1140
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1141
    """Complete CPU pinning.
1142

1143
    @type instance_name: string
1144
    @param instance_name: name of instance
1145
    @type cpu_mask: string
1146
    @param cpu_mask: CPU pinning mask as entered by user
1147

1148
    """
1149
    # Get KVM process ID, to be used if need to pin entire VM
1150
    _, pid, _ = self._InstancePidAlive(instance_name)
1151
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1152
    thread_dict = self._GetVcpuThreadIds(instance_name)
1153
    # Run CPU pinning, based on configured mask
1154
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1155

    
1156
  def ListInstances(self):
1157
    """Get the list of running instances.
1158

1159
    We can do this by listing our live instances directory and
1160
    checking whether the associated kvm process is still alive.
1161

1162
    """
1163
    result = []
1164
    for name in os.listdir(self._PIDS_DIR):
1165
      if self._InstancePidAlive(name)[2]:
1166
        result.append(name)
1167
    return result
1168

    
1169
  def GetInstanceInfo(self, instance_name):
1170
    """Get instance properties.
1171

1172
    @type instance_name: string
1173
    @param instance_name: the instance name
1174
    @rtype: tuple of strings
1175
    @return: (name, id, memory, vcpus, stat, times)
1176

1177
    """
1178
    _, pid, alive = self._InstancePidAlive(instance_name)
1179
    if not alive:
1180
      return None
1181

    
1182
    _, memory, vcpus = self._InstancePidInfo(pid)
1183
    istat = "---b-"
1184
    times = "0"
1185

    
1186
    try:
1187
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1188
      qmp.connect()
1189
      vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1190
      # Will fail if ballooning is not enabled, but we can then just resort to
1191
      # the value above.
1192
      mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1193
      memory = mem_bytes / 1048576
1194
    except errors.HypervisorError:
1195
      pass
1196
    except TyperError:
1197
      logging.warning("QMP race detected!!")
1198

    
1199
    return (instance_name, pid, memory, vcpus, istat, times)
1200

    
1201
  def GetAllInstancesInfo(self):
1202
    """Get properties of all instances.
1203

1204
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1205

1206
    """
1207
    data = []
1208
    for name in os.listdir(self._PIDS_DIR):
1209
      try:
1210
        info = self.GetInstanceInfo(name)
1211
      except errors.HypervisorError:
1212
        # Ignore exceptions due to instances being shut down
1213
        continue
1214
      if info:
1215
        data.append(info)
1216
    return data
1217

    
1218
  def _GenerateKVMBlockDevicesOptions(self, instance, kvm_disks,
1219
                                      kvmhelp, devlist):
1220
    """Generate KVM options regarding instance's block devices.
1221

1222
    @type instance: L{objects.Instance}
1223
    @param instance: the instance object
1224
    @type kvm_disks: list of tuples
1225
    @param kvm_disks: list of tuples [(disk, link_name)..]
1226
    @type kvmhelp: string
1227
    @param kvmhelp: output of kvm --help
1228
    @type devlist: string
1229
    @param devlist: output of kvm -device ?
1230
    @rtype: list
1231
    @return: list of command line options eventually used by kvm executable
1232

1233
    """
1234
    hvp = instance.hvparams
1235
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1236
    if kernel_path:
1237
      boot_disk = False
1238
    else:
1239
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1240

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

    
1245
    dev_opts = []
1246
    device_driver = None
1247
    disk_type = hvp[constants.HV_DISK_TYPE]
1248
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
1249
      if_val = ",if=%s" % self._VIRTIO
1250
      try:
1251
        if self._VIRTIO_BLK_RE.search(devlist):
1252
          if_val = ",if=none"
1253
          # will be passed in -device option as driver
1254
          device_driver = self._VIRTIO_BLK_PCI
1255
      except errors.HypervisorError, _:
1256
        pass
1257
    else:
1258
      if_val = ",if=%s" % disk_type
1259
    # Cache mode
1260
    disk_cache = hvp[constants.HV_DISK_CACHE]
1261
    if instance.disk_template in constants.DTS_EXT_MIRROR:
1262
      if disk_cache != "none":
1263
        # TODO: make this a hard error, instead of a silent overwrite
1264
        logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1265
                        " to prevent shared storage corruption on migration",
1266
                        disk_cache)
1267
      cache_val = ",cache=none"
1268
    elif disk_cache != constants.HT_CACHE_DEFAULT:
1269
      cache_val = ",cache=%s" % disk_cache
1270
    else:
1271
      cache_val = ""
1272
    for idx, (cfdev, link_name) in enumerate(kvm_disks):
1273
      if cfdev.mode != constants.DISK_RDWR:
1274
        raise errors.HypervisorError("Instance has read-only disks which"
1275
                                     " are not supported by KVM")
1276
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
1277
      boot_val = ""
1278
      if boot_disk:
1279
        dev_opts.extend(["-boot", "c"])
1280
        boot_disk = False
1281
        if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1282
          boot_val = ",boot=on"
1283

    
1284
      # For ext we allow overriding disk_cache hypervisor params per disk
1285
      disk_cache = cfdev.params.get("cache", None)
1286
      if disk_cache:
1287
        cache_val = ",cache=%s" % disk_cache
1288
      drive_val = "file=%s,format=raw%s%s%s" % \
1289
                  (link_name, if_val, boot_val, cache_val)
1290

    
1291
      if device_driver:
1292
        # kvm_disks are the 4th entry of runtime file that did not exist in
1293
        # the past. That means that cfdev should always have pci slot and
1294
        # _GenerateDeviceKVMId() will not raise a exception.
1295
        kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_DISK,
1296
                                         cfdev, idx)
1297
        drive_val += (",id=%s" % kvm_devid)
1298
        if cfdev.pci:
1299
          drive_val += (",bus=0,unit=%d" % cfdev.pci)
1300
        dev_val = ("%s,drive=%s,id=%s" %
1301
                   (device_driver, kvm_devid, kvm_devid))
1302
        if cfdev.pci:
1303
          dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci)
1304
        dev_opts.extend(["-device", dev_val])
1305

    
1306
      # TODO: export disk geometry in IDISK_PARAMS
1307
      heads = cfdev.params.get('heads', None)
1308
      secs = cfdev.params.get('secs', None)
1309
      if heads and secs:
1310
        nr_sectors = cfdev.size * 1024 * 1024 / 512
1311
        cyls = nr_sectors / (int(heads) * int(secs))
1312
        if cyls > 16383:
1313
          cyls = 16383
1314
        elif cyls < 2:
1315
          cyls = 2
1316
        if cyls and heads and secs:
1317
          drive_val += (",cyls=%d,heads=%d,secs=%d" %
1318
                        (cyls, int(heads), int(secs)))
1319

    
1320
      dev_opts.extend(["-drive", drive_val])
1321

    
1322
    return dev_opts
1323

    
1324
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1325
                          kvmhelp):
1326
    """Generate KVM information to start an instance.
1327

1328
    @type kvmhelp: string
1329
    @param kvmhelp: output of kvm --help
1330
    @attention: this function must not have any side-effects; for
1331
        example, it must not write to the filesystem, or read values
1332
        from the current system the are expected to differ between
1333
        nodes, since it is only run once at instance startup;
1334
        actions/kvm arguments that can vary between systems should be
1335
        done in L{_ExecuteKVMRuntime}
1336

1337
    """
1338
    # pylint: disable=R0912,R0914,R0915
1339
    hvp = instance.hvparams
1340
    self.ValidateParameters(hvp)
1341

    
1342
    pidfile = self._InstancePidFile(instance.name)
1343
    kvm = hvp[constants.HV_KVM_PATH]
1344
    kvm_cmd = [kvm]
1345
    # used just by the vnc server, if enabled
1346
    kvm_cmd.extend(["-name", instance.name])
1347
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1348

    
1349
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1350
    if hvp[constants.HV_CPU_CORES]:
1351
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1352
    if hvp[constants.HV_CPU_THREADS]:
1353
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1354
    if hvp[constants.HV_CPU_SOCKETS]:
1355
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1356

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

    
1359
    kvm_cmd.extend(["-pidfile", pidfile])
1360
    kvm_cmd.extend(["-balloon", "virtio"])
1361
    kvm_cmd.extend(["-daemonize"])
1362
    if not instance.hvparams[constants.HV_ACPI]:
1363
      kvm_cmd.extend(["-no-acpi"])
1364
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1365
        constants.INSTANCE_REBOOT_EXIT:
1366
      kvm_cmd.extend(["-no-reboot"])
1367

    
1368
    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1369
    if not mversion:
1370
      mversion = self._GetDefaultMachineVersion(kvm)
1371
    if self._MACHINE_RE.search(kvmhelp):
1372
      # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1373
      # extra hypervisor parameters. We should also investigate whether and how
1374
      # shadow_mem should be considered for the resource model.
1375
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1376
        specprop = ",accel=kvm"
1377
      else:
1378
        specprop = ""
1379
      machinespec = "%s%s" % (mversion, specprop)
1380
      kvm_cmd.extend(["-machine", machinespec])
1381
    else:
1382
      kvm_cmd.extend(["-M", mversion])
1383
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1384
          self._ENABLE_KVM_RE.search(kvmhelp)):
1385
        kvm_cmd.extend(["-enable-kvm"])
1386
      elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1387
            self._DISABLE_KVM_RE.search(kvmhelp)):
1388
        kvm_cmd.extend(["-disable-kvm"])
1389

    
1390
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1391
    if kernel_path:
1392
      boot_cdrom = boot_floppy = boot_network = False
1393
    else:
1394
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1395
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1396
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1397

    
1398
    if startup_paused:
1399
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1400

    
1401
    if boot_network:
1402
      kvm_cmd.extend(["-boot", "n"])
1403

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

    
1408
    disk_type = hvp[constants.HV_DISK_TYPE]
1409

    
1410
    #Now we can specify a different device type for CDROM devices.
1411
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1412
    if not cdrom_disk_type:
1413
      cdrom_disk_type = disk_type
1414

    
1415
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1416
    if iso_image:
1417
      options = ",format=raw,media=cdrom"
1418
      # set cdrom 'if' type
1419
      if boot_cdrom:
1420
        actual_cdrom_type = constants.HT_DISK_IDE
1421
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1422
        actual_cdrom_type = "virtio"
1423
      else:
1424
        actual_cdrom_type = cdrom_disk_type
1425
      if_val = ",if=%s" % actual_cdrom_type
1426
      # set boot flag, if needed
1427
      boot_val = ""
1428
      if boot_cdrom:
1429
        kvm_cmd.extend(["-boot", "d"])
1430
        if needs_boot_flag:
1431
          boot_val = ",boot=on"
1432
      # and finally build the entire '-drive' value
1433
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1434
      kvm_cmd.extend(["-drive", drive_val])
1435

    
1436
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1437
    if iso_image2:
1438
      options = ",format=raw,media=cdrom"
1439
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1440
        if_val = ",if=virtio"
1441
      else:
1442
        if_val = ",if=%s" % cdrom_disk_type
1443
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1444
      kvm_cmd.extend(["-drive", drive_val])
1445

    
1446
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1447
    if floppy_image:
1448
      options = ",format=raw,media=disk"
1449
      if boot_floppy:
1450
        kvm_cmd.extend(["-boot", "a"])
1451
        options = "%s,boot=on" % options
1452
      if_val = ",if=floppy"
1453
      options = "%s%s" % (options, if_val)
1454
      drive_val = "file=%s%s" % (floppy_image, options)
1455
      kvm_cmd.extend(["-drive", drive_val])
1456

    
1457
    if kernel_path:
1458
      kvm_cmd.extend(["-kernel", kernel_path])
1459
      initrd_path = hvp[constants.HV_INITRD_PATH]
1460
      if initrd_path:
1461
        kvm_cmd.extend(["-initrd", initrd_path])
1462
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1463
                     hvp[constants.HV_KERNEL_ARGS]]
1464
      if hvp[constants.HV_SERIAL_CONSOLE]:
1465
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1466
        root_append.append("console=ttyS0,%s" % serial_speed)
1467
      kvm_cmd.extend(["-append", " ".join(root_append)])
1468

    
1469
    mem_path = hvp[constants.HV_MEM_PATH]
1470
    if mem_path:
1471
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1472

    
1473
    monitor_dev = ("unix:%s,server,nowait" %
1474
                   self._InstanceMonitor(instance.name))
1475
    kvm_cmd.extend(["-monitor", monitor_dev])
1476
    if hvp[constants.HV_SERIAL_CONSOLE]:
1477
      serial_dev = ("unix:%s,server,nowait" %
1478
                    self._InstanceSerial(instance.name))
1479
      kvm_cmd.extend(["-serial", serial_dev])
1480
    else:
1481
      kvm_cmd.extend(["-serial", "none"])
1482

    
1483
    mouse_type = hvp[constants.HV_USB_MOUSE]
1484
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1485
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1486
    spice_ip_version = None
1487

    
1488
    kvm_cmd.extend(["-usb"])
1489

    
1490
    if mouse_type:
1491
      kvm_cmd.extend(["-usbdevice", mouse_type])
1492
    elif vnc_bind_address:
1493
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1494

    
1495
    if vnc_bind_address:
1496
      if netutils.IP4Address.IsValid(vnc_bind_address):
1497
        if instance.network_port > constants.VNC_BASE_PORT:
1498
          display = instance.network_port - constants.VNC_BASE_PORT
1499
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1500
            vnc_arg = ":%d" % (display)
1501
          else:
1502
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1503
        else:
1504
          logging.error("Network port is not a valid VNC display (%d < %d),"
1505
                        " not starting VNC",
1506
                        instance.network_port, constants.VNC_BASE_PORT)
1507
          vnc_arg = "none"
1508

    
1509
        # Only allow tls and other option when not binding to a file, for now.
1510
        # kvm/qemu gets confused otherwise about the filename to use.
1511
        vnc_append = ""
1512
        if hvp[constants.HV_VNC_TLS]:
1513
          vnc_append = "%s,tls" % vnc_append
1514
          if hvp[constants.HV_VNC_X509_VERIFY]:
1515
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1516
                                               hvp[constants.HV_VNC_X509])
1517
          elif hvp[constants.HV_VNC_X509]:
1518
            vnc_append = "%s,x509=%s" % (vnc_append,
1519
                                         hvp[constants.HV_VNC_X509])
1520
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1521
          vnc_append = "%s,password" % vnc_append
1522

    
1523
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1524

    
1525
      else:
1526
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1527

    
1528
      kvm_cmd.extend(["-vnc", vnc_arg])
1529
    elif spice_bind:
1530
      # FIXME: this is wrong here; the iface ip address differs
1531
      # between systems, so it should be done in _ExecuteKVMRuntime
1532
      if netutils.IsValidInterface(spice_bind):
1533
        # The user specified a network interface, we have to figure out the IP
1534
        # address.
1535
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1536
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1537

    
1538
        # if the user specified an IP version and the interface does not
1539
        # have that kind of IP addresses, throw an exception
1540
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1541
          if not addresses[spice_ip_version]:
1542
            raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1543
                                         " for %s" % (spice_ip_version,
1544
                                                      spice_bind))
1545

    
1546
        # the user did not specify an IP version, we have to figure it out
1547
        elif (addresses[constants.IP4_VERSION] and
1548
              addresses[constants.IP6_VERSION]):
1549
          # we have both ipv4 and ipv6, let's use the cluster default IP
1550
          # version
1551
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1552
          spice_ip_version = \
1553
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1554
        elif addresses[constants.IP4_VERSION]:
1555
          spice_ip_version = constants.IP4_VERSION
1556
        elif addresses[constants.IP6_VERSION]:
1557
          spice_ip_version = constants.IP6_VERSION
1558
        else:
1559
          raise errors.HypervisorError("SPICE: Unable to get an IP address"
1560
                                       " for %s" % (spice_bind))
1561

    
1562
        spice_address = addresses[spice_ip_version][0]
1563

    
1564
      else:
1565
        # spice_bind is known to be a valid IP address, because
1566
        # ValidateParameters checked it.
1567
        spice_address = spice_bind
1568

    
1569
      spice_arg = "addr=%s" % spice_address
1570
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1571
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1572
                     (spice_arg, instance.network_port,
1573
                      pathutils.SPICE_CACERT_FILE))
1574
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1575
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1576
                      pathutils.SPICE_CERT_FILE))
1577
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1578
        if tls_ciphers:
1579
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1580
      else:
1581
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1582

    
1583
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1584
        spice_arg = "%s,disable-ticketing" % spice_arg
1585

    
1586
      if spice_ip_version:
1587
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1588

    
1589
      # Image compression options
1590
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1591
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1592
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1593
      if img_lossless:
1594
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1595
      if img_jpeg:
1596
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1597
      if img_zlib_glz:
1598
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1599

    
1600
      # Video stream detection
1601
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1602
      if video_streaming:
1603
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1604

    
1605
      # Audio compression, by default in qemu-kvm it is on
1606
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1607
        spice_arg = "%s,playback-compression=off" % spice_arg
1608
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1609
        spice_arg = "%s,agent-mouse=off" % spice_arg
1610
      else:
1611
        # Enable the spice agent communication channel between the host and the
1612
        # agent.
1613
        kvm_cmd.extend(["-device", "virtio-serial-pci"])
1614
        kvm_cmd.extend([
1615
          "-device",
1616
          "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1617
          ])
1618
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1619

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

    
1623
    else:
1624
      # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1625
      # also works in earlier versions though (tested with 1.1 and 1.3)
1626
      if self._DISPLAY_RE.search(kvmhelp):
1627
        kvm_cmd.extend(["-display", "none"])
1628
      else:
1629
        kvm_cmd.extend(["-nographic"])
1630

    
1631
    if hvp[constants.HV_USE_LOCALTIME]:
1632
      kvm_cmd.extend(["-localtime"])
1633

    
1634
    if hvp[constants.HV_KVM_USE_CHROOT]:
1635
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1636

    
1637
    # Add qemu-KVM -cpu param
1638
    if hvp[constants.HV_CPU_TYPE]:
1639
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1640

    
1641
    # As requested by music lovers
1642
    if hvp[constants.HV_SOUNDHW]:
1643
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1644

    
1645
    # Pass a -vga option if requested, or if spice is used, for backwards
1646
    # compatibility.
1647
    if hvp[constants.HV_VGA]:
1648
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1649
    elif spice_bind:
1650
      kvm_cmd.extend(["-vga", "qxl"])
1651

    
1652
    # Various types of usb devices, comma separated
1653
    if hvp[constants.HV_USB_DEVICES]:
1654
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1655
        kvm_cmd.extend(["-usbdevice", dev])
1656

    
1657
    if hvp[constants.HV_KVM_EXTRA]:
1658
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1659

    
1660
    pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1661
    kvm_disks = []
1662
    for disk, link_name in block_devices:
1663
      _UpdatePCISlots(disk, pci_reservations)
1664
      kvm_disks.append((disk, link_name))
1665

    
1666
    kvm_nics = []
1667
    for nic in instance.nics:
1668
      _UpdatePCISlots(nic, pci_reservations)
1669
      kvm_nics.append(nic)
1670

    
1671
    hvparams = hvp
1672

    
1673
    return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1674

    
1675
  def _WriteKVMRuntime(self, instance_name, data):
1676
    """Write an instance's KVM runtime
1677

1678
    """
1679
    try:
1680
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1681
                      data=data)
1682
    except EnvironmentError, err:
1683
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1684

    
1685
  def _ReadKVMRuntime(self, instance_name):
1686
    """Read an instance's KVM runtime
1687

1688
    """
1689
    try:
1690
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1691
    except EnvironmentError, err:
1692
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1693
    return file_content
1694

    
1695
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1696
    """Save an instance's KVM runtime
1697

1698
    """
1699
    kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1700

    
1701
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1702
    serialized_disks = [(blk.ToDict(), link)
1703
                            for blk, link in kvm_disks]
1704
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1705
                                      serialized_disks))
1706

    
1707
    self._WriteKVMRuntime(instance.name, serialized_form)
1708

    
1709
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1710
    """Load an instance's KVM runtime
1711

1712
    """
1713
    if not serialized_runtime:
1714
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1715

    
1716
    return _AnalyzeSerializedRuntime(serialized_runtime)
1717

    
1718
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1719
    """Run the KVM cmd and check for errors
1720

1721
    @type name: string
1722
    @param name: instance name
1723
    @type kvm_cmd: list of strings
1724
    @param kvm_cmd: runcmd input for kvm
1725
    @type tap_fds: list of int
1726
    @param tap_fds: fds of tap devices opened by Ganeti
1727

1728
    """
1729
    try:
1730
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1731
    finally:
1732
      for fd in tap_fds:
1733
        utils_wrapper.CloseFdNoError(fd)
1734

    
1735
    if result.failed:
1736
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1737
                                   (name, result.fail_reason, result.output))
1738
    if not self._InstancePidAlive(name)[2]:
1739
      raise errors.HypervisorError("Failed to start instance %s" % name)
1740

    
1741
  # too many local variables
1742
  # pylint: disable=R0914
1743
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1744
    """Execute a KVM cmd, after completing it with some last minute data.
1745

1746
    @type incoming: tuple of strings
1747
    @param incoming: (target_host_ip, port)
1748
    @type kvmhelp: string
1749
    @param kvmhelp: output of kvm --help
1750

1751
    """
1752
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1753
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1754
    #    have changed since the instance started; only use them if the change
1755
    #    won't affect the inside of the instance (which hasn't been rebooted).
1756
    #  - up_hvp contains the parameters as they were when the instance was
1757
    #    started, plus any new parameter which has been added between ganeti
1758
    #    versions: it is paramount that those default to a value which won't
1759
    #    affect the inside of the instance as well.
1760
    conf_hvp = instance.hvparams
1761
    name = instance.name
1762
    self._CheckDown(name)
1763

    
1764
    temp_files = []
1765

    
1766
    kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1767
    # the first element of kvm_cmd is always the path to the kvm binary
1768
    kvm_path = kvm_cmd[0]
1769
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1770

    
1771
    # We know it's safe to run as a different user upon migration, so we'll use
1772
    # the latest conf, from conf_hvp.
1773
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1774
    if security_model == constants.HT_SM_USER:
1775
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1776

    
1777
    keymap = conf_hvp[constants.HV_KEYMAP]
1778
    if keymap:
1779
      keymap_path = self._InstanceKeymapFile(name)
1780
      # If a keymap file is specified, KVM won't use its internal defaults. By
1781
      # first including the "en-us" layout, an error on loading the actual
1782
      # layout (e.g. because it can't be found) won't lead to a non-functional
1783
      # keyboard. A keyboard with incorrect keys is still better than none.
1784
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1785
      kvm_cmd.extend(["-k", keymap_path])
1786

    
1787
    # We have reasons to believe changing something like the nic driver/type
1788
    # upon migration won't exactly fly with the instance kernel, so for nic
1789
    # related parameters we'll use up_hvp
1790
    tapfds = []
1791
    taps = []
1792
    devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1793

    
1794
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1795
                                                     kvm_disks,
1796
                                                     kvmhelp,
1797
                                                     devlist)
1798
    kvm_cmd.extend(bdev_opts)
1799

    
1800
    if not kvm_nics:
1801
      kvm_cmd.extend(["-net", "none"])
1802
    else:
1803
      vnet_hdr = False
1804
      tap_extra = ""
1805
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1806
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1807
        nic_model = self._VIRTIO
1808
        try:
1809
          if self._VIRTIO_NET_RE.search(devlist):
1810
            nic_model = self._VIRTIO_NET_PCI
1811
            vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1812
        except errors.HypervisorError, _:
1813
          # Older versions of kvm don't support DEVICE_LIST, but they don't
1814
          # have new virtio syntax either.
1815
          pass
1816

    
1817
        if up_hvp[constants.HV_VHOST_NET]:
1818
          # check for vhost_net support
1819
          if self._VHOST_RE.search(kvmhelp):
1820
            tap_extra = ",vhost=on"
1821
          else:
1822
            raise errors.HypervisorError("vhost_net is configured"
1823
                                         " but it is not available")
1824
      else:
1825
        nic_model = nic_type
1826

    
1827
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1828

    
1829
      for nic_seq, nic in enumerate(kvm_nics):
1830
        tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1831
        tapfds.append(tapfd)
1832
        taps.append(tapname)
1833
        if kvm_supports_netdev:
1834
          nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1835
          try:
1836
            # kvm_nics already exist in old runtime files and thus there might
1837
            # be some entries without pci slot (therefore try: except:)
1838
            kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1839
            netdev = kvm_devid
1840
            nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1841
          except errors.HotplugError:
1842
            netdev = "netdev%d" % nic_seq
1843
          nic_val += (",netdev=%s" % netdev)
1844
          tap_val = ("type=tap,id=%s,fd=%d%s" %
1845
                     (netdev, tapfd, tap_extra))
1846
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1847
        else:
1848
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1849
                                                         nic.mac, nic_model)
1850
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1851
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1852

    
1853
    if incoming:
1854
      target, port = incoming
1855
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1856

    
1857
    # Changing the vnc password doesn't bother the guest that much. At most it
1858
    # will surprise people who connect to it. Whether positively or negatively
1859
    # it's debatable.
1860
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1861
    vnc_pwd = None
1862
    if vnc_pwd_file:
1863
      try:
1864
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1865
      except EnvironmentError, err:
1866
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1867
                                     % (vnc_pwd_file, err))
1868

    
1869
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1870
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1871
                         constants.SECURE_DIR_MODE)])
1872

    
1873
    # Automatically enable QMP if version is >= 0.14
1874
    if self._QMP_RE.search(kvmhelp):
1875
      logging.debug("Enabling QMP")
1876
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1877
                      self._InstanceQmpMonitor(instance.name)])
1878

    
1879
    # Configure the network now for starting instances and bridged interfaces,
1880
    # during FinalizeMigration for incoming instances' routed interfaces
1881
    for nic_seq, nic in enumerate(kvm_nics):
1882
      if (incoming and
1883
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1884
        continue
1885
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1886

    
1887
    # CPU affinity requires kvm to start paused, so we set this flag if the
1888
    # instance is not already paused and if we are not going to accept a
1889
    # migrating instance. In the latter case, pausing is not needed.
1890
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1891
    if start_kvm_paused:
1892
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1893

    
1894
    # Note: CPU pinning is using up_hvp since changes take effect
1895
    # during instance startup anyway, and to avoid problems when soft
1896
    # rebooting the instance.
1897
    cpu_pinning = False
1898
    if up_hvp.get(constants.HV_CPU_MASK, None):
1899
      cpu_pinning = True
1900

    
1901
    if security_model == constants.HT_SM_POOL:
1902
      ss = ssconf.SimpleStore()
1903
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1904
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1905
      uid = uidpool.RequestUnusedUid(all_uids)
1906
      try:
1907
        username = pwd.getpwuid(uid.GetUid()).pw_name
1908
        kvm_cmd.extend(["-runas", username])
1909
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1910
      except:
1911
        uidpool.ReleaseUid(uid)
1912
        raise
1913
      else:
1914
        uid.Unlock()
1915
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1916
    else:
1917
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1918

    
1919
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1920
                     constants.RUN_DIRS_MODE)])
1921
    for nic_seq, tap in enumerate(taps):
1922
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1923
                      data=tap)
1924

    
1925
    if vnc_pwd:
1926
      change_cmd = "change vnc password %s" % vnc_pwd
1927
      self._CallMonitorCommand(instance.name, change_cmd)
1928

    
1929
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1930
    # connection attempts because SPICE by default does not allow connections
1931
    # if neither a password nor the "disable_ticketing" options are specified.
1932
    # As soon as we send the password via QMP, that password is a valid ticket
1933
    # for connection.
1934
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1935
    if spice_password_file:
1936
      spice_pwd = ""
1937
      try:
1938
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1939
      except EnvironmentError, err:
1940
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1941
                                     % (spice_password_file, err))
1942

    
1943
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1944
      qmp.connect()
1945
      arguments = {
1946
          "protocol": "spice",
1947
          "password": spice_pwd,
1948
      }
1949
      qmp.Execute("set_password", arguments)
1950

    
1951
    for filename in temp_files:
1952
      utils.RemoveFile(filename)
1953

    
1954
    # If requested, set CPU affinity and resume instance execution
1955
    if cpu_pinning:
1956
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1957

    
1958
    start_memory = self._InstanceStartupMemory(instance)
1959
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1960
      self.BalloonInstanceMemory(instance, start_memory)
1961

    
1962
    if start_kvm_paused:
1963
      # To control CPU pinning, ballooning, and vnc/spice passwords
1964
      # the VM was started in a frozen state. If freezing was not
1965
      # explicitly requested resume the vm status.
1966
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1967

    
1968
  def StartInstance(self, instance, block_devices, startup_paused):
1969
    """Start an instance.
1970

1971
    """
1972
    self._CheckDown(instance.name)
1973
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1974
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1975
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1976
                                           startup_paused, kvmhelp)
1977
    self._SaveKVMRuntime(instance, kvm_runtime)
1978
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1979

    
1980
  def _CallMonitorCommand(self, instance_name, command):
1981
    """Invoke a command on the instance monitor.
1982

1983
    """
1984
    # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1985
    # version. The monitor protocol is designed for human consumption, whereas
1986
    # QMP is made for programmatic usage. In the worst case QMP can also
1987
    # execute monitor commands. As it is, all calls to socat take at least
1988
    # 500ms and likely more: socat can't detect the end of the reply and waits
1989
    # for 500ms of no data received before exiting (500 ms is the default for
1990
    # the "-t" parameter).
1991
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1992
             (utils.ShellQuote(command),
1993
              constants.SOCAT_PATH,
1994
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1995
    result = utils.RunCmd(socat)
1996
    if result.failed:
1997
      msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1998
             " output: %s" %
1999
             (command, instance_name, result.fail_reason, result.output))
2000
      raise errors.HypervisorError(msg)
2001

    
2002
    return result
2003

    
2004
  def _GetFreePCISlot(self, instance, dev):
2005
    """Get the first available pci slot of a runnung instance.
2006

2007
    """
2008
    slots = bitarray(32)
2009
    slots.setall(False) # pylint: disable=E1101
2010
    output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
2011
    for line in output.stdout.splitlines():
2012
      match = self._INFO_PCI_RE.search(line)
2013
      if match:
2014
        slot = int(match.group(1))
2015
        slots[slot] = True
2016

    
2017
    [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
2018
    if not free:
2019
      raise errors.HypervisorError("All PCI slots occupied")
2020

    
2021
    dev.pci = int(free)
2022

    
2023
  def VerifyHotplugSupport(self, instance, action, dev_type):
2024
    """Verifies that hotplug is supported.
2025

2026
    Hotplug is *not* supported in case of:
2027
     - security models and chroot (disk hotplug)
2028
     - fdsend module is missing (nic hot-add)
2029

2030
    @raise errors.HypervisorError: in one of the previous cases
2031

2032
    """
2033
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2034
      hvp = instance.hvparams
2035
      security_model = hvp[constants.HV_SECURITY_MODEL]
2036
      use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
2037
      if use_chroot:
2038
        raise errors.HotplugError("Disk hotplug is not supported"
2039
                                  " in case of chroot.")
2040
      if security_model != constants.HT_SM_NONE:
2041
        raise errors.HotplugError("Disk Hotplug is not supported in case"
2042
                                  " security models are used.")
2043

    
2044
    if (dev_type == constants.HOTPLUG_TARGET_NIC and
2045
        action == constants.HOTPLUG_ACTION_ADD and not fdsend):
2046
      raise errors.HotplugError("Cannot hot-add NIC."
2047
                                " fdsend python module is missing.")
2048

    
2049
  def HotplugSupported(self, instance):
2050
    """Checks if hotplug is generally supported.
2051

2052
    Hotplug is *not* supported in case of:
2053
     - qemu versions < 1.0
2054
     - for stopped instances
2055

2056
    @raise errors.HypervisorError: in one of the previous cases
2057

2058
    """
2059
    try:
2060
      output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2061
    except errors.HypervisorError:
2062
      raise errors.HotplugError("Instance is probably down")
2063

    
2064
    # TODO: search for netdev_add, drive_add, device_add.....
2065
    match = self._INFO_VERSION_RE.search(output.stdout)
2066
    if not match:
2067
      raise errors.HotplugError("Cannot parse qemu version via monitor")
2068

    
2069
    v_major, v_min, _, _ = match.groups()
2070
    if (int(v_major), int(v_min)) < (1, 0):
2071
      raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2072

    
2073
  def _CallHotplugCommands(self, name, cmds):
2074
    for c in cmds:
2075
      output = self._CallMonitorCommand(name, c)
2076
      # TODO: parse output and check if succeeded
2077
      for line in output.stdout.splitlines():
2078
        logging.info("%s", line)
2079
      time.sleep(2)
2080

    
2081
  def HotAddDevice(self, instance, dev_type, device, extra, seq):
2082
    """ Helper method to hot-add a new device
2083

2084
    It gets free pci slot generates the device name and invokes the
2085
    device specific method.
2086

2087
    """
2088
    # in case of hot-mod if the device already exists this is given
2089
    if device.pci is None:
2090
      self._GetFreePCISlot(instance, device)
2091
    kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2092
    runtime = self._LoadKVMRuntime(instance)
2093
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2094
      cmds = ["drive_add dummy file=%s,if=none,id=%s,format=raw" %
2095
                (extra, kvm_devid)]
2096
      cmds += ["device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
2097
                (hex(device.pci), kvm_devid, kvm_devid)]
2098
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
2099
      (tap, fd) = _OpenTap()
2100
      self._ConfigureNIC(instance, seq, device, tap)
2101
      self._PassTapFd(instance, fd, device)
2102
      cmds = ["netdev_add tap,id=%s,fd=%s" % (kvm_devid, kvm_devid)]
2103
      args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
2104
               (hex(device.pci), device.mac, kvm_devid, kvm_devid)
2105
      cmds += ["device_add %s" % args]
2106
      utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
2107

    
2108
    self._CallHotplugCommands(instance.name, cmds)
2109
    # update relevant entries in runtime file
2110
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2111
    entry = _RUNTIME_ENTRY[dev_type](device, extra)
2112
    runtime[index].append(entry)
2113
    self._SaveKVMRuntime(instance, runtime)
2114

    
2115
  def HotDelDevice(self, instance, dev_type, device, _, seq):
2116
    """ Helper method for hot-del device
2117

2118
    It gets device info from runtime file, generates the device name and
2119
    invokes the device specific method.
2120

2121
    """
2122
    runtime = self._LoadKVMRuntime(instance)
2123
    entry = _GetExistingDeviceInfo(dev_type, device, runtime)
2124
    kvm_device = _RUNTIME_DEVICE[dev_type](entry)
2125
    kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
2126
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2127
      cmds = ["device_del %s" % kvm_devid]
2128
      cmds += ["drive_del %s" % kvm_devid]
2129
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
2130
      cmds = ["device_del %s" % kvm_devid]
2131
      cmds += ["netdev_del %s" % kvm_devid]
2132
      utils.RemoveFile(self._InstanceNICFile(instance.name, seq))
2133
    self._CallHotplugCommands(instance.name, cmds)
2134
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2135
    runtime[index].remove(entry)
2136
    self._SaveKVMRuntime(instance, runtime)
2137

    
2138
    return kvm_device.pci
2139

    
2140
  def HotModDevice(self, instance, dev_type, device, _, seq):
2141
    """ Helper method for hot-mod device
2142

2143
    It gets device info from runtime file, generates the device name and
2144
    invokes the device specific method. Currently only NICs support hot-mod
2145

2146
    """
2147
    if dev_type == constants.HOTPLUG_TARGET_NIC:
2148
      # putting it back in the same pci slot
2149
      try:
2150
        device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2151
      except errors.HotplugError:
2152
        logging.info("Device not found in runtime file. Assuming it was"
2153
                     " previously added without --hotplug option.")
2154
      # TODO: remove sleep when socat gets removed
2155
      self.HotAddDevice(instance, dev_type, device, _, seq)
2156

    
2157
  def _PassTapFd(self, instance, fd, nic):
2158
    """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2159

2160
    """
2161
    # TODO: factor out code related to unix sockets.
2162
    #       squash common parts between monitor and qmp
2163
    kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2164
    command = "getfd %s\n" % kvm_devid
2165
    fds = [fd]
2166
    logging.info("%s", fds)
2167
    try:
2168
      monsock = MonitorSocket(self._InstanceMonitor(instance.name))
2169
      monsock.connect()
2170
      fdsend.sendfds(monsock.sock, command, fds=fds)
2171
    finally:
2172
      monsock.close()
2173

    
2174
  @classmethod
2175
  def _ParseKVMVersion(cls, text):
2176
    """Parse the KVM version from the --help output.
2177

2178
    @type text: string
2179
    @param text: output of kvm --help
2180
    @return: (version, v_maj, v_min, v_rev)
2181
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2182

2183
    """
2184
    match = cls._VERSION_RE.search(text.splitlines()[0])
2185
    if not match:
2186
      raise errors.HypervisorError("Unable to get KVM version")
2187

    
2188
    v_all = match.group(0)
2189
    v_maj = int(match.group(1))
2190
    v_min = int(match.group(2))
2191
    if match.group(4):
2192
      v_rev = int(match.group(4))
2193
    else:
2194
      v_rev = 0
2195
    return (v_all, v_maj, v_min, v_rev)
2196

    
2197
  @classmethod
2198
  def _GetKVMOutput(cls, kvm_path, option):
2199
    """Return the output of a kvm invocation
2200

2201
    @type kvm_path: string
2202
    @param kvm_path: path to the kvm executable
2203
    @type option: a key of _KVMOPTS_CMDS
2204
    @param option: kvm option to fetch the output from
2205
    @return: output a supported kvm invocation
2206
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2207

2208
    """
2209
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2210

    
2211
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
2212

    
2213
    result = utils.RunCmd([kvm_path] + optlist)
2214
    if result.failed and not can_fail:
2215
      raise errors.HypervisorError("Unable to get KVM %s output" %
2216
                                    " ".join(optlist))
2217
    return result.output
2218

    
2219
  @classmethod
2220
  def _GetKVMVersion(cls, kvm_path):
2221
    """Return the installed KVM version.
2222

2223
    @return: (version, v_maj, v_min, v_rev)
2224
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2225

2226
    """
2227
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2228

    
2229
  @classmethod
2230
  def _GetDefaultMachineVersion(cls, kvm_path):
2231
    """Return the default hardware revision (e.g. pc-1.1)
2232

2233
    """
2234
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2235
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2236
    if match:
2237
      return match.group(1)
2238
    else:
2239
      return "pc"
2240

    
2241
  def StopInstance(self, instance, force=False, retry=False, name=None):
2242
    """Stop an instance.
2243

2244
    """
2245
    if name is not None and not force:
2246
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2247
    if name is None:
2248
      name = instance.name
2249
      acpi = instance.hvparams[constants.HV_ACPI]
2250
    else:
2251
      acpi = False
2252
    _, pid, alive = self._InstancePidAlive(name)
2253
    if pid > 0 and alive:
2254
      if force or not acpi:
2255
        utils.KillProcess(pid)
2256
      else:
2257
        self._CallMonitorCommand(name, "system_powerdown")
2258

    
2259
  def CleanupInstance(self, instance_name):
2260
    """Cleanup after a stopped instance
2261

2262
    """
2263
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
2264
    if pid > 0 and alive:
2265
      raise errors.HypervisorError("Cannot cleanup a live instance")
2266
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2267

    
2268
  def RebootInstance(self, instance):
2269
    """Reboot an instance.
2270

2271
    """
2272
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2273
    # socket the instance will stop, but now power up again. So we'll resort
2274
    # to shutdown and restart.
2275
    _, _, alive = self._InstancePidAlive(instance.name)
2276
    if not alive:
2277
      raise errors.HypervisorError("Failed to reboot instance %s:"
2278
                                   " not running" % instance.name)
2279
    # StopInstance will delete the saved KVM runtime so:
2280
    # ...first load it...
2281
    kvm_runtime = self._LoadKVMRuntime(instance)
2282
    # ...now we can safely call StopInstance...
2283
    if not self.StopInstance(instance):
2284
      self.StopInstance(instance, force=True)
2285
    # ...and finally we can save it again, and execute it...
2286
    self._SaveKVMRuntime(instance, kvm_runtime)
2287
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2288
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2289
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2290

    
2291
  def MigrationInfo(self, instance):
2292
    """Get instance information to perform a migration.
2293

2294
    @type instance: L{objects.Instance}
2295
    @param instance: instance to be migrated
2296
    @rtype: string
2297
    @return: content of the KVM runtime file
2298

2299
    """
2300
    return self._ReadKVMRuntime(instance.name)
2301

    
2302
  def AcceptInstance(self, instance, info, target):
2303
    """Prepare to accept an instance.
2304

2305
    @type instance: L{objects.Instance}
2306
    @param instance: instance to be accepted
2307
    @type info: string
2308
    @param info: content of the KVM runtime file on the source node
2309
    @type target: string
2310
    @param target: target host (usually ip), on this node
2311

2312
    """
2313
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2314
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2315
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2316
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2317
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2318
                            incoming=incoming_address)
2319

    
2320
  def FinalizeMigrationDst(self, instance, info, success):
2321
    """Finalize the instance migration on the target node.
2322

2323
    Stop the incoming mode KVM.
2324

2325
    @type instance: L{objects.Instance}
2326
    @param instance: instance whose migration is being finalized
2327

2328
    """
2329
    if success:
2330
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2331
      kvm_nics = kvm_runtime[1]
2332

    
2333
      for nic_seq, nic in enumerate(kvm_nics):
2334
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2335
          # Bridged interfaces have already been configured
2336
          continue
2337
        try:
2338
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2339
        except EnvironmentError, err:
2340
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
2341
                          instance.name, nic_seq, str(err))
2342
          continue
2343
        try:
2344
          self._ConfigureNIC(instance, nic_seq, nic, tap)
2345
        except errors.HypervisorError, err:
2346
          logging.warning(str(err))
2347

    
2348
      self._WriteKVMRuntime(instance.name, info)
2349
    else:
2350
      self.StopInstance(instance, force=True)
2351

    
2352
  def MigrateInstance(self, instance, target, live):
2353
    """Migrate an instance to a target node.
2354

2355
    The migration will not be attempted if the instance is not
2356
    currently running.
2357

2358
    @type instance: L{objects.Instance}
2359
    @param instance: the instance to be migrated
2360
    @type target: string
2361
    @param target: ip address of the target node
2362
    @type live: boolean
2363
    @param live: perform a live migration
2364

2365
    """
2366
    instance_name = instance.name
2367
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
2368
    _, _, alive = self._InstancePidAlive(instance_name)
2369
    if not alive:
2370
      raise errors.HypervisorError("Instance not running, cannot migrate")
2371

    
2372
    if not live:
2373
      self._CallMonitorCommand(instance_name, "stop")
2374

    
2375
    migrate_command = ("migrate_set_speed %dm" %
2376
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2377
    self._CallMonitorCommand(instance_name, migrate_command)
2378

    
2379
    migrate_command = ("migrate_set_downtime %dms" %
2380
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2381
    self._CallMonitorCommand(instance_name, migrate_command)
2382

    
2383
    # These commands are supported in latest qemu versions.
2384
    # Since _CallMonitorCommand does not catch monitor errors
2385
    # this does not raise an exception in case command is not supported
2386
    # TODO: either parse output of command or see if the command supported
2387
    # via info help (see hotplug)
2388
    migrate_command = ("migrate_set_capability xbzrle on")
2389
    self._CallMonitorCommand(instance_name, migrate_command)
2390

    
2391
    migrate_command = ("migrate_set_capability auto-converge on")
2392
    self._CallMonitorCommand(instance_name, migrate_command)
2393

    
2394
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2395
    self._CallMonitorCommand(instance_name, migrate_command)
2396

    
2397
  def FinalizeMigrationSource(self, instance, success, live):
2398
    """Finalize the instance migration on the source node.
2399

2400
    @type instance: L{objects.Instance}
2401
    @param instance: the instance that was migrated
2402
    @type success: bool
2403
    @param success: whether the migration succeeded or not
2404
    @type live: bool
2405
    @param live: whether the user requested a live migration or not
2406

2407
    """
2408
    if success:
2409
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2410
      utils.KillProcess(pid)
2411
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2412
    elif live:
2413
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2414

    
2415
  def GetMigrationStatus(self, instance):
2416
    """Get the migration status
2417

2418
    @type instance: L{objects.Instance}
2419
    @param instance: the instance that is being migrated
2420
    @rtype: L{objects.MigrationStatus}
2421
    @return: the status of the current migration (one of
2422
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2423
             progress info that can be retrieved from the hypervisor
2424

2425
    """
2426
    info_command = "info migrate"
2427
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2428
      result = self._CallMonitorCommand(instance.name, info_command)
2429
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
2430
      if not match:
2431
        if not result.stdout:
2432
          logging.info("KVM: empty 'info migrate' result")
2433
        else:
2434
          logging.warning("KVM: unknown 'info migrate' result: %s",
2435
                          result.stdout)
2436
      else:
2437
        status = match.group(1)
2438
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2439
          migration_status = objects.MigrationStatus(status=status)
2440
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2441
          if match:
2442
            migration_status.transferred_ram = match.group("transferred")
2443
            migration_status.total_ram = match.group("total")
2444

    
2445
          return migration_status
2446

    
2447
        logging.warning("KVM: unknown migration status '%s'", status)
2448

    
2449
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2450

    
2451
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2452

    
2453
  def BalloonInstanceMemory(self, instance, mem):
2454
    """Balloon an instance memory to a certain value.
2455

2456
    @type instance: L{objects.Instance}
2457
    @param instance: instance to be accepted
2458
    @type mem: int
2459
    @param mem: actual memory size to use for instance runtime
2460

2461
    """
2462
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2463

    
2464
  def GetNodeInfo(self):
2465
    """Return information about the node.
2466

2467
    @return: a dict with the following keys (values in MiB):
2468
          - memory_total: the total memory size on the node
2469
          - memory_free: the available memory on the node for instances
2470
          - memory_dom0: the memory used by the node itself, if available
2471
          - hv_version: the hypervisor version in the form (major, minor,
2472
                        revision)
2473

2474
    """
2475
    result = self.GetLinuxNodeInfo()
2476
    # FIXME: this is the global kvm version, but the actual version can be
2477
    # customized as an hv parameter. we should use the nodegroup's default kvm
2478
    # path parameter here.
2479
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2480
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2481
    return result
2482

    
2483
  @classmethod
2484
  def GetInstanceConsole(cls, instance, hvparams, beparams):
2485
    """Return a command for connecting to the console of an instance.
2486

2487
    """
2488
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2489
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2490
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2491
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2492
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2493
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2494
      return objects.InstanceConsole(instance=instance.name,
2495
                                     kind=constants.CONS_SSH,
2496
                                     host=instance.primary_node,
2497
                                     user=constants.SSH_CONSOLE_USER,
2498
                                     command=cmd)
2499

    
2500
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2501
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2502
      display = instance.network_port - constants.VNC_BASE_PORT
2503
      return objects.InstanceConsole(instance=instance.name,
2504
                                     kind=constants.CONS_VNC,
2505
                                     host=vnc_bind_address,
2506
                                     port=instance.network_port,
2507
                                     display=display)
2508

    
2509
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2510
    if spice_bind:
2511
      return objects.InstanceConsole(instance=instance.name,
2512
                                     kind=constants.CONS_SPICE,
2513
                                     host=spice_bind,
2514
                                     port=instance.network_port)
2515

    
2516
    return objects.InstanceConsole(instance=instance.name,
2517
                                   kind=constants.CONS_MESSAGE,
2518
                                   message=("No serial shell for instance %s" %
2519
                                            instance.name))
2520

    
2521
  def Verify(self):
2522
    """Verify the hypervisor.
2523

2524
    Check that the required binaries exist.
2525

2526
    @return: Problem description if something is wrong, C{None} otherwise
2527

2528
    """
2529
    msgs = []
2530
    # FIXME: this is the global kvm binary, but the actual path can be
2531
    # customized as an hv parameter; we should use the nodegroup's
2532
    # default kvm path parameter here.
2533
    if not os.path.exists(constants.KVM_PATH):
2534
      msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2535
    if not os.path.exists(constants.SOCAT_PATH):
2536
      msgs.append("The socat binary ('%s') does not exist" %
2537
                  constants.SOCAT_PATH)
2538

    
2539
    return self._FormatVerifyResults(msgs)
2540

    
2541
  @classmethod
2542
  def CheckParameterSyntax(cls, hvparams):
2543
    """Check the given parameters for validity.
2544

2545
    @type hvparams:  dict
2546
    @param hvparams: dictionary with parameter names/value
2547
    @raise errors.HypervisorError: when a parameter is not valid
2548

2549
    """
2550
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2551

    
2552
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2553
    if kernel_path:
2554
      if not hvparams[constants.HV_ROOT_PATH]:
2555
        raise errors.HypervisorError("Need a root partition for the instance,"
2556
                                     " if a kernel is defined")
2557

    
2558
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2559
        not hvparams[constants.HV_VNC_X509]):
2560
      raise errors.HypervisorError("%s must be defined, if %s is" %
2561
                                   (constants.HV_VNC_X509,
2562
                                    constants.HV_VNC_X509_VERIFY))
2563

    
2564
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2565
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2566
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2567
      if not serial_speed or serial_speed not in valid_speeds:
2568
        raise errors.HypervisorError("Invalid serial console speed, must be"
2569
                                     " one of: %s" %
2570
                                     utils.CommaJoin(valid_speeds))
2571

    
2572
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2573
    if (boot_order == constants.HT_BO_CDROM and
2574
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2575
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2576
                                   " ISO path")
2577

    
2578
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2579
    if security_model == constants.HT_SM_USER:
2580
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2581
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2582
                                     " must be specified")
2583
    elif (security_model == constants.HT_SM_NONE or
2584
          security_model == constants.HT_SM_POOL):
2585
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2586
        raise errors.HypervisorError("Cannot have a security domain when the"
2587
                                     " security model is 'none' or 'pool'")
2588

    
2589
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2590
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2591
    if spice_bind:
2592
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2593
        # if an IP version is specified, the spice_bind parameter must be an
2594
        # IP of that family
2595
        if (netutils.IP4Address.IsValid(spice_bind) and
2596
            spice_ip_version != constants.IP4_VERSION):
2597
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2598
                                       " the specified IP version is %s" %
2599
                                       (spice_bind, spice_ip_version))
2600

    
2601
        if (netutils.IP6Address.IsValid(spice_bind) and
2602
            spice_ip_version != constants.IP6_VERSION):
2603
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2604
                                       " the specified IP version is %s" %
2605
                                       (spice_bind, spice_ip_version))
2606
    else:
2607
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2608
      # error if any of them is set without it.
2609
      for param in _SPICE_ADDITIONAL_PARAMS:
2610
        if hvparams[param]:
2611
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2612
                                       (param, constants.HV_KVM_SPICE_BIND))
2613

    
2614
  @classmethod
2615
  def ValidateParameters(cls, hvparams):
2616
    """Check the given parameters for validity.
2617

2618
    @type hvparams:  dict
2619
    @param hvparams: dictionary with parameter names/value
2620
    @raise errors.HypervisorError: when a parameter is not valid
2621

2622
    """
2623
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2624

    
2625
    kvm_path = hvparams[constants.HV_KVM_PATH]
2626

    
2627
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2628
    if security_model == constants.HT_SM_USER:
2629
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2630
      try:
2631
        pwd.getpwnam(username)
2632
      except KeyError:
2633
        raise errors.HypervisorError("Unknown security domain user %s"
2634
                                     % username)
2635

    
2636
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2637
    if spice_bind:
2638
      # only one of VNC and SPICE can be used currently.
2639
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2640
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2641
                                     " only one of them can be used at a"
2642
                                     " given time")
2643

    
2644
      # check that KVM supports SPICE
2645
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2646
      if not cls._SPICE_RE.search(kvmhelp):
2647
        raise errors.HypervisorError("SPICE is configured, but it is not"
2648
                                     " supported according to 'kvm --help'")
2649

    
2650
      # if spice_bind is not an IP address, it must be a valid interface
2651
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2652
                       netutils.IP6Address.IsValid(spice_bind))
2653
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2654
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2655
                                     " a valid IP address or interface name" %
2656
                                     constants.HV_KVM_SPICE_BIND)
2657

    
2658
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2659
    if machine_version:
2660
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2661
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2662
        raise errors.HypervisorError("Unsupported machine version: %s" %
2663
                                     machine_version)
2664

    
2665
  @classmethod
2666
  def PowercycleNode(cls):
2667
    """KVM powercycle, just a wrapper over Linux powercycle.
2668

2669
    """
2670
    cls.LinuxPowercycle()