Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ f44c88c7

History | View | Annotate | Download (95.3 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
      dev_opts.extend(["-drive", drive_val])
1300

    
1301
    return dev_opts
1302

    
1303
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1304
                          kvmhelp):
1305
    """Generate KVM information to start an instance.
1306

1307
    @type kvmhelp: string
1308
    @param kvmhelp: output of kvm --help
1309
    @attention: this function must not have any side-effects; for
1310
        example, it must not write to the filesystem, or read values
1311
        from the current system the are expected to differ between
1312
        nodes, since it is only run once at instance startup;
1313
        actions/kvm arguments that can vary between systems should be
1314
        done in L{_ExecuteKVMRuntime}
1315

1316
    """
1317
    # pylint: disable=R0912,R0914,R0915
1318
    hvp = instance.hvparams
1319
    self.ValidateParameters(hvp)
1320

    
1321
    pidfile = self._InstancePidFile(instance.name)
1322
    kvm = hvp[constants.HV_KVM_PATH]
1323
    kvm_cmd = [kvm]
1324
    # used just by the vnc server, if enabled
1325
    kvm_cmd.extend(["-name", instance.name])
1326
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1327

    
1328
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1329
    if hvp[constants.HV_CPU_CORES]:
1330
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1331
    if hvp[constants.HV_CPU_THREADS]:
1332
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1333
    if hvp[constants.HV_CPU_SOCKETS]:
1334
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1335

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

    
1338
    kvm_cmd.extend(["-pidfile", pidfile])
1339
    kvm_cmd.extend(["-balloon", "virtio"])
1340
    kvm_cmd.extend(["-daemonize"])
1341
    if not instance.hvparams[constants.HV_ACPI]:
1342
      kvm_cmd.extend(["-no-acpi"])
1343
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1344
        constants.INSTANCE_REBOOT_EXIT:
1345
      kvm_cmd.extend(["-no-reboot"])
1346

    
1347
    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1348
    if not mversion:
1349
      mversion = self._GetDefaultMachineVersion(kvm)
1350
    if self._MACHINE_RE.search(kvmhelp):
1351
      # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1352
      # extra hypervisor parameters. We should also investigate whether and how
1353
      # shadow_mem should be considered for the resource model.
1354
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1355
        specprop = ",accel=kvm"
1356
      else:
1357
        specprop = ""
1358
      machinespec = "%s%s" % (mversion, specprop)
1359
      kvm_cmd.extend(["-machine", machinespec])
1360
    else:
1361
      kvm_cmd.extend(["-M", mversion])
1362
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1363
          self._ENABLE_KVM_RE.search(kvmhelp)):
1364
        kvm_cmd.extend(["-enable-kvm"])
1365
      elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1366
            self._DISABLE_KVM_RE.search(kvmhelp)):
1367
        kvm_cmd.extend(["-disable-kvm"])
1368

    
1369
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1370
    if kernel_path:
1371
      boot_cdrom = boot_floppy = boot_network = False
1372
    else:
1373
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1374
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1375
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1376

    
1377
    if startup_paused:
1378
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1379

    
1380
    if boot_network:
1381
      kvm_cmd.extend(["-boot", "n"])
1382

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

    
1387
    disk_type = hvp[constants.HV_DISK_TYPE]
1388

    
1389
    #Now we can specify a different device type for CDROM devices.
1390
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1391
    if not cdrom_disk_type:
1392
      cdrom_disk_type = disk_type
1393

    
1394
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1395
    if iso_image:
1396
      options = ",format=raw,media=cdrom"
1397
      # set cdrom 'if' type
1398
      if boot_cdrom:
1399
        actual_cdrom_type = constants.HT_DISK_IDE
1400
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1401
        actual_cdrom_type = "virtio"
1402
      else:
1403
        actual_cdrom_type = cdrom_disk_type
1404
      if_val = ",if=%s" % actual_cdrom_type
1405
      # set boot flag, if needed
1406
      boot_val = ""
1407
      if boot_cdrom:
1408
        kvm_cmd.extend(["-boot", "d"])
1409
        if needs_boot_flag:
1410
          boot_val = ",boot=on"
1411
      # and finally build the entire '-drive' value
1412
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1413
      kvm_cmd.extend(["-drive", drive_val])
1414

    
1415
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1416
    if iso_image2:
1417
      options = ",format=raw,media=cdrom"
1418
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1419
        if_val = ",if=virtio"
1420
      else:
1421
        if_val = ",if=%s" % cdrom_disk_type
1422
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1423
      kvm_cmd.extend(["-drive", drive_val])
1424

    
1425
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1426
    if floppy_image:
1427
      options = ",format=raw,media=disk"
1428
      if boot_floppy:
1429
        kvm_cmd.extend(["-boot", "a"])
1430
        options = "%s,boot=on" % options
1431
      if_val = ",if=floppy"
1432
      options = "%s%s" % (options, if_val)
1433
      drive_val = "file=%s%s" % (floppy_image, options)
1434
      kvm_cmd.extend(["-drive", drive_val])
1435

    
1436
    if kernel_path:
1437
      kvm_cmd.extend(["-kernel", kernel_path])
1438
      initrd_path = hvp[constants.HV_INITRD_PATH]
1439
      if initrd_path:
1440
        kvm_cmd.extend(["-initrd", initrd_path])
1441
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1442
                     hvp[constants.HV_KERNEL_ARGS]]
1443
      if hvp[constants.HV_SERIAL_CONSOLE]:
1444
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1445
        root_append.append("console=ttyS0,%s" % serial_speed)
1446
      kvm_cmd.extend(["-append", " ".join(root_append)])
1447

    
1448
    mem_path = hvp[constants.HV_MEM_PATH]
1449
    if mem_path:
1450
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1451

    
1452
    monitor_dev = ("unix:%s,server,nowait" %
1453
                   self._InstanceMonitor(instance.name))
1454
    kvm_cmd.extend(["-monitor", monitor_dev])
1455
    if hvp[constants.HV_SERIAL_CONSOLE]:
1456
      serial_dev = ("unix:%s,server,nowait" %
1457
                    self._InstanceSerial(instance.name))
1458
      kvm_cmd.extend(["-serial", serial_dev])
1459
    else:
1460
      kvm_cmd.extend(["-serial", "none"])
1461

    
1462
    mouse_type = hvp[constants.HV_USB_MOUSE]
1463
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1464
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1465
    spice_ip_version = None
1466

    
1467
    kvm_cmd.extend(["-usb"])
1468

    
1469
    if mouse_type:
1470
      kvm_cmd.extend(["-usbdevice", mouse_type])
1471
    elif vnc_bind_address:
1472
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1473

    
1474
    if vnc_bind_address:
1475
      if netutils.IP4Address.IsValid(vnc_bind_address):
1476
        if instance.network_port > constants.VNC_BASE_PORT:
1477
          display = instance.network_port - constants.VNC_BASE_PORT
1478
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1479
            vnc_arg = ":%d" % (display)
1480
          else:
1481
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1482
        else:
1483
          logging.error("Network port is not a valid VNC display (%d < %d),"
1484
                        " not starting VNC",
1485
                        instance.network_port, constants.VNC_BASE_PORT)
1486
          vnc_arg = "none"
1487

    
1488
        # Only allow tls and other option when not binding to a file, for now.
1489
        # kvm/qemu gets confused otherwise about the filename to use.
1490
        vnc_append = ""
1491
        if hvp[constants.HV_VNC_TLS]:
1492
          vnc_append = "%s,tls" % vnc_append
1493
          if hvp[constants.HV_VNC_X509_VERIFY]:
1494
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1495
                                               hvp[constants.HV_VNC_X509])
1496
          elif hvp[constants.HV_VNC_X509]:
1497
            vnc_append = "%s,x509=%s" % (vnc_append,
1498
                                         hvp[constants.HV_VNC_X509])
1499
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1500
          vnc_append = "%s,password" % vnc_append
1501

    
1502
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1503

    
1504
      else:
1505
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1506

    
1507
      kvm_cmd.extend(["-vnc", vnc_arg])
1508
    elif spice_bind:
1509
      # FIXME: this is wrong here; the iface ip address differs
1510
      # between systems, so it should be done in _ExecuteKVMRuntime
1511
      if netutils.IsValidInterface(spice_bind):
1512
        # The user specified a network interface, we have to figure out the IP
1513
        # address.
1514
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1515
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1516

    
1517
        # if the user specified an IP version and the interface does not
1518
        # have that kind of IP addresses, throw an exception
1519
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1520
          if not addresses[spice_ip_version]:
1521
            raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1522
                                         " for %s" % (spice_ip_version,
1523
                                                      spice_bind))
1524

    
1525
        # the user did not specify an IP version, we have to figure it out
1526
        elif (addresses[constants.IP4_VERSION] and
1527
              addresses[constants.IP6_VERSION]):
1528
          # we have both ipv4 and ipv6, let's use the cluster default IP
1529
          # version
1530
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1531
          spice_ip_version = \
1532
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1533
        elif addresses[constants.IP4_VERSION]:
1534
          spice_ip_version = constants.IP4_VERSION
1535
        elif addresses[constants.IP6_VERSION]:
1536
          spice_ip_version = constants.IP6_VERSION
1537
        else:
1538
          raise errors.HypervisorError("SPICE: Unable to get an IP address"
1539
                                       " for %s" % (spice_bind))
1540

    
1541
        spice_address = addresses[spice_ip_version][0]
1542

    
1543
      else:
1544
        # spice_bind is known to be a valid IP address, because
1545
        # ValidateParameters checked it.
1546
        spice_address = spice_bind
1547

    
1548
      spice_arg = "addr=%s" % spice_address
1549
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1550
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1551
                     (spice_arg, instance.network_port,
1552
                      pathutils.SPICE_CACERT_FILE))
1553
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1554
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1555
                      pathutils.SPICE_CERT_FILE))
1556
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1557
        if tls_ciphers:
1558
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1559
      else:
1560
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1561

    
1562
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1563
        spice_arg = "%s,disable-ticketing" % spice_arg
1564

    
1565
      if spice_ip_version:
1566
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1567

    
1568
      # Image compression options
1569
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1570
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1571
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1572
      if img_lossless:
1573
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1574
      if img_jpeg:
1575
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1576
      if img_zlib_glz:
1577
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1578

    
1579
      # Video stream detection
1580
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1581
      if video_streaming:
1582
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1583

    
1584
      # Audio compression, by default in qemu-kvm it is on
1585
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1586
        spice_arg = "%s,playback-compression=off" % spice_arg
1587
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1588
        spice_arg = "%s,agent-mouse=off" % spice_arg
1589
      else:
1590
        # Enable the spice agent communication channel between the host and the
1591
        # agent.
1592
        kvm_cmd.extend(["-device", "virtio-serial-pci"])
1593
        kvm_cmd.extend([
1594
          "-device",
1595
          "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1596
          ])
1597
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1598

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

    
1602
    else:
1603
      # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1604
      # also works in earlier versions though (tested with 1.1 and 1.3)
1605
      if self._DISPLAY_RE.search(kvmhelp):
1606
        kvm_cmd.extend(["-display", "none"])
1607
      else:
1608
        kvm_cmd.extend(["-nographic"])
1609

    
1610
    if hvp[constants.HV_USE_LOCALTIME]:
1611
      kvm_cmd.extend(["-localtime"])
1612

    
1613
    if hvp[constants.HV_KVM_USE_CHROOT]:
1614
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1615

    
1616
    # Add qemu-KVM -cpu param
1617
    if hvp[constants.HV_CPU_TYPE]:
1618
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1619

    
1620
    # As requested by music lovers
1621
    if hvp[constants.HV_SOUNDHW]:
1622
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1623

    
1624
    # Pass a -vga option if requested, or if spice is used, for backwards
1625
    # compatibility.
1626
    if hvp[constants.HV_VGA]:
1627
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1628
    elif spice_bind:
1629
      kvm_cmd.extend(["-vga", "qxl"])
1630

    
1631
    # Various types of usb devices, comma separated
1632
    if hvp[constants.HV_USB_DEVICES]:
1633
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1634
        kvm_cmd.extend(["-usbdevice", dev])
1635

    
1636
    if hvp[constants.HV_KVM_EXTRA]:
1637
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1638

    
1639
    pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1640
    kvm_disks = []
1641
    for disk, link_name in block_devices:
1642
      _UpdatePCISlots(disk, pci_reservations)
1643
      kvm_disks.append((disk, link_name))
1644

    
1645
    kvm_nics = []
1646
    for nic in instance.nics:
1647
      _UpdatePCISlots(nic, pci_reservations)
1648
      kvm_nics.append(nic)
1649

    
1650
    hvparams = hvp
1651

    
1652
    return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1653

    
1654
  def _WriteKVMRuntime(self, instance_name, data):
1655
    """Write an instance's KVM runtime
1656

1657
    """
1658
    try:
1659
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1660
                      data=data)
1661
    except EnvironmentError, err:
1662
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1663

    
1664
  def _ReadKVMRuntime(self, instance_name):
1665
    """Read an instance's KVM runtime
1666

1667
    """
1668
    try:
1669
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1670
    except EnvironmentError, err:
1671
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1672
    return file_content
1673

    
1674
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1675
    """Save an instance's KVM runtime
1676

1677
    """
1678
    kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1679

    
1680
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1681
    serialized_disks = [(blk.ToDict(), link)
1682
                            for blk, link in kvm_disks]
1683
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1684
                                      serialized_disks))
1685

    
1686
    self._WriteKVMRuntime(instance.name, serialized_form)
1687

    
1688
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1689
    """Load an instance's KVM runtime
1690

1691
    """
1692
    if not serialized_runtime:
1693
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1694

    
1695
    return _AnalyzeSerializedRuntime(serialized_runtime)
1696

    
1697
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1698
    """Run the KVM cmd and check for errors
1699

1700
    @type name: string
1701
    @param name: instance name
1702
    @type kvm_cmd: list of strings
1703
    @param kvm_cmd: runcmd input for kvm
1704
    @type tap_fds: list of int
1705
    @param tap_fds: fds of tap devices opened by Ganeti
1706

1707
    """
1708
    try:
1709
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1710
    finally:
1711
      for fd in tap_fds:
1712
        utils_wrapper.CloseFdNoError(fd)
1713

    
1714
    if result.failed:
1715
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1716
                                   (name, result.fail_reason, result.output))
1717
    if not self._InstancePidAlive(name)[2]:
1718
      raise errors.HypervisorError("Failed to start instance %s" % name)
1719

    
1720
  # too many local variables
1721
  # pylint: disable=R0914
1722
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1723
    """Execute a KVM cmd, after completing it with some last minute data.
1724

1725
    @type incoming: tuple of strings
1726
    @param incoming: (target_host_ip, port)
1727
    @type kvmhelp: string
1728
    @param kvmhelp: output of kvm --help
1729

1730
    """
1731
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1732
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1733
    #    have changed since the instance started; only use them if the change
1734
    #    won't affect the inside of the instance (which hasn't been rebooted).
1735
    #  - up_hvp contains the parameters as they were when the instance was
1736
    #    started, plus any new parameter which has been added between ganeti
1737
    #    versions: it is paramount that those default to a value which won't
1738
    #    affect the inside of the instance as well.
1739
    conf_hvp = instance.hvparams
1740
    name = instance.name
1741
    self._CheckDown(name)
1742

    
1743
    temp_files = []
1744

    
1745
    kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1746
    # the first element of kvm_cmd is always the path to the kvm binary
1747
    kvm_path = kvm_cmd[0]
1748
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1749

    
1750
    # We know it's safe to run as a different user upon migration, so we'll use
1751
    # the latest conf, from conf_hvp.
1752
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1753
    if security_model == constants.HT_SM_USER:
1754
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1755

    
1756
    keymap = conf_hvp[constants.HV_KEYMAP]
1757
    if keymap:
1758
      keymap_path = self._InstanceKeymapFile(name)
1759
      # If a keymap file is specified, KVM won't use its internal defaults. By
1760
      # first including the "en-us" layout, an error on loading the actual
1761
      # layout (e.g. because it can't be found) won't lead to a non-functional
1762
      # keyboard. A keyboard with incorrect keys is still better than none.
1763
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1764
      kvm_cmd.extend(["-k", keymap_path])
1765

    
1766
    # We have reasons to believe changing something like the nic driver/type
1767
    # upon migration won't exactly fly with the instance kernel, so for nic
1768
    # related parameters we'll use up_hvp
1769
    tapfds = []
1770
    taps = []
1771
    devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1772

    
1773
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1774
                                                     kvm_disks,
1775
                                                     kvmhelp,
1776
                                                     devlist)
1777
    kvm_cmd.extend(bdev_opts)
1778

    
1779
    if not kvm_nics:
1780
      kvm_cmd.extend(["-net", "none"])
1781
    else:
1782
      vnet_hdr = False
1783
      tap_extra = ""
1784
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1785
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1786
        nic_model = self._VIRTIO
1787
        try:
1788
          if self._VIRTIO_NET_RE.search(devlist):
1789
            nic_model = self._VIRTIO_NET_PCI
1790
            vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1791
        except errors.HypervisorError, _:
1792
          # Older versions of kvm don't support DEVICE_LIST, but they don't
1793
          # have new virtio syntax either.
1794
          pass
1795

    
1796
        if up_hvp[constants.HV_VHOST_NET]:
1797
          # check for vhost_net support
1798
          if self._VHOST_RE.search(kvmhelp):
1799
            tap_extra = ",vhost=on"
1800
          else:
1801
            raise errors.HypervisorError("vhost_net is configured"
1802
                                         " but it is not available")
1803
      else:
1804
        nic_model = nic_type
1805

    
1806
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1807

    
1808
      for nic_seq, nic in enumerate(kvm_nics):
1809
        tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1810
        tapfds.append(tapfd)
1811
        taps.append(tapname)
1812
        if kvm_supports_netdev:
1813
          nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1814
          try:
1815
            # kvm_nics already exist in old runtime files and thus there might
1816
            # be some entries without pci slot (therefore try: except:)
1817
            kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1818
            netdev = kvm_devid
1819
            nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1820
          except errors.HotplugError:
1821
            netdev = "netdev%d" % nic_seq
1822
          nic_val += (",netdev=%s" % netdev)
1823
          tap_val = ("type=tap,id=%s,fd=%d%s" %
1824
                     (netdev, tapfd, tap_extra))
1825
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1826
        else:
1827
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1828
                                                         nic.mac, nic_model)
1829
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1830
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1831

    
1832
    if incoming:
1833
      target, port = incoming
1834
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1835

    
1836
    # Changing the vnc password doesn't bother the guest that much. At most it
1837
    # will surprise people who connect to it. Whether positively or negatively
1838
    # it's debatable.
1839
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1840
    vnc_pwd = None
1841
    if vnc_pwd_file:
1842
      try:
1843
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1844
      except EnvironmentError, err:
1845
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1846
                                     % (vnc_pwd_file, err))
1847

    
1848
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1849
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1850
                         constants.SECURE_DIR_MODE)])
1851

    
1852
    # Automatically enable QMP if version is >= 0.14
1853
    if self._QMP_RE.search(kvmhelp):
1854
      logging.debug("Enabling QMP")
1855
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1856
                      self._InstanceQmpMonitor(instance.name)])
1857

    
1858
    # Configure the network now for starting instances and bridged interfaces,
1859
    # during FinalizeMigration for incoming instances' routed interfaces
1860
    for nic_seq, nic in enumerate(kvm_nics):
1861
      if (incoming and
1862
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1863
        continue
1864
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1865

    
1866
    # CPU affinity requires kvm to start paused, so we set this flag if the
1867
    # instance is not already paused and if we are not going to accept a
1868
    # migrating instance. In the latter case, pausing is not needed.
1869
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1870
    if start_kvm_paused:
1871
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1872

    
1873
    # Note: CPU pinning is using up_hvp since changes take effect
1874
    # during instance startup anyway, and to avoid problems when soft
1875
    # rebooting the instance.
1876
    cpu_pinning = False
1877
    if up_hvp.get(constants.HV_CPU_MASK, None):
1878
      cpu_pinning = True
1879

    
1880
    if security_model == constants.HT_SM_POOL:
1881
      ss = ssconf.SimpleStore()
1882
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1883
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1884
      uid = uidpool.RequestUnusedUid(all_uids)
1885
      try:
1886
        username = pwd.getpwuid(uid.GetUid()).pw_name
1887
        kvm_cmd.extend(["-runas", username])
1888
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1889
      except:
1890
        uidpool.ReleaseUid(uid)
1891
        raise
1892
      else:
1893
        uid.Unlock()
1894
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1895
    else:
1896
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1897

    
1898
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1899
                     constants.RUN_DIRS_MODE)])
1900
    for nic_seq, tap in enumerate(taps):
1901
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1902
                      data=tap)
1903

    
1904
    if vnc_pwd:
1905
      change_cmd = "change vnc password %s" % vnc_pwd
1906
      self._CallMonitorCommand(instance.name, change_cmd)
1907

    
1908
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1909
    # connection attempts because SPICE by default does not allow connections
1910
    # if neither a password nor the "disable_ticketing" options are specified.
1911
    # As soon as we send the password via QMP, that password is a valid ticket
1912
    # for connection.
1913
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1914
    if spice_password_file:
1915
      spice_pwd = ""
1916
      try:
1917
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1918
      except EnvironmentError, err:
1919
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1920
                                     % (spice_password_file, err))
1921

    
1922
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1923
      qmp.connect()
1924
      arguments = {
1925
          "protocol": "spice",
1926
          "password": spice_pwd,
1927
      }
1928
      qmp.Execute("set_password", arguments)
1929

    
1930
    for filename in temp_files:
1931
      utils.RemoveFile(filename)
1932

    
1933
    # If requested, set CPU affinity and resume instance execution
1934
    if cpu_pinning:
1935
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1936

    
1937
    start_memory = self._InstanceStartupMemory(instance)
1938
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1939
      self.BalloonInstanceMemory(instance, start_memory)
1940

    
1941
    if start_kvm_paused:
1942
      # To control CPU pinning, ballooning, and vnc/spice passwords
1943
      # the VM was started in a frozen state. If freezing was not
1944
      # explicitly requested resume the vm status.
1945
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1946

    
1947
  def StartInstance(self, instance, block_devices, startup_paused):
1948
    """Start an instance.
1949

1950
    """
1951
    self._CheckDown(instance.name)
1952
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1953
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1954
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1955
                                           startup_paused, kvmhelp)
1956
    self._SaveKVMRuntime(instance, kvm_runtime)
1957
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1958

    
1959
  def _CallMonitorCommand(self, instance_name, command):
1960
    """Invoke a command on the instance monitor.
1961

1962
    """
1963
    # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1964
    # version. The monitor protocol is designed for human consumption, whereas
1965
    # QMP is made for programmatic usage. In the worst case QMP can also
1966
    # execute monitor commands. As it is, all calls to socat take at least
1967
    # 500ms and likely more: socat can't detect the end of the reply and waits
1968
    # for 500ms of no data received before exiting (500 ms is the default for
1969
    # the "-t" parameter).
1970
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1971
             (utils.ShellQuote(command),
1972
              constants.SOCAT_PATH,
1973
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1974
    result = utils.RunCmd(socat)
1975
    if result.failed:
1976
      msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1977
             " output: %s" %
1978
             (command, instance_name, result.fail_reason, result.output))
1979
      raise errors.HypervisorError(msg)
1980

    
1981
    return result
1982

    
1983
  def _GetFreePCISlot(self, instance, dev):
1984
    """Get the first available pci slot of a runnung instance.
1985

1986
    """
1987
    slots = bitarray(32)
1988
    slots.setall(False) # pylint: disable=E1101
1989
    output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
1990
    for line in output.stdout.splitlines():
1991
      match = self._INFO_PCI_RE.search(line)
1992
      if match:
1993
        slot = int(match.group(1))
1994
        slots[slot] = True
1995

    
1996
    [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
1997
    if not free:
1998
      raise errors.HypervisorError("All PCI slots occupied")
1999

    
2000
    dev.pci = int(free)
2001

    
2002
  def VerifyHotplugSupport(self, instance, action, dev_type):
2003
    """Verifies that hotplug is supported.
2004

2005
    Hotplug is *not* supported in case of:
2006
     - security models and chroot (disk hotplug)
2007
     - fdsend module is missing (nic hot-add)
2008

2009
    @raise errors.HypervisorError: in one of the previous cases
2010

2011
    """
2012
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2013
      hvp = instance.hvparams
2014
      security_model = hvp[constants.HV_SECURITY_MODEL]
2015
      use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
2016
      if use_chroot:
2017
        raise errors.HotplugError("Disk hotplug is not supported"
2018
                                  " in case of chroot.")
2019
      if security_model != constants.HT_SM_NONE:
2020
        raise errors.HotplugError("Disk Hotplug is not supported in case"
2021
                                  " security models are used.")
2022

    
2023
    if (dev_type == constants.HOTPLUG_TARGET_NIC and
2024
        action == constants.HOTPLUG_ACTION_ADD and not fdsend):
2025
      raise errors.HotplugError("Cannot hot-add NIC."
2026
                                " fdsend python module is missing.")
2027

    
2028
  def HotplugSupported(self, instance):
2029
    """Checks if hotplug is generally supported.
2030

2031
    Hotplug is *not* supported in case of:
2032
     - qemu versions < 1.0
2033
     - for stopped instances
2034

2035
    @raise errors.HypervisorError: in one of the previous cases
2036

2037
    """
2038
    try:
2039
      output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2040
    except errors.HypervisorError:
2041
      raise errors.HotplugError("Instance is probably down")
2042

    
2043
    # TODO: search for netdev_add, drive_add, device_add.....
2044
    match = self._INFO_VERSION_RE.search(output.stdout)
2045
    if not match:
2046
      raise errors.HotplugError("Cannot parse qemu version via monitor")
2047

    
2048
    v_major, v_min, _, _ = match.groups()
2049
    if (int(v_major), int(v_min)) < (1, 0):
2050
      raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2051

    
2052
  def _CallHotplugCommand(self, name, cmd):
2053
    output = self._CallMonitorCommand(name, cmd)
2054
    # TODO: parse output and check if succeeded
2055
    for line in output.stdout.splitlines():
2056
      logging.info("%s", line)
2057

    
2058
  def HotAddDevice(self, instance, dev_type, device, extra, seq):
2059
    """ Helper method to hot-add a new device
2060

2061
    It gets free pci slot generates the device name and invokes the
2062
    device specific method.
2063

2064
    """
2065
    # in case of hot-mod this is given
2066
    if device.pci is None:
2067
      self._GetFreePCISlot(instance, device)
2068
    kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2069
    runtime = self._LoadKVMRuntime(instance)
2070
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2071
      command = "drive_add dummy file=%s,if=none,id=%s,format=raw\n" % \
2072
                 (extra, kvm_devid)
2073
      command += ("device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
2074
                  (hex(device.pci), kvm_devid, kvm_devid))
2075
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
2076
      (tap, fd) = _OpenTap()
2077
      self._ConfigureNIC(instance, seq, device, tap)
2078
      self._PassTapFd(instance, fd, device)
2079
      command = "netdev_add tap,id=%s,fd=%s\n" % (kvm_devid, kvm_devid)
2080
      args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
2081
               (hex(device.pci), device.mac, kvm_devid, kvm_devid)
2082
      command += "device_add %s" % args
2083
      utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
2084

    
2085
    self._CallHotplugCommand(instance.name, command)
2086
    # update relevant entries in runtime file
2087
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2088
    entry = _RUNTIME_ENTRY[dev_type](device, extra)
2089
    runtime[index].append(entry)
2090
    self._SaveKVMRuntime(instance, runtime)
2091

    
2092
  def HotDelDevice(self, instance, dev_type, device, _, seq):
2093
    """ Helper method for hot-del device
2094

2095
    It gets device info from runtime file, generates the device name and
2096
    invokes the device specific method.
2097

2098
    """
2099
    runtime = self._LoadKVMRuntime(instance)
2100
    entry = _GetExistingDeviceInfo(dev_type, device, runtime)
2101
    kvm_device = _RUNTIME_DEVICE[dev_type](entry)
2102
    kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
2103
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2104
      command = "device_del %s\n" % kvm_devid
2105
      command += "drive_del %s" % kvm_devid
2106
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
2107
      command = "device_del %s\n" % kvm_devid
2108
      command += "netdev_del %s" % kvm_devid
2109
      utils.RemoveFile(self._InstanceNICFile(instance.name, seq))
2110
    self._CallHotplugCommand(instance.name, command)
2111
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2112
    runtime[index].remove(entry)
2113
    self._SaveKVMRuntime(instance, runtime)
2114

    
2115
    return kvm_device.pci
2116

    
2117
  def HotModDevice(self, instance, dev_type, device, _, seq):
2118
    """ Helper method for hot-mod device
2119

2120
    It gets device info from runtime file, generates the device name and
2121
    invokes the device specific method. Currently only NICs support hot-mod
2122

2123
    """
2124
    if dev_type == constants.HOTPLUG_TARGET_NIC:
2125
      # putting it back in the same pci slot
2126
      device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2127
      # TODO: remove sleep when socat gets removed
2128
      time.sleep(2)
2129
      self.HotAddDevice(instance, dev_type, device, _, seq)
2130

    
2131
  def _PassTapFd(self, instance, fd, nic):
2132
    """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2133

2134
    """
2135
    # TODO: factor out code related to unix sockets.
2136
    #       squash common parts between monitor and qmp
2137
    kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2138
    command = "getfd %s\n" % kvm_devid
2139
    fds = [fd]
2140
    logging.info("%s", fds)
2141
    try:
2142
      monsock = MonitorSocket(self._InstanceMonitor(instance.name))
2143
      monsock.connect()
2144
      fdsend.sendfds(monsock.sock, command, fds=fds)
2145
    finally:
2146
      monsock.close()
2147

    
2148
  @classmethod
2149
  def _ParseKVMVersion(cls, text):
2150
    """Parse the KVM version from the --help output.
2151

2152
    @type text: string
2153
    @param text: output of kvm --help
2154
    @return: (version, v_maj, v_min, v_rev)
2155
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2156

2157
    """
2158
    match = cls._VERSION_RE.search(text.splitlines()[0])
2159
    if not match:
2160
      raise errors.HypervisorError("Unable to get KVM version")
2161

    
2162
    v_all = match.group(0)
2163
    v_maj = int(match.group(1))
2164
    v_min = int(match.group(2))
2165
    if match.group(4):
2166
      v_rev = int(match.group(4))
2167
    else:
2168
      v_rev = 0
2169
    return (v_all, v_maj, v_min, v_rev)
2170

    
2171
  @classmethod
2172
  def _GetKVMOutput(cls, kvm_path, option):
2173
    """Return the output of a kvm invocation
2174

2175
    @type kvm_path: string
2176
    @param kvm_path: path to the kvm executable
2177
    @type option: a key of _KVMOPTS_CMDS
2178
    @param option: kvm option to fetch the output from
2179
    @return: output a supported kvm invocation
2180
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2181

2182
    """
2183
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2184

    
2185
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
2186

    
2187
    result = utils.RunCmd([kvm_path] + optlist)
2188
    if result.failed and not can_fail:
2189
      raise errors.HypervisorError("Unable to get KVM %s output" %
2190
                                    " ".join(optlist))
2191
    return result.output
2192

    
2193
  @classmethod
2194
  def _GetKVMVersion(cls, kvm_path):
2195
    """Return the installed KVM version.
2196

2197
    @return: (version, v_maj, v_min, v_rev)
2198
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2199

2200
    """
2201
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2202

    
2203
  @classmethod
2204
  def _GetDefaultMachineVersion(cls, kvm_path):
2205
    """Return the default hardware revision (e.g. pc-1.1)
2206

2207
    """
2208
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2209
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2210
    if match:
2211
      return match.group(1)
2212
    else:
2213
      return "pc"
2214

    
2215
  def StopInstance(self, instance, force=False, retry=False, name=None):
2216
    """Stop an instance.
2217

2218
    """
2219
    if name is not None and not force:
2220
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2221
    if name is None:
2222
      name = instance.name
2223
      acpi = instance.hvparams[constants.HV_ACPI]
2224
    else:
2225
      acpi = False
2226
    _, pid, alive = self._InstancePidAlive(name)
2227
    if pid > 0 and alive:
2228
      if force or not acpi:
2229
        utils.KillProcess(pid)
2230
      else:
2231
        self._CallMonitorCommand(name, "system_powerdown")
2232

    
2233
  def CleanupInstance(self, instance_name):
2234
    """Cleanup after a stopped instance
2235

2236
    """
2237
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
2238
    if pid > 0 and alive:
2239
      raise errors.HypervisorError("Cannot cleanup a live instance")
2240
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2241

    
2242
  def RebootInstance(self, instance):
2243
    """Reboot an instance.
2244

2245
    """
2246
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2247
    # socket the instance will stop, but now power up again. So we'll resort
2248
    # to shutdown and restart.
2249
    _, _, alive = self._InstancePidAlive(instance.name)
2250
    if not alive:
2251
      raise errors.HypervisorError("Failed to reboot instance %s:"
2252
                                   " not running" % instance.name)
2253
    # StopInstance will delete the saved KVM runtime so:
2254
    # ...first load it...
2255
    kvm_runtime = self._LoadKVMRuntime(instance)
2256
    # ...now we can safely call StopInstance...
2257
    if not self.StopInstance(instance):
2258
      self.StopInstance(instance, force=True)
2259
    # ...and finally we can save it again, and execute it...
2260
    self._SaveKVMRuntime(instance, kvm_runtime)
2261
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2262
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2263
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2264

    
2265
  def MigrationInfo(self, instance):
2266
    """Get instance information to perform a migration.
2267

2268
    @type instance: L{objects.Instance}
2269
    @param instance: instance to be migrated
2270
    @rtype: string
2271
    @return: content of the KVM runtime file
2272

2273
    """
2274
    return self._ReadKVMRuntime(instance.name)
2275

    
2276
  def AcceptInstance(self, instance, info, target):
2277
    """Prepare to accept an instance.
2278

2279
    @type instance: L{objects.Instance}
2280
    @param instance: instance to be accepted
2281
    @type info: string
2282
    @param info: content of the KVM runtime file on the source node
2283
    @type target: string
2284
    @param target: target host (usually ip), on this node
2285

2286
    """
2287
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2288
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2289
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2290
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2291
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2292
                            incoming=incoming_address)
2293

    
2294
  def FinalizeMigrationDst(self, instance, info, success):
2295
    """Finalize the instance migration on the target node.
2296

2297
    Stop the incoming mode KVM.
2298

2299
    @type instance: L{objects.Instance}
2300
    @param instance: instance whose migration is being finalized
2301

2302
    """
2303
    if success:
2304
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2305
      kvm_nics = kvm_runtime[1]
2306

    
2307
      for nic_seq, nic in enumerate(kvm_nics):
2308
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2309
          # Bridged interfaces have already been configured
2310
          continue
2311
        try:
2312
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2313
        except EnvironmentError, err:
2314
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
2315
                          instance.name, nic_seq, str(err))
2316
          continue
2317
        try:
2318
          self._ConfigureNIC(instance, nic_seq, nic, tap)
2319
        except errors.HypervisorError, err:
2320
          logging.warning(str(err))
2321

    
2322
      self._WriteKVMRuntime(instance.name, info)
2323
    else:
2324
      self.StopInstance(instance, force=True)
2325

    
2326
  def MigrateInstance(self, instance, target, live):
2327
    """Migrate an instance to a target node.
2328

2329
    The migration will not be attempted if the instance is not
2330
    currently running.
2331

2332
    @type instance: L{objects.Instance}
2333
    @param instance: the instance to be migrated
2334
    @type target: string
2335
    @param target: ip address of the target node
2336
    @type live: boolean
2337
    @param live: perform a live migration
2338

2339
    """
2340
    instance_name = instance.name
2341
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
2342
    _, _, alive = self._InstancePidAlive(instance_name)
2343
    if not alive:
2344
      raise errors.HypervisorError("Instance not running, cannot migrate")
2345

    
2346
    if not live:
2347
      self._CallMonitorCommand(instance_name, "stop")
2348

    
2349
    migrate_command = ("migrate_set_speed %dm" %
2350
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2351
    self._CallMonitorCommand(instance_name, migrate_command)
2352

    
2353
    migrate_command = ("migrate_set_downtime %dms" %
2354
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2355
    self._CallMonitorCommand(instance_name, migrate_command)
2356

    
2357
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2358
    self._CallMonitorCommand(instance_name, migrate_command)
2359

    
2360
  def FinalizeMigrationSource(self, instance, success, live):
2361
    """Finalize the instance migration on the source node.
2362

2363
    @type instance: L{objects.Instance}
2364
    @param instance: the instance that was migrated
2365
    @type success: bool
2366
    @param success: whether the migration succeeded or not
2367
    @type live: bool
2368
    @param live: whether the user requested a live migration or not
2369

2370
    """
2371
    if success:
2372
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2373
      utils.KillProcess(pid)
2374
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2375
    elif live:
2376
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2377

    
2378
  def GetMigrationStatus(self, instance):
2379
    """Get the migration status
2380

2381
    @type instance: L{objects.Instance}
2382
    @param instance: the instance that is being migrated
2383
    @rtype: L{objects.MigrationStatus}
2384
    @return: the status of the current migration (one of
2385
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2386
             progress info that can be retrieved from the hypervisor
2387

2388
    """
2389
    info_command = "info migrate"
2390
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2391
      result = self._CallMonitorCommand(instance.name, info_command)
2392
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
2393
      if not match:
2394
        if not result.stdout:
2395
          logging.info("KVM: empty 'info migrate' result")
2396
        else:
2397
          logging.warning("KVM: unknown 'info migrate' result: %s",
2398
                          result.stdout)
2399
      else:
2400
        status = match.group(1)
2401
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2402
          migration_status = objects.MigrationStatus(status=status)
2403
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2404
          if match:
2405
            migration_status.transferred_ram = match.group("transferred")
2406
            migration_status.total_ram = match.group("total")
2407

    
2408
          return migration_status
2409

    
2410
        logging.warning("KVM: unknown migration status '%s'", status)
2411

    
2412
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2413

    
2414
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2415

    
2416
  def BalloonInstanceMemory(self, instance, mem):
2417
    """Balloon an instance memory to a certain value.
2418

2419
    @type instance: L{objects.Instance}
2420
    @param instance: instance to be accepted
2421
    @type mem: int
2422
    @param mem: actual memory size to use for instance runtime
2423

2424
    """
2425
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2426

    
2427
  def GetNodeInfo(self):
2428
    """Return information about the node.
2429

2430
    @return: a dict with the following keys (values in MiB):
2431
          - memory_total: the total memory size on the node
2432
          - memory_free: the available memory on the node for instances
2433
          - memory_dom0: the memory used by the node itself, if available
2434
          - hv_version: the hypervisor version in the form (major, minor,
2435
                        revision)
2436

2437
    """
2438
    result = self.GetLinuxNodeInfo()
2439
    # FIXME: this is the global kvm version, but the actual version can be
2440
    # customized as an hv parameter. we should use the nodegroup's default kvm
2441
    # path parameter here.
2442
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2443
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2444
    return result
2445

    
2446
  @classmethod
2447
  def GetInstanceConsole(cls, instance, hvparams, beparams):
2448
    """Return a command for connecting to the console of an instance.
2449

2450
    """
2451
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2452
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2453
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2454
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2455
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2456
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2457
      return objects.InstanceConsole(instance=instance.name,
2458
                                     kind=constants.CONS_SSH,
2459
                                     host=instance.primary_node,
2460
                                     user=constants.SSH_CONSOLE_USER,
2461
                                     command=cmd)
2462

    
2463
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2464
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2465
      display = instance.network_port - constants.VNC_BASE_PORT
2466
      return objects.InstanceConsole(instance=instance.name,
2467
                                     kind=constants.CONS_VNC,
2468
                                     host=vnc_bind_address,
2469
                                     port=instance.network_port,
2470
                                     display=display)
2471

    
2472
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2473
    if spice_bind:
2474
      return objects.InstanceConsole(instance=instance.name,
2475
                                     kind=constants.CONS_SPICE,
2476
                                     host=spice_bind,
2477
                                     port=instance.network_port)
2478

    
2479
    return objects.InstanceConsole(instance=instance.name,
2480
                                   kind=constants.CONS_MESSAGE,
2481
                                   message=("No serial shell for instance %s" %
2482
                                            instance.name))
2483

    
2484
  def Verify(self):
2485
    """Verify the hypervisor.
2486

2487
    Check that the required binaries exist.
2488

2489
    @return: Problem description if something is wrong, C{None} otherwise
2490

2491
    """
2492
    msgs = []
2493
    # FIXME: this is the global kvm binary, but the actual path can be
2494
    # customized as an hv parameter; we should use the nodegroup's
2495
    # default kvm path parameter here.
2496
    if not os.path.exists(constants.KVM_PATH):
2497
      msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2498
    if not os.path.exists(constants.SOCAT_PATH):
2499
      msgs.append("The socat binary ('%s') does not exist" %
2500
                  constants.SOCAT_PATH)
2501

    
2502
    return self._FormatVerifyResults(msgs)
2503

    
2504
  @classmethod
2505
  def CheckParameterSyntax(cls, hvparams):
2506
    """Check the given parameters for validity.
2507

2508
    @type hvparams:  dict
2509
    @param hvparams: dictionary with parameter names/value
2510
    @raise errors.HypervisorError: when a parameter is not valid
2511

2512
    """
2513
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2514

    
2515
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2516
    if kernel_path:
2517
      if not hvparams[constants.HV_ROOT_PATH]:
2518
        raise errors.HypervisorError("Need a root partition for the instance,"
2519
                                     " if a kernel is defined")
2520

    
2521
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2522
        not hvparams[constants.HV_VNC_X509]):
2523
      raise errors.HypervisorError("%s must be defined, if %s is" %
2524
                                   (constants.HV_VNC_X509,
2525
                                    constants.HV_VNC_X509_VERIFY))
2526

    
2527
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2528
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2529
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2530
      if not serial_speed or serial_speed not in valid_speeds:
2531
        raise errors.HypervisorError("Invalid serial console speed, must be"
2532
                                     " one of: %s" %
2533
                                     utils.CommaJoin(valid_speeds))
2534

    
2535
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2536
    if (boot_order == constants.HT_BO_CDROM and
2537
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2538
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2539
                                   " ISO path")
2540

    
2541
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2542
    if security_model == constants.HT_SM_USER:
2543
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2544
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2545
                                     " must be specified")
2546
    elif (security_model == constants.HT_SM_NONE or
2547
          security_model == constants.HT_SM_POOL):
2548
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2549
        raise errors.HypervisorError("Cannot have a security domain when the"
2550
                                     " security model is 'none' or 'pool'")
2551

    
2552
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2553
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2554
    if spice_bind:
2555
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2556
        # if an IP version is specified, the spice_bind parameter must be an
2557
        # IP of that family
2558
        if (netutils.IP4Address.IsValid(spice_bind) and
2559
            spice_ip_version != constants.IP4_VERSION):
2560
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2561
                                       " the specified IP version is %s" %
2562
                                       (spice_bind, spice_ip_version))
2563

    
2564
        if (netutils.IP6Address.IsValid(spice_bind) and
2565
            spice_ip_version != constants.IP6_VERSION):
2566
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2567
                                       " the specified IP version is %s" %
2568
                                       (spice_bind, spice_ip_version))
2569
    else:
2570
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2571
      # error if any of them is set without it.
2572
      for param in _SPICE_ADDITIONAL_PARAMS:
2573
        if hvparams[param]:
2574
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2575
                                       (param, constants.HV_KVM_SPICE_BIND))
2576

    
2577
  @classmethod
2578
  def ValidateParameters(cls, hvparams):
2579
    """Check the given parameters for validity.
2580

2581
    @type hvparams:  dict
2582
    @param hvparams: dictionary with parameter names/value
2583
    @raise errors.HypervisorError: when a parameter is not valid
2584

2585
    """
2586
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2587

    
2588
    kvm_path = hvparams[constants.HV_KVM_PATH]
2589

    
2590
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2591
    if security_model == constants.HT_SM_USER:
2592
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2593
      try:
2594
        pwd.getpwnam(username)
2595
      except KeyError:
2596
        raise errors.HypervisorError("Unknown security domain user %s"
2597
                                     % username)
2598

    
2599
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2600
    if spice_bind:
2601
      # only one of VNC and SPICE can be used currently.
2602
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2603
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2604
                                     " only one of them can be used at a"
2605
                                     " given time")
2606

    
2607
      # check that KVM supports SPICE
2608
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2609
      if not cls._SPICE_RE.search(kvmhelp):
2610
        raise errors.HypervisorError("SPICE is configured, but it is not"
2611
                                     " supported according to 'kvm --help'")
2612

    
2613
      # if spice_bind is not an IP address, it must be a valid interface
2614
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2615
                       netutils.IP6Address.IsValid(spice_bind))
2616
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2617
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2618
                                     " a valid IP address or interface name" %
2619
                                     constants.HV_KVM_SPICE_BIND)
2620

    
2621
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2622
    if machine_version:
2623
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2624
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2625
        raise errors.HypervisorError("Unsupported machine version: %s" %
2626
                                     machine_version)
2627

    
2628
  @classmethod
2629
  def PowercycleNode(cls):
2630
    """KVM powercycle, just a wrapper over Linux powercycle.
2631

2632
    """
2633
    cls.LinuxPowercycle()