Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 150e31ec

History | View | Annotate | Download (94.9 kB)

1
#
2
#
3

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

    
21

    
22
"""KVM hypervisor
23

24
"""
25

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

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

    
62

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

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

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

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

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

    
117

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

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

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

131
  """
132

    
133
  if not dev.pci:
134
    raise errors.HotplugError("Hotplug is not supported for %s with UUID %s" %
135
                              (dev_type, dev.uuid))
136

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

    
139

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

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

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

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

    
162
  pci_reservations[free] = True
163

    
164

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

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

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

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

    
188
  return found[0]
189

    
190

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

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

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

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

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

    
216
  return kvm_cmd, serialized_nics, hvparams, serialized_disks
217

    
218

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

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

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

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

    
236

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

240
  @see: L{_ProbeTapVnetHdr}
241

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

    
253

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

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

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

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

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

    
277
  result = bool(flags & IFF_VNET_HDR)
278

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

    
282
  return result
283

    
284

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

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

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

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

    
302
  flags = IFF_TAP | IFF_NO_PI
303

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

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

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

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

    
320

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

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

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

    
332
    self.data = data
333

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

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

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

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

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

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

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

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

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

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

    
374

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

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

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

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

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

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

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

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

417
    Connects to the UNIX socket
418

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

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

    
425
    self._check_socket()
426

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

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

437
    It cannot be used after this call.
438

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

    
442

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

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

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

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

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

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

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

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

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

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

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

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

    
509
    return (message, buf)
510

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

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

519
    """
520
    self._check_connection()
521

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

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

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

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

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

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

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

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

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

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

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

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

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

    
606

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

610
  """
611
  CAN_MIGRATE = True
612

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

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

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

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

    
727
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
728
  _MIGRATION_INFO_RETRY_DELAY = 2
729

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

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

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

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

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

    
761
  _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
762

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
847
    return (instance, memory, vcpus)
848

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

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

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

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

    
868
    return (pidfile, pid, alive)
869

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1132
    return result
1133

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1292
    return dev_opts
1293

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

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

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

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

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

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

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

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

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

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

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

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

    
1378
    disk_type = hvp[constants.HV_DISK_TYPE]
1379

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1532
        spice_address = addresses[spice_ip_version][0]
1533

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1641
    hvparams = hvp
1642

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

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

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

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

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

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

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

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

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

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

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

    
1686
    return _AnalyzeSerializedRuntime(serialized_runtime)
1687

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

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

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

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

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

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

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

    
1734
    temp_files = []
1735

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

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

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

    
1757
    # We have reasons to believe changing something like the nic driver/type
1758
    # upon migration won't exactly fly with the instance kernel, so for nic
1759
    # related parameters we'll use up_hvp
1760
    tapfds = []
1761
    taps = []
1762
    devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1763

    
1764
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1765
                                                     kvm_disks,
1766
                                                     kvmhelp,
1767
                                                     devlist)
1768
    kvm_cmd.extend(bdev_opts)
1769

    
1770
    if not kvm_nics:
1771
      kvm_cmd.extend(["-net", "none"])
1772
    else:
1773
      vnet_hdr = False
1774
      tap_extra = ""
1775
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1776
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1777
        nic_model = self._VIRTIO
1778
        try:
1779
          if self._VIRTIO_NET_RE.search(devlist):
1780
            nic_model = self._VIRTIO_NET_PCI
1781
            vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1782
        except errors.HypervisorError, _:
1783
          # Older versions of kvm don't support DEVICE_LIST, but they don't
1784
          # have new virtio syntax either.
1785
          pass
1786

    
1787
        if up_hvp[constants.HV_VHOST_NET]:
1788
          # check for vhost_net support
1789
          if self._VHOST_RE.search(kvmhelp):
1790
            tap_extra = ",vhost=on"
1791
          else:
1792
            raise errors.HypervisorError("vhost_net is configured"
1793
                                         " but it is not available")
1794
      else:
1795
        nic_model = nic_type
1796

    
1797
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1798

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

    
1823
    if incoming:
1824
      target, port = incoming
1825
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1826

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

    
1839
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1840
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1841
                         constants.SECURE_DIR_MODE)])
1842

    
1843
    # Automatically enable QMP if version is >= 0.14
1844
    if self._QMP_RE.search(kvmhelp):
1845
      logging.debug("Enabling QMP")
1846
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1847
                      self._InstanceQmpMonitor(instance.name)])
1848

    
1849
    # Configure the network now for starting instances and bridged interfaces,
1850
    # during FinalizeMigration for incoming instances' routed interfaces
1851
    for nic_seq, nic in enumerate(kvm_nics):
1852
      if (incoming and
1853
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1854
        continue
1855
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1856

    
1857
    # CPU affinity requires kvm to start paused, so we set this flag if the
1858
    # instance is not already paused and if we are not going to accept a
1859
    # migrating instance. In the latter case, pausing is not needed.
1860
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1861
    if start_kvm_paused:
1862
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1863

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

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

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

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

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

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

    
1921
    for filename in temp_files:
1922
      utils.RemoveFile(filename)
1923

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

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

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

    
1938
  def StartInstance(self, instance, block_devices, startup_paused):
1939
    """Start an instance.
1940

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

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

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

    
1972
    return result
1973

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

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

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

    
1991
    dev.pci = int(free)
1992

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

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

2000
    @raise errors.HypervisorError: in one of the previous cases
2001

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

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

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

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

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

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

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

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

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

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

2052
    It gets free pci slot generates the device name and invokes the
2053
    device specific method.
2054

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

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

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

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

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

    
2106
    return kvm_device.pci
2107

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

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

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

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

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

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

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

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

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

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

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

2173
    """
2174
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2175

    
2176
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
2177

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

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

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

2191
    """
2192
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2193

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

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

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

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

    
2224
  def CleanupInstance(self, instance_name):
2225
    """Cleanup after a stopped instance
2226

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

    
2233
  def RebootInstance(self, instance):
2234
    """Reboot an instance.
2235

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

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

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

2264
    """
2265
    return self._ReadKVMRuntime(instance.name)
2266

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

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

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

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

2288
    Stop the incoming mode KVM.
2289

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

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

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

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

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

2320
    The migration will not be attempted if the instance is not
2321
    currently running.
2322

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

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

    
2337
    if not live:
2338
      self._CallMonitorCommand(instance_name, "stop")
2339

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

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

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

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

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

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

    
2369
  def GetMigrationStatus(self, instance):
2370
    """Get the migration status
2371

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

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

    
2399
          return migration_status
2400

    
2401
        logging.warning("KVM: unknown migration status '%s'", status)
2402

    
2403
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2404

    
2405
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2406

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

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

2415
    """
2416
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2417

    
2418
  def GetNodeInfo(self):
2419
    """Return information about the node.
2420

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

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

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

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

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

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

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

    
2475
  def Verify(self):
2476
    """Verify the hypervisor.
2477

2478
    Check that the required binaries exist.
2479

2480
    @return: Problem description if something is wrong, C{None} otherwise
2481

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

    
2493
    return self._FormatVerifyResults(msgs)
2494

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

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

2503
    """
2504
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2505

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

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

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

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

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

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

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

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

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

2576
    """
2577
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2578

    
2579
    kvm_path = hvparams[constants.HV_KVM_PATH]
2580

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

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

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

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

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

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

2623
    """
2624
    cls.LinuxPowercycle()