Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 691d8725

History | View | Annotate | Download (96.4 kB)

1
#
2
#
3

    
4
# Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

    
21

    
22
"""KVM hypervisor
23

24
"""
25

    
26
import errno
27
import os
28
import os.path
29
import re
30
import tempfile
31
import time
32
import logging
33
import pwd
34
import struct
35
import fcntl
36
import shutil
37
import socket
38
import stat
39
import StringIO
40
from bitarray import bitarray
41
try:
42
  import affinity   # pylint: disable=F0401
43
except ImportError:
44
  affinity = None
45
try:
46
  import fdsend   # pylint: disable=F0401
47
except ImportError:
48
  fdsend = None
49

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

    
62

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

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

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

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

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

    
117

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

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

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

131
  """
132

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

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

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

    
145

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

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

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

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

    
168
  pci_reservations[free] = True
169

    
170

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

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

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

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

    
194
  return found[0]
195

    
196

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

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

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

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

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

    
222
  return kvm_cmd, serialized_nics, hvparams, serialized_disks
223

    
224

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

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

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

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

    
242

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

246
  @see: L{_ProbeTapVnetHdr}
247

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

    
259

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

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

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

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

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

    
283
  result = bool(flags & IFF_VNET_HDR)
284

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

    
288
  return result
289

    
290

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

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

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

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

    
308
  flags = IFF_TAP | IFF_NO_PI
309

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

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

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

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

    
326

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

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

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

    
338
    self.data = data
339

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

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

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

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

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

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

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

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

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

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

    
380

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

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

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

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

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

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

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

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

423
    Connects to the UNIX socket
424

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

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

    
431
    self._check_socket()
432

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

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

443
    It cannot be used after this call.
444

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

    
448

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

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

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

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

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

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

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

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

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

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

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

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

    
514
    return (message, buf)
515

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

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

524
    """
525
    self._check_connection()
526

    
527
    # Check if there is already a message in the buffer
528
    (message, self._buf) = self._ParseMessage(self._buf)
529
    if message:
530
      return message
531

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

    
541
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
542
        if message:
543
          return message
544

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

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

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

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

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

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

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

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

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

    
607
      elif not response[self._EVENT_KEY]:
608
        return response
609

    
610

    
611
class KVMHypervisor(hv_base.BaseHypervisor):
612
  """KVM hypervisor interface
613

614
  """
615
  CAN_MIGRATE = True
616

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

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

    
720
  _VIRTIO = "virtio"
721
  _VIRTIO_NET_PCI = "virtio-net-pci"
722
  _VIRTIO_BLK_PCI = "virtio-blk-pci"
723

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

    
731
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
732
  _MIGRATION_INFO_RETRY_DELAY = 2
733

    
734
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
735

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

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

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

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

    
765
  _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
766

    
767
  ANCILLARY_FILES = [
768
    _KVM_NETWORK_SCRIPT,
769
    ]
770
  ANCILLARY_FILES_OPT = [
771
    _KVM_NETWORK_SCRIPT,
772
    ]
773

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

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

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

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

798
    """
799
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
800

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

805
    """
806
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
807

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

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

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

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

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

    
833
    instance = None
834
    memory = 0
835
    vcpus = 0
836

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

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

    
851
    return (instance, memory, vcpus)
852

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

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

861
    """
862
    pidfile = self._InstancePidFile(instance_name)
863
    pid = utils.ReadPidFile(pidfile)
864

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

    
872
    return (pidfile, pid, alive)
873

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

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

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

887
    """
888
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
889

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

894
    """
895
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
896

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

901
    """
902
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
903

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

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

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

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

920
    """
921
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
922

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

927
    """
928
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
929

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

935
    """
936
    return utils.PathJoin(cls._NICS_DIR, instance_name)
937

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

942
    """
943
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
944

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

949
    """
950
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
951

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

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

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

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

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

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

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

    
1032
    if nic.ip:
1033
      env["IP"] = nic.ip
1034

    
1035
    if nic.name:
1036
      env["INTERFACE_NAME"] = nic.name
1037

    
1038
    if nic.nicparams[constants.NIC_LINK]:
1039
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
1040

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1136
    return result
1137

    
1138
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1139
    """Complete CPU pinning.
1140

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

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

    
1154
  def ListInstances(self):
1155
    """Get the list of running instances.
1156

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

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

    
1167
  def GetInstanceInfo(self, instance_name):
1168
    """Get instance properties.
1169

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

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

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

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

    
1195
    return (instance_name, pid, memory, vcpus, istat, times)
1196

    
1197
  def GetAllInstancesInfo(self):
1198
    """Get properties of all instances.
1199

1200
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1201

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

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

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

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

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

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

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

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

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

    
1316
      dev_opts.extend(["-drive", drive_val])
1317

    
1318
    return dev_opts
1319

    
1320
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1321
                          kvmhelp):
1322
    """Generate KVM information to start an instance.
1323

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

1333
    """
1334
    # pylint: disable=R0912,R0914,R0915
1335
    hvp = instance.hvparams
1336
    self.ValidateParameters(hvp)
1337

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

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

    
1353
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1354

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

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

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

    
1394
    if startup_paused:
1395
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1396

    
1397
    if boot_network:
1398
      kvm_cmd.extend(["-boot", "n"])
1399

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

    
1404
    disk_type = hvp[constants.HV_DISK_TYPE]
1405

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

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

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

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

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

    
1465
    mem_path = hvp[constants.HV_MEM_PATH]
1466
    if mem_path:
1467
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1468

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

    
1479
    mouse_type = hvp[constants.HV_USB_MOUSE]
1480
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1481
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1482
    spice_ip_version = None
1483

    
1484
    kvm_cmd.extend(["-usb"])
1485

    
1486
    if mouse_type:
1487
      kvm_cmd.extend(["-usbdevice", mouse_type])
1488
    elif vnc_bind_address:
1489
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1490

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

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

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

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

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

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

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

    
1558
        spice_address = addresses[spice_ip_version][0]
1559

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1653
    if hvp[constants.HV_KVM_EXTRA]:
1654
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1655

    
1656
    pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1657
    kvm_disks = []
1658
    for disk, link_name in block_devices:
1659
      _UpdatePCISlots(disk, pci_reservations)
1660
      kvm_disks.append((disk, link_name))
1661

    
1662
    kvm_nics = []
1663
    for nic in instance.nics:
1664
      _UpdatePCISlots(nic, pci_reservations)
1665
      kvm_nics.append(nic)
1666

    
1667
    hvparams = hvp
1668

    
1669
    return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1670

    
1671
  def _WriteKVMRuntime(self, instance_name, data):
1672
    """Write an instance's KVM runtime
1673

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

    
1681
  def _ReadKVMRuntime(self, instance_name):
1682
    """Read an instance's KVM runtime
1683

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

    
1691
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1692
    """Save an instance's KVM runtime
1693

1694
    """
1695
    kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1696

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

    
1703
    self._WriteKVMRuntime(instance.name, serialized_form)
1704

    
1705
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1706
    """Load an instance's KVM runtime
1707

1708
    """
1709
    if not serialized_runtime:
1710
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1711

    
1712
    return _AnalyzeSerializedRuntime(serialized_runtime)
1713

    
1714
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1715
    """Run the KVM cmd and check for errors
1716

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

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

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

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

1742
    @type incoming: tuple of strings
1743
    @param incoming: (target_host_ip, port)
1744
    @type kvmhelp: string
1745
    @param kvmhelp: output of kvm --help
1746

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

    
1760
    temp_files = []
1761

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

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

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

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

    
1790
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1791
                                                     kvm_disks,
1792
                                                     kvmhelp,
1793
                                                     devlist)
1794
    kvm_cmd.extend(bdev_opts)
1795

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

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

    
1823
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1824

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

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

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

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

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

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

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

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

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

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

    
1921
    if vnc_pwd:
1922
      change_cmd = "change vnc password %s" % vnc_pwd
1923
      self._CallMonitorCommand(instance.name, change_cmd)
1924

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

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

    
1947
    for filename in temp_files:
1948
      utils.RemoveFile(filename)
1949

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

    
1954
    start_memory = self._InstanceStartupMemory(instance)
1955
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1956
      self.BalloonInstanceMemory(instance, start_memory)
1957

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

    
1964
  def StartInstance(self, instance, block_devices, startup_paused):
1965
    """Start an instance.
1966

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

    
1976
  def _CallMonitorCommand(self, instance_name, command):
1977
    """Invoke a command on the instance monitor.
1978

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

    
1998
    return result
1999

    
2000
  def _GetFreePCISlot(self, instance, dev):
2001
    """Get the first available pci slot of a runnung instance.
2002

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

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

    
2017
    dev.pci = int(free)
2018

    
2019
  def VerifyHotplugSupport(self, instance, action, dev_type):
2020
    """Verifies that hotplug is supported.
2021

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

2026
    @raise errors.HypervisorError: in one of the previous cases
2027

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

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

    
2045
  def HotplugSupported(self, instance):
2046
    """Checks if hotplug is generally supported.
2047

2048
    Hotplug is *not* supported in case of:
2049
     - qemu versions < 1.0
2050
     - for stopped instances
2051

2052
    @raise errors.HypervisorError: in one of the previous cases
2053

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

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

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

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

    
2075
  def HotAddDevice(self, instance, dev_type, device, extra, seq):
2076
    """ Helper method to hot-add a new device
2077

2078
    It gets free pci slot generates the device name and invokes the
2079
    device specific method.
2080

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

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

    
2109
  def HotDelDevice(self, instance, dev_type, device, _, seq):
2110
    """ Helper method for hot-del device
2111

2112
    It gets device info from runtime file, generates the device name and
2113
    invokes the device specific method.
2114

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

    
2132
    return kvm_device.pci
2133

    
2134
  def HotModDevice(self, instance, dev_type, device, _, seq):
2135
    """ Helper method for hot-mod device
2136

2137
    It gets device info from runtime file, generates the device name and
2138
    invokes the device specific method. Currently only NICs support hot-mod
2139

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

    
2148
  def _PassTapFd(self, instance, fd, nic):
2149
    """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2150

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

    
2165
  @classmethod
2166
  def _ParseKVMVersion(cls, text):
2167
    """Parse the KVM version from the --help output.
2168

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

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

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

    
2188
  @classmethod
2189
  def _GetKVMOutput(cls, kvm_path, option):
2190
    """Return the output of a kvm invocation
2191

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

2199
    """
2200
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2201

    
2202
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
2203

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

    
2210
  @classmethod
2211
  def _GetKVMVersion(cls, kvm_path):
2212
    """Return the installed KVM version.
2213

2214
    @return: (version, v_maj, v_min, v_rev)
2215
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2216

2217
    """
2218
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2219

    
2220
  @classmethod
2221
  def _GetDefaultMachineVersion(cls, kvm_path):
2222
    """Return the default hardware revision (e.g. pc-1.1)
2223

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

    
2232
  def StopInstance(self, instance, force=False, retry=False, name=None):
2233
    """Stop an instance.
2234

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

    
2250
  def CleanupInstance(self, instance_name):
2251
    """Cleanup after a stopped instance
2252

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

    
2259
  def RebootInstance(self, instance):
2260
    """Reboot an instance.
2261

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

    
2282
  def MigrationInfo(self, instance):
2283
    """Get instance information to perform a migration.
2284

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

2290
    """
2291
    return self._ReadKVMRuntime(instance.name)
2292

    
2293
  def AcceptInstance(self, instance, info, target):
2294
    """Prepare to accept an instance.
2295

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

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

    
2311
  def FinalizeMigrationDst(self, instance, info, success):
2312
    """Finalize the instance migration on the target node.
2313

2314
    Stop the incoming mode KVM.
2315

2316
    @type instance: L{objects.Instance}
2317
    @param instance: instance whose migration is being finalized
2318

2319
    """
2320
    if success:
2321
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2322
      kvm_nics = kvm_runtime[1]
2323

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

    
2339
      self._WriteKVMRuntime(instance.name, info)
2340
    else:
2341
      self.StopInstance(instance, force=True)
2342

    
2343
  def MigrateInstance(self, instance, target, live):
2344
    """Migrate an instance to a target node.
2345

2346
    The migration will not be attempted if the instance is not
2347
    currently running.
2348

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

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

    
2363
    if not live:
2364
      self._CallMonitorCommand(instance_name, "stop")
2365

    
2366
    migrate_command = ("migrate_set_speed %dm" %
2367
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2368
    self._CallMonitorCommand(instance_name, migrate_command)
2369

    
2370
    migrate_command = ("migrate_set_downtime %dms" %
2371
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2372
    self._CallMonitorCommand(instance_name, migrate_command)
2373

    
2374
    # These commands are supported in latest qemu versions.
2375
    # Since _CallMonitorCommand does not catch monitor errors
2376
    # this does not raise an exception in case command is not supported
2377
    # TODO: either parse output of command or see if the command supported
2378
    # via info help (see hotplug)
2379
    migrate_command = ("migrate_set_capability xbzrle on")
2380
    self._CallMonitorCommand(instance_name, migrate_command)
2381

    
2382
    migrate_command = ("migrate_set_capability auto-converge on")
2383
    self._CallMonitorCommand(instance_name, migrate_command)
2384

    
2385
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2386
    self._CallMonitorCommand(instance_name, migrate_command)
2387

    
2388
  def FinalizeMigrationSource(self, instance, success, live):
2389
    """Finalize the instance migration on the source node.
2390

2391
    @type instance: L{objects.Instance}
2392
    @param instance: the instance that was migrated
2393
    @type success: bool
2394
    @param success: whether the migration succeeded or not
2395
    @type live: bool
2396
    @param live: whether the user requested a live migration or not
2397

2398
    """
2399
    if success:
2400
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2401
      utils.KillProcess(pid)
2402
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2403
    elif live:
2404
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2405

    
2406
  def GetMigrationStatus(self, instance):
2407
    """Get the migration status
2408

2409
    @type instance: L{objects.Instance}
2410
    @param instance: the instance that is being migrated
2411
    @rtype: L{objects.MigrationStatus}
2412
    @return: the status of the current migration (one of
2413
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2414
             progress info that can be retrieved from the hypervisor
2415

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

    
2436
          return migration_status
2437

    
2438
        logging.warning("KVM: unknown migration status '%s'", status)
2439

    
2440
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2441

    
2442
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2443

    
2444
  def BalloonInstanceMemory(self, instance, mem):
2445
    """Balloon an instance memory to a certain value.
2446

2447
    @type instance: L{objects.Instance}
2448
    @param instance: instance to be accepted
2449
    @type mem: int
2450
    @param mem: actual memory size to use for instance runtime
2451

2452
    """
2453
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2454

    
2455
  def GetNodeInfo(self):
2456
    """Return information about the node.
2457

2458
    @return: a dict with the following keys (values in MiB):
2459
          - memory_total: the total memory size on the node
2460
          - memory_free: the available memory on the node for instances
2461
          - memory_dom0: the memory used by the node itself, if available
2462
          - hv_version: the hypervisor version in the form (major, minor,
2463
                        revision)
2464

2465
    """
2466
    result = self.GetLinuxNodeInfo()
2467
    # FIXME: this is the global kvm version, but the actual version can be
2468
    # customized as an hv parameter. we should use the nodegroup's default kvm
2469
    # path parameter here.
2470
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2471
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2472
    return result
2473

    
2474
  @classmethod
2475
  def GetInstanceConsole(cls, instance, hvparams, beparams):
2476
    """Return a command for connecting to the console of an instance.
2477

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

    
2491
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2492
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2493
      display = instance.network_port - constants.VNC_BASE_PORT
2494
      return objects.InstanceConsole(instance=instance.name,
2495
                                     kind=constants.CONS_VNC,
2496
                                     host=vnc_bind_address,
2497
                                     port=instance.network_port,
2498
                                     display=display)
2499

    
2500
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2501
    if spice_bind:
2502
      return objects.InstanceConsole(instance=instance.name,
2503
                                     kind=constants.CONS_SPICE,
2504
                                     host=spice_bind,
2505
                                     port=instance.network_port)
2506

    
2507
    return objects.InstanceConsole(instance=instance.name,
2508
                                   kind=constants.CONS_MESSAGE,
2509
                                   message=("No serial shell for instance %s" %
2510
                                            instance.name))
2511

    
2512
  def Verify(self):
2513
    """Verify the hypervisor.
2514

2515
    Check that the required binaries exist.
2516

2517
    @return: Problem description if something is wrong, C{None} otherwise
2518

2519
    """
2520
    msgs = []
2521
    # FIXME: this is the global kvm binary, but the actual path can be
2522
    # customized as an hv parameter; we should use the nodegroup's
2523
    # default kvm path parameter here.
2524
    if not os.path.exists(constants.KVM_PATH):
2525
      msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2526
    if not os.path.exists(constants.SOCAT_PATH):
2527
      msgs.append("The socat binary ('%s') does not exist" %
2528
                  constants.SOCAT_PATH)
2529

    
2530
    return self._FormatVerifyResults(msgs)
2531

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

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

2540
    """
2541
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2542

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

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

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

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

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

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

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

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

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

2613
    """
2614
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2615

    
2616
    kvm_path = hvparams[constants.HV_KVM_PATH]
2617

    
2618
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2619
    if security_model == constants.HT_SM_USER:
2620
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2621
      try:
2622
        pwd.getpwnam(username)
2623
      except KeyError:
2624
        raise errors.HypervisorError("Unknown security domain user %s"
2625
                                     % username)
2626

    
2627
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2628
    if spice_bind:
2629
      # only one of VNC and SPICE can be used currently.
2630
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2631
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2632
                                     " only one of them can be used at a"
2633
                                     " given time")
2634

    
2635
      # check that KVM supports SPICE
2636
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2637
      if not cls._SPICE_RE.search(kvmhelp):
2638
        raise errors.HypervisorError("SPICE is configured, but it is not"
2639
                                     " supported according to 'kvm --help'")
2640

    
2641
      # if spice_bind is not an IP address, it must be a valid interface
2642
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2643
                       netutils.IP6Address.IsValid(spice_bind))
2644
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2645
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2646
                                     " a valid IP address or interface name" %
2647
                                     constants.HV_KVM_SPICE_BIND)
2648

    
2649
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2650
    if machine_version:
2651
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2652
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2653
        raise errors.HypervisorError("Unsupported machine version: %s" %
2654
                                     machine_version)
2655

    
2656
  @classmethod
2657
  def PowercycleNode(cls):
2658
    """KVM powercycle, just a wrapper over Linux powercycle.
2659

2660
    """
2661
    cls.LinuxPowercycle()