Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 89c10241

History | View | Annotate | Download (96.7 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, uri)
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, u) for (d, l, u) 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, None)
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, uri)
232
               for sdisk, link, uri 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
  def __len__(self):
352
    """Return the number of fields stored in this QmpMessage.
353

354
    """
355
    return len(self.data)
356

    
357
  def __delitem__(self, key):
358
    """Delete the specified element from the QmpMessage.
359

360
    """
361
    del(self.data[key])
362

    
363
  @staticmethod
364
  def BuildFromJsonString(json_string):
365
    """Build a QmpMessage from a JSON encoded string.
366

367
    @type json_string: str
368
    @param json_string: JSON string representing the message
369
    @rtype: L{QmpMessage}
370
    @return: a L{QmpMessage} built from json_string
371

372
    """
373
    # Parse the string
374
    data = serializer.LoadJson(json_string)
375
    return QmpMessage(data)
376

    
377
  def __str__(self):
378
    # The protocol expects the JSON object to be sent as a single line.
379
    return serializer.DumpJson(self.data)
380

    
381
  def __eq__(self, other):
382
    # When comparing two QmpMessages, we are interested in comparing
383
    # their internal representation of the message data
384
    return self.data == other.data
385

    
386

    
387
class MonitorSocket(object):
388
  _SOCKET_TIMEOUT = 5
389

    
390
  def __init__(self, monitor_filename):
391
    """Instantiates the MonitorSocket object.
392

393
    @type monitor_filename: string
394
    @param monitor_filename: the filename of the UNIX raw socket on which the
395
                             monitor (QMP or simple one) is listening
396

397
    """
398
    self.monitor_filename = monitor_filename
399
    self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
400
    # We want to fail if the server doesn't send a complete message
401
    # in a reasonable amount of time
402
    self.sock.settimeout(self._SOCKET_TIMEOUT)
403
    self._connected = False
404

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

    
418
  def _check_connection(self):
419
    """Make sure that the connection is established.
420

421
    """
422
    if not self._connected:
423
      raise errors.ProgrammerError("To use a MonitorSocket you need to first"
424
                                   " invoke connect() on it")
425

    
426
  def connect(self):
427
    """Connects to the monitor.
428

429
    Connects to the UNIX socket
430

431
    @raise errors.HypervisorError: when there are communication errors
432

433
    """
434
    if self._connected:
435
      raise errors.ProgrammerError("Cannot connect twice")
436

    
437
    self._check_socket()
438

    
439
    # Check file existance/stuff
440
    try:
441
      self.sock.connect(self.monitor_filename)
442
    except EnvironmentError:
443
      raise errors.HypervisorError("Can't connect to qmp socket")
444
    self._connected = True
445

    
446
  def close(self):
447
    """Closes the socket
448

449
    It cannot be used after this call.
450

451
    """
452
    self.sock.close()
453

    
454

    
455
class QmpConnection(MonitorSocket):
456
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
457

458
  """
459
  _FIRST_MESSAGE_KEY = "QMP"
460
  _EVENT_KEY = "event"
461
  _ERROR_KEY = "error"
462
  _RETURN_KEY = RETURN_KEY = "return"
463
  _ACTUAL_KEY = ACTUAL_KEY = "actual"
464
  _ERROR_CLASS_KEY = "class"
465
  _ERROR_DESC_KEY = "desc"
466
  _EXECUTE_KEY = "execute"
467
  _ARGUMENTS_KEY = "arguments"
468
  _CAPABILITIES_COMMAND = "qmp_capabilities"
469
  _MESSAGE_END_TOKEN = "\r\n"
470

    
471
  def __init__(self, monitor_filename):
472
    super(QmpConnection, self).__init__(monitor_filename)
473
    self._buf = ""
474

    
475
  def connect(self):
476
    """Connects to the QMP monitor.
477

478
    Connects to the UNIX socket and makes sure that we can actually send and
479
    receive data to the kvm instance via QMP.
480

481
    @raise errors.HypervisorError: when there are communication errors
482
    @raise errors.ProgrammerError: when there are data serialization errors
483

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

    
494
    # Let's put the monitor in command mode using the qmp_capabilities
495
    # command, or else no command will be executable.
496
    # (As per the QEMU Protocol Specification 0.1 - section 4)
497
    self.Execute(self._CAPABILITIES_COMMAND)
498

    
499
  def _ParseMessage(self, buf):
500
    """Extract and parse a QMP message from the given buffer.
501

502
    Seeks for a QMP message in the given buf. If found, it parses it and
503
    returns it together with the rest of the characters in the buf.
504
    If no message is found, returns None and the whole buffer.
505

506
    @raise errors.ProgrammerError: when there are data serialization errors
507

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

    
520
    return (message, buf)
521

    
522
  def _Recv(self):
523
    """Receives a message from QMP and decodes the received JSON object.
524

525
    @rtype: QmpMessage
526
    @return: the received message
527
    @raise errors.HypervisorError: when there are communication errors
528
    @raise errors.ProgrammerError: when there are data serialization errors
529

530
    """
531
    self._check_connection()
532

    
533
    # Check if there is already a message in the buffer
534
    (message, self._buf) = self._ParseMessage(self._buf)
535
    if message:
536
      return message
537

    
538
    recv_buffer = StringIO.StringIO(self._buf)
539
    recv_buffer.seek(len(self._buf))
540
    try:
541
      while True:
542
        data = self.sock.recv(4096)
543
        if not data:
544
          break
545
        recv_buffer.write(data)
546

    
547
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
548
        if message:
549
          return message
550

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

    
558
  def _Send(self, message):
559
    """Encodes and sends a message to KVM using QMP.
560

561
    @type message: QmpMessage
562
    @param message: message to send to KVM
563
    @raise errors.HypervisorError: when there are communication errors
564
    @raise errors.ProgrammerError: when there are data serialization errors
565

566
    """
567
    self._check_connection()
568
    try:
569
      message_str = str(message)
570
    except Exception, err:
571
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
572

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

    
582
  def Execute(self, command, arguments=None):
583
    """Executes a QMP command and returns the response of the server.
584

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

594
    """
595
    self._check_connection()
596
    message = QmpMessage({self._EXECUTE_KEY: command})
597
    if arguments:
598
      message[self._ARGUMENTS_KEY] = arguments
599
    self._Send(message)
600

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

    
613
      elif not response[self._EVENT_KEY]:
614
        return response
615

    
616

    
617
class KVMHypervisor(hv_base.BaseHypervisor):
618
  """KVM hypervisor interface
619

620
  """
621
  CAN_MIGRATE = True
622

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

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

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

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

    
733
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
734
  _MIGRATION_INFO_RETRY_DELAY = 2
735

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

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

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

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

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

    
768
  _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
769

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
854
    return (instance, memory, vcpus)
855

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

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

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

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

    
875
    return (pidfile, pid, alive)
876

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1139
    return result
1140

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

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

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

    
1157
  def ListInstances(self, hvparams=None):
1158
    """Get the list of running instances.
1159

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

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

    
1170
  def GetInstanceInfo(self, instance_name, hvparams=None):
1171
    """Get instance properties.
1172

1173
    @type instance_name: string
1174
    @param instance_name: the instance name
1175
    @type hvparams: dict of strings
1176
    @param hvparams: hvparams to be used with this instance
1177
    @rtype: tuple of strings
1178
    @return: (name, id, memory, vcpus, stat, times)
1179

1180
    """
1181
    _, pid, alive = self._InstancePidAlive(instance_name)
1182
    if not alive:
1183
      return None
1184

    
1185
    _, memory, vcpus = self._InstancePidInfo(pid)
1186
    istat = "---b-"
1187
    times = "0"
1188

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

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

    
1202
  def GetAllInstancesInfo(self, hvparams=None):
1203
    """Get properties of all instances.
1204

1205
    @type hvparams: dict of strings
1206
    @param hvparams: hypervisor parameter
1207
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1208

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

    
1221
  def _GenerateKVMBlockDevicesOptions(self, instance, kvm_disks,
1222
                                      kvmhelp, devlist):
1223
    """Generate KVM options regarding instance's block devices.
1224

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

1236
    """
1237
    hvp = instance.hvparams
1238
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1239
    if kernel_path:
1240
      boot_disk = False
1241
    else:
1242
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1243

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

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

    
1287
      access_mode = cfdev.params.get(constants.LDP_ACCESS,
1288
                                     constants.DISK_KERNELSPACE)
1289
      if (uri and access_mode == constants.DISK_USERSPACE):
1290
        drive_uri = uri
1291
      else:
1292
        drive_uri = link_name
1293

    
1294
      drive_val = "file=%s,format=raw%s%s%s" % \
1295
                  (drive_uri, if_val, boot_val, cache_val)
1296

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

    
1309
      dev_opts.extend(["-drive", drive_val])
1310

    
1311
    return dev_opts
1312

    
1313
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1314
                          kvmhelp):
1315
    """Generate KVM information to start an instance.
1316

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

1326
    """
1327
    # pylint: disable=R0912,R0914,R0915
1328
    hvp = instance.hvparams
1329
    self.ValidateParameters(hvp)
1330

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

    
1338
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1339
    if hvp[constants.HV_CPU_CORES]:
1340
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1341
    if hvp[constants.HV_CPU_THREADS]:
1342
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1343
    if hvp[constants.HV_CPU_SOCKETS]:
1344
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1345

    
1346
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1347

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

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

    
1379
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1380
    if kernel_path:
1381
      boot_cdrom = boot_floppy = boot_network = False
1382
    else:
1383
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1384
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1385
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1386

    
1387
    if startup_paused:
1388
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1389

    
1390
    if boot_network:
1391
      kvm_cmd.extend(["-boot", "n"])
1392

    
1393
    # whether this is an older KVM version that uses the boot=on flag
1394
    # on devices
1395
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1396

    
1397
    disk_type = hvp[constants.HV_DISK_TYPE]
1398

    
1399
    #Now we can specify a different device type for CDROM devices.
1400
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1401
    if not cdrom_disk_type:
1402
      cdrom_disk_type = disk_type
1403

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

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

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

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

    
1458
    mem_path = hvp[constants.HV_MEM_PATH]
1459
    if mem_path:
1460
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1461

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

    
1472
    mouse_type = hvp[constants.HV_USB_MOUSE]
1473
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1474
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1475
    spice_ip_version = None
1476

    
1477
    kvm_cmd.extend(["-usb"])
1478

    
1479
    if mouse_type:
1480
      kvm_cmd.extend(["-usbdevice", mouse_type])
1481
    elif vnc_bind_address:
1482
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1483

    
1484
    if vnc_bind_address:
1485
      if netutils.IsValidInterface(vnc_bind_address):
1486
        if_addresses = netutils.GetInterfaceIpAddresses(vnc_bind_address)
1487
        if_ip4_addresses = if_addresses[constants.IP4_VERSION]
1488
        if len(if_ip4_addresses) < 1:
1489
          logging.error("Could not determine IPv4 address of interface %s",
1490
                        vnc_bind_address)
1491
        else:
1492
          vnc_bind_address = if_ip4_addresses[0]
1493
      if netutils.IP4Address.IsValid(vnc_bind_address):
1494
        if instance.network_port > constants.VNC_BASE_PORT:
1495
          display = instance.network_port - constants.VNC_BASE_PORT
1496
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1497
            vnc_arg = ":%d" % (display)
1498
          else:
1499
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1500
        else:
1501
          logging.error("Network port is not a valid VNC display (%d < %d),"
1502
                        " not starting VNC",
1503
                        instance.network_port, constants.VNC_BASE_PORT)
1504
          vnc_arg = "none"
1505

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

    
1520
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1521

    
1522
      else:
1523
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1524

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

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

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

    
1559
        spice_address = addresses[spice_ip_version][0]
1560

    
1561
      else:
1562
        # spice_bind is known to be a valid IP address, because
1563
        # ValidateParameters checked it.
1564
        spice_address = spice_bind
1565

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

    
1580
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1581
        spice_arg = "%s,disable-ticketing" % spice_arg
1582

    
1583
      if spice_ip_version:
1584
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1585

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

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

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

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

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

    
1628
    if hvp[constants.HV_USE_LOCALTIME]:
1629
      kvm_cmd.extend(["-localtime"])
1630

    
1631
    if hvp[constants.HV_KVM_USE_CHROOT]:
1632
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1633

    
1634
    # Add qemu-KVM -cpu param
1635
    if hvp[constants.HV_CPU_TYPE]:
1636
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1637

    
1638
    # As requested by music lovers
1639
    if hvp[constants.HV_SOUNDHW]:
1640
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1641

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

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

    
1654
    # Set system UUID to instance UUID
1655
    if self._UUID_RE.search(kvmhelp):
1656
      kvm_cmd.extend(["-uuid", instance.uuid])
1657

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

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

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

    
1672
    hvparams = hvp
1673

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

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

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

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

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

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

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

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

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

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

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

    
1717
    return _AnalyzeSerializedRuntime(serialized_runtime)
1718

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

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

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

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

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

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

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

    
1765
    temp_files = []
1766

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

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

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

    
1788
    # We have reasons to believe changing something like the nic driver/type
1789
    # upon migration won't exactly fly with the instance kernel, so for nic
1790
    # related parameters we'll use up_hvp
1791
    tapfds = []
1792
    taps = []
1793
    devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1794
    if not kvm_nics:
1795
      kvm_cmd.extend(["-net", "none"])
1796
    else:
1797
      vnet_hdr = False
1798
      tap_extra = ""
1799
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1800
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1801
        nic_model = self._VIRTIO
1802
        try:
1803
          if self._VIRTIO_NET_RE.search(devlist):
1804
            nic_model = self._VIRTIO_NET_PCI
1805
            vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1806
        except errors.HypervisorError, _:
1807
          # Older versions of kvm don't support DEVICE_LIST, but they don't
1808
          # have new virtio syntax either.
1809
          pass
1810

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

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

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

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

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

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

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

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

    
1881
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1882
                                                     kvm_disks,
1883
                                                     kvmhelp,
1884
                                                     devlist)
1885
    kvm_cmd.extend(bdev_opts)
1886
    # CPU affinity requires kvm to start paused, so we set this flag if the
1887
    # instance is not already paused and if we are not going to accept a
1888
    # migrating instance. In the latter case, pausing is not needed.
1889
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1890
    if start_kvm_paused:
1891
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1892

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2001
    return result
2002

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

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

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

    
2020
    dev.pci = int(free)
2021

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2137
    return kvm_device.pci
2138

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

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

2145
    """
2146
    if dev_type == constants.HOTPLUG_TARGET_NIC:
2147
      # putting it back in the same pci slot
2148
      device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2149
      self.HotAddDevice(instance, dev_type, device, _, seq)
2150

    
2151
  def _PassTapFd(self, instance, fd, nic):
2152
    """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2153

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

    
2168
  @classmethod
2169
  def _ParseKVMVersion(cls, text):
2170
    """Parse the KVM version from the --help output.
2171

2172
    @type text: string
2173
    @param text: output of kvm --help
2174
    @return: (version, v_maj, v_min, v_rev)
2175
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2176

2177
    """
2178
    match = cls._VERSION_RE.search(text.splitlines()[0])
2179
    if not match:
2180
      raise errors.HypervisorError("Unable to get KVM version")
2181

    
2182
    v_all = match.group(0)
2183
    v_maj = int(match.group(1))
2184
    v_min = int(match.group(2))
2185
    if match.group(4):
2186
      v_rev = int(match.group(4))
2187
    else:
2188
      v_rev = 0
2189
    return (v_all, v_maj, v_min, v_rev)
2190

    
2191
  @classmethod
2192
  def _GetKVMOutput(cls, kvm_path, option):
2193
    """Return the output of a kvm invocation
2194

2195
    @type kvm_path: string
2196
    @param kvm_path: path to the kvm executable
2197
    @type option: a key of _KVMOPTS_CMDS
2198
    @param option: kvm option to fetch the output from
2199
    @return: output a supported kvm invocation
2200
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2201

2202
    """
2203
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2204

    
2205
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
2206

    
2207
    result = utils.RunCmd([kvm_path] + optlist)
2208
    if result.failed and not can_fail:
2209
      raise errors.HypervisorError("Unable to get KVM %s output" %
2210
                                    " ".join(optlist))
2211
    return result.output
2212

    
2213
  @classmethod
2214
  def _GetKVMVersion(cls, kvm_path):
2215
    """Return the installed KVM version.
2216

2217
    @return: (version, v_maj, v_min, v_rev)
2218
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2219

2220
    """
2221
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2222

    
2223
  @classmethod
2224
  def _GetDefaultMachineVersion(cls, kvm_path):
2225
    """Return the default hardware revision (e.g. pc-1.1)
2226

2227
    """
2228
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2229
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2230
    if match:
2231
      return match.group(1)
2232
    else:
2233
      return "pc"
2234

    
2235
  def StopInstance(self, instance, force=False, retry=False, name=None):
2236
    """Stop an instance.
2237

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

    
2253
  def CleanupInstance(self, instance_name):
2254
    """Cleanup after a stopped instance
2255

2256
    """
2257
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
2258
    if pid > 0 and alive:
2259
      raise errors.HypervisorError("Cannot cleanup a live instance")
2260
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2261

    
2262
  def RebootInstance(self, instance):
2263
    """Reboot an instance.
2264

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

    
2285
  def MigrationInfo(self, instance):
2286
    """Get instance information to perform a migration.
2287

2288
    @type instance: L{objects.Instance}
2289
    @param instance: instance to be migrated
2290
    @rtype: string
2291
    @return: content of the KVM runtime file
2292

2293
    """
2294
    return self._ReadKVMRuntime(instance.name)
2295

    
2296
  def AcceptInstance(self, instance, info, target):
2297
    """Prepare to accept an instance.
2298

2299
    @type instance: L{objects.Instance}
2300
    @param instance: instance to be accepted
2301
    @type info: string
2302
    @param info: content of the KVM runtime file on the source node
2303
    @type target: string
2304
    @param target: target host (usually ip), on this node
2305

2306
    """
2307
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2308
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2309
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2310
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2311
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2312
                            incoming=incoming_address)
2313

    
2314
  def FinalizeMigrationDst(self, instance, info, success):
2315
    """Finalize the instance migration on the target node.
2316

2317
    Stop the incoming mode KVM.
2318

2319
    @type instance: L{objects.Instance}
2320
    @param instance: instance whose migration is being finalized
2321

2322
    """
2323
    if success:
2324
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2325
      kvm_nics = kvm_runtime[1]
2326

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

    
2342
      self._WriteKVMRuntime(instance.name, info)
2343
    else:
2344
      self.StopInstance(instance, force=True)
2345

    
2346
  def MigrateInstance(self, cluster_name, instance, target, live):
2347
    """Migrate an instance to a target node.
2348

2349
    The migration will not be attempted if the instance is not
2350
    currently running.
2351

2352
    @type cluster_name: string
2353
    @param cluster_name: name of the cluster
2354
    @type instance: L{objects.Instance}
2355
    @param instance: the instance to be migrated
2356
    @type target: string
2357
    @param target: ip address of the target node
2358
    @type live: boolean
2359
    @param live: perform a live migration
2360

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

    
2368
    if not live:
2369
      self._CallMonitorCommand(instance_name, "stop")
2370

    
2371
    migrate_command = ("migrate_set_speed %dm" %
2372
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2373
    self._CallMonitorCommand(instance_name, migrate_command)
2374

    
2375
    migrate_command = ("migrate_set_downtime %dms" %
2376
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2377
    self._CallMonitorCommand(instance_name, migrate_command)
2378

    
2379
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2380
    self._CallMonitorCommand(instance_name, migrate_command)
2381

    
2382
  def FinalizeMigrationSource(self, instance, success, live):
2383
    """Finalize the instance migration on the source node.
2384

2385
    @type instance: L{objects.Instance}
2386
    @param instance: the instance that was migrated
2387
    @type success: bool
2388
    @param success: whether the migration succeeded or not
2389
    @type live: bool
2390
    @param live: whether the user requested a live migration or not
2391

2392
    """
2393
    if success:
2394
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2395
      utils.KillProcess(pid)
2396
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2397
    elif live:
2398
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2399

    
2400
  def GetMigrationStatus(self, instance):
2401
    """Get the migration status
2402

2403
    @type instance: L{objects.Instance}
2404
    @param instance: the instance that is being migrated
2405
    @rtype: L{objects.MigrationStatus}
2406
    @return: the status of the current migration (one of
2407
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2408
             progress info that can be retrieved from the hypervisor
2409

2410
    """
2411
    info_command = "info migrate"
2412
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2413
      result = self._CallMonitorCommand(instance.name, info_command)
2414
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
2415
      if not match:
2416
        if not result.stdout:
2417
          logging.info("KVM: empty 'info migrate' result")
2418
        else:
2419
          logging.warning("KVM: unknown 'info migrate' result: %s",
2420
                          result.stdout)
2421
      else:
2422
        status = match.group(1)
2423
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2424
          migration_status = objects.MigrationStatus(status=status)
2425
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2426
          if match:
2427
            migration_status.transferred_ram = match.group("transferred")
2428
            migration_status.total_ram = match.group("total")
2429

    
2430
          return migration_status
2431

    
2432
        logging.warning("KVM: unknown migration status '%s'", status)
2433

    
2434
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2435

    
2436
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2437

    
2438
  def BalloonInstanceMemory(self, instance, mem):
2439
    """Balloon an instance memory to a certain value.
2440

2441
    @type instance: L{objects.Instance}
2442
    @param instance: instance to be accepted
2443
    @type mem: int
2444
    @param mem: actual memory size to use for instance runtime
2445

2446
    """
2447
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2448

    
2449
  def GetNodeInfo(self, hvparams=None):
2450
    """Return information about the node.
2451

2452
    @type hvparams: dict of strings
2453
    @param hvparams: hypervisor parameters, not used in this class
2454

2455
    @return: a dict as returned by L{BaseHypervisor.GetLinuxNodeInfo} plus
2456
        the following keys:
2457
          - hv_version: the hypervisor version in the form (major, minor,
2458
                        revision)
2459

2460
    """
2461
    result = self.GetLinuxNodeInfo()
2462
    kvmpath = constants.KVM_PATH
2463
    if hvparams is not None:
2464
      kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2465
    _, v_major, v_min, v_rev = self._GetKVMVersion(kvmpath)
2466
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2467
    return result
2468

    
2469
  @classmethod
2470
  def GetInstanceConsole(cls, instance, primary_node, hvparams, beparams):
2471
    """Return a command for connecting to the console of an instance.
2472

2473
    """
2474
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2475
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2476
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2477
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2478
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2479
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2480
      return objects.InstanceConsole(instance=instance.name,
2481
                                     kind=constants.CONS_SSH,
2482
                                     host=primary_node.name,
2483
                                     user=constants.SSH_CONSOLE_USER,
2484
                                     command=cmd)
2485

    
2486
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2487
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2488
      display = instance.network_port - constants.VNC_BASE_PORT
2489
      return objects.InstanceConsole(instance=instance.name,
2490
                                     kind=constants.CONS_VNC,
2491
                                     host=vnc_bind_address,
2492
                                     port=instance.network_port,
2493
                                     display=display)
2494

    
2495
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2496
    if spice_bind:
2497
      return objects.InstanceConsole(instance=instance.name,
2498
                                     kind=constants.CONS_SPICE,
2499
                                     host=spice_bind,
2500
                                     port=instance.network_port)
2501

    
2502
    return objects.InstanceConsole(instance=instance.name,
2503
                                   kind=constants.CONS_MESSAGE,
2504
                                   message=("No serial shell for instance %s" %
2505
                                            instance.name))
2506

    
2507
  def Verify(self, hvparams=None):
2508
    """Verify the hypervisor.
2509

2510
    Check that the required binaries exist.
2511

2512
    @type hvparams: dict of strings
2513
    @param hvparams: hypervisor parameters to be verified against, not used here
2514

2515
    @return: Problem description if something is wrong, C{None} otherwise
2516

2517
    """
2518
    msgs = []
2519
    kvmpath = constants.KVM_PATH
2520
    if hvparams is not None:
2521
      kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2522
    if not os.path.exists(kvmpath):
2523
      msgs.append("The KVM binary ('%s') does not exist" % kvmpath)
2524
    if not os.path.exists(constants.SOCAT_PATH):
2525
      msgs.append("The socat binary ('%s') does not exist" %
2526
                  constants.SOCAT_PATH)
2527

    
2528
    return self._FormatVerifyResults(msgs)
2529

    
2530
  @classmethod
2531
  def CheckParameterSyntax(cls, hvparams):
2532
    """Check the given parameters for validity.
2533

2534
    @type hvparams:  dict
2535
    @param hvparams: dictionary with parameter names/value
2536
    @raise errors.HypervisorError: when a parameter is not valid
2537

2538
    """
2539
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2540

    
2541
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2542
    if kernel_path:
2543
      if not hvparams[constants.HV_ROOT_PATH]:
2544
        raise errors.HypervisorError("Need a root partition for the instance,"
2545
                                     " if a kernel is defined")
2546

    
2547
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2548
        not hvparams[constants.HV_VNC_X509]):
2549
      raise errors.HypervisorError("%s must be defined, if %s is" %
2550
                                   (constants.HV_VNC_X509,
2551
                                    constants.HV_VNC_X509_VERIFY))
2552

    
2553
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2554
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2555
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2556
      if not serial_speed or serial_speed not in valid_speeds:
2557
        raise errors.HypervisorError("Invalid serial console speed, must be"
2558
                                     " one of: %s" %
2559
                                     utils.CommaJoin(valid_speeds))
2560

    
2561
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2562
    if (boot_order == constants.HT_BO_CDROM and
2563
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2564
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2565
                                   " ISO path")
2566

    
2567
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2568
    if security_model == constants.HT_SM_USER:
2569
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2570
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2571
                                     " must be specified")
2572
    elif (security_model == constants.HT_SM_NONE or
2573
          security_model == constants.HT_SM_POOL):
2574
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2575
        raise errors.HypervisorError("Cannot have a security domain when the"
2576
                                     " security model is 'none' or 'pool'")
2577

    
2578
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2579
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2580
    if spice_bind:
2581
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2582
        # if an IP version is specified, the spice_bind parameter must be an
2583
        # IP of that family
2584
        if (netutils.IP4Address.IsValid(spice_bind) and
2585
            spice_ip_version != constants.IP4_VERSION):
2586
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2587
                                       " the specified IP version is %s" %
2588
                                       (spice_bind, spice_ip_version))
2589

    
2590
        if (netutils.IP6Address.IsValid(spice_bind) and
2591
            spice_ip_version != constants.IP6_VERSION):
2592
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2593
                                       " the specified IP version is %s" %
2594
                                       (spice_bind, spice_ip_version))
2595
    else:
2596
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2597
      # error if any of them is set without it.
2598
      for param in _SPICE_ADDITIONAL_PARAMS:
2599
        if hvparams[param]:
2600
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2601
                                       (param, constants.HV_KVM_SPICE_BIND))
2602

    
2603
  @classmethod
2604
  def ValidateParameters(cls, hvparams):
2605
    """Check the given parameters for validity.
2606

2607
    @type hvparams:  dict
2608
    @param hvparams: dictionary with parameter names/value
2609
    @raise errors.HypervisorError: when a parameter is not valid
2610

2611
    """
2612
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2613

    
2614
    kvm_path = hvparams[constants.HV_KVM_PATH]
2615

    
2616
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2617
    if security_model == constants.HT_SM_USER:
2618
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2619
      try:
2620
        pwd.getpwnam(username)
2621
      except KeyError:
2622
        raise errors.HypervisorError("Unknown security domain user %s"
2623
                                     % username)
2624
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2625
    if vnc_bind_address:
2626
      bound_to_addr = netutils.IP4Address.IsValid(vnc_bind_address)
2627
      is_interface = netutils.IsValidInterface(vnc_bind_address)
2628
      is_path = utils.IsNormAbsPath(vnc_bind_address)
2629
      if not bound_to_addr and not is_interface and not is_path:
2630
        raise errors.HypervisorError("VNC: The %s parameter must be either"
2631
                                     " a valid IP address, an interface name,"
2632
                                     " or an absolute path" %
2633
                                     constants.HV_KVM_SPICE_BIND)
2634

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

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

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

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

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

2668
    @type hvparams: dict of strings
2669
    @param hvparams: hypervisor params to be used on this node
2670

2671
    """
2672
    cls.LinuxPowercycle()