Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 84ba0048

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 _CallHotplugCommands(self, name, cmds):
2070
    for c in cmds:
2071
      output = self._CallMonitorCommand(name, c)
2072
      # TODO: parse output and check if succeeded
2073
      for line in output.stdout.splitlines():
2074
        logging.info("%s", line)
2075
      time.sleep(1)
2076

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

2080
    It gets free pci slot generates the device name and invokes the
2081
    device specific method.
2082

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

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

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

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

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

    
2134
    return kvm_device.pci
2135

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2315
    Stop the incoming mode KVM.
2316

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2437
          return migration_status
2438

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

    
2441
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2442

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

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

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

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

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

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

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

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

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

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

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

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

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

2516
    Check that the required binaries exist.
2517

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

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

    
2531
    return self._FormatVerifyResults(msgs)
2532

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2617
    kvm_path = hvparams[constants.HV_KVM_PATH]
2618

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

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

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

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

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

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

2661
    """
2662
    cls.LinuxPowercycle()