Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ e2800fca

History | View | Annotate | Download (94.9 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):
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
  if not dev.pci:
134
    raise errors.HotplugError("Hotplug is not supported for %s with UUID %s" %
135
                              (dev_type, dev.uuid))
136

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

    
139

    
140
def _UpdatePCISlots(dev, pci_reservations):
141
  """Update pci configuration for a stopped instance
142

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

147
  @type dev: L{objects.Disk} or L{objects.NIC}
148
  @param dev: the device object for which we update its pci slot
149
  @type pci_reservations: bitarray
150
  @param pci_reservations: existing pci reservations for an instance
151
  @raise errors.HotplugError: in case an instance has all its slot occupied
152

153
  """
154
  if dev.pci:
155
    free = dev.pci
156
  else: # pylint: disable=E1103
157
    [free] = pci_reservations.search(_AVAILABLE_PCI_SLOT, 1)
158
    if not free:
159
      raise errors.HypervisorError("All PCI slots occupied")
160
    dev.pci = int(free)
161

    
162
  pci_reservations[free] = True
163

    
164

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

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

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

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

    
188
  return found[0]
189

    
190

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

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

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

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

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

    
216
  return kvm_cmd, serialized_nics, hvparams, serialized_disks
217

    
218

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

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

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

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

    
236

    
237
def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
238
  """Retrieves supported TUN features from file descriptor.
239

240
  @see: L{_ProbeTapVnetHdr}
241

242
  """
243
  req = struct.pack("I", 0)
244
  try:
245
    buf = _ioctl(fd, TUNGETFEATURES, req)
246
  except EnvironmentError, err:
247
    logging.warning("ioctl(TUNGETFEATURES) failed: %s", err)
248
    return None
249
  else:
250
    (flags, ) = struct.unpack("I", buf)
251
    return flags
252

    
253

    
254
def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
255
  """Check whether to enable the IFF_VNET_HDR flag.
256

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

267
   @type fd: int
268
   @param fd: the file descriptor of /dev/net/tun
269

270
  """
271
  flags = _features_fn(fd)
272

    
273
  if flags is None:
274
    # Not supported
275
    return False
276

    
277
  result = bool(flags & IFF_VNET_HDR)
278

    
279
  if not result:
280
    logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
281

    
282
  return result
283

    
284

    
285
def _OpenTap(vnet_hdr=True):
286
  """Open a new tap device and return its file descriptor.
287

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

291
  @type vnet_hdr: boolean
292
  @param vnet_hdr: Enable the VNET Header
293
  @return: (ifname, tapfd)
294
  @rtype: tuple
295

296
  """
297
  try:
298
    tapfd = os.open("/dev/net/tun", os.O_RDWR)
299
  except EnvironmentError:
300
    raise errors.HypervisorError("Failed to open /dev/net/tun")
301

    
302
  flags = IFF_TAP | IFF_NO_PI
303

    
304
  if vnet_hdr and _ProbeTapVnetHdr(tapfd):
305
    flags |= IFF_VNET_HDR
306

    
307
  # The struct ifreq ioctl request (see netdevice(7))
308
  ifr = struct.pack("16sh", "", flags)
309

    
310
  try:
311
    res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
312
  except EnvironmentError, err:
313
    raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
314
                                 err)
315

    
316
  # Get the interface name from the ioctl
317
  ifname = struct.unpack("16sh", res)[0].strip("\x00")
318
  return (ifname, tapfd)
319

    
320

    
321
class QmpMessage:
322
  """QEMU Messaging Protocol (QMP) message.
323

324
  """
325
  def __init__(self, data):
326
    """Creates a new QMP message based on the passed data.
327

328
    """
329
    if not isinstance(data, dict):
330
      raise TypeError("QmpMessage must be initialized with a dict")
331

    
332
    self.data = data
333

    
334
  def __getitem__(self, field_name):
335
    """Get the value of the required field if present, or None.
336

337
    Overrides the [] operator to provide access to the message data,
338
    returning None if the required item is not in the message
339
    @return: the value of the field_name field, or None if field_name
340
             is not contained in the message
341

342
    """
343
    return self.data.get(field_name, None)
344

    
345
  def __setitem__(self, field_name, field_value):
346
    """Set the value of the required field_name to field_value.
347

348
    """
349
    self.data[field_name] = field_value
350

    
351
  @staticmethod
352
  def BuildFromJsonString(json_string):
353
    """Build a QmpMessage from a JSON encoded string.
354

355
    @type json_string: str
356
    @param json_string: JSON string representing the message
357
    @rtype: L{QmpMessage}
358
    @return: a L{QmpMessage} built from json_string
359

360
    """
361
    # Parse the string
362
    data = serializer.LoadJson(json_string)
363
    return QmpMessage(data)
364

    
365
  def __str__(self):
366
    # The protocol expects the JSON object to be sent as a single line.
367
    return serializer.DumpJson(self.data)
368

    
369
  def __eq__(self, other):
370
    # When comparing two QmpMessages, we are interested in comparing
371
    # their internal representation of the message data
372
    return self.data == other.data
373

    
374

    
375
class MonitorSocket(object):
376
  _SOCKET_TIMEOUT = 5
377

    
378
  def __init__(self, monitor_filename):
379
    """Instantiates the MonitorSocket object.
380

381
    @type monitor_filename: string
382
    @param monitor_filename: the filename of the UNIX raw socket on which the
383
                             monitor (QMP or simple one) is listening
384

385
    """
386
    self.monitor_filename = monitor_filename
387
    self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
388
    # We want to fail if the server doesn't send a complete message
389
    # in a reasonable amount of time
390
    self.sock.settimeout(self._SOCKET_TIMEOUT)
391
    self._connected = False
392

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

    
406
  def _check_connection(self):
407
    """Make sure that the connection is established.
408

409
    """
410
    if not self._connected:
411
      raise errors.ProgrammerError("To use a MonitorSocket you need to first"
412
                                   " invoke connect() on it")
413

    
414
  def connect(self):
415
    """Connects to the monitor.
416

417
    Connects to the UNIX socket
418

419
    @raise errors.HypervisorError: when there are communication errors
420

421
    """
422
    if self._connected:
423
      raise errors.ProgrammerError("Cannot connect twice")
424

    
425
    self._check_socket()
426

    
427
    # Check file existance/stuff
428
    try:
429
      self.sock.connect(self.monitor_filename)
430
    except EnvironmentError:
431
      raise errors.HypervisorError("Can't connect to qmp socket")
432
    self._connected = True
433

    
434
  def close(self):
435
    """Closes the socket
436

437
    It cannot be used after this call.
438

439
    """
440
    self.sock.close()
441

    
442

    
443
class QmpConnection(MonitorSocket):
444
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
445

446
  """
447
  _FIRST_MESSAGE_KEY = "QMP"
448
  _EVENT_KEY = "event"
449
  _ERROR_KEY = "error"
450
  _RETURN_KEY = RETURN_KEY = "return"
451
  _ACTUAL_KEY = ACTUAL_KEY = "actual"
452
  _ERROR_CLASS_KEY = "class"
453
  _ERROR_DATA_KEY = "data"
454
  _ERROR_DESC_KEY = "desc"
455
  _EXECUTE_KEY = "execute"
456
  _ARGUMENTS_KEY = "arguments"
457
  _CAPABILITIES_COMMAND = "qmp_capabilities"
458
  _MESSAGE_END_TOKEN = "\r\n"
459

    
460
  def __init__(self, monitor_filename):
461
    super(QmpConnection, self).__init__(monitor_filename)
462
    self._buf = ""
463

    
464
  def connect(self):
465
    """Connects to the QMP monitor.
466

467
    Connects to the UNIX socket and makes sure that we can actually send and
468
    receive data to the kvm instance via QMP.
469

470
    @raise errors.HypervisorError: when there are communication errors
471
    @raise errors.ProgrammerError: when there are data serialization errors
472

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

    
483
    # Let's put the monitor in command mode using the qmp_capabilities
484
    # command, or else no command will be executable.
485
    # (As per the QEMU Protocol Specification 0.1 - section 4)
486
    self.Execute(self._CAPABILITIES_COMMAND)
487

    
488
  def _ParseMessage(self, buf):
489
    """Extract and parse a QMP message from the given buffer.
490

491
    Seeks for a QMP message in the given buf. If found, it parses it and
492
    returns it together with the rest of the characters in the buf.
493
    If no message is found, returns None and the whole buffer.
494

495
    @raise errors.ProgrammerError: when there are data serialization errors
496

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

    
509
    return (message, buf)
510

    
511
  def _Recv(self):
512
    """Receives a message from QMP and decodes the received JSON object.
513

514
    @rtype: QmpMessage
515
    @return: the received message
516
    @raise errors.HypervisorError: when there are communication errors
517
    @raise errors.ProgrammerError: when there are data serialization errors
518

519
    """
520
    self._check_connection()
521

    
522
    # Check if there is already a message in the buffer
523
    (message, self._buf) = self._ParseMessage(self._buf)
524
    if message:
525
      return message
526

    
527
    recv_buffer = StringIO.StringIO(self._buf)
528
    recv_buffer.seek(len(self._buf))
529
    try:
530
      while True:
531
        data = self.sock.recv(4096)
532
        if not data:
533
          break
534
        recv_buffer.write(data)
535

    
536
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
537
        if message:
538
          return message
539

    
540
    except socket.timeout, err:
541
      raise errors.HypervisorError("Timeout while receiving a QMP message: "
542
                                   "%s" % (err))
543
    except socket.error, err:
544
      raise errors.HypervisorError("Unable to receive data from KVM using the"
545
                                   " QMP protocol: %s" % err)
546

    
547
  def _Send(self, message):
548
    """Encodes and sends a message to KVM using QMP.
549

550
    @type message: QmpMessage
551
    @param message: message to send to KVM
552
    @raise errors.HypervisorError: when there are communication errors
553
    @raise errors.ProgrammerError: when there are data serialization errors
554

555
    """
556
    self._check_connection()
557
    try:
558
      message_str = str(message)
559
    except Exception, err:
560
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
561

    
562
    try:
563
      self.sock.sendall(message_str)
564
    except socket.timeout, err:
565
      raise errors.HypervisorError("Timeout while sending a QMP message: "
566
                                   "%s (%s)" % (err.string, err.errno))
567
    except socket.error, err:
568
      raise errors.HypervisorError("Unable to send data from KVM using the"
569
                                   " QMP protocol: %s" % err)
570

    
571
  def Execute(self, command, arguments=None):
572
    """Executes a QMP command and returns the response of the server.
573

574
    @type command: str
575
    @param command: the command to execute
576
    @type arguments: dict
577
    @param arguments: dictionary of arguments to be passed to the command
578
    @rtype: dict
579
    @return: dictionary representing the received JSON object
580
    @raise errors.HypervisorError: when there are communication errors
581
    @raise errors.ProgrammerError: when there are data serialization errors
582

583
    """
584
    self._check_connection()
585
    message = QmpMessage({self._EXECUTE_KEY: command})
586
    if arguments:
587
      message[self._ARGUMENTS_KEY] = arguments
588
    self._Send(message)
589

    
590
    # Events can occur between the sending of the command and the reception
591
    # of the response, so we need to filter out messages with the event key.
592
    while True:
593
      response = self._Recv()
594
      err = response[self._ERROR_KEY]
595
      if err:
596
        raise errors.HypervisorError("kvm: error executing the %s"
597
                                     " command: %s (%s, %s):" %
598
                                     (command,
599
                                      err[self._ERROR_DESC_KEY],
600
                                      err[self._ERROR_CLASS_KEY],
601
                                      err[self._ERROR_DATA_KEY]))
602

    
603
      elif not response[self._EVENT_KEY]:
604
        return response
605

    
606

    
607
class KVMHypervisor(hv_base.BaseHypervisor):
608
  """KVM hypervisor interface
609

610
  """
611
  CAN_MIGRATE = True
612

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

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

    
716
  _VIRTIO = "virtio"
717
  _VIRTIO_NET_PCI = "virtio-net-pci"
718
  _VIRTIO_BLK_PCI = "virtio-blk-pci"
719

    
720
  _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
721
                                    re.M | re.I)
722
  _MIGRATION_PROGRESS_RE = \
723
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
724
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
725
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
726

    
727
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
728
  _MIGRATION_INFO_RETRY_DELAY = 2
729

    
730
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
731

    
732
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
733
  _CPU_INFO_CMD = "info cpus"
734
  _CONT_CMD = "cont"
735

    
736
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
737
  _CHECK_MACHINE_VERSION_RE = \
738
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
739

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

    
755
  _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
756
  _INFO_PCI_CMD = "info pci"
757
  _INFO_VERSION_RE = \
758
    re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
759
  _INFO_VERSION_CMD = "info version"
760

    
761
  _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
762

    
763
  ANCILLARY_FILES = [
764
    _KVM_NETWORK_SCRIPT,
765
    ]
766
  ANCILLARY_FILES_OPT = [
767
    _KVM_NETWORK_SCRIPT,
768
    ]
769

    
770
  # Supported kvm options to get output from
771
  _KVMOPT_HELP = "help"
772
  _KVMOPT_MLIST = "mlist"
773
  _KVMOPT_DEVICELIST = "devicelist"
774

    
775
  # Command to execute to get the output from kvm, and whether to
776
  # accept the output even on failure.
777
  _KVMOPTS_CMDS = {
778
    _KVMOPT_HELP: (["--help"], False),
779
    _KVMOPT_MLIST: (["-M", "?"], False),
780
    _KVMOPT_DEVICELIST: (["-device", "?"], True),
781
  }
782

    
783
  def __init__(self):
784
    hv_base.BaseHypervisor.__init__(self)
785
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
786
    # in a tmpfs filesystem or has been otherwise wiped out.
787
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
788
    utils.EnsureDirs(dirs)
789

    
790
  @classmethod
791
  def _InstancePidFile(cls, instance_name):
792
    """Returns the instance pidfile.
793

794
    """
795
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
796

    
797
  @classmethod
798
  def _InstanceUidFile(cls, instance_name):
799
    """Returns the instance uidfile.
800

801
    """
802
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
803

    
804
  @classmethod
805
  def _InstancePidInfo(cls, pid):
806
    """Check pid file for instance information.
807

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

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

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

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

    
829
    instance = None
830
    memory = 0
831
    vcpus = 0
832

    
833
    arg_list = cmdline.split("\x00")
834
    while arg_list:
835
      arg = arg_list.pop(0)
836
      if arg == "-name":
837
        instance = arg_list.pop(0)
838
      elif arg == "-m":
839
        memory = int(arg_list.pop(0))
840
      elif arg == "-smp":
841
        vcpus = int(arg_list.pop(0).split(",")[0])
842

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

    
847
    return (instance, memory, vcpus)
848

    
849
  def _InstancePidAlive(self, instance_name):
850
    """Returns the instance pidfile, pid, and liveness.
851

852
    @type instance_name: string
853
    @param instance_name: instance name
854
    @rtype: tuple
855
    @return: (pid file name, pid, liveness)
856

857
    """
858
    pidfile = self._InstancePidFile(instance_name)
859
    pid = utils.ReadPidFile(pidfile)
860

    
861
    alive = False
862
    try:
863
      cmd_instance = self._InstancePidInfo(pid)[0]
864
      alive = (cmd_instance == instance_name)
865
    except errors.HypervisorError:
866
      pass
867

    
868
    return (pidfile, pid, alive)
869

    
870
  def _CheckDown(self, instance_name):
871
    """Raises an error unless the given instance is down.
872

873
    """
874
    alive = self._InstancePidAlive(instance_name)[2]
875
    if alive:
876
      raise errors.HypervisorError("Failed to start instance %s: %s" %
877
                                   (instance_name, "already running"))
878

    
879
  @classmethod
880
  def _InstanceMonitor(cls, instance_name):
881
    """Returns the instance monitor socket name
882

883
    """
884
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
885

    
886
  @classmethod
887
  def _InstanceSerial(cls, instance_name):
888
    """Returns the instance serial socket name
889

890
    """
891
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
892

    
893
  @classmethod
894
  def _InstanceQmpMonitor(cls, instance_name):
895
    """Returns the instance serial QMP socket name
896

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

    
900
  @staticmethod
901
  def _SocatUnixConsoleParams():
902
    """Returns the correct parameters for socat
903

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

906
    """
907
    if constants.SOCAT_USE_ESCAPE:
908
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
909
    else:
910
      return "echo=0,icanon=0"
911

    
912
  @classmethod
913
  def _InstanceKVMRuntime(cls, instance_name):
914
    """Returns the instance KVM runtime filename
915

916
    """
917
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
918

    
919
  @classmethod
920
  def _InstanceChrootDir(cls, instance_name):
921
    """Returns the name of the KVM chroot dir of the instance
922

923
    """
924
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
925

    
926
  @classmethod
927
  def _InstanceNICDir(cls, instance_name):
928
    """Returns the name of the directory holding the tap device files for a
929
    given instance.
930

931
    """
932
    return utils.PathJoin(cls._NICS_DIR, instance_name)
933

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

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

    
941
  @classmethod
942
  def _InstanceKeymapFile(cls, instance_name):
943
    """Returns the name of the file containing the keymap for a given instance
944

945
    """
946
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
947

    
948
  @classmethod
949
  def _TryReadUidFile(cls, uid_file):
950
    """Try to read a uid file
951

952
    """
953
    if os.path.exists(uid_file):
954
      try:
955
        uid = int(utils.ReadOneLineFile(uid_file))
956
        return uid
957
      except EnvironmentError:
958
        logging.warning("Can't read uid file", exc_info=True)
959
      except (TypeError, ValueError):
960
        logging.warning("Can't parse uid file contents", exc_info=True)
961
    return None
962

    
963
  @classmethod
964
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
965
    """Removes an instance's rutime sockets/files/dirs.
966

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

    
1003
  @staticmethod
1004
  def _ConfigureNIC(instance, seq, nic, tap):
1005
    """Run the network configuration script for a specified NIC
1006

1007
    @param instance: instance we're acting on
1008
    @type instance: instance object
1009
    @param seq: nic sequence number
1010
    @type seq: int
1011
    @param nic: nic we're acting on
1012
    @type nic: nic object
1013
    @param tap: the host's tap interface this NIC corresponds to
1014
    @type tap: str
1015

1016
    """
1017
    env = {
1018
      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
1019
      "INSTANCE": instance.name,
1020
      "MAC": nic.mac,
1021
      "MODE": nic.nicparams[constants.NIC_MODE],
1022
      "INTERFACE": tap,
1023
      "INTERFACE_INDEX": str(seq),
1024
      "INTERFACE_UUID": nic.uuid,
1025
      "TAGS": " ".join(instance.GetTags()),
1026
    }
1027

    
1028
    if nic.ip:
1029
      env["IP"] = nic.ip
1030

    
1031
    if nic.name:
1032
      env["INTERFACE_NAME"] = nic.name
1033

    
1034
    if nic.nicparams[constants.NIC_LINK]:
1035
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
1036

    
1037
    if nic.network:
1038
      n = objects.Network.FromDict(nic.netinfo)
1039
      env.update(n.HooksDict())
1040

    
1041
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1042
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
1043

    
1044
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
1045
    if result.failed:
1046
      raise errors.HypervisorError("Failed to configure interface %s: %s;"
1047
                                   " network configuration script output: %s" %
1048
                                   (tap, result.fail_reason, result.output))
1049

    
1050
  @staticmethod
1051
  def _VerifyAffinityPackage():
1052
    if affinity is None:
1053
      raise errors.HypervisorError("affinity Python package not"
1054
                                   " found; cannot use CPU pinning under KVM")
1055

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

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

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

1069
    """
1070
    if cpu_list == constants.CPU_PINNING_OFF:
1071
      return constants.CPU_PINNING_ALL_KVM
1072
    else:
1073
      return sum(2 ** cpu for cpu in cpu_list)
1074

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

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

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

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

    
1109
      # For each vCPU, map it to the proper list of physical CPUs
1110
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1111
        affinity.set_process_affinity_mask(thread_dict[i],
1112
                                           cls._BuildAffinityCpuMask(vcpu))
1113

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

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

1122
    """
1123
    result = {}
1124
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1125
    for line in output.stdout.splitlines():
1126
      match = self._CPU_INFO_RE.search(line)
1127
      if not match:
1128
        continue
1129
      grp = map(int, match.groups())
1130
      result[grp[0]] = grp[1]
1131

    
1132
    return result
1133

    
1134
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1135
    """Complete CPU pinning.
1136

1137
    @type instance_name: string
1138
    @param instance_name: name of instance
1139
    @type cpu_mask: string
1140
    @param cpu_mask: CPU pinning mask as entered by user
1141

1142
    """
1143
    # Get KVM process ID, to be used if need to pin entire VM
1144
    _, pid, _ = self._InstancePidAlive(instance_name)
1145
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1146
    thread_dict = self._GetVcpuThreadIds(instance_name)
1147
    # Run CPU pinning, based on configured mask
1148
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1149

    
1150
  def ListInstances(self):
1151
    """Get the list of running instances.
1152

1153
    We can do this by listing our live instances directory and
1154
    checking whether the associated kvm process is still alive.
1155

1156
    """
1157
    result = []
1158
    for name in os.listdir(self._PIDS_DIR):
1159
      if self._InstancePidAlive(name)[2]:
1160
        result.append(name)
1161
    return result
1162

    
1163
  def GetInstanceInfo(self, instance_name):
1164
    """Get instance properties.
1165

1166
    @type instance_name: string
1167
    @param instance_name: the instance name
1168
    @rtype: tuple of strings
1169
    @return: (name, id, memory, vcpus, stat, times)
1170

1171
    """
1172
    _, pid, alive = self._InstancePidAlive(instance_name)
1173
    if not alive:
1174
      return None
1175

    
1176
    _, memory, vcpus = self._InstancePidInfo(pid)
1177
    istat = "---b-"
1178
    times = "0"
1179

    
1180
    try:
1181
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1182
      qmp.connect()
1183
      vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1184
      # Will fail if ballooning is not enabled, but we can then just resort to
1185
      # the value above.
1186
      mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1187
      memory = mem_bytes / 1048576
1188
    except errors.HypervisorError:
1189
      pass
1190

    
1191
    return (instance_name, pid, memory, vcpus, istat, times)
1192

    
1193
  def GetAllInstancesInfo(self):
1194
    """Get properties of all instances.
1195

1196
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1197

1198
    """
1199
    data = []
1200
    for name in os.listdir(self._PIDS_DIR):
1201
      try:
1202
        info = self.GetInstanceInfo(name)
1203
      except errors.HypervisorError:
1204
        # Ignore exceptions due to instances being shut down
1205
        continue
1206
      if info:
1207
        data.append(info)
1208
    return data
1209

    
1210
  def _GenerateKVMBlockDevicesOptions(self, instance, kvm_disks,
1211
                                      kvmhelp, devlist):
1212
    """Generate KVM options regarding instance's block devices.
1213

1214
    @type instance: L{objects.Instance}
1215
    @param instance: the instance object
1216
    @type kvm_disks: list of tuples
1217
    @param kvm_disks: list of tuples [(disk, link_name)..]
1218
    @type kvmhelp: string
1219
    @param kvmhelp: output of kvm --help
1220
    @type devlist: string
1221
    @param devlist: output of kvm -device ?
1222
    @rtype: list
1223
    @return: list of command line options eventually used by kvm executable
1224

1225
    """
1226
    hvp = instance.hvparams
1227
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1228
    if kernel_path:
1229
      boot_disk = False
1230
    else:
1231
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1232

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

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

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

    
1290
      dev_opts.extend(["-drive", drive_val])
1291

    
1292
    return dev_opts
1293

    
1294
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1295
                          kvmhelp):
1296
    """Generate KVM information to start an instance.
1297

1298
    @type kvmhelp: string
1299
    @param kvmhelp: output of kvm --help
1300
    @attention: this function must not have any side-effects; for
1301
        example, it must not write to the filesystem, or read values
1302
        from the current system the are expected to differ between
1303
        nodes, since it is only run once at instance startup;
1304
        actions/kvm arguments that can vary between systems should be
1305
        done in L{_ExecuteKVMRuntime}
1306

1307
    """
1308
    # pylint: disable=R0912,R0914,R0915
1309
    hvp = instance.hvparams
1310
    self.ValidateParameters(hvp)
1311

    
1312
    pidfile = self._InstancePidFile(instance.name)
1313
    kvm = hvp[constants.HV_KVM_PATH]
1314
    kvm_cmd = [kvm]
1315
    # used just by the vnc server, if enabled
1316
    kvm_cmd.extend(["-name", instance.name])
1317
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1318

    
1319
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1320
    if hvp[constants.HV_CPU_CORES]:
1321
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1322
    if hvp[constants.HV_CPU_THREADS]:
1323
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1324
    if hvp[constants.HV_CPU_SOCKETS]:
1325
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1326

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

    
1329
    kvm_cmd.extend(["-pidfile", pidfile])
1330
    kvm_cmd.extend(["-balloon", "virtio"])
1331
    kvm_cmd.extend(["-daemonize"])
1332
    if not instance.hvparams[constants.HV_ACPI]:
1333
      kvm_cmd.extend(["-no-acpi"])
1334
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1335
        constants.INSTANCE_REBOOT_EXIT:
1336
      kvm_cmd.extend(["-no-reboot"])
1337

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

    
1360
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1361
    if kernel_path:
1362
      boot_cdrom = boot_floppy = boot_network = False
1363
    else:
1364
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1365
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1366
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1367

    
1368
    if startup_paused:
1369
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1370

    
1371
    if boot_network:
1372
      kvm_cmd.extend(["-boot", "n"])
1373

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

    
1378
    disk_type = hvp[constants.HV_DISK_TYPE]
1379

    
1380
    #Now we can specify a different device type for CDROM devices.
1381
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1382
    if not cdrom_disk_type:
1383
      cdrom_disk_type = disk_type
1384

    
1385
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1386
    if iso_image:
1387
      options = ",format=raw,media=cdrom"
1388
      # set cdrom 'if' type
1389
      if boot_cdrom:
1390
        actual_cdrom_type = constants.HT_DISK_IDE
1391
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1392
        actual_cdrom_type = "virtio"
1393
      else:
1394
        actual_cdrom_type = cdrom_disk_type
1395
      if_val = ",if=%s" % actual_cdrom_type
1396
      # set boot flag, if needed
1397
      boot_val = ""
1398
      if boot_cdrom:
1399
        kvm_cmd.extend(["-boot", "d"])
1400
        if needs_boot_flag:
1401
          boot_val = ",boot=on"
1402
      # and finally build the entire '-drive' value
1403
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1404
      kvm_cmd.extend(["-drive", drive_val])
1405

    
1406
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1407
    if iso_image2:
1408
      options = ",format=raw,media=cdrom"
1409
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1410
        if_val = ",if=virtio"
1411
      else:
1412
        if_val = ",if=%s" % cdrom_disk_type
1413
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1414
      kvm_cmd.extend(["-drive", drive_val])
1415

    
1416
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1417
    if floppy_image:
1418
      options = ",format=raw,media=disk"
1419
      if boot_floppy:
1420
        kvm_cmd.extend(["-boot", "a"])
1421
        options = "%s,boot=on" % options
1422
      if_val = ",if=floppy"
1423
      options = "%s%s" % (options, if_val)
1424
      drive_val = "file=%s%s" % (floppy_image, options)
1425
      kvm_cmd.extend(["-drive", drive_val])
1426

    
1427
    if kernel_path:
1428
      kvm_cmd.extend(["-kernel", kernel_path])
1429
      initrd_path = hvp[constants.HV_INITRD_PATH]
1430
      if initrd_path:
1431
        kvm_cmd.extend(["-initrd", initrd_path])
1432
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1433
                     hvp[constants.HV_KERNEL_ARGS]]
1434
      if hvp[constants.HV_SERIAL_CONSOLE]:
1435
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1436
        root_append.append("console=ttyS0,%s" % serial_speed)
1437
      kvm_cmd.extend(["-append", " ".join(root_append)])
1438

    
1439
    mem_path = hvp[constants.HV_MEM_PATH]
1440
    if mem_path:
1441
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1442

    
1443
    monitor_dev = ("unix:%s,server,nowait" %
1444
                   self._InstanceMonitor(instance.name))
1445
    kvm_cmd.extend(["-monitor", monitor_dev])
1446
    if hvp[constants.HV_SERIAL_CONSOLE]:
1447
      serial_dev = ("unix:%s,server,nowait" %
1448
                    self._InstanceSerial(instance.name))
1449
      kvm_cmd.extend(["-serial", serial_dev])
1450
    else:
1451
      kvm_cmd.extend(["-serial", "none"])
1452

    
1453
    mouse_type = hvp[constants.HV_USB_MOUSE]
1454
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1455
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1456
    spice_ip_version = None
1457

    
1458
    kvm_cmd.extend(["-usb"])
1459

    
1460
    if mouse_type:
1461
      kvm_cmd.extend(["-usbdevice", mouse_type])
1462
    elif vnc_bind_address:
1463
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1464

    
1465
    if vnc_bind_address:
1466
      if netutils.IP4Address.IsValid(vnc_bind_address):
1467
        if instance.network_port > constants.VNC_BASE_PORT:
1468
          display = instance.network_port - constants.VNC_BASE_PORT
1469
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1470
            vnc_arg = ":%d" % (display)
1471
          else:
1472
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1473
        else:
1474
          logging.error("Network port is not a valid VNC display (%d < %d),"
1475
                        " not starting VNC",
1476
                        instance.network_port, constants.VNC_BASE_PORT)
1477
          vnc_arg = "none"
1478

    
1479
        # Only allow tls and other option when not binding to a file, for now.
1480
        # kvm/qemu gets confused otherwise about the filename to use.
1481
        vnc_append = ""
1482
        if hvp[constants.HV_VNC_TLS]:
1483
          vnc_append = "%s,tls" % vnc_append
1484
          if hvp[constants.HV_VNC_X509_VERIFY]:
1485
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1486
                                               hvp[constants.HV_VNC_X509])
1487
          elif hvp[constants.HV_VNC_X509]:
1488
            vnc_append = "%s,x509=%s" % (vnc_append,
1489
                                         hvp[constants.HV_VNC_X509])
1490
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1491
          vnc_append = "%s,password" % vnc_append
1492

    
1493
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1494

    
1495
      else:
1496
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1497

    
1498
      kvm_cmd.extend(["-vnc", vnc_arg])
1499
    elif spice_bind:
1500
      # FIXME: this is wrong here; the iface ip address differs
1501
      # between systems, so it should be done in _ExecuteKVMRuntime
1502
      if netutils.IsValidInterface(spice_bind):
1503
        # The user specified a network interface, we have to figure out the IP
1504
        # address.
1505
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1506
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1507

    
1508
        # if the user specified an IP version and the interface does not
1509
        # have that kind of IP addresses, throw an exception
1510
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1511
          if not addresses[spice_ip_version]:
1512
            raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1513
                                         " for %s" % (spice_ip_version,
1514
                                                      spice_bind))
1515

    
1516
        # the user did not specify an IP version, we have to figure it out
1517
        elif (addresses[constants.IP4_VERSION] and
1518
              addresses[constants.IP6_VERSION]):
1519
          # we have both ipv4 and ipv6, let's use the cluster default IP
1520
          # version
1521
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1522
          spice_ip_version = \
1523
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1524
        elif addresses[constants.IP4_VERSION]:
1525
          spice_ip_version = constants.IP4_VERSION
1526
        elif addresses[constants.IP6_VERSION]:
1527
          spice_ip_version = constants.IP6_VERSION
1528
        else:
1529
          raise errors.HypervisorError("SPICE: Unable to get an IP address"
1530
                                       " for %s" % (spice_bind))
1531

    
1532
        spice_address = addresses[spice_ip_version][0]
1533

    
1534
      else:
1535
        # spice_bind is known to be a valid IP address, because
1536
        # ValidateParameters checked it.
1537
        spice_address = spice_bind
1538

    
1539
      spice_arg = "addr=%s" % spice_address
1540
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1541
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1542
                     (spice_arg, instance.network_port,
1543
                      pathutils.SPICE_CACERT_FILE))
1544
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1545
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1546
                      pathutils.SPICE_CERT_FILE))
1547
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1548
        if tls_ciphers:
1549
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1550
      else:
1551
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1552

    
1553
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1554
        spice_arg = "%s,disable-ticketing" % spice_arg
1555

    
1556
      if spice_ip_version:
1557
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1558

    
1559
      # Image compression options
1560
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1561
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1562
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1563
      if img_lossless:
1564
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1565
      if img_jpeg:
1566
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1567
      if img_zlib_glz:
1568
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1569

    
1570
      # Video stream detection
1571
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1572
      if video_streaming:
1573
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1574

    
1575
      # Audio compression, by default in qemu-kvm it is on
1576
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1577
        spice_arg = "%s,playback-compression=off" % spice_arg
1578
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1579
        spice_arg = "%s,agent-mouse=off" % spice_arg
1580
      else:
1581
        # Enable the spice agent communication channel between the host and the
1582
        # agent.
1583
        kvm_cmd.extend(["-device", "virtio-serial-pci"])
1584
        kvm_cmd.extend([
1585
          "-device",
1586
          "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1587
          ])
1588
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1589

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

    
1593
    else:
1594
      # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1595
      # also works in earlier versions though (tested with 1.1 and 1.3)
1596
      if self._DISPLAY_RE.search(kvmhelp):
1597
        kvm_cmd.extend(["-display", "none"])
1598
      else:
1599
        kvm_cmd.extend(["-nographic"])
1600

    
1601
    if hvp[constants.HV_USE_LOCALTIME]:
1602
      kvm_cmd.extend(["-localtime"])
1603

    
1604
    if hvp[constants.HV_KVM_USE_CHROOT]:
1605
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1606

    
1607
    # Add qemu-KVM -cpu param
1608
    if hvp[constants.HV_CPU_TYPE]:
1609
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1610

    
1611
    # As requested by music lovers
1612
    if hvp[constants.HV_SOUNDHW]:
1613
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1614

    
1615
    # Pass a -vga option if requested, or if spice is used, for backwards
1616
    # compatibility.
1617
    if hvp[constants.HV_VGA]:
1618
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1619
    elif spice_bind:
1620
      kvm_cmd.extend(["-vga", "qxl"])
1621

    
1622
    # Various types of usb devices, comma separated
1623
    if hvp[constants.HV_USB_DEVICES]:
1624
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1625
        kvm_cmd.extend(["-usbdevice", dev])
1626

    
1627
    if hvp[constants.HV_KVM_EXTRA]:
1628
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1629

    
1630
    pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1631
    kvm_disks = []
1632
    for disk, link_name in block_devices:
1633
      _UpdatePCISlots(disk, pci_reservations)
1634
      kvm_disks.append((disk, link_name))
1635

    
1636
    kvm_nics = []
1637
    for nic in instance.nics:
1638
      _UpdatePCISlots(nic, pci_reservations)
1639
      kvm_nics.append(nic)
1640

    
1641
    hvparams = hvp
1642

    
1643
    return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1644

    
1645
  def _WriteKVMRuntime(self, instance_name, data):
1646
    """Write an instance's KVM runtime
1647

1648
    """
1649
    try:
1650
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1651
                      data=data)
1652
    except EnvironmentError, err:
1653
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1654

    
1655
  def _ReadKVMRuntime(self, instance_name):
1656
    """Read an instance's KVM runtime
1657

1658
    """
1659
    try:
1660
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1661
    except EnvironmentError, err:
1662
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1663
    return file_content
1664

    
1665
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1666
    """Save an instance's KVM runtime
1667

1668
    """
1669
    kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1670

    
1671
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1672
    serialized_disks = [(blk.ToDict(), link)
1673
                            for blk, link in kvm_disks]
1674
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1675
                                      serialized_disks))
1676

    
1677
    self._WriteKVMRuntime(instance.name, serialized_form)
1678

    
1679
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1680
    """Load an instance's KVM runtime
1681

1682
    """
1683
    if not serialized_runtime:
1684
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1685

    
1686
    return _AnalyzeSerializedRuntime(serialized_runtime)
1687

    
1688
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1689
    """Run the KVM cmd and check for errors
1690

1691
    @type name: string
1692
    @param name: instance name
1693
    @type kvm_cmd: list of strings
1694
    @param kvm_cmd: runcmd input for kvm
1695
    @type tap_fds: list of int
1696
    @param tap_fds: fds of tap devices opened by Ganeti
1697

1698
    """
1699
    try:
1700
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1701
    finally:
1702
      for fd in tap_fds:
1703
        utils_wrapper.CloseFdNoError(fd)
1704

    
1705
    if result.failed:
1706
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1707
                                   (name, result.fail_reason, result.output))
1708
    if not self._InstancePidAlive(name)[2]:
1709
      raise errors.HypervisorError("Failed to start instance %s" % name)
1710

    
1711
  # too many local variables
1712
  # pylint: disable=R0914
1713
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1714
    """Execute a KVM cmd, after completing it with some last minute data.
1715

1716
    @type incoming: tuple of strings
1717
    @param incoming: (target_host_ip, port)
1718
    @type kvmhelp: string
1719
    @param kvmhelp: output of kvm --help
1720

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

    
1734
    temp_files = []
1735

    
1736
    kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1737
    # the first element of kvm_cmd is always the path to the kvm binary
1738
    kvm_path = kvm_cmd[0]
1739
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1740

    
1741
    # We know it's safe to run as a different user upon migration, so we'll use
1742
    # the latest conf, from conf_hvp.
1743
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1744
    if security_model == constants.HT_SM_USER:
1745
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1746

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

    
1757
    # We have reasons to believe changing something like the nic driver/type
1758
    # upon migration won't exactly fly with the instance kernel, so for nic
1759
    # related parameters we'll use up_hvp
1760
    tapfds = []
1761
    taps = []
1762
    devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1763
    if not kvm_nics:
1764
      kvm_cmd.extend(["-net", "none"])
1765
    else:
1766
      vnet_hdr = False
1767
      tap_extra = ""
1768
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1769
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1770
        nic_model = self._VIRTIO
1771
        try:
1772
          if self._VIRTIO_NET_RE.search(devlist):
1773
            nic_model = self._VIRTIO_NET_PCI
1774
            vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1775
        except errors.HypervisorError, _:
1776
          # Older versions of kvm don't support DEVICE_LIST, but they don't
1777
          # have new virtio syntax either.
1778
          pass
1779

    
1780
        if up_hvp[constants.HV_VHOST_NET]:
1781
          # check for vhost_net support
1782
          if self._VHOST_RE.search(kvmhelp):
1783
            tap_extra = ",vhost=on"
1784
          else:
1785
            raise errors.HypervisorError("vhost_net is configured"
1786
                                         " but it is not available")
1787
      else:
1788
        nic_model = nic_type
1789

    
1790
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1791

    
1792
      for nic_seq, nic in enumerate(kvm_nics):
1793
        tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1794
        tapfds.append(tapfd)
1795
        taps.append(tapname)
1796
        if kvm_supports_netdev:
1797
          nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1798
          try:
1799
            # kvm_nics already exist in old runtime files and thus there might
1800
            # be some entries without pci slot (therefore try: except:)
1801
            kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1802
            netdev = kvm_devid
1803
            nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1804
          except errors.HotplugError:
1805
            netdev = "netdev%d" % nic_seq
1806
          nic_val += (",netdev=%s" % netdev)
1807
          tap_val = ("type=tap,id=%s,fd=%d%s" %
1808
                     (netdev, tapfd, tap_extra))
1809
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1810
        else:
1811
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1812
                                                         nic.mac, nic_model)
1813
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1814
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1815

    
1816
    if incoming:
1817
      target, port = incoming
1818
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1819

    
1820
    # Changing the vnc password doesn't bother the guest that much. At most it
1821
    # will surprise people who connect to it. Whether positively or negatively
1822
    # it's debatable.
1823
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1824
    vnc_pwd = None
1825
    if vnc_pwd_file:
1826
      try:
1827
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1828
      except EnvironmentError, err:
1829
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1830
                                     % (vnc_pwd_file, err))
1831

    
1832
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1833
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1834
                         constants.SECURE_DIR_MODE)])
1835

    
1836
    # Automatically enable QMP if version is >= 0.14
1837
    if self._QMP_RE.search(kvmhelp):
1838
      logging.debug("Enabling QMP")
1839
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1840
                      self._InstanceQmpMonitor(instance.name)])
1841

    
1842
    # Configure the network now for starting instances and bridged interfaces,
1843
    # during FinalizeMigration for incoming instances' routed interfaces
1844
    for nic_seq, nic in enumerate(kvm_nics):
1845
      if (incoming and
1846
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1847
        continue
1848
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1849

    
1850
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1851
                                                     kvm_disks,
1852
                                                     kvmhelp,
1853
                                                     devlist)
1854
    kvm_cmd.extend(bdev_opts)
1855
    # CPU affinity requires kvm to start paused, so we set this flag if the
1856
    # instance is not already paused and if we are not going to accept a
1857
    # migrating instance. In the latter case, pausing is not needed.
1858
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1859
    if start_kvm_paused:
1860
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1861

    
1862
    # Note: CPU pinning is using up_hvp since changes take effect
1863
    # during instance startup anyway, and to avoid problems when soft
1864
    # rebooting the instance.
1865
    cpu_pinning = False
1866
    if up_hvp.get(constants.HV_CPU_MASK, None):
1867
      cpu_pinning = True
1868

    
1869
    if security_model == constants.HT_SM_POOL:
1870
      ss = ssconf.SimpleStore()
1871
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1872
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1873
      uid = uidpool.RequestUnusedUid(all_uids)
1874
      try:
1875
        username = pwd.getpwuid(uid.GetUid()).pw_name
1876
        kvm_cmd.extend(["-runas", username])
1877
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1878
      except:
1879
        uidpool.ReleaseUid(uid)
1880
        raise
1881
      else:
1882
        uid.Unlock()
1883
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1884
    else:
1885
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1886

    
1887
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1888
                     constants.RUN_DIRS_MODE)])
1889
    for nic_seq, tap in enumerate(taps):
1890
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1891
                      data=tap)
1892

    
1893
    if vnc_pwd:
1894
      change_cmd = "change vnc password %s" % vnc_pwd
1895
      self._CallMonitorCommand(instance.name, change_cmd)
1896

    
1897
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1898
    # connection attempts because SPICE by default does not allow connections
1899
    # if neither a password nor the "disable_ticketing" options are specified.
1900
    # As soon as we send the password via QMP, that password is a valid ticket
1901
    # for connection.
1902
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1903
    if spice_password_file:
1904
      spice_pwd = ""
1905
      try:
1906
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1907
      except EnvironmentError, err:
1908
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1909
                                     % (spice_password_file, err))
1910

    
1911
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1912
      qmp.connect()
1913
      arguments = {
1914
          "protocol": "spice",
1915
          "password": spice_pwd,
1916
      }
1917
      qmp.Execute("set_password", arguments)
1918

    
1919
    for filename in temp_files:
1920
      utils.RemoveFile(filename)
1921

    
1922
    # If requested, set CPU affinity and resume instance execution
1923
    if cpu_pinning:
1924
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1925

    
1926
    start_memory = self._InstanceStartupMemory(instance)
1927
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1928
      self.BalloonInstanceMemory(instance, start_memory)
1929

    
1930
    if start_kvm_paused:
1931
      # To control CPU pinning, ballooning, and vnc/spice passwords
1932
      # the VM was started in a frozen state. If freezing was not
1933
      # explicitly requested resume the vm status.
1934
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1935

    
1936
  def StartInstance(self, instance, block_devices, startup_paused):
1937
    """Start an instance.
1938

1939
    """
1940
    self._CheckDown(instance.name)
1941
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1942
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1943
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1944
                                           startup_paused, kvmhelp)
1945
    self._SaveKVMRuntime(instance, kvm_runtime)
1946
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1947

    
1948
  def _CallMonitorCommand(self, instance_name, command):
1949
    """Invoke a command on the instance monitor.
1950

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

    
1970
    return result
1971

    
1972
  def _GetFreePCISlot(self, instance, dev):
1973
    """Get the first available pci slot of a runnung instance.
1974

1975
    """
1976
    slots = bitarray(32)
1977
    slots.setall(False) # pylint: disable=E1101
1978
    output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
1979
    for line in output.stdout.splitlines():
1980
      match = self._INFO_PCI_RE.search(line)
1981
      if match:
1982
        slot = int(match.group(1))
1983
        slots[slot] = True
1984

    
1985
    [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
1986
    if not free:
1987
      raise errors.HypervisorError("All PCI slots occupied")
1988

    
1989
    dev.pci = int(free)
1990

    
1991
  def VerifyHotplugSupport(self, instance, action, dev_type):
1992
    """Verifies that hotplug is supported.
1993

1994
    Hotplug is *not* supported in case of:
1995
     - security models and chroot (disk hotplug)
1996
     - fdsend module is missing (nic hot-add)
1997

1998
    @raise errors.HypervisorError: in one of the previous cases
1999

2000
    """
2001
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2002
      hvp = instance.hvparams
2003
      security_model = hvp[constants.HV_SECURITY_MODEL]
2004
      use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
2005
      if use_chroot:
2006
        raise errors.HotplugError("Disk hotplug is not supported"
2007
                                  " in case of chroot.")
2008
      if security_model != constants.HT_SM_NONE:
2009
        raise errors.HotplugError("Disk Hotplug is not supported in case"
2010
                                  " security models are used.")
2011

    
2012
    if (dev_type == constants.HOTPLUG_TARGET_NIC and
2013
        action == constants.HOTPLUG_ACTION_ADD and not fdsend):
2014
      raise errors.HotplugError("Cannot hot-add NIC."
2015
                                " fdsend python module is missing.")
2016

    
2017
  def HotplugSupported(self, instance):
2018
    """Checks if hotplug is generally supported.
2019

2020
    Hotplug is *not* supported in case of:
2021
     - qemu versions < 1.0
2022
     - for stopped instances
2023

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

2026
    """
2027
    try:
2028
      output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2029
    except errors.HypervisorError:
2030
      raise errors.HotplugError("Instance is probably down")
2031

    
2032
    # TODO: search for netdev_add, drive_add, device_add.....
2033
    match = self._INFO_VERSION_RE.search(output.stdout)
2034
    if not match:
2035
      raise errors.HotplugError("Cannot parse qemu version via monitor")
2036

    
2037
    v_major, v_min, _, _ = match.groups()
2038
    if (int(v_major), int(v_min)) < (1, 0):
2039
      raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2040

    
2041
  def _CallHotplugCommand(self, name, cmd):
2042
    output = self._CallMonitorCommand(name, cmd)
2043
    # TODO: parse output and check if succeeded
2044
    for line in output.stdout.splitlines():
2045
      logging.info("%s", line)
2046

    
2047
  def HotAddDevice(self, instance, dev_type, device, extra, seq):
2048
    """ Helper method to hot-add a new device
2049

2050
    It gets free pci slot generates the device name and invokes the
2051
    device specific method.
2052

2053
    """
2054
    # in case of hot-mod this is given
2055
    if device.pci is None:
2056
      self._GetFreePCISlot(instance, device)
2057
    kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2058
    runtime = self._LoadKVMRuntime(instance)
2059
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2060
      command = "drive_add dummy file=%s,if=none,id=%s,format=raw\n" % \
2061
                 (extra, kvm_devid)
2062
      command += ("device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
2063
                  (hex(device.pci), kvm_devid, kvm_devid))
2064
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
2065
      (tap, fd) = _OpenTap()
2066
      self._ConfigureNIC(instance, seq, device, tap)
2067
      self._PassTapFd(instance, fd, device)
2068
      command = "netdev_add tap,id=%s,fd=%s\n" % (kvm_devid, kvm_devid)
2069
      args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
2070
               (hex(device.pci), device.mac, kvm_devid, kvm_devid)
2071
      command += "device_add %s" % args
2072
      utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
2073

    
2074
    self._CallHotplugCommand(instance.name, command)
2075
    # update relevant entries in runtime file
2076
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2077
    entry = _RUNTIME_ENTRY[dev_type](device, extra)
2078
    runtime[index].append(entry)
2079
    self._SaveKVMRuntime(instance, runtime)
2080

    
2081
  def HotDelDevice(self, instance, dev_type, device, _, seq):
2082
    """ Helper method for hot-del device
2083

2084
    It gets device info from runtime file, generates the device name and
2085
    invokes the device specific method.
2086

2087
    """
2088
    runtime = self._LoadKVMRuntime(instance)
2089
    entry = _GetExistingDeviceInfo(dev_type, device, runtime)
2090
    kvm_device = _RUNTIME_DEVICE[dev_type](entry)
2091
    kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
2092
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2093
      command = "device_del %s\n" % kvm_devid
2094
      command += "drive_del %s" % kvm_devid
2095
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
2096
      command = "device_del %s\n" % kvm_devid
2097
      command += "netdev_del %s" % kvm_devid
2098
      utils.RemoveFile(self._InstanceNICFile(instance.name, seq))
2099
    self._CallHotplugCommand(instance.name, command)
2100
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2101
    runtime[index].remove(entry)
2102
    self._SaveKVMRuntime(instance, runtime)
2103

    
2104
    return kvm_device.pci
2105

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

2109
    It gets device info from runtime file, generates the device name and
2110
    invokes the device specific method. Currently only NICs support hot-mod
2111

2112
    """
2113
    if dev_type == constants.HOTPLUG_TARGET_NIC:
2114
      # putting it back in the same pci slot
2115
      device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2116
      # TODO: remove sleep when socat gets removed
2117
      time.sleep(2)
2118
      self.HotAddDevice(instance, dev_type, device, _, seq)
2119

    
2120
  def _PassTapFd(self, instance, fd, nic):
2121
    """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2122

2123
    """
2124
    # TODO: factor out code related to unix sockets.
2125
    #       squash common parts between monitor and qmp
2126
    kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2127
    command = "getfd %s\n" % kvm_devid
2128
    fds = [fd]
2129
    logging.info("%s", fds)
2130
    try:
2131
      monsock = MonitorSocket(self._InstanceMonitor(instance.name))
2132
      monsock.connect()
2133
      fdsend.sendfds(monsock.sock, command, fds=fds)
2134
    finally:
2135
      monsock.close()
2136

    
2137
  @classmethod
2138
  def _ParseKVMVersion(cls, text):
2139
    """Parse the KVM version from the --help output.
2140

2141
    @type text: string
2142
    @param text: output of kvm --help
2143
    @return: (version, v_maj, v_min, v_rev)
2144
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2145

2146
    """
2147
    match = cls._VERSION_RE.search(text.splitlines()[0])
2148
    if not match:
2149
      raise errors.HypervisorError("Unable to get KVM version")
2150

    
2151
    v_all = match.group(0)
2152
    v_maj = int(match.group(1))
2153
    v_min = int(match.group(2))
2154
    if match.group(4):
2155
      v_rev = int(match.group(4))
2156
    else:
2157
      v_rev = 0
2158
    return (v_all, v_maj, v_min, v_rev)
2159

    
2160
  @classmethod
2161
  def _GetKVMOutput(cls, kvm_path, option):
2162
    """Return the output of a kvm invocation
2163

2164
    @type kvm_path: string
2165
    @param kvm_path: path to the kvm executable
2166
    @type option: a key of _KVMOPTS_CMDS
2167
    @param option: kvm option to fetch the output from
2168
    @return: output a supported kvm invocation
2169
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2170

2171
    """
2172
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2173

    
2174
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
2175

    
2176
    result = utils.RunCmd([kvm_path] + optlist)
2177
    if result.failed and not can_fail:
2178
      raise errors.HypervisorError("Unable to get KVM %s output" %
2179
                                    " ".join(optlist))
2180
    return result.output
2181

    
2182
  @classmethod
2183
  def _GetKVMVersion(cls, kvm_path):
2184
    """Return the installed KVM version.
2185

2186
    @return: (version, v_maj, v_min, v_rev)
2187
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2188

2189
    """
2190
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2191

    
2192
  @classmethod
2193
  def _GetDefaultMachineVersion(cls, kvm_path):
2194
    """Return the default hardware revision (e.g. pc-1.1)
2195

2196
    """
2197
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2198
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2199
    if match:
2200
      return match.group(1)
2201
    else:
2202
      return "pc"
2203

    
2204
  def StopInstance(self, instance, force=False, retry=False, name=None):
2205
    """Stop an instance.
2206

2207
    """
2208
    if name is not None and not force:
2209
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2210
    if name is None:
2211
      name = instance.name
2212
      acpi = instance.hvparams[constants.HV_ACPI]
2213
    else:
2214
      acpi = False
2215
    _, pid, alive = self._InstancePidAlive(name)
2216
    if pid > 0 and alive:
2217
      if force or not acpi:
2218
        utils.KillProcess(pid)
2219
      else:
2220
        self._CallMonitorCommand(name, "system_powerdown")
2221

    
2222
  def CleanupInstance(self, instance_name):
2223
    """Cleanup after a stopped instance
2224

2225
    """
2226
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
2227
    if pid > 0 and alive:
2228
      raise errors.HypervisorError("Cannot cleanup a live instance")
2229
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2230

    
2231
  def RebootInstance(self, instance):
2232
    """Reboot an instance.
2233

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

    
2254
  def MigrationInfo(self, instance):
2255
    """Get instance information to perform a migration.
2256

2257
    @type instance: L{objects.Instance}
2258
    @param instance: instance to be migrated
2259
    @rtype: string
2260
    @return: content of the KVM runtime file
2261

2262
    """
2263
    return self._ReadKVMRuntime(instance.name)
2264

    
2265
  def AcceptInstance(self, instance, info, target):
2266
    """Prepare to accept an instance.
2267

2268
    @type instance: L{objects.Instance}
2269
    @param instance: instance to be accepted
2270
    @type info: string
2271
    @param info: content of the KVM runtime file on the source node
2272
    @type target: string
2273
    @param target: target host (usually ip), on this node
2274

2275
    """
2276
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2277
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2278
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2279
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2280
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2281
                            incoming=incoming_address)
2282

    
2283
  def FinalizeMigrationDst(self, instance, info, success):
2284
    """Finalize the instance migration on the target node.
2285

2286
    Stop the incoming mode KVM.
2287

2288
    @type instance: L{objects.Instance}
2289
    @param instance: instance whose migration is being finalized
2290

2291
    """
2292
    if success:
2293
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2294
      kvm_nics = kvm_runtime[1]
2295

    
2296
      for nic_seq, nic in enumerate(kvm_nics):
2297
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2298
          # Bridged interfaces have already been configured
2299
          continue
2300
        try:
2301
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2302
        except EnvironmentError, err:
2303
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
2304
                          instance.name, nic_seq, str(err))
2305
          continue
2306
        try:
2307
          self._ConfigureNIC(instance, nic_seq, nic, tap)
2308
        except errors.HypervisorError, err:
2309
          logging.warning(str(err))
2310

    
2311
      self._WriteKVMRuntime(instance.name, info)
2312
    else:
2313
      self.StopInstance(instance, force=True)
2314

    
2315
  def MigrateInstance(self, instance, target, live):
2316
    """Migrate an instance to a target node.
2317

2318
    The migration will not be attempted if the instance is not
2319
    currently running.
2320

2321
    @type instance: L{objects.Instance}
2322
    @param instance: the instance to be migrated
2323
    @type target: string
2324
    @param target: ip address of the target node
2325
    @type live: boolean
2326
    @param live: perform a live migration
2327

2328
    """
2329
    instance_name = instance.name
2330
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
2331
    _, _, alive = self._InstancePidAlive(instance_name)
2332
    if not alive:
2333
      raise errors.HypervisorError("Instance not running, cannot migrate")
2334

    
2335
    if not live:
2336
      self._CallMonitorCommand(instance_name, "stop")
2337

    
2338
    migrate_command = ("migrate_set_speed %dm" %
2339
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2340
    self._CallMonitorCommand(instance_name, migrate_command)
2341

    
2342
    migrate_command = ("migrate_set_downtime %dms" %
2343
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2344
    self._CallMonitorCommand(instance_name, migrate_command)
2345

    
2346
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2347
    self._CallMonitorCommand(instance_name, migrate_command)
2348

    
2349
  def FinalizeMigrationSource(self, instance, success, live):
2350
    """Finalize the instance migration on the source node.
2351

2352
    @type instance: L{objects.Instance}
2353
    @param instance: the instance that was migrated
2354
    @type success: bool
2355
    @param success: whether the migration succeeded or not
2356
    @type live: bool
2357
    @param live: whether the user requested a live migration or not
2358

2359
    """
2360
    if success:
2361
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2362
      utils.KillProcess(pid)
2363
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2364
    elif live:
2365
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2366

    
2367
  def GetMigrationStatus(self, instance):
2368
    """Get the migration status
2369

2370
    @type instance: L{objects.Instance}
2371
    @param instance: the instance that is being migrated
2372
    @rtype: L{objects.MigrationStatus}
2373
    @return: the status of the current migration (one of
2374
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2375
             progress info that can be retrieved from the hypervisor
2376

2377
    """
2378
    info_command = "info migrate"
2379
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2380
      result = self._CallMonitorCommand(instance.name, info_command)
2381
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
2382
      if not match:
2383
        if not result.stdout:
2384
          logging.info("KVM: empty 'info migrate' result")
2385
        else:
2386
          logging.warning("KVM: unknown 'info migrate' result: %s",
2387
                          result.stdout)
2388
      else:
2389
        status = match.group(1)
2390
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2391
          migration_status = objects.MigrationStatus(status=status)
2392
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2393
          if match:
2394
            migration_status.transferred_ram = match.group("transferred")
2395
            migration_status.total_ram = match.group("total")
2396

    
2397
          return migration_status
2398

    
2399
        logging.warning("KVM: unknown migration status '%s'", status)
2400

    
2401
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2402

    
2403
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2404

    
2405
  def BalloonInstanceMemory(self, instance, mem):
2406
    """Balloon an instance memory to a certain value.
2407

2408
    @type instance: L{objects.Instance}
2409
    @param instance: instance to be accepted
2410
    @type mem: int
2411
    @param mem: actual memory size to use for instance runtime
2412

2413
    """
2414
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2415

    
2416
  def GetNodeInfo(self):
2417
    """Return information about the node.
2418

2419
    @return: a dict with the following keys (values in MiB):
2420
          - memory_total: the total memory size on the node
2421
          - memory_free: the available memory on the node for instances
2422
          - memory_dom0: the memory used by the node itself, if available
2423
          - hv_version: the hypervisor version in the form (major, minor,
2424
                        revision)
2425

2426
    """
2427
    result = self.GetLinuxNodeInfo()
2428
    # FIXME: this is the global kvm version, but the actual version can be
2429
    # customized as an hv parameter. we should use the nodegroup's default kvm
2430
    # path parameter here.
2431
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2432
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2433
    return result
2434

    
2435
  @classmethod
2436
  def GetInstanceConsole(cls, instance, hvparams, beparams):
2437
    """Return a command for connecting to the console of an instance.
2438

2439
    """
2440
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2441
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2442
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2443
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2444
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2445
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2446
      return objects.InstanceConsole(instance=instance.name,
2447
                                     kind=constants.CONS_SSH,
2448
                                     host=instance.primary_node,
2449
                                     user=constants.SSH_CONSOLE_USER,
2450
                                     command=cmd)
2451

    
2452
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2453
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2454
      display = instance.network_port - constants.VNC_BASE_PORT
2455
      return objects.InstanceConsole(instance=instance.name,
2456
                                     kind=constants.CONS_VNC,
2457
                                     host=vnc_bind_address,
2458
                                     port=instance.network_port,
2459
                                     display=display)
2460

    
2461
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2462
    if spice_bind:
2463
      return objects.InstanceConsole(instance=instance.name,
2464
                                     kind=constants.CONS_SPICE,
2465
                                     host=spice_bind,
2466
                                     port=instance.network_port)
2467

    
2468
    return objects.InstanceConsole(instance=instance.name,
2469
                                   kind=constants.CONS_MESSAGE,
2470
                                   message=("No serial shell for instance %s" %
2471
                                            instance.name))
2472

    
2473
  def Verify(self):
2474
    """Verify the hypervisor.
2475

2476
    Check that the required binaries exist.
2477

2478
    @return: Problem description if something is wrong, C{None} otherwise
2479

2480
    """
2481
    msgs = []
2482
    # FIXME: this is the global kvm binary, but the actual path can be
2483
    # customized as an hv parameter; we should use the nodegroup's
2484
    # default kvm path parameter here.
2485
    if not os.path.exists(constants.KVM_PATH):
2486
      msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2487
    if not os.path.exists(constants.SOCAT_PATH):
2488
      msgs.append("The socat binary ('%s') does not exist" %
2489
                  constants.SOCAT_PATH)
2490

    
2491
    return self._FormatVerifyResults(msgs)
2492

    
2493
  @classmethod
2494
  def CheckParameterSyntax(cls, hvparams):
2495
    """Check the given parameters for validity.
2496

2497
    @type hvparams:  dict
2498
    @param hvparams: dictionary with parameter names/value
2499
    @raise errors.HypervisorError: when a parameter is not valid
2500

2501
    """
2502
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2503

    
2504
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2505
    if kernel_path:
2506
      if not hvparams[constants.HV_ROOT_PATH]:
2507
        raise errors.HypervisorError("Need a root partition for the instance,"
2508
                                     " if a kernel is defined")
2509

    
2510
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2511
        not hvparams[constants.HV_VNC_X509]):
2512
      raise errors.HypervisorError("%s must be defined, if %s is" %
2513
                                   (constants.HV_VNC_X509,
2514
                                    constants.HV_VNC_X509_VERIFY))
2515

    
2516
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2517
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2518
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2519
      if not serial_speed or serial_speed not in valid_speeds:
2520
        raise errors.HypervisorError("Invalid serial console speed, must be"
2521
                                     " one of: %s" %
2522
                                     utils.CommaJoin(valid_speeds))
2523

    
2524
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2525
    if (boot_order == constants.HT_BO_CDROM and
2526
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2527
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2528
                                   " ISO path")
2529

    
2530
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2531
    if security_model == constants.HT_SM_USER:
2532
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2533
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2534
                                     " must be specified")
2535
    elif (security_model == constants.HT_SM_NONE or
2536
          security_model == constants.HT_SM_POOL):
2537
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2538
        raise errors.HypervisorError("Cannot have a security domain when the"
2539
                                     " security model is 'none' or 'pool'")
2540

    
2541
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2542
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2543
    if spice_bind:
2544
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2545
        # if an IP version is specified, the spice_bind parameter must be an
2546
        # IP of that family
2547
        if (netutils.IP4Address.IsValid(spice_bind) and
2548
            spice_ip_version != constants.IP4_VERSION):
2549
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2550
                                       " the specified IP version is %s" %
2551
                                       (spice_bind, spice_ip_version))
2552

    
2553
        if (netutils.IP6Address.IsValid(spice_bind) and
2554
            spice_ip_version != constants.IP6_VERSION):
2555
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2556
                                       " the specified IP version is %s" %
2557
                                       (spice_bind, spice_ip_version))
2558
    else:
2559
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2560
      # error if any of them is set without it.
2561
      for param in _SPICE_ADDITIONAL_PARAMS:
2562
        if hvparams[param]:
2563
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2564
                                       (param, constants.HV_KVM_SPICE_BIND))
2565

    
2566
  @classmethod
2567
  def ValidateParameters(cls, hvparams):
2568
    """Check the given parameters for validity.
2569

2570
    @type hvparams:  dict
2571
    @param hvparams: dictionary with parameter names/value
2572
    @raise errors.HypervisorError: when a parameter is not valid
2573

2574
    """
2575
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2576

    
2577
    kvm_path = hvparams[constants.HV_KVM_PATH]
2578

    
2579
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2580
    if security_model == constants.HT_SM_USER:
2581
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2582
      try:
2583
        pwd.getpwnam(username)
2584
      except KeyError:
2585
        raise errors.HypervisorError("Unknown security domain user %s"
2586
                                     % username)
2587

    
2588
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2589
    if spice_bind:
2590
      # only one of VNC and SPICE can be used currently.
2591
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2592
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2593
                                     " only one of them can be used at a"
2594
                                     " given time")
2595

    
2596
      # check that KVM supports SPICE
2597
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2598
      if not cls._SPICE_RE.search(kvmhelp):
2599
        raise errors.HypervisorError("SPICE is configured, but it is not"
2600
                                     " supported according to 'kvm --help'")
2601

    
2602
      # if spice_bind is not an IP address, it must be a valid interface
2603
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2604
                       netutils.IP6Address.IsValid(spice_bind))
2605
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2606
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2607
                                     " a valid IP address or interface name" %
2608
                                     constants.HV_KVM_SPICE_BIND)
2609

    
2610
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2611
    if machine_version:
2612
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2613
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2614
        raise errors.HypervisorError("Unsupported machine version: %s" %
2615
                                     machine_version)
2616

    
2617
  @classmethod
2618
  def PowercycleNode(cls):
2619
    """KVM powercycle, just a wrapper over Linux powercycle.
2620

2621
    """
2622
    cls.LinuxPowercycle()