Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 9209d947

History | View | Annotate | Download (95.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_DATA_KEY = "data"
460
  _ERROR_DESC_KEY = "desc"
461
  _EXECUTE_KEY = "execute"
462
  _ARGUMENTS_KEY = "arguments"
463
  _CAPABILITIES_COMMAND = "qmp_capabilities"
464
  _MESSAGE_END_TOKEN = "\r\n"
465

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

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

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

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

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

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

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

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

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

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

    
515
    return (message, buf)
516

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

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

525
    """
526
    self._check_connection()
527

    
528
    # Check if there is already a message in the buffer
529
    (message, self._buf) = self._ParseMessage(self._buf)
530
    if 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
          return message
545

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

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

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

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

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

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

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

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

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

    
1197
    return (instance_name, pid, memory, vcpus, istat, times)
1198

    
1199
  def GetAllInstancesInfo(self):
1200
    """Get properties of all instances.
1201

1202
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1203

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

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

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

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

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

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

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

    
1299
      # TODO: export disk geometry in IDISK_PARAMS
1300
      heads = cfdev.params.get('heads', None)
1301
      secs = cfdev.params.get('secs', None)
1302
      if heads and secs:
1303
        nr_sectors = cfdev.size * 1024 * 1024 / 512
1304
        cyls = nr_sectors / (int(heads) * int(secs))
1305
        if cyls > 16383:
1306
          cyls = 16383
1307
        elif cyls < 2:
1308
          cyls = 2
1309
        if cyls and heads and secs:
1310
          drive_val += (",cyls=%d,heads=%d,secs=%d" %
1311
                        (cyls, int(heads), int(secs)))
1312

    
1313
      dev_opts.extend(["-drive", drive_val])
1314

    
1315
    return dev_opts
1316

    
1317
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1318
                          kvmhelp):
1319
    """Generate KVM information to start an instance.
1320

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

1330
    """
1331
    # pylint: disable=R0912,R0914,R0915
1332
    hvp = instance.hvparams
1333
    self.ValidateParameters(hvp)
1334

    
1335
    pidfile = self._InstancePidFile(instance.name)
1336
    kvm = hvp[constants.HV_KVM_PATH]
1337
    kvm_cmd = [kvm]
1338
    # used just by the vnc server, if enabled
1339
    kvm_cmd.extend(["-name", instance.name])
1340
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1341

    
1342
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1343
    if hvp[constants.HV_CPU_CORES]:
1344
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1345
    if hvp[constants.HV_CPU_THREADS]:
1346
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1347
    if hvp[constants.HV_CPU_SOCKETS]:
1348
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1349

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

    
1352
    kvm_cmd.extend(["-pidfile", pidfile])
1353
    kvm_cmd.extend(["-balloon", "virtio"])
1354
    kvm_cmd.extend(["-daemonize"])
1355
    if not instance.hvparams[constants.HV_ACPI]:
1356
      kvm_cmd.extend(["-no-acpi"])
1357
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1358
        constants.INSTANCE_REBOOT_EXIT:
1359
      kvm_cmd.extend(["-no-reboot"])
1360

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

    
1383
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1384
    if kernel_path:
1385
      boot_cdrom = boot_floppy = boot_network = False
1386
    else:
1387
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1388
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1389
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1390

    
1391
    if startup_paused:
1392
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1393

    
1394
    if boot_network:
1395
      kvm_cmd.extend(["-boot", "n"])
1396

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

    
1401
    disk_type = hvp[constants.HV_DISK_TYPE]
1402

    
1403
    #Now we can specify a different device type for CDROM devices.
1404
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1405
    if not cdrom_disk_type:
1406
      cdrom_disk_type = disk_type
1407

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

    
1429
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1430
    if iso_image2:
1431
      options = ",format=raw,media=cdrom"
1432
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1433
        if_val = ",if=virtio"
1434
      else:
1435
        if_val = ",if=%s" % cdrom_disk_type
1436
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1437
      kvm_cmd.extend(["-drive", drive_val])
1438

    
1439
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1440
    if floppy_image:
1441
      options = ",format=raw,media=disk"
1442
      if boot_floppy:
1443
        kvm_cmd.extend(["-boot", "a"])
1444
        options = "%s,boot=on" % options
1445
      if_val = ",if=floppy"
1446
      options = "%s%s" % (options, if_val)
1447
      drive_val = "file=%s%s" % (floppy_image, options)
1448
      kvm_cmd.extend(["-drive", drive_val])
1449

    
1450
    if kernel_path:
1451
      kvm_cmd.extend(["-kernel", kernel_path])
1452
      initrd_path = hvp[constants.HV_INITRD_PATH]
1453
      if initrd_path:
1454
        kvm_cmd.extend(["-initrd", initrd_path])
1455
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1456
                     hvp[constants.HV_KERNEL_ARGS]]
1457
      if hvp[constants.HV_SERIAL_CONSOLE]:
1458
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1459
        root_append.append("console=ttyS0,%s" % serial_speed)
1460
      kvm_cmd.extend(["-append", " ".join(root_append)])
1461

    
1462
    mem_path = hvp[constants.HV_MEM_PATH]
1463
    if mem_path:
1464
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1465

    
1466
    monitor_dev = ("unix:%s,server,nowait" %
1467
                   self._InstanceMonitor(instance.name))
1468
    kvm_cmd.extend(["-monitor", monitor_dev])
1469
    if hvp[constants.HV_SERIAL_CONSOLE]:
1470
      serial_dev = ("unix:%s,server,nowait" %
1471
                    self._InstanceSerial(instance.name))
1472
      kvm_cmd.extend(["-serial", serial_dev])
1473
    else:
1474
      kvm_cmd.extend(["-serial", "none"])
1475

    
1476
    mouse_type = hvp[constants.HV_USB_MOUSE]
1477
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1478
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1479
    spice_ip_version = None
1480

    
1481
    kvm_cmd.extend(["-usb"])
1482

    
1483
    if mouse_type:
1484
      kvm_cmd.extend(["-usbdevice", mouse_type])
1485
    elif vnc_bind_address:
1486
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1487

    
1488
    if vnc_bind_address:
1489
      if netutils.IP4Address.IsValid(vnc_bind_address):
1490
        if instance.network_port > constants.VNC_BASE_PORT:
1491
          display = instance.network_port - constants.VNC_BASE_PORT
1492
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1493
            vnc_arg = ":%d" % (display)
1494
          else:
1495
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1496
        else:
1497
          logging.error("Network port is not a valid VNC display (%d < %d),"
1498
                        " not starting VNC",
1499
                        instance.network_port, constants.VNC_BASE_PORT)
1500
          vnc_arg = "none"
1501

    
1502
        # Only allow tls and other option when not binding to a file, for now.
1503
        # kvm/qemu gets confused otherwise about the filename to use.
1504
        vnc_append = ""
1505
        if hvp[constants.HV_VNC_TLS]:
1506
          vnc_append = "%s,tls" % vnc_append
1507
          if hvp[constants.HV_VNC_X509_VERIFY]:
1508
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1509
                                               hvp[constants.HV_VNC_X509])
1510
          elif hvp[constants.HV_VNC_X509]:
1511
            vnc_append = "%s,x509=%s" % (vnc_append,
1512
                                         hvp[constants.HV_VNC_X509])
1513
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1514
          vnc_append = "%s,password" % vnc_append
1515

    
1516
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1517

    
1518
      else:
1519
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1520

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

    
1531
        # if the user specified an IP version and the interface does not
1532
        # have that kind of IP addresses, throw an exception
1533
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1534
          if not addresses[spice_ip_version]:
1535
            raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1536
                                         " for %s" % (spice_ip_version,
1537
                                                      spice_bind))
1538

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

    
1555
        spice_address = addresses[spice_ip_version][0]
1556

    
1557
      else:
1558
        # spice_bind is known to be a valid IP address, because
1559
        # ValidateParameters checked it.
1560
        spice_address = spice_bind
1561

    
1562
      spice_arg = "addr=%s" % spice_address
1563
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1564
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1565
                     (spice_arg, instance.network_port,
1566
                      pathutils.SPICE_CACERT_FILE))
1567
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1568
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1569
                      pathutils.SPICE_CERT_FILE))
1570
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1571
        if tls_ciphers:
1572
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1573
      else:
1574
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1575

    
1576
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1577
        spice_arg = "%s,disable-ticketing" % spice_arg
1578

    
1579
      if spice_ip_version:
1580
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1581

    
1582
      # Image compression options
1583
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1584
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1585
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1586
      if img_lossless:
1587
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1588
      if img_jpeg:
1589
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1590
      if img_zlib_glz:
1591
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1592

    
1593
      # Video stream detection
1594
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1595
      if video_streaming:
1596
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1597

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

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

    
1616
    else:
1617
      # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1618
      # also works in earlier versions though (tested with 1.1 and 1.3)
1619
      if self._DISPLAY_RE.search(kvmhelp):
1620
        kvm_cmd.extend(["-display", "none"])
1621
      else:
1622
        kvm_cmd.extend(["-nographic"])
1623

    
1624
    if hvp[constants.HV_USE_LOCALTIME]:
1625
      kvm_cmd.extend(["-localtime"])
1626

    
1627
    if hvp[constants.HV_KVM_USE_CHROOT]:
1628
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1629

    
1630
    # Add qemu-KVM -cpu param
1631
    if hvp[constants.HV_CPU_TYPE]:
1632
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1633

    
1634
    # As requested by music lovers
1635
    if hvp[constants.HV_SOUNDHW]:
1636
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1637

    
1638
    # Pass a -vga option if requested, or if spice is used, for backwards
1639
    # compatibility.
1640
    if hvp[constants.HV_VGA]:
1641
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1642
    elif spice_bind:
1643
      kvm_cmd.extend(["-vga", "qxl"])
1644

    
1645
    # Various types of usb devices, comma separated
1646
    if hvp[constants.HV_USB_DEVICES]:
1647
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1648
        kvm_cmd.extend(["-usbdevice", dev])
1649

    
1650
    if hvp[constants.HV_KVM_EXTRA]:
1651
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1652

    
1653
    pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1654
    kvm_disks = []
1655
    for disk, link_name in block_devices:
1656
      _UpdatePCISlots(disk, pci_reservations)
1657
      kvm_disks.append((disk, link_name))
1658

    
1659
    kvm_nics = []
1660
    for nic in instance.nics:
1661
      _UpdatePCISlots(nic, pci_reservations)
1662
      kvm_nics.append(nic)
1663

    
1664
    hvparams = hvp
1665

    
1666
    return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1667

    
1668
  def _WriteKVMRuntime(self, instance_name, data):
1669
    """Write an instance's KVM runtime
1670

1671
    """
1672
    try:
1673
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1674
                      data=data)
1675
    except EnvironmentError, err:
1676
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1677

    
1678
  def _ReadKVMRuntime(self, instance_name):
1679
    """Read an instance's KVM runtime
1680

1681
    """
1682
    try:
1683
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1684
    except EnvironmentError, err:
1685
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1686
    return file_content
1687

    
1688
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1689
    """Save an instance's KVM runtime
1690

1691
    """
1692
    kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1693

    
1694
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1695
    serialized_disks = [(blk.ToDict(), link)
1696
                            for blk, link in kvm_disks]
1697
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1698
                                      serialized_disks))
1699

    
1700
    self._WriteKVMRuntime(instance.name, serialized_form)
1701

    
1702
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1703
    """Load an instance's KVM runtime
1704

1705
    """
1706
    if not serialized_runtime:
1707
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1708

    
1709
    return _AnalyzeSerializedRuntime(serialized_runtime)
1710

    
1711
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1712
    """Run the KVM cmd and check for errors
1713

1714
    @type name: string
1715
    @param name: instance name
1716
    @type kvm_cmd: list of strings
1717
    @param kvm_cmd: runcmd input for kvm
1718
    @type tap_fds: list of int
1719
    @param tap_fds: fds of tap devices opened by Ganeti
1720

1721
    """
1722
    try:
1723
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1724
    finally:
1725
      for fd in tap_fds:
1726
        utils_wrapper.CloseFdNoError(fd)
1727

    
1728
    if result.failed:
1729
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1730
                                   (name, result.fail_reason, result.output))
1731
    if not self._InstancePidAlive(name)[2]:
1732
      raise errors.HypervisorError("Failed to start instance %s" % name)
1733

    
1734
  # too many local variables
1735
  # pylint: disable=R0914
1736
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1737
    """Execute a KVM cmd, after completing it with some last minute data.
1738

1739
    @type incoming: tuple of strings
1740
    @param incoming: (target_host_ip, port)
1741
    @type kvmhelp: string
1742
    @param kvmhelp: output of kvm --help
1743

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

    
1757
    temp_files = []
1758

    
1759
    kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1760
    # the first element of kvm_cmd is always the path to the kvm binary
1761
    kvm_path = kvm_cmd[0]
1762
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1763

    
1764
    # We know it's safe to run as a different user upon migration, so we'll use
1765
    # the latest conf, from conf_hvp.
1766
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1767
    if security_model == constants.HT_SM_USER:
1768
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1769

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

    
1780
    # We have reasons to believe changing something like the nic driver/type
1781
    # upon migration won't exactly fly with the instance kernel, so for nic
1782
    # related parameters we'll use up_hvp
1783
    tapfds = []
1784
    taps = []
1785
    devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1786

    
1787
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1788
                                                     kvm_disks,
1789
                                                     kvmhelp,
1790
                                                     devlist)
1791
    kvm_cmd.extend(bdev_opts)
1792

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

    
1810
        if up_hvp[constants.HV_VHOST_NET]:
1811
          # check for vhost_net support
1812
          if self._VHOST_RE.search(kvmhelp):
1813
            tap_extra = ",vhost=on"
1814
          else:
1815
            raise errors.HypervisorError("vhost_net is configured"
1816
                                         " but it is not available")
1817
      else:
1818
        nic_model = nic_type
1819

    
1820
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1821

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

    
1846
    if incoming:
1847
      target, port = incoming
1848
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1849

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

    
1862
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1863
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1864
                         constants.SECURE_DIR_MODE)])
1865

    
1866
    # Automatically enable QMP if version is >= 0.14
1867
    if self._QMP_RE.search(kvmhelp):
1868
      logging.debug("Enabling QMP")
1869
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1870
                      self._InstanceQmpMonitor(instance.name)])
1871

    
1872
    # Configure the network now for starting instances and bridged interfaces,
1873
    # during FinalizeMigration for incoming instances' routed interfaces
1874
    for nic_seq, nic in enumerate(kvm_nics):
1875
      if (incoming and
1876
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1877
        continue
1878
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1879

    
1880
    # CPU affinity requires kvm to start paused, so we set this flag if the
1881
    # instance is not already paused and if we are not going to accept a
1882
    # migrating instance. In the latter case, pausing is not needed.
1883
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1884
    if start_kvm_paused:
1885
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1886

    
1887
    # Note: CPU pinning is using up_hvp since changes take effect
1888
    # during instance startup anyway, and to avoid problems when soft
1889
    # rebooting the instance.
1890
    cpu_pinning = False
1891
    if up_hvp.get(constants.HV_CPU_MASK, None):
1892
      cpu_pinning = True
1893

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

    
1912
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1913
                     constants.RUN_DIRS_MODE)])
1914
    for nic_seq, tap in enumerate(taps):
1915
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1916
                      data=tap)
1917

    
1918
    if vnc_pwd:
1919
      change_cmd = "change vnc password %s" % vnc_pwd
1920
      self._CallMonitorCommand(instance.name, change_cmd)
1921

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

    
1936
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1937
      qmp.connect()
1938
      arguments = {
1939
          "protocol": "spice",
1940
          "password": spice_pwd,
1941
      }
1942
      qmp.Execute("set_password", arguments)
1943

    
1944
    for filename in temp_files:
1945
      utils.RemoveFile(filename)
1946

    
1947
    # If requested, set CPU affinity and resume instance execution
1948
    if cpu_pinning:
1949
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1950

    
1951
    start_memory = self._InstanceStartupMemory(instance)
1952
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1953
      self.BalloonInstanceMemory(instance, start_memory)
1954

    
1955
    if start_kvm_paused:
1956
      # To control CPU pinning, ballooning, and vnc/spice passwords
1957
      # the VM was started in a frozen state. If freezing was not
1958
      # explicitly requested resume the vm status.
1959
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1960

    
1961
  def StartInstance(self, instance, block_devices, startup_paused):
1962
    """Start an instance.
1963

1964
    """
1965
    self._CheckDown(instance.name)
1966
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1967
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1968
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1969
                                           startup_paused, kvmhelp)
1970
    self._SaveKVMRuntime(instance, kvm_runtime)
1971
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1972

    
1973
  def _CallMonitorCommand(self, instance_name, command):
1974
    """Invoke a command on the instance monitor.
1975

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

    
1995
    return result
1996

    
1997
  def _GetFreePCISlot(self, instance, dev):
1998
    """Get the first available pci slot of a runnung instance.
1999

2000
    """
2001
    slots = bitarray(32)
2002
    slots.setall(False) # pylint: disable=E1101
2003
    output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
2004
    for line in output.stdout.splitlines():
2005
      match = self._INFO_PCI_RE.search(line)
2006
      if match:
2007
        slot = int(match.group(1))
2008
        slots[slot] = True
2009

    
2010
    [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
2011
    if not free:
2012
      raise errors.HypervisorError("All PCI slots occupied")
2013

    
2014
    dev.pci = int(free)
2015

    
2016
  def VerifyHotplugSupport(self, instance, action, dev_type):
2017
    """Verifies that hotplug is supported.
2018

2019
    Hotplug is *not* supported in case of:
2020
     - security models and chroot (disk hotplug)
2021
     - fdsend module is missing (nic hot-add)
2022

2023
    @raise errors.HypervisorError: in one of the previous cases
2024

2025
    """
2026
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2027
      hvp = instance.hvparams
2028
      security_model = hvp[constants.HV_SECURITY_MODEL]
2029
      use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
2030
      if use_chroot:
2031
        raise errors.HotplugError("Disk hotplug is not supported"
2032
                                  " in case of chroot.")
2033
      if security_model != constants.HT_SM_NONE:
2034
        raise errors.HotplugError("Disk Hotplug is not supported in case"
2035
                                  " security models are used.")
2036

    
2037
    if (dev_type == constants.HOTPLUG_TARGET_NIC and
2038
        action == constants.HOTPLUG_ACTION_ADD and not fdsend):
2039
      raise errors.HotplugError("Cannot hot-add NIC."
2040
                                " fdsend python module is missing.")
2041

    
2042
  def HotplugSupported(self, instance):
2043
    """Checks if hotplug is generally supported.
2044

2045
    Hotplug is *not* supported in case of:
2046
     - qemu versions < 1.0
2047
     - for stopped instances
2048

2049
    @raise errors.HypervisorError: in one of the previous cases
2050

2051
    """
2052
    try:
2053
      output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2054
    except errors.HypervisorError:
2055
      raise errors.HotplugError("Instance is probably down")
2056

    
2057
    # TODO: search for netdev_add, drive_add, device_add.....
2058
    match = self._INFO_VERSION_RE.search(output.stdout)
2059
    if not match:
2060
      raise errors.HotplugError("Cannot parse qemu version via monitor")
2061

    
2062
    v_major, v_min, _, _ = match.groups()
2063
    if (int(v_major), int(v_min)) < (1, 0):
2064
      raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2065

    
2066
  def _CallHotplugCommand(self, name, cmd):
2067
    output = self._CallMonitorCommand(name, cmd)
2068
    # TODO: parse output and check if succeeded
2069
    for line in output.stdout.splitlines():
2070
      logging.info("%s", line)
2071

    
2072
  def HotAddDevice(self, instance, dev_type, device, extra, seq):
2073
    """ Helper method to hot-add a new device
2074

2075
    It gets free pci slot generates the device name and invokes the
2076
    device specific method.
2077

2078
    """
2079
    # in case of hot-mod this is given
2080
    if device.pci is None:
2081
      self._GetFreePCISlot(instance, device)
2082
    kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2083
    runtime = self._LoadKVMRuntime(instance)
2084
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2085
      command = "drive_add dummy file=%s,if=none,id=%s,format=raw\n" % \
2086
                 (extra, kvm_devid)
2087
      command += ("device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
2088
                  (hex(device.pci), kvm_devid, kvm_devid))
2089
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
2090
      (tap, fd) = _OpenTap()
2091
      self._ConfigureNIC(instance, seq, device, tap)
2092
      self._PassTapFd(instance, fd, device)
2093
      command = "netdev_add tap,id=%s,fd=%s\n" % (kvm_devid, kvm_devid)
2094
      args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
2095
               (hex(device.pci), device.mac, kvm_devid, kvm_devid)
2096
      command += "device_add %s" % args
2097
      utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
2098

    
2099
    self._CallHotplugCommand(instance.name, command)
2100
    # update relevant entries in runtime file
2101
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2102
    entry = _RUNTIME_ENTRY[dev_type](device, extra)
2103
    runtime[index].append(entry)
2104
    self._SaveKVMRuntime(instance, runtime)
2105

    
2106
  def HotDelDevice(self, instance, dev_type, device, _, seq):
2107
    """ Helper method for hot-del device
2108

2109
    It gets device info from runtime file, generates the device name and
2110
    invokes the device specific method.
2111

2112
    """
2113
    runtime = self._LoadKVMRuntime(instance)
2114
    entry = _GetExistingDeviceInfo(dev_type, device, runtime)
2115
    kvm_device = _RUNTIME_DEVICE[dev_type](entry)
2116
    kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
2117
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2118
      command = "device_del %s\n" % kvm_devid
2119
      command += "drive_del %s" % kvm_devid
2120
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
2121
      command = "device_del %s\n" % kvm_devid
2122
      command += "netdev_del %s" % kvm_devid
2123
      utils.RemoveFile(self._InstanceNICFile(instance.name, seq))
2124
    self._CallHotplugCommand(instance.name, command)
2125
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2126
    runtime[index].remove(entry)
2127
    self._SaveKVMRuntime(instance, runtime)
2128

    
2129
    return kvm_device.pci
2130

    
2131
  def HotModDevice(self, instance, dev_type, device, _, seq):
2132
    """ Helper method for hot-mod device
2133

2134
    It gets device info from runtime file, generates the device name and
2135
    invokes the device specific method. Currently only NICs support hot-mod
2136

2137
    """
2138
    if dev_type == constants.HOTPLUG_TARGET_NIC:
2139
      # putting it back in the same pci slot
2140
      device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2141
      # TODO: remove sleep when socat gets removed
2142
      time.sleep(2)
2143
      self.HotAddDevice(instance, dev_type, device, _, seq)
2144

    
2145
  def _PassTapFd(self, instance, fd, nic):
2146
    """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2147

2148
    """
2149
    # TODO: factor out code related to unix sockets.
2150
    #       squash common parts between monitor and qmp
2151
    kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2152
    command = "getfd %s\n" % kvm_devid
2153
    fds = [fd]
2154
    logging.info("%s", fds)
2155
    try:
2156
      monsock = MonitorSocket(self._InstanceMonitor(instance.name))
2157
      monsock.connect()
2158
      fdsend.sendfds(monsock.sock, command, fds=fds)
2159
    finally:
2160
      monsock.close()
2161

    
2162
  @classmethod
2163
  def _ParseKVMVersion(cls, text):
2164
    """Parse the KVM version from the --help output.
2165

2166
    @type text: string
2167
    @param text: output of kvm --help
2168
    @return: (version, v_maj, v_min, v_rev)
2169
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2170

2171
    """
2172
    match = cls._VERSION_RE.search(text.splitlines()[0])
2173
    if not match:
2174
      raise errors.HypervisorError("Unable to get KVM version")
2175

    
2176
    v_all = match.group(0)
2177
    v_maj = int(match.group(1))
2178
    v_min = int(match.group(2))
2179
    if match.group(4):
2180
      v_rev = int(match.group(4))
2181
    else:
2182
      v_rev = 0
2183
    return (v_all, v_maj, v_min, v_rev)
2184

    
2185
  @classmethod
2186
  def _GetKVMOutput(cls, kvm_path, option):
2187
    """Return the output of a kvm invocation
2188

2189
    @type kvm_path: string
2190
    @param kvm_path: path to the kvm executable
2191
    @type option: a key of _KVMOPTS_CMDS
2192
    @param option: kvm option to fetch the output from
2193
    @return: output a supported kvm invocation
2194
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2195

2196
    """
2197
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2198

    
2199
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
2200

    
2201
    result = utils.RunCmd([kvm_path] + optlist)
2202
    if result.failed and not can_fail:
2203
      raise errors.HypervisorError("Unable to get KVM %s output" %
2204
                                    " ".join(optlist))
2205
    return result.output
2206

    
2207
  @classmethod
2208
  def _GetKVMVersion(cls, kvm_path):
2209
    """Return the installed KVM version.
2210

2211
    @return: (version, v_maj, v_min, v_rev)
2212
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2213

2214
    """
2215
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2216

    
2217
  @classmethod
2218
  def _GetDefaultMachineVersion(cls, kvm_path):
2219
    """Return the default hardware revision (e.g. pc-1.1)
2220

2221
    """
2222
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2223
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2224
    if match:
2225
      return match.group(1)
2226
    else:
2227
      return "pc"
2228

    
2229
  def StopInstance(self, instance, force=False, retry=False, name=None):
2230
    """Stop an instance.
2231

2232
    """
2233
    if name is not None and not force:
2234
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2235
    if name is None:
2236
      name = instance.name
2237
      acpi = instance.hvparams[constants.HV_ACPI]
2238
    else:
2239
      acpi = False
2240
    _, pid, alive = self._InstancePidAlive(name)
2241
    if pid > 0 and alive:
2242
      if force or not acpi:
2243
        utils.KillProcess(pid)
2244
      else:
2245
        self._CallMonitorCommand(name, "system_powerdown")
2246

    
2247
  def CleanupInstance(self, instance_name):
2248
    """Cleanup after a stopped instance
2249

2250
    """
2251
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
2252
    if pid > 0 and alive:
2253
      raise errors.HypervisorError("Cannot cleanup a live instance")
2254
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2255

    
2256
  def RebootInstance(self, instance):
2257
    """Reboot an instance.
2258

2259
    """
2260
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2261
    # socket the instance will stop, but now power up again. So we'll resort
2262
    # to shutdown and restart.
2263
    _, _, alive = self._InstancePidAlive(instance.name)
2264
    if not alive:
2265
      raise errors.HypervisorError("Failed to reboot instance %s:"
2266
                                   " not running" % instance.name)
2267
    # StopInstance will delete the saved KVM runtime so:
2268
    # ...first load it...
2269
    kvm_runtime = self._LoadKVMRuntime(instance)
2270
    # ...now we can safely call StopInstance...
2271
    if not self.StopInstance(instance):
2272
      self.StopInstance(instance, force=True)
2273
    # ...and finally we can save it again, and execute it...
2274
    self._SaveKVMRuntime(instance, kvm_runtime)
2275
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2276
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2277
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2278

    
2279
  def MigrationInfo(self, instance):
2280
    """Get instance information to perform a migration.
2281

2282
    @type instance: L{objects.Instance}
2283
    @param instance: instance to be migrated
2284
    @rtype: string
2285
    @return: content of the KVM runtime file
2286

2287
    """
2288
    return self._ReadKVMRuntime(instance.name)
2289

    
2290
  def AcceptInstance(self, instance, info, target):
2291
    """Prepare to accept an instance.
2292

2293
    @type instance: L{objects.Instance}
2294
    @param instance: instance to be accepted
2295
    @type info: string
2296
    @param info: content of the KVM runtime file on the source node
2297
    @type target: string
2298
    @param target: target host (usually ip), on this node
2299

2300
    """
2301
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2302
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2303
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2304
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2305
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2306
                            incoming=incoming_address)
2307

    
2308
  def FinalizeMigrationDst(self, instance, info, success):
2309
    """Finalize the instance migration on the target node.
2310

2311
    Stop the incoming mode KVM.
2312

2313
    @type instance: L{objects.Instance}
2314
    @param instance: instance whose migration is being finalized
2315

2316
    """
2317
    if success:
2318
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2319
      kvm_nics = kvm_runtime[1]
2320

    
2321
      for nic_seq, nic in enumerate(kvm_nics):
2322
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2323
          # Bridged interfaces have already been configured
2324
          continue
2325
        try:
2326
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2327
        except EnvironmentError, err:
2328
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
2329
                          instance.name, nic_seq, str(err))
2330
          continue
2331
        try:
2332
          self._ConfigureNIC(instance, nic_seq, nic, tap)
2333
        except errors.HypervisorError, err:
2334
          logging.warning(str(err))
2335

    
2336
      self._WriteKVMRuntime(instance.name, info)
2337
    else:
2338
      self.StopInstance(instance, force=True)
2339

    
2340
  def MigrateInstance(self, instance, target, live):
2341
    """Migrate an instance to a target node.
2342

2343
    The migration will not be attempted if the instance is not
2344
    currently running.
2345

2346
    @type instance: L{objects.Instance}
2347
    @param instance: the instance to be migrated
2348
    @type target: string
2349
    @param target: ip address of the target node
2350
    @type live: boolean
2351
    @param live: perform a live migration
2352

2353
    """
2354
    instance_name = instance.name
2355
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
2356
    _, _, alive = self._InstancePidAlive(instance_name)
2357
    if not alive:
2358
      raise errors.HypervisorError("Instance not running, cannot migrate")
2359

    
2360
    if not live:
2361
      self._CallMonitorCommand(instance_name, "stop")
2362

    
2363
    migrate_command = ("migrate_set_speed %dm" %
2364
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2365
    self._CallMonitorCommand(instance_name, migrate_command)
2366

    
2367
    migrate_command = ("migrate_set_downtime %dms" %
2368
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2369
    self._CallMonitorCommand(instance_name, migrate_command)
2370

    
2371
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2372
    self._CallMonitorCommand(instance_name, migrate_command)
2373

    
2374
  def FinalizeMigrationSource(self, instance, success, live):
2375
    """Finalize the instance migration on the source node.
2376

2377
    @type instance: L{objects.Instance}
2378
    @param instance: the instance that was migrated
2379
    @type success: bool
2380
    @param success: whether the migration succeeded or not
2381
    @type live: bool
2382
    @param live: whether the user requested a live migration or not
2383

2384
    """
2385
    if success:
2386
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2387
      utils.KillProcess(pid)
2388
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2389
    elif live:
2390
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2391

    
2392
  def GetMigrationStatus(self, instance):
2393
    """Get the migration status
2394

2395
    @type instance: L{objects.Instance}
2396
    @param instance: the instance that is being migrated
2397
    @rtype: L{objects.MigrationStatus}
2398
    @return: the status of the current migration (one of
2399
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2400
             progress info that can be retrieved from the hypervisor
2401

2402
    """
2403
    info_command = "info migrate"
2404
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2405
      result = self._CallMonitorCommand(instance.name, info_command)
2406
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
2407
      if not match:
2408
        if not result.stdout:
2409
          logging.info("KVM: empty 'info migrate' result")
2410
        else:
2411
          logging.warning("KVM: unknown 'info migrate' result: %s",
2412
                          result.stdout)
2413
      else:
2414
        status = match.group(1)
2415
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2416
          migration_status = objects.MigrationStatus(status=status)
2417
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2418
          if match:
2419
            migration_status.transferred_ram = match.group("transferred")
2420
            migration_status.total_ram = match.group("total")
2421

    
2422
          return migration_status
2423

    
2424
        logging.warning("KVM: unknown migration status '%s'", status)
2425

    
2426
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2427

    
2428
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2429

    
2430
  def BalloonInstanceMemory(self, instance, mem):
2431
    """Balloon an instance memory to a certain value.
2432

2433
    @type instance: L{objects.Instance}
2434
    @param instance: instance to be accepted
2435
    @type mem: int
2436
    @param mem: actual memory size to use for instance runtime
2437

2438
    """
2439
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2440

    
2441
  def GetNodeInfo(self):
2442
    """Return information about the node.
2443

2444
    @return: a dict with the following keys (values in MiB):
2445
          - memory_total: the total memory size on the node
2446
          - memory_free: the available memory on the node for instances
2447
          - memory_dom0: the memory used by the node itself, if available
2448
          - hv_version: the hypervisor version in the form (major, minor,
2449
                        revision)
2450

2451
    """
2452
    result = self.GetLinuxNodeInfo()
2453
    # FIXME: this is the global kvm version, but the actual version can be
2454
    # customized as an hv parameter. we should use the nodegroup's default kvm
2455
    # path parameter here.
2456
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2457
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2458
    return result
2459

    
2460
  @classmethod
2461
  def GetInstanceConsole(cls, instance, hvparams, beparams):
2462
    """Return a command for connecting to the console of an instance.
2463

2464
    """
2465
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2466
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2467
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2468
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2469
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2470
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2471
      return objects.InstanceConsole(instance=instance.name,
2472
                                     kind=constants.CONS_SSH,
2473
                                     host=instance.primary_node,
2474
                                     user=constants.SSH_CONSOLE_USER,
2475
                                     command=cmd)
2476

    
2477
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2478
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2479
      display = instance.network_port - constants.VNC_BASE_PORT
2480
      return objects.InstanceConsole(instance=instance.name,
2481
                                     kind=constants.CONS_VNC,
2482
                                     host=vnc_bind_address,
2483
                                     port=instance.network_port,
2484
                                     display=display)
2485

    
2486
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2487
    if spice_bind:
2488
      return objects.InstanceConsole(instance=instance.name,
2489
                                     kind=constants.CONS_SPICE,
2490
                                     host=spice_bind,
2491
                                     port=instance.network_port)
2492

    
2493
    return objects.InstanceConsole(instance=instance.name,
2494
                                   kind=constants.CONS_MESSAGE,
2495
                                   message=("No serial shell for instance %s" %
2496
                                            instance.name))
2497

    
2498
  def Verify(self):
2499
    """Verify the hypervisor.
2500

2501
    Check that the required binaries exist.
2502

2503
    @return: Problem description if something is wrong, C{None} otherwise
2504

2505
    """
2506
    msgs = []
2507
    # FIXME: this is the global kvm binary, but the actual path can be
2508
    # customized as an hv parameter; we should use the nodegroup's
2509
    # default kvm path parameter here.
2510
    if not os.path.exists(constants.KVM_PATH):
2511
      msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2512
    if not os.path.exists(constants.SOCAT_PATH):
2513
      msgs.append("The socat binary ('%s') does not exist" %
2514
                  constants.SOCAT_PATH)
2515

    
2516
    return self._FormatVerifyResults(msgs)
2517

    
2518
  @classmethod
2519
  def CheckParameterSyntax(cls, hvparams):
2520
    """Check the given parameters for validity.
2521

2522
    @type hvparams:  dict
2523
    @param hvparams: dictionary with parameter names/value
2524
    @raise errors.HypervisorError: when a parameter is not valid
2525

2526
    """
2527
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2528

    
2529
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2530
    if kernel_path:
2531
      if not hvparams[constants.HV_ROOT_PATH]:
2532
        raise errors.HypervisorError("Need a root partition for the instance,"
2533
                                     " if a kernel is defined")
2534

    
2535
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2536
        not hvparams[constants.HV_VNC_X509]):
2537
      raise errors.HypervisorError("%s must be defined, if %s is" %
2538
                                   (constants.HV_VNC_X509,
2539
                                    constants.HV_VNC_X509_VERIFY))
2540

    
2541
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2542
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2543
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2544
      if not serial_speed or serial_speed not in valid_speeds:
2545
        raise errors.HypervisorError("Invalid serial console speed, must be"
2546
                                     " one of: %s" %
2547
                                     utils.CommaJoin(valid_speeds))
2548

    
2549
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2550
    if (boot_order == constants.HT_BO_CDROM and
2551
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2552
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2553
                                   " ISO path")
2554

    
2555
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2556
    if security_model == constants.HT_SM_USER:
2557
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2558
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2559
                                     " must be specified")
2560
    elif (security_model == constants.HT_SM_NONE or
2561
          security_model == constants.HT_SM_POOL):
2562
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2563
        raise errors.HypervisorError("Cannot have a security domain when the"
2564
                                     " security model is 'none' or 'pool'")
2565

    
2566
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2567
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2568
    if spice_bind:
2569
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2570
        # if an IP version is specified, the spice_bind parameter must be an
2571
        # IP of that family
2572
        if (netutils.IP4Address.IsValid(spice_bind) and
2573
            spice_ip_version != constants.IP4_VERSION):
2574
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2575
                                       " the specified IP version is %s" %
2576
                                       (spice_bind, spice_ip_version))
2577

    
2578
        if (netutils.IP6Address.IsValid(spice_bind) and
2579
            spice_ip_version != constants.IP6_VERSION):
2580
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2581
                                       " the specified IP version is %s" %
2582
                                       (spice_bind, spice_ip_version))
2583
    else:
2584
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2585
      # error if any of them is set without it.
2586
      for param in _SPICE_ADDITIONAL_PARAMS:
2587
        if hvparams[param]:
2588
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2589
                                       (param, constants.HV_KVM_SPICE_BIND))
2590

    
2591
  @classmethod
2592
  def ValidateParameters(cls, hvparams):
2593
    """Check the given parameters for validity.
2594

2595
    @type hvparams:  dict
2596
    @param hvparams: dictionary with parameter names/value
2597
    @raise errors.HypervisorError: when a parameter is not valid
2598

2599
    """
2600
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2601

    
2602
    kvm_path = hvparams[constants.HV_KVM_PATH]
2603

    
2604
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2605
    if security_model == constants.HT_SM_USER:
2606
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2607
      try:
2608
        pwd.getpwnam(username)
2609
      except KeyError:
2610
        raise errors.HypervisorError("Unknown security domain user %s"
2611
                                     % username)
2612

    
2613
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2614
    if spice_bind:
2615
      # only one of VNC and SPICE can be used currently.
2616
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2617
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2618
                                     " only one of them can be used at a"
2619
                                     " given time")
2620

    
2621
      # check that KVM supports SPICE
2622
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2623
      if not cls._SPICE_RE.search(kvmhelp):
2624
        raise errors.HypervisorError("SPICE is configured, but it is not"
2625
                                     " supported according to 'kvm --help'")
2626

    
2627
      # if spice_bind is not an IP address, it must be a valid interface
2628
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2629
                       netutils.IP6Address.IsValid(spice_bind))
2630
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2631
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2632
                                     " a valid IP address or interface name" %
2633
                                     constants.HV_KVM_SPICE_BIND)
2634

    
2635
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2636
    if machine_version:
2637
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2638
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2639
        raise errors.HypervisorError("Unsupported machine version: %s" %
2640
                                     machine_version)
2641

    
2642
  @classmethod
2643
  def PowercycleNode(cls):
2644
    """KVM powercycle, just a wrapper over Linux powercycle.
2645

2646
    """
2647
    cls.LinuxPowercycle()