Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 75b21ca0

History | View | Annotate | Download (94.3 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 _AnalyzeSerializedRuntime(serialized_runtime):
192
  """Return runtime entries for a serialized runtime file
193

194
  @type serialized_runtime: string
195
  @param serialized_runtime: raw text data read from actual runtime file
196
  @return: (cmd, nics, hvparams, bdevs)
197
  @rtype: list
198

199
  """
200
  loaded_runtime = serializer.Load(serialized_runtime)
201
  if len(loaded_runtime) == 3:
202
    serialized_disks = []
203
    kvm_cmd, serialized_nics, hvparams = loaded_runtime
204
  else:
205
    kvm_cmd, serialized_nics, hvparams, serialized_disks = loaded_runtime
206

    
207
  kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
208
  kvm_disks = [(objects.Disk.FromDict(sdisk), link)
209
               for sdisk, link in serialized_disks]
210

    
211
  return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
212

    
213

    
214
def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
215
  """Retrieves supported TUN features from file descriptor.
216

217
  @see: L{_ProbeTapVnetHdr}
218

219
  """
220
  req = struct.pack("I", 0)
221
  try:
222
    buf = _ioctl(fd, TUNGETFEATURES, req)
223
  except EnvironmentError, err:
224
    logging.warning("ioctl(TUNGETFEATURES) failed: %s", err)
225
    return None
226
  else:
227
    (flags, ) = struct.unpack("I", buf)
228
    return flags
229

    
230

    
231
def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
232
  """Check whether to enable the IFF_VNET_HDR flag.
233

234
  To do this, _all_ of the following conditions must be met:
235
   1. TUNGETFEATURES ioctl() *must* be implemented
236
   2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
237
   3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
238
      drivers/net/tun.c there is no way to test this until after the tap device
239
      has been created using TUNSETIFF, and there is no way to change the
240
      IFF_VNET_HDR flag after creating the interface, catch-22! However both
241
      TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
242
      thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
243

244
   @type fd: int
245
   @param fd: the file descriptor of /dev/net/tun
246

247
  """
248
  flags = _features_fn(fd)
249

    
250
  if flags is None:
251
    # Not supported
252
    return False
253

    
254
  result = bool(flags & IFF_VNET_HDR)
255

    
256
  if not result:
257
    logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
258

    
259
  return result
260

    
261

    
262
def _OpenTap(vnet_hdr=True):
263
  """Open a new tap device and return its file descriptor.
264

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

268
  @type vnet_hdr: boolean
269
  @param vnet_hdr: Enable the VNET Header
270
  @return: (ifname, tapfd)
271
  @rtype: tuple
272

273
  """
274
  try:
275
    tapfd = os.open("/dev/net/tun", os.O_RDWR)
276
  except EnvironmentError:
277
    raise errors.HypervisorError("Failed to open /dev/net/tun")
278

    
279
  flags = IFF_TAP | IFF_NO_PI
280

    
281
  if vnet_hdr and _ProbeTapVnetHdr(tapfd):
282
    flags |= IFF_VNET_HDR
283

    
284
  # The struct ifreq ioctl request (see netdevice(7))
285
  ifr = struct.pack("16sh", "", flags)
286

    
287
  try:
288
    res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
289
  except EnvironmentError, err:
290
    raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
291
                                 err)
292

    
293
  # Get the interface name from the ioctl
294
  ifname = struct.unpack("16sh", res)[0].strip("\x00")
295
  return (ifname, tapfd)
296

    
297

    
298
class QmpMessage:
299
  """QEMU Messaging Protocol (QMP) message.
300

301
  """
302
  def __init__(self, data):
303
    """Creates a new QMP message based on the passed data.
304

305
    """
306
    if not isinstance(data, dict):
307
      raise TypeError("QmpMessage must be initialized with a dict")
308

    
309
    self.data = data
310

    
311
  def __getitem__(self, field_name):
312
    """Get the value of the required field if present, or None.
313

314
    Overrides the [] operator to provide access to the message data,
315
    returning None if the required item is not in the message
316
    @return: the value of the field_name field, or None if field_name
317
             is not contained in the message
318

319
    """
320
    return self.data.get(field_name, None)
321

    
322
  def __setitem__(self, field_name, field_value):
323
    """Set the value of the required field_name to field_value.
324

325
    """
326
    self.data[field_name] = field_value
327

    
328
  @staticmethod
329
  def BuildFromJsonString(json_string):
330
    """Build a QmpMessage from a JSON encoded string.
331

332
    @type json_string: str
333
    @param json_string: JSON string representing the message
334
    @rtype: L{QmpMessage}
335
    @return: a L{QmpMessage} built from json_string
336

337
    """
338
    # Parse the string
339
    data = serializer.LoadJson(json_string)
340
    return QmpMessage(data)
341

    
342
  def __str__(self):
343
    # The protocol expects the JSON object to be sent as a single line.
344
    return serializer.DumpJson(self.data)
345

    
346
  def __eq__(self, other):
347
    # When comparing two QmpMessages, we are interested in comparing
348
    # their internal representation of the message data
349
    return self.data == other.data
350

    
351

    
352
class MonitorSocket(object):
353
  _SOCKET_TIMEOUT = 5
354

    
355
  def __init__(self, monitor_filename):
356
    """Instantiates the MonitorSocket object.
357

358
    @type monitor_filename: string
359
    @param monitor_filename: the filename of the UNIX raw socket on which the
360
                             monitor (QMP or simple one) is listening
361

362
    """
363
    self.monitor_filename = monitor_filename
364
    self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
365
    # We want to fail if the server doesn't send a complete message
366
    # in a reasonable amount of time
367
    self.sock.settimeout(self._SOCKET_TIMEOUT)
368
    self._connected = False
369

    
370
  def _check_socket(self):
371
    sock_stat = None
372
    try:
373
      sock_stat = os.stat(self.monitor_filename)
374
    except EnvironmentError, err:
375
      if err.errno == errno.ENOENT:
376
        raise errors.HypervisorError("No monitor socket found")
377
      else:
378
        raise errors.HypervisorError("Error checking monitor socket: %s",
379
                                     utils.ErrnoOrStr(err))
380
    if not stat.S_ISSOCK(sock_stat.st_mode):
381
      raise errors.HypervisorError("Monitor socket is not a socket")
382

    
383
  def _check_connection(self):
384
    """Make sure that the connection is established.
385

386
    """
387
    if not self._connected:
388
      raise errors.ProgrammerError("To use a MonitorSocket you need to first"
389
                                   " invoke connect() on it")
390

    
391
  def connect(self):
392
    """Connects to the monitor.
393

394
    Connects to the UNIX socket
395

396
    @raise errors.HypervisorError: when there are communication errors
397

398
    """
399
    if self._connected:
400
      raise errors.ProgrammerError("Cannot connect twice")
401

    
402
    self._check_socket()
403

    
404
    # Check file existance/stuff
405
    try:
406
      self.sock.connect(self.monitor_filename)
407
    except EnvironmentError:
408
      raise errors.HypervisorError("Can't connect to qmp socket")
409
    self._connected = True
410

    
411
  def close(self):
412
    """Closes the socket
413

414
    It cannot be used after this call.
415

416
    """
417
    self.sock.close()
418

    
419

    
420
class QmpConnection(MonitorSocket):
421
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
422

423
  """
424
  _FIRST_MESSAGE_KEY = "QMP"
425
  _EVENT_KEY = "event"
426
  _ERROR_KEY = "error"
427
  _RETURN_KEY = RETURN_KEY = "return"
428
  _ACTUAL_KEY = ACTUAL_KEY = "actual"
429
  _ERROR_CLASS_KEY = "class"
430
  _ERROR_DATA_KEY = "data"
431
  _ERROR_DESC_KEY = "desc"
432
  _EXECUTE_KEY = "execute"
433
  _ARGUMENTS_KEY = "arguments"
434
  _CAPABILITIES_COMMAND = "qmp_capabilities"
435
  _MESSAGE_END_TOKEN = "\r\n"
436

    
437
  def __init__(self, monitor_filename):
438
    super(QmpConnection, self).__init__(monitor_filename)
439
    self._buf = ""
440

    
441
  def connect(self):
442
    """Connects to the QMP monitor.
443

444
    Connects to the UNIX socket and makes sure that we can actually send and
445
    receive data to the kvm instance via QMP.
446

447
    @raise errors.HypervisorError: when there are communication errors
448
    @raise errors.ProgrammerError: when there are data serialization errors
449

450
    """
451
    super(QmpConnection, self).connect()
452
    # Check if we receive a correct greeting message from the server
453
    # (As per the QEMU Protocol Specification 0.1 - section 2.2)
454
    greeting = self._Recv()
455
    if not greeting[self._FIRST_MESSAGE_KEY]:
456
      self._connected = False
457
      raise errors.HypervisorError("kvm: QMP communication error (wrong"
458
                                   " server greeting")
459

    
460
    # Let's put the monitor in command mode using the qmp_capabilities
461
    # command, or else no command will be executable.
462
    # (As per the QEMU Protocol Specification 0.1 - section 4)
463
    self.Execute(self._CAPABILITIES_COMMAND)
464

    
465
  def _ParseMessage(self, buf):
466
    """Extract and parse a QMP message from the given buffer.
467

468
    Seeks for a QMP message in the given buf. If found, it parses it and
469
    returns it together with the rest of the characters in the buf.
470
    If no message is found, returns None and the whole buffer.
471

472
    @raise errors.ProgrammerError: when there are data serialization errors
473

474
    """
475
    message = None
476
    # Check if we got the message end token (CRLF, as per the QEMU Protocol
477
    # Specification 0.1 - Section 2.1.1)
478
    pos = buf.find(self._MESSAGE_END_TOKEN)
479
    if pos >= 0:
480
      try:
481
        message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
482
      except Exception, err:
483
        raise errors.ProgrammerError("QMP data serialization error: %s" % err)
484
      buf = buf[pos + 1:]
485

    
486
    return (message, buf)
487

    
488
  def _Recv(self):
489
    """Receives a message from QMP and decodes the received JSON object.
490

491
    @rtype: QmpMessage
492
    @return: the received message
493
    @raise errors.HypervisorError: when there are communication errors
494
    @raise errors.ProgrammerError: when there are data serialization errors
495

496
    """
497
    self._check_connection()
498

    
499
    # Check if there is already a message in the buffer
500
    (message, self._buf) = self._ParseMessage(self._buf)
501
    if message:
502
      return message
503

    
504
    recv_buffer = StringIO.StringIO(self._buf)
505
    recv_buffer.seek(len(self._buf))
506
    try:
507
      while True:
508
        data = self.sock.recv(4096)
509
        if not data:
510
          break
511
        recv_buffer.write(data)
512

    
513
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
514
        if message:
515
          return message
516

    
517
    except socket.timeout, err:
518
      raise errors.HypervisorError("Timeout while receiving a QMP message: "
519
                                   "%s" % (err))
520
    except socket.error, err:
521
      raise errors.HypervisorError("Unable to receive data from KVM using the"
522
                                   " QMP protocol: %s" % err)
523

    
524
  def _Send(self, message):
525
    """Encodes and sends a message to KVM using QMP.
526

527
    @type message: QmpMessage
528
    @param message: message to send to KVM
529
    @raise errors.HypervisorError: when there are communication errors
530
    @raise errors.ProgrammerError: when there are data serialization errors
531

532
    """
533
    self._check_connection()
534
    try:
535
      message_str = str(message)
536
    except Exception, err:
537
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
538

    
539
    try:
540
      self.sock.sendall(message_str)
541
    except socket.timeout, err:
542
      raise errors.HypervisorError("Timeout while sending a QMP message: "
543
                                   "%s (%s)" % (err.string, err.errno))
544
    except socket.error, err:
545
      raise errors.HypervisorError("Unable to send data from KVM using the"
546
                                   " QMP protocol: %s" % err)
547

    
548
  def Execute(self, command, arguments=None):
549
    """Executes a QMP command and returns the response of the server.
550

551
    @type command: str
552
    @param command: the command to execute
553
    @type arguments: dict
554
    @param arguments: dictionary of arguments to be passed to the command
555
    @rtype: dict
556
    @return: dictionary representing the received JSON object
557
    @raise errors.HypervisorError: when there are communication errors
558
    @raise errors.ProgrammerError: when there are data serialization errors
559

560
    """
561
    self._check_connection()
562
    message = QmpMessage({self._EXECUTE_KEY: command})
563
    if arguments:
564
      message[self._ARGUMENTS_KEY] = arguments
565
    self._Send(message)
566

    
567
    # Events can occur between the sending of the command and the reception
568
    # of the response, so we need to filter out messages with the event key.
569
    while True:
570
      response = self._Recv()
571
      err = response[self._ERROR_KEY]
572
      if err:
573
        raise errors.HypervisorError("kvm: error executing the %s"
574
                                     " command: %s (%s, %s):" %
575
                                     (command,
576
                                      err[self._ERROR_DESC_KEY],
577
                                      err[self._ERROR_CLASS_KEY],
578
                                      err[self._ERROR_DATA_KEY]))
579

    
580
      elif not response[self._EVENT_KEY]:
581
        return response
582

    
583

    
584
class KVMHypervisor(hv_base.BaseHypervisor):
585
  """KVM hypervisor interface
586

587
  """
588
  CAN_MIGRATE = True
589

    
590
  _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
591
  _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
592
  _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
593
  _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
594
  _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
595
  _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
596
  _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
597
  # KVM instances with chroot enabled are started in empty chroot directories.
598
  _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
599
  # After an instance is stopped, its chroot directory is removed.
600
  # If the chroot directory is not empty, it can't be removed.
601
  # A non-empty chroot directory indicates a possible security incident.
602
  # To support forensics, the non-empty chroot directory is quarantined in
603
  # a separate directory, called 'chroot-quarantine'.
604
  _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
605
  _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
606
           _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
607

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

    
693
  _VIRTIO = "virtio"
694
  _VIRTIO_NET_PCI = "virtio-net-pci"
695
  _VIRTIO_BLK_PCI = "virtio-blk-pci"
696

    
697
  _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
698
                                    re.M | re.I)
699
  _MIGRATION_PROGRESS_RE = \
700
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
701
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
702
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
703

    
704
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
705
  _MIGRATION_INFO_RETRY_DELAY = 2
706

    
707
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
708

    
709
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
710
  _CPU_INFO_CMD = "info cpus"
711
  _CONT_CMD = "cont"
712

    
713
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
714
  _CHECK_MACHINE_VERSION_RE = \
715
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
716

    
717
  _QMP_RE = re.compile(r"^-qmp\s", re.M)
718
  _SPICE_RE = re.compile(r"^-spice\s", re.M)
719
  _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
720
  _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
721
  _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
722
  _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
723
  _DISPLAY_RE = re.compile(r"^-display\s", re.M)
724
  _MACHINE_RE = re.compile(r"^-machine\s", re.M)
725
  _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
726
  _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M)
727
  # match  -drive.*boot=on|off on different lines, but in between accept only
728
  # dashes not preceeded by a new line (which would mean another option
729
  # different than -drive is starting)
730
  _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
731

    
732
  _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
733
  _INFO_PCI_CMD = "info pci"
734
  _INFO_VERSION_RE = \
735
    re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
736
  _INFO_VERSION_CMD = "info version"
737

    
738
  _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
739

    
740
  ANCILLARY_FILES = [
741
    _KVM_NETWORK_SCRIPT,
742
    ]
743
  ANCILLARY_FILES_OPT = [
744
    _KVM_NETWORK_SCRIPT,
745
    ]
746

    
747
  # Supported kvm options to get output from
748
  _KVMOPT_HELP = "help"
749
  _KVMOPT_MLIST = "mlist"
750
  _KVMOPT_DEVICELIST = "devicelist"
751

    
752
  # Command to execute to get the output from kvm, and whether to
753
  # accept the output even on failure.
754
  _KVMOPTS_CMDS = {
755
    _KVMOPT_HELP: (["--help"], False),
756
    _KVMOPT_MLIST: (["-M", "?"], False),
757
    _KVMOPT_DEVICELIST: (["-device", "?"], True),
758
  }
759

    
760
  def __init__(self):
761
    hv_base.BaseHypervisor.__init__(self)
762
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
763
    # in a tmpfs filesystem or has been otherwise wiped out.
764
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
765
    utils.EnsureDirs(dirs)
766

    
767
  @classmethod
768
  def _InstancePidFile(cls, instance_name):
769
    """Returns the instance pidfile.
770

771
    """
772
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
773

    
774
  @classmethod
775
  def _InstanceUidFile(cls, instance_name):
776
    """Returns the instance uidfile.
777

778
    """
779
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
780

    
781
  @classmethod
782
  def _InstancePidInfo(cls, pid):
783
    """Check pid file for instance information.
784

785
    Check that a pid file is associated with an instance, and retrieve
786
    information from its command line.
787

788
    @type pid: string or int
789
    @param pid: process id of the instance to check
790
    @rtype: tuple
791
    @return: (instance_name, memory, vcpus)
792
    @raise errors.HypervisorError: when an instance cannot be found
793

794
    """
795
    alive = utils.IsProcessAlive(pid)
796
    if not alive:
797
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
798

    
799
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
800
    try:
801
      cmdline = utils.ReadFile(cmdline_file)
802
    except EnvironmentError, err:
803
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
804
                                   (pid, err))
805

    
806
    instance = None
807
    memory = 0
808
    vcpus = 0
809

    
810
    arg_list = cmdline.split("\x00")
811
    while arg_list:
812
      arg = arg_list.pop(0)
813
      if arg == "-name":
814
        instance = arg_list.pop(0)
815
      elif arg == "-m":
816
        memory = int(arg_list.pop(0))
817
      elif arg == "-smp":
818
        vcpus = int(arg_list.pop(0).split(",")[0])
819

    
820
    if instance is None:
821
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
822
                                   " instance" % pid)
823

    
824
    return (instance, memory, vcpus)
825

    
826
  def _InstancePidAlive(self, instance_name):
827
    """Returns the instance pidfile, pid, and liveness.
828

829
    @type instance_name: string
830
    @param instance_name: instance name
831
    @rtype: tuple
832
    @return: (pid file name, pid, liveness)
833

834
    """
835
    pidfile = self._InstancePidFile(instance_name)
836
    pid = utils.ReadPidFile(pidfile)
837

    
838
    alive = False
839
    try:
840
      cmd_instance = self._InstancePidInfo(pid)[0]
841
      alive = (cmd_instance == instance_name)
842
    except errors.HypervisorError:
843
      pass
844

    
845
    return (pidfile, pid, alive)
846

    
847
  def _CheckDown(self, instance_name):
848
    """Raises an error unless the given instance is down.
849

850
    """
851
    alive = self._InstancePidAlive(instance_name)[2]
852
    if alive:
853
      raise errors.HypervisorError("Failed to start instance %s: %s" %
854
                                   (instance_name, "already running"))
855

    
856
  @classmethod
857
  def _InstanceMonitor(cls, instance_name):
858
    """Returns the instance monitor socket name
859

860
    """
861
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
862

    
863
  @classmethod
864
  def _InstanceSerial(cls, instance_name):
865
    """Returns the instance serial socket name
866

867
    """
868
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
869

    
870
  @classmethod
871
  def _InstanceQmpMonitor(cls, instance_name):
872
    """Returns the instance serial QMP socket name
873

874
    """
875
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
876

    
877
  @staticmethod
878
  def _SocatUnixConsoleParams():
879
    """Returns the correct parameters for socat
880

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

883
    """
884
    if constants.SOCAT_USE_ESCAPE:
885
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
886
    else:
887
      return "echo=0,icanon=0"
888

    
889
  @classmethod
890
  def _InstanceKVMRuntime(cls, instance_name):
891
    """Returns the instance KVM runtime filename
892

893
    """
894
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
895

    
896
  @classmethod
897
  def _InstanceChrootDir(cls, instance_name):
898
    """Returns the name of the KVM chroot dir of the instance
899

900
    """
901
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
902

    
903
  @classmethod
904
  def _InstanceNICDir(cls, instance_name):
905
    """Returns the name of the directory holding the tap device files for a
906
    given instance.
907

908
    """
909
    return utils.PathJoin(cls._NICS_DIR, instance_name)
910

    
911
  @classmethod
912
  def _InstanceNICFile(cls, instance_name, seq):
913
    """Returns the name of the file containing the tap device for a given NIC
914

915
    """
916
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
917

    
918
  @classmethod
919
  def _InstanceKeymapFile(cls, instance_name):
920
    """Returns the name of the file containing the keymap for a given instance
921

922
    """
923
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
924

    
925
  @classmethod
926
  def _TryReadUidFile(cls, uid_file):
927
    """Try to read a uid file
928

929
    """
930
    if os.path.exists(uid_file):
931
      try:
932
        uid = int(utils.ReadOneLineFile(uid_file))
933
        return uid
934
      except EnvironmentError:
935
        logging.warning("Can't read uid file", exc_info=True)
936
      except (TypeError, ValueError):
937
        logging.warning("Can't parse uid file contents", exc_info=True)
938
    return None
939

    
940
  @classmethod
941
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
942
    """Removes an instance's rutime sockets/files/dirs.
943

944
    """
945
    utils.RemoveFile(pidfile)
946
    utils.RemoveFile(cls._InstanceMonitor(instance_name))
947
    utils.RemoveFile(cls._InstanceSerial(instance_name))
948
    utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
949
    utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
950
    utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
951
    uid_file = cls._InstanceUidFile(instance_name)
952
    uid = cls._TryReadUidFile(uid_file)
953
    utils.RemoveFile(uid_file)
954
    if uid is not None:
955
      uidpool.ReleaseUid(uid)
956
    try:
957
      shutil.rmtree(cls._InstanceNICDir(instance_name))
958
    except OSError, err:
959
      if err.errno != errno.ENOENT:
960
        raise
961
    try:
962
      chroot_dir = cls._InstanceChrootDir(instance_name)
963
      utils.RemoveDir(chroot_dir)
964
    except OSError, err:
965
      if err.errno == errno.ENOTEMPTY:
966
        # The chroot directory is expected to be empty, but it isn't.
967
        new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
968
                                          prefix="%s-%s-" %
969
                                          (instance_name,
970
                                           utils.TimestampForFilename()))
971
        logging.warning("The chroot directory of instance %s can not be"
972
                        " removed as it is not empty. Moving it to the"
973
                        " quarantine instead. Please investigate the"
974
                        " contents (%s) and clean up manually",
975
                        instance_name, new_chroot_dir)
976
        utils.RenameFile(chroot_dir, new_chroot_dir)
977
      else:
978
        raise
979

    
980
  @staticmethod
981
  def _ConfigureNIC(instance, seq, nic, tap):
982
    """Run the network configuration script for a specified NIC
983

984
    @param instance: instance we're acting on
985
    @type instance: instance object
986
    @param seq: nic sequence number
987
    @type seq: int
988
    @param nic: nic we're acting on
989
    @type nic: nic object
990
    @param tap: the host's tap interface this NIC corresponds to
991
    @type tap: str
992

993
    """
994
    if instance.tags:
995
      tags = " ".join(instance.tags)
996
    else:
997
      tags = ""
998

    
999
    env = {
1000
      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
1001
      "INSTANCE": instance.name,
1002
      "MAC": nic.mac,
1003
      "MODE": nic.nicparams[constants.NIC_MODE],
1004
      "INTERFACE": tap,
1005
      "INTERFACE_INDEX": str(seq),
1006
      "TAGS": tags,
1007
    }
1008

    
1009
    if nic.ip:
1010
      env["IP"] = nic.ip
1011

    
1012
    if nic.nicparams[constants.NIC_LINK]:
1013
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
1014

    
1015
    if nic.network:
1016
      n = objects.Network.FromDict(nic.netinfo)
1017
      env.update(n.HooksDict())
1018

    
1019
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1020
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
1021

    
1022
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
1023
    if result.failed:
1024
      raise errors.HypervisorError("Failed to configure interface %s: %s;"
1025
                                   " network configuration script output: %s" %
1026
                                   (tap, result.fail_reason, result.output))
1027

    
1028
  @staticmethod
1029
  def _VerifyAffinityPackage():
1030
    if affinity is None:
1031
      raise errors.HypervisorError("affinity Python package not"
1032
                                   " found; cannot use CPU pinning under KVM")
1033

    
1034
  @staticmethod
1035
  def _BuildAffinityCpuMask(cpu_list):
1036
    """Create a CPU mask suitable for sched_setaffinity from a list of
1037
    CPUs.
1038

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

1042
    @type cpu_list: list of int
1043
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
1044
    @rtype: int
1045
    @return: a bit mask of CPU affinities
1046

1047
    """
1048
    if cpu_list == constants.CPU_PINNING_OFF:
1049
      return constants.CPU_PINNING_ALL_KVM
1050
    else:
1051
      return sum(2 ** cpu for cpu in cpu_list)
1052

    
1053
  @classmethod
1054
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
1055
    """Change CPU affinity for running VM according to given CPU mask.
1056

1057
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
1058
    @type cpu_mask: string
1059
    @param process_id: process ID of KVM process. Used to pin entire VM
1060
                       to physical CPUs.
1061
    @type process_id: int
1062
    @param thread_dict: map of virtual CPUs to KVM thread IDs
1063
    @type thread_dict: dict int:int
1064

1065
    """
1066
    # Convert the string CPU mask to a list of list of int's
1067
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
1068

    
1069
    if len(cpu_list) == 1:
1070
      all_cpu_mapping = cpu_list[0]
1071
      if all_cpu_mapping == constants.CPU_PINNING_OFF:
1072
        # If CPU pinning has 1 entry that's "all", then do nothing
1073
        pass
1074
      else:
1075
        # If CPU pinning has one non-all entry, map the entire VM to
1076
        # one set of physical CPUs
1077
        cls._VerifyAffinityPackage()
1078
        affinity.set_process_affinity_mask(
1079
          process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
1080
    else:
1081
      # The number of vCPUs mapped should match the number of vCPUs
1082
      # reported by KVM. This was already verified earlier, so
1083
      # here only as a sanity check.
1084
      assert len(thread_dict) == len(cpu_list)
1085
      cls._VerifyAffinityPackage()
1086

    
1087
      # For each vCPU, map it to the proper list of physical CPUs
1088
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1089
        affinity.set_process_affinity_mask(thread_dict[i],
1090
                                           cls._BuildAffinityCpuMask(vcpu))
1091

    
1092
  def _GetVcpuThreadIds(self, instance_name):
1093
    """Get a mapping of vCPU no. to thread IDs for the instance
1094

1095
    @type instance_name: string
1096
    @param instance_name: instance in question
1097
    @rtype: dictionary of int:int
1098
    @return: a dictionary mapping vCPU numbers to thread IDs
1099

1100
    """
1101
    result = {}
1102
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1103
    for line in output.stdout.splitlines():
1104
      match = self._CPU_INFO_RE.search(line)
1105
      if not match:
1106
        continue
1107
      grp = map(int, match.groups())
1108
      result[grp[0]] = grp[1]
1109

    
1110
    return result
1111

    
1112
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1113
    """Complete CPU pinning.
1114

1115
    @type instance_name: string
1116
    @param instance_name: name of instance
1117
    @type cpu_mask: string
1118
    @param cpu_mask: CPU pinning mask as entered by user
1119

1120
    """
1121
    # Get KVM process ID, to be used if need to pin entire VM
1122
    _, pid, _ = self._InstancePidAlive(instance_name)
1123
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1124
    thread_dict = self._GetVcpuThreadIds(instance_name)
1125
    # Run CPU pinning, based on configured mask
1126
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1127

    
1128
  def ListInstances(self):
1129
    """Get the list of running instances.
1130

1131
    We can do this by listing our live instances directory and
1132
    checking whether the associated kvm process is still alive.
1133

1134
    """
1135
    result = []
1136
    for name in os.listdir(self._PIDS_DIR):
1137
      if self._InstancePidAlive(name)[2]:
1138
        result.append(name)
1139
    return result
1140

    
1141
  def GetInstanceInfo(self, instance_name):
1142
    """Get instance properties.
1143

1144
    @type instance_name: string
1145
    @param instance_name: the instance name
1146
    @rtype: tuple of strings
1147
    @return: (name, id, memory, vcpus, stat, times)
1148

1149
    """
1150
    _, pid, alive = self._InstancePidAlive(instance_name)
1151
    if not alive:
1152
      return None
1153

    
1154
    _, memory, vcpus = self._InstancePidInfo(pid)
1155
    istat = "---b-"
1156
    times = "0"
1157

    
1158
    try:
1159
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1160
      qmp.connect()
1161
      vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1162
      # Will fail if ballooning is not enabled, but we can then just resort to
1163
      # the value above.
1164
      mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1165
      memory = mem_bytes / 1048576
1166
    except errors.HypervisorError:
1167
      pass
1168

    
1169
    return (instance_name, pid, memory, vcpus, istat, times)
1170

    
1171
  def GetAllInstancesInfo(self):
1172
    """Get properties of all instances.
1173

1174
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1175

1176
    """
1177
    data = []
1178
    for name in os.listdir(self._PIDS_DIR):
1179
      try:
1180
        info = self.GetInstanceInfo(name)
1181
      except errors.HypervisorError:
1182
        # Ignore exceptions due to instances being shut down
1183
        continue
1184
      if info:
1185
        data.append(info)
1186
    return data
1187

    
1188
  def _GenerateKVMBlockDevicesOptions(self, instance, kvm_disks,
1189
                                      kvmhelp, devlist):
1190
    """Generate KVM options regarding instance's block devices.
1191

1192
    @type instance: L{objects.Instance}
1193
    @param instance: the instance object
1194
    @type kvm_disks: list of tuples
1195
    @param kvm_disks: list of tuples [(disk, link_name)..]
1196
    @type kvmhelp: string
1197
    @param kvmhelp: output of kvm --help
1198
    @type devlist: string
1199
    @param devlist: output of kvm -device ?
1200
    @rtype: list
1201
    @return: list of command line options eventually used by kvm executable
1202

1203
    """
1204
    hvp = instance.hvparams
1205
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1206
    if kernel_path:
1207
      boot_disk = False
1208
    else:
1209
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1210

    
1211
    # whether this is an older KVM version that uses the boot=on flag
1212
    # on devices
1213
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1214

    
1215
    dev_opts = []
1216
    device_driver = None
1217
    disk_type = hvp[constants.HV_DISK_TYPE]
1218
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
1219
      if_val = ",if=%s" % self._VIRTIO
1220
      try:
1221
        if self._VIRTIO_BLK_RE.search(devlist):
1222
          if_val = ",if=none"
1223
          # will be passed in -device option as driver
1224
          device_driver = self._VIRTIO_BLK_PCI
1225
      except errors.HypervisorError, _:
1226
        pass
1227
    else:
1228
      if_val = ",if=%s" % disk_type
1229
    # Cache mode
1230
    disk_cache = hvp[constants.HV_DISK_CACHE]
1231
    if instance.disk_template in constants.DTS_EXT_MIRROR:
1232
      if disk_cache != "none":
1233
        # TODO: make this a hard error, instead of a silent overwrite
1234
        logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1235
                        " to prevent shared storage corruption on migration",
1236
                        disk_cache)
1237
      cache_val = ",cache=none"
1238
    elif disk_cache != constants.HT_CACHE_DEFAULT:
1239
      cache_val = ",cache=%s" % disk_cache
1240
    else:
1241
      cache_val = ""
1242
    for cfdev, link_name in kvm_disks:
1243
      if cfdev.mode != constants.DISK_RDWR:
1244
        raise errors.HypervisorError("Instance has read-only disks which"
1245
                                     " are not supported by KVM")
1246
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
1247
      boot_val = ""
1248
      if boot_disk:
1249
        dev_opts.extend(["-boot", "c"])
1250
        boot_disk = False
1251
        if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1252
          boot_val = ",boot=on"
1253
      drive_val = "file=%s,format=raw%s%s%s" % \
1254
                  (dev_path, if_val, boot_val, cache_val)
1255

    
1256
      if device_driver:
1257
        # kvm_disks are the 4th entry of runtime file that did not exist in
1258
        # the past. That means that cfdev should always have pci slot and
1259
        # _GenerateDeviceKVMId() will not raise a exception.
1260
        kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_DISK, cfdev)
1261
        drive_val += (",id=%s" % kvm_devid)
1262
        drive_val += (",bus=0,unit=%d" % cfdev.pci)
1263
        dev_val = ("%s,drive=%s,id=%s" %
1264
                   (device_driver, kvm_devid, kvm_devid))
1265
        dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci)
1266
        dev_opts.extend(["-device", dev_val])
1267

    
1268
      dev_opts.extend(["-drive", drive_val])
1269

    
1270
    return dev_opts
1271

    
1272
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1273
                          kvmhelp):
1274
    """Generate KVM information to start an instance.
1275

1276
    @type kvmhelp: string
1277
    @param kvmhelp: output of kvm --help
1278
    @attention: this function must not have any side-effects; for
1279
        example, it must not write to the filesystem, or read values
1280
        from the current system the are expected to differ between
1281
        nodes, since it is only run once at instance startup;
1282
        actions/kvm arguments that can vary between systems should be
1283
        done in L{_ExecuteKVMRuntime}
1284

1285
    """
1286
    # pylint: disable=R0912,R0914,R0915
1287
    hvp = instance.hvparams
1288
    self.ValidateParameters(hvp)
1289

    
1290
    pidfile = self._InstancePidFile(instance.name)
1291
    kvm = hvp[constants.HV_KVM_PATH]
1292
    kvm_cmd = [kvm]
1293
    # used just by the vnc server, if enabled
1294
    kvm_cmd.extend(["-name", instance.name])
1295
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1296

    
1297
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1298
    if hvp[constants.HV_CPU_CORES]:
1299
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1300
    if hvp[constants.HV_CPU_THREADS]:
1301
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1302
    if hvp[constants.HV_CPU_SOCKETS]:
1303
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1304

    
1305
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1306

    
1307
    kvm_cmd.extend(["-pidfile", pidfile])
1308
    kvm_cmd.extend(["-balloon", "virtio"])
1309
    kvm_cmd.extend(["-daemonize"])
1310
    if not instance.hvparams[constants.HV_ACPI]:
1311
      kvm_cmd.extend(["-no-acpi"])
1312
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1313
        constants.INSTANCE_REBOOT_EXIT:
1314
      kvm_cmd.extend(["-no-reboot"])
1315

    
1316
    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1317
    if not mversion:
1318
      mversion = self._GetDefaultMachineVersion(kvm)
1319
    if self._MACHINE_RE.search(kvmhelp):
1320
      # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1321
      # extra hypervisor parameters. We should also investigate whether and how
1322
      # shadow_mem should be considered for the resource model.
1323
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1324
        specprop = ",accel=kvm"
1325
      else:
1326
        specprop = ""
1327
      machinespec = "%s%s" % (mversion, specprop)
1328
      kvm_cmd.extend(["-machine", machinespec])
1329
    else:
1330
      kvm_cmd.extend(["-M", mversion])
1331
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1332
          self._ENABLE_KVM_RE.search(kvmhelp)):
1333
        kvm_cmd.extend(["-enable-kvm"])
1334
      elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1335
            self._DISABLE_KVM_RE.search(kvmhelp)):
1336
        kvm_cmd.extend(["-disable-kvm"])
1337

    
1338
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1339
    if kernel_path:
1340
      boot_cdrom = boot_floppy = boot_network = False
1341
    else:
1342
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1343
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1344
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1345

    
1346
    if startup_paused:
1347
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1348

    
1349
    if boot_network:
1350
      kvm_cmd.extend(["-boot", "n"])
1351

    
1352
    # whether this is an older KVM version that uses the boot=on flag
1353
    # on devices
1354
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1355

    
1356
    disk_type = hvp[constants.HV_DISK_TYPE]
1357

    
1358
    #Now we can specify a different device type for CDROM devices.
1359
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1360
    if not cdrom_disk_type:
1361
      cdrom_disk_type = disk_type
1362

    
1363
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1364
    if iso_image:
1365
      options = ",format=raw,media=cdrom"
1366
      # set cdrom 'if' type
1367
      if boot_cdrom:
1368
        actual_cdrom_type = constants.HT_DISK_IDE
1369
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1370
        actual_cdrom_type = "virtio"
1371
      else:
1372
        actual_cdrom_type = cdrom_disk_type
1373
      if_val = ",if=%s" % actual_cdrom_type
1374
      # set boot flag, if needed
1375
      boot_val = ""
1376
      if boot_cdrom:
1377
        kvm_cmd.extend(["-boot", "d"])
1378
        if needs_boot_flag:
1379
          boot_val = ",boot=on"
1380
      # and finally build the entire '-drive' value
1381
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1382
      kvm_cmd.extend(["-drive", drive_val])
1383

    
1384
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1385
    if iso_image2:
1386
      options = ",format=raw,media=cdrom"
1387
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1388
        if_val = ",if=virtio"
1389
      else:
1390
        if_val = ",if=%s" % cdrom_disk_type
1391
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1392
      kvm_cmd.extend(["-drive", drive_val])
1393

    
1394
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1395
    if floppy_image:
1396
      options = ",format=raw,media=disk"
1397
      if boot_floppy:
1398
        kvm_cmd.extend(["-boot", "a"])
1399
        options = "%s,boot=on" % options
1400
      if_val = ",if=floppy"
1401
      options = "%s%s" % (options, if_val)
1402
      drive_val = "file=%s%s" % (floppy_image, options)
1403
      kvm_cmd.extend(["-drive", drive_val])
1404

    
1405
    if kernel_path:
1406
      kvm_cmd.extend(["-kernel", kernel_path])
1407
      initrd_path = hvp[constants.HV_INITRD_PATH]
1408
      if initrd_path:
1409
        kvm_cmd.extend(["-initrd", initrd_path])
1410
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1411
                     hvp[constants.HV_KERNEL_ARGS]]
1412
      if hvp[constants.HV_SERIAL_CONSOLE]:
1413
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1414
        root_append.append("console=ttyS0,%s" % serial_speed)
1415
      kvm_cmd.extend(["-append", " ".join(root_append)])
1416

    
1417
    mem_path = hvp[constants.HV_MEM_PATH]
1418
    if mem_path:
1419
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1420

    
1421
    monitor_dev = ("unix:%s,server,nowait" %
1422
                   self._InstanceMonitor(instance.name))
1423
    kvm_cmd.extend(["-monitor", monitor_dev])
1424
    if hvp[constants.HV_SERIAL_CONSOLE]:
1425
      serial_dev = ("unix:%s,server,nowait" %
1426
                    self._InstanceSerial(instance.name))
1427
      kvm_cmd.extend(["-serial", serial_dev])
1428
    else:
1429
      kvm_cmd.extend(["-serial", "none"])
1430

    
1431
    mouse_type = hvp[constants.HV_USB_MOUSE]
1432
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1433
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1434
    spice_ip_version = None
1435

    
1436
    kvm_cmd.extend(["-usb"])
1437

    
1438
    if mouse_type:
1439
      kvm_cmd.extend(["-usbdevice", mouse_type])
1440
    elif vnc_bind_address:
1441
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1442

    
1443
    if vnc_bind_address:
1444
      if netutils.IP4Address.IsValid(vnc_bind_address):
1445
        if instance.network_port > constants.VNC_BASE_PORT:
1446
          display = instance.network_port - constants.VNC_BASE_PORT
1447
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1448
            vnc_arg = ":%d" % (display)
1449
          else:
1450
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1451
        else:
1452
          logging.error("Network port is not a valid VNC display (%d < %d),"
1453
                        " not starting VNC",
1454
                        instance.network_port, constants.VNC_BASE_PORT)
1455
          vnc_arg = "none"
1456

    
1457
        # Only allow tls and other option when not binding to a file, for now.
1458
        # kvm/qemu gets confused otherwise about the filename to use.
1459
        vnc_append = ""
1460
        if hvp[constants.HV_VNC_TLS]:
1461
          vnc_append = "%s,tls" % vnc_append
1462
          if hvp[constants.HV_VNC_X509_VERIFY]:
1463
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1464
                                               hvp[constants.HV_VNC_X509])
1465
          elif hvp[constants.HV_VNC_X509]:
1466
            vnc_append = "%s,x509=%s" % (vnc_append,
1467
                                         hvp[constants.HV_VNC_X509])
1468
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1469
          vnc_append = "%s,password" % vnc_append
1470

    
1471
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1472

    
1473
      else:
1474
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1475

    
1476
      kvm_cmd.extend(["-vnc", vnc_arg])
1477
    elif spice_bind:
1478
      # FIXME: this is wrong here; the iface ip address differs
1479
      # between systems, so it should be done in _ExecuteKVMRuntime
1480
      if netutils.IsValidInterface(spice_bind):
1481
        # The user specified a network interface, we have to figure out the IP
1482
        # address.
1483
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1484
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1485

    
1486
        # if the user specified an IP version and the interface does not
1487
        # have that kind of IP addresses, throw an exception
1488
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1489
          if not addresses[spice_ip_version]:
1490
            raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1491
                                         " for %s" % (spice_ip_version,
1492
                                                      spice_bind))
1493

    
1494
        # the user did not specify an IP version, we have to figure it out
1495
        elif (addresses[constants.IP4_VERSION] and
1496
              addresses[constants.IP6_VERSION]):
1497
          # we have both ipv4 and ipv6, let's use the cluster default IP
1498
          # version
1499
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1500
          spice_ip_version = \
1501
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1502
        elif addresses[constants.IP4_VERSION]:
1503
          spice_ip_version = constants.IP4_VERSION
1504
        elif addresses[constants.IP6_VERSION]:
1505
          spice_ip_version = constants.IP6_VERSION
1506
        else:
1507
          raise errors.HypervisorError("SPICE: Unable to get an IP address"
1508
                                       " for %s" % (spice_bind))
1509

    
1510
        spice_address = addresses[spice_ip_version][0]
1511

    
1512
      else:
1513
        # spice_bind is known to be a valid IP address, because
1514
        # ValidateParameters checked it.
1515
        spice_address = spice_bind
1516

    
1517
      spice_arg = "addr=%s" % spice_address
1518
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1519
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1520
                     (spice_arg, instance.network_port,
1521
                      pathutils.SPICE_CACERT_FILE))
1522
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1523
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1524
                      pathutils.SPICE_CERT_FILE))
1525
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1526
        if tls_ciphers:
1527
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1528
      else:
1529
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1530

    
1531
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1532
        spice_arg = "%s,disable-ticketing" % spice_arg
1533

    
1534
      if spice_ip_version:
1535
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1536

    
1537
      # Image compression options
1538
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1539
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1540
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1541
      if img_lossless:
1542
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1543
      if img_jpeg:
1544
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1545
      if img_zlib_glz:
1546
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1547

    
1548
      # Video stream detection
1549
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1550
      if video_streaming:
1551
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1552

    
1553
      # Audio compression, by default in qemu-kvm it is on
1554
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1555
        spice_arg = "%s,playback-compression=off" % spice_arg
1556
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1557
        spice_arg = "%s,agent-mouse=off" % spice_arg
1558
      else:
1559
        # Enable the spice agent communication channel between the host and the
1560
        # agent.
1561
        kvm_cmd.extend(["-device", "virtio-serial-pci"])
1562
        kvm_cmd.extend([
1563
          "-device",
1564
          "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1565
          ])
1566
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1567

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

    
1571
    else:
1572
      # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1573
      # also works in earlier versions though (tested with 1.1 and 1.3)
1574
      if self._DISPLAY_RE.search(kvmhelp):
1575
        kvm_cmd.extend(["-display", "none"])
1576
      else:
1577
        kvm_cmd.extend(["-nographic"])
1578

    
1579
    if hvp[constants.HV_USE_LOCALTIME]:
1580
      kvm_cmd.extend(["-localtime"])
1581

    
1582
    if hvp[constants.HV_KVM_USE_CHROOT]:
1583
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1584

    
1585
    # Add qemu-KVM -cpu param
1586
    if hvp[constants.HV_CPU_TYPE]:
1587
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1588

    
1589
    # As requested by music lovers
1590
    if hvp[constants.HV_SOUNDHW]:
1591
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1592

    
1593
    # Pass a -vga option if requested, or if spice is used, for backwards
1594
    # compatibility.
1595
    if hvp[constants.HV_VGA]:
1596
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1597
    elif spice_bind:
1598
      kvm_cmd.extend(["-vga", "qxl"])
1599

    
1600
    # Various types of usb devices, comma separated
1601
    if hvp[constants.HV_USB_DEVICES]:
1602
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1603
        kvm_cmd.extend(["-usbdevice", dev])
1604

    
1605
    if hvp[constants.HV_KVM_EXTRA]:
1606
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1607

    
1608
    pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1609
    kvm_disks = []
1610
    for disk, link_name in block_devices:
1611
      _UpdatePCISlots(disk, pci_reservations)
1612
      kvm_disks.append((disk, link_name))
1613

    
1614
    kvm_nics = []
1615
    for nic in instance.nics:
1616
      _UpdatePCISlots(nic, pci_reservations)
1617
      kvm_nics.append(nic)
1618

    
1619
    hvparams = hvp
1620

    
1621
    return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1622

    
1623
  def _WriteKVMRuntime(self, instance_name, data):
1624
    """Write an instance's KVM runtime
1625

1626
    """
1627
    try:
1628
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1629
                      data=data)
1630
    except EnvironmentError, err:
1631
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1632

    
1633
  def _ReadKVMRuntime(self, instance_name):
1634
    """Read an instance's KVM runtime
1635

1636
    """
1637
    try:
1638
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1639
    except EnvironmentError, err:
1640
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1641
    return file_content
1642

    
1643
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1644
    """Save an instance's KVM runtime
1645

1646
    """
1647
    kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1648

    
1649
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1650
    serialized_disks = [(blk.ToDict(), link)
1651
                            for blk, link in kvm_disks]
1652
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1653
                                      serialized_disks))
1654

    
1655
    self._WriteKVMRuntime(instance.name, serialized_form)
1656

    
1657
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1658
    """Load an instance's KVM runtime
1659

1660
    """
1661
    if not serialized_runtime:
1662
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1663

    
1664
    return _AnalyzeSerializedRuntime(serialized_runtime)
1665

    
1666
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1667
    """Run the KVM cmd and check for errors
1668

1669
    @type name: string
1670
    @param name: instance name
1671
    @type kvm_cmd: list of strings
1672
    @param kvm_cmd: runcmd input for kvm
1673
    @type tap_fds: list of int
1674
    @param tap_fds: fds of tap devices opened by Ganeti
1675

1676
    """
1677
    try:
1678
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1679
    finally:
1680
      for fd in tap_fds:
1681
        utils_wrapper.CloseFdNoError(fd)
1682

    
1683
    if result.failed:
1684
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1685
                                   (name, result.fail_reason, result.output))
1686
    if not self._InstancePidAlive(name)[2]:
1687
      raise errors.HypervisorError("Failed to start instance %s" % name)
1688

    
1689
  # too many local variables
1690
  # pylint: disable=R0914
1691
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1692
    """Execute a KVM cmd, after completing it with some last minute data.
1693

1694
    @type incoming: tuple of strings
1695
    @param incoming: (target_host_ip, port)
1696
    @type kvmhelp: string
1697
    @param kvmhelp: output of kvm --help
1698

1699
    """
1700
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1701
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1702
    #    have changed since the instance started; only use them if the change
1703
    #    won't affect the inside of the instance (which hasn't been rebooted).
1704
    #  - up_hvp contains the parameters as they were when the instance was
1705
    #    started, plus any new parameter which has been added between ganeti
1706
    #    versions: it is paramount that those default to a value which won't
1707
    #    affect the inside of the instance as well.
1708
    conf_hvp = instance.hvparams
1709
    name = instance.name
1710
    self._CheckDown(name)
1711

    
1712
    temp_files = []
1713

    
1714
    kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1715
    # the first element of kvm_cmd is always the path to the kvm binary
1716
    kvm_path = kvm_cmd[0]
1717
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1718

    
1719
    # We know it's safe to run as a different user upon migration, so we'll use
1720
    # the latest conf, from conf_hvp.
1721
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1722
    if security_model == constants.HT_SM_USER:
1723
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1724

    
1725
    keymap = conf_hvp[constants.HV_KEYMAP]
1726
    if keymap:
1727
      keymap_path = self._InstanceKeymapFile(name)
1728
      # If a keymap file is specified, KVM won't use its internal defaults. By
1729
      # first including the "en-us" layout, an error on loading the actual
1730
      # layout (e.g. because it can't be found) won't lead to a non-functional
1731
      # keyboard. A keyboard with incorrect keys is still better than none.
1732
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1733
      kvm_cmd.extend(["-k", keymap_path])
1734

    
1735
    # We have reasons to believe changing something like the nic driver/type
1736
    # upon migration won't exactly fly with the instance kernel, so for nic
1737
    # related parameters we'll use up_hvp
1738
    tapfds = []
1739
    taps = []
1740
    devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1741
    if not kvm_nics:
1742
      kvm_cmd.extend(["-net", "none"])
1743
    else:
1744
      vnet_hdr = False
1745
      tap_extra = ""
1746
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1747
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1748
        nic_model = self._VIRTIO
1749
        try:
1750
          if self._VIRTIO_NET_RE.search(devlist):
1751
            nic_model = self._VIRTIO_NET_PCI
1752
            vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1753
        except errors.HypervisorError, _:
1754
          # Older versions of kvm don't support DEVICE_LIST, but they don't
1755
          # have new virtio syntax either.
1756
          pass
1757

    
1758
        if up_hvp[constants.HV_VHOST_NET]:
1759
          # check for vhost_net support
1760
          if self._VHOST_RE.search(kvmhelp):
1761
            tap_extra = ",vhost=on"
1762
          else:
1763
            raise errors.HypervisorError("vhost_net is configured"
1764
                                         " but it is not available")
1765
      else:
1766
        nic_model = nic_type
1767

    
1768
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1769

    
1770
      for nic_seq, nic in enumerate(kvm_nics):
1771
        tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1772
        tapfds.append(tapfd)
1773
        taps.append(tapname)
1774
        if kvm_supports_netdev:
1775
          nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1776
          try:
1777
            # kvm_nics already exist in old runtime files and thus there might
1778
            # be some entries without pci slot (therefore try: except:)
1779
            kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1780
            netdev = kvm_devid
1781
            nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1782
          except errors.HotplugError:
1783
            netdev = "netdev%d" % nic_seq
1784
          nic_val += (",netdev=%s" % netdev)
1785
          tap_val = ("type=tap,id=%s,fd=%d%s" %
1786
                     (netdev, tapfd, tap_extra))
1787
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1788
        else:
1789
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1790
                                                         nic.mac, nic_model)
1791
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1792
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1793

    
1794
    if incoming:
1795
      target, port = incoming
1796
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1797

    
1798
    # Changing the vnc password doesn't bother the guest that much. At most it
1799
    # will surprise people who connect to it. Whether positively or negatively
1800
    # it's debatable.
1801
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1802
    vnc_pwd = None
1803
    if vnc_pwd_file:
1804
      try:
1805
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1806
      except EnvironmentError, err:
1807
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1808
                                     % (vnc_pwd_file, err))
1809

    
1810
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1811
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1812
                         constants.SECURE_DIR_MODE)])
1813

    
1814
    # Automatically enable QMP if version is >= 0.14
1815
    if self._QMP_RE.search(kvmhelp):
1816
      logging.debug("Enabling QMP")
1817
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1818
                      self._InstanceQmpMonitor(instance.name)])
1819

    
1820
    # Configure the network now for starting instances and bridged interfaces,
1821
    # during FinalizeMigration for incoming instances' routed interfaces
1822
    for nic_seq, nic in enumerate(kvm_nics):
1823
      if (incoming and
1824
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1825
        continue
1826
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1827

    
1828
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1829
                                                     kvm_disks,
1830
                                                     kvmhelp,
1831
                                                     devlist)
1832
    kvm_cmd.extend(bdev_opts)
1833
    # CPU affinity requires kvm to start paused, so we set this flag if the
1834
    # instance is not already paused and if we are not going to accept a
1835
    # migrating instance. In the latter case, pausing is not needed.
1836
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1837
    if start_kvm_paused:
1838
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1839

    
1840
    # Note: CPU pinning is using up_hvp since changes take effect
1841
    # during instance startup anyway, and to avoid problems when soft
1842
    # rebooting the instance.
1843
    cpu_pinning = False
1844
    if up_hvp.get(constants.HV_CPU_MASK, None):
1845
      cpu_pinning = True
1846

    
1847
    if security_model == constants.HT_SM_POOL:
1848
      ss = ssconf.SimpleStore()
1849
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1850
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1851
      uid = uidpool.RequestUnusedUid(all_uids)
1852
      try:
1853
        username = pwd.getpwuid(uid.GetUid()).pw_name
1854
        kvm_cmd.extend(["-runas", username])
1855
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1856
      except:
1857
        uidpool.ReleaseUid(uid)
1858
        raise
1859
      else:
1860
        uid.Unlock()
1861
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1862
    else:
1863
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1864

    
1865
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1866
                     constants.RUN_DIRS_MODE)])
1867
    for nic_seq, tap in enumerate(taps):
1868
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1869
                      data=tap)
1870

    
1871
    if vnc_pwd:
1872
      change_cmd = "change vnc password %s" % vnc_pwd
1873
      self._CallMonitorCommand(instance.name, change_cmd)
1874

    
1875
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1876
    # connection attempts because SPICE by default does not allow connections
1877
    # if neither a password nor the "disable_ticketing" options are specified.
1878
    # As soon as we send the password via QMP, that password is a valid ticket
1879
    # for connection.
1880
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1881
    if spice_password_file:
1882
      spice_pwd = ""
1883
      try:
1884
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1885
      except EnvironmentError, err:
1886
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1887
                                     % (spice_password_file, err))
1888

    
1889
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1890
      qmp.connect()
1891
      arguments = {
1892
          "protocol": "spice",
1893
          "password": spice_pwd,
1894
      }
1895
      qmp.Execute("set_password", arguments)
1896

    
1897
    for filename in temp_files:
1898
      utils.RemoveFile(filename)
1899

    
1900
    # If requested, set CPU affinity and resume instance execution
1901
    if cpu_pinning:
1902
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1903

    
1904
    start_memory = self._InstanceStartupMemory(instance)
1905
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1906
      self.BalloonInstanceMemory(instance, start_memory)
1907

    
1908
    if start_kvm_paused:
1909
      # To control CPU pinning, ballooning, and vnc/spice passwords
1910
      # the VM was started in a frozen state. If freezing was not
1911
      # explicitly requested resume the vm status.
1912
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1913

    
1914
  def StartInstance(self, instance, block_devices, startup_paused):
1915
    """Start an instance.
1916

1917
    """
1918
    self._CheckDown(instance.name)
1919
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1920
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1921
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1922
                                           startup_paused, kvmhelp)
1923
    self._SaveKVMRuntime(instance, kvm_runtime)
1924
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1925

    
1926
  def _CallMonitorCommand(self, instance_name, command, timeout=None):
1927
    """Invoke a command on the instance monitor.
1928

1929
    """
1930
    if timeout is not None:
1931
      timeout_cmd = "timeout %s" % (timeout, )
1932
    else:
1933
      timeout_cmd = ""
1934

    
1935
    # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1936
    # version. The monitor protocol is designed for human consumption, whereas
1937
    # QMP is made for programmatic usage. In the worst case QMP can also
1938
    # execute monitor commands. As it is, all calls to socat take at least
1939
    # 500ms and likely more: socat can't detect the end of the reply and waits
1940
    # for 500ms of no data received before exiting (500 ms is the default for
1941
    # the "-t" parameter).
1942
    socat = ("echo %s | %s %s STDIO UNIX-CONNECT:%s" %
1943
             (utils.ShellQuote(command),
1944
              timeout_cmd,
1945
              constants.SOCAT_PATH,
1946
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1947

    
1948
    result = utils.RunCmd(socat)
1949
    if result.failed:
1950
      msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1951
             " output: %s" %
1952
             (command, instance_name, result.fail_reason, result.output))
1953
      raise errors.HypervisorError(msg)
1954

    
1955
    return result
1956

    
1957
  def _GetFreePCISlot(self, instance, dev):
1958
    """Get the first available pci slot of a runnung instance.
1959

1960
    """
1961
    slots = bitarray(32)
1962
    slots.setall(False) # pylint: disable=E1101
1963
    output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
1964
    for line in output.stdout.splitlines():
1965
      match = self._INFO_PCI_RE.search(line)
1966
      if match:
1967
        slot = int(match.group(1))
1968
        slots[slot] = True
1969

    
1970
    [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
1971
    if not free:
1972
      raise errors.HypervisorError("All PCI slots occupied")
1973

    
1974
    dev.pci = int(free)
1975

    
1976
  def VerifyHotplugSupport(self, instance, action, dev_type):
1977
    """Verifies that hotplug is supported.
1978

1979
    Hotplug is *not* supported in case of:
1980
     - security models and chroot (disk hotplug)
1981
     - fdsend module is missing (nic hot-add)
1982

1983
    @raise errors.HypervisorError: in one of the previous cases
1984

1985
    """
1986
    if dev_type == constants.HOTPLUG_TARGET_DISK:
1987
      hvp = instance.hvparams
1988
      security_model = hvp[constants.HV_SECURITY_MODEL]
1989
      use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
1990
      if use_chroot:
1991
        raise errors.HotplugError("Disk hotplug is not supported"
1992
                                  " in case of chroot.")
1993
      if security_model != constants.HT_SM_NONE:
1994
        raise errors.HotplugError("Disk Hotplug is not supported in case"
1995
                                  " security models are used.")
1996

    
1997
    if (dev_type == constants.HOTPLUG_TARGET_NIC and
1998
        action == constants.HOTPLUG_ACTION_ADD and not fdsend):
1999
      raise errors.HotplugError("Cannot hot-add NIC."
2000
                                " fdsend python module is missing.")
2001

    
2002
  def HotplugSupported(self, instance):
2003
    """Checks if hotplug is generally supported.
2004

2005
    Hotplug is *not* supported in case of:
2006
     - qemu versions < 1.0
2007
     - for stopped instances
2008

2009
    @raise errors.HypervisorError: in one of the previous cases
2010

2011
    """
2012
    output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2013
    # TODO: search for netdev_add, drive_add, device_add.....
2014
    match = self._INFO_VERSION_RE.search(output.stdout)
2015
    if not match:
2016
      raise errors.HotplugError("Try hotplug only in running instances.")
2017
    v_major, v_min, _, _ = match.groups()
2018
    if (int(v_major), int(v_min)) < (1, 0):
2019
      raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2020

    
2021
  def _CallHotplugCommand(self, name, cmd):
2022
    output = self._CallMonitorCommand(name, cmd)
2023
    # TODO: parse output and check if succeeded
2024
    for line in output.stdout.splitlines():
2025
      logging.info("%s", line)
2026

    
2027
  def HotAddDevice(self, instance, dev_type, device, extra, seq):
2028
    """ Helper method to hot-add a new device
2029

2030
    It gets free pci slot generates the device name and invokes the
2031
    device specific method.
2032

2033
    """
2034
    # in case of hot-mod this is given
2035
    if device.pci is None:
2036
      self._GetFreePCISlot(instance, device)
2037
    kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2038
    runtime = self._LoadKVMRuntime(instance)
2039
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2040
      command = "drive_add dummy file=%s,if=none,id=%s,format=raw\n" % \
2041
                 (extra, kvm_devid)
2042
      command += ("device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
2043
                  (hex(device.pci), kvm_devid, kvm_devid))
2044
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
2045
      (tap, fd) = _OpenTap()
2046
      self._ConfigureNIC(instance, seq, device, tap)
2047
      self._PassTapFd(instance, fd, device)
2048
      command = "netdev_add tap,id=%s,fd=%s\n" % (kvm_devid, kvm_devid)
2049
      args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
2050
               (hex(device.pci), device.mac, kvm_devid, kvm_devid)
2051
      command += "device_add %s" % args
2052
      utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
2053

    
2054
    self._CallHotplugCommand(instance.name, command)
2055
    # update relevant entries in runtime file
2056
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2057
    entry = _RUNTIME_ENTRY[dev_type](device, extra)
2058
    runtime[index].append(entry)
2059
    self._SaveKVMRuntime(instance, runtime)
2060

    
2061
  def HotDelDevice(self, instance, dev_type, device, _, seq):
2062
    """ Helper method for hot-del device
2063

2064
    It gets device info from runtime file, generates the device name and
2065
    invokes the device specific method.
2066

2067
    """
2068
    runtime = self._LoadKVMRuntime(instance)
2069
    entry = _GetExistingDeviceInfo(dev_type, device, runtime)
2070
    kvm_device = _RUNTIME_DEVICE[dev_type](entry)
2071
    kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
2072
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2073
      command = "device_del %s\n" % kvm_devid
2074
      command += "drive_del %s" % kvm_devid
2075
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
2076
      command = "device_del %s\n" % kvm_devid
2077
      command += "netdev_del %s" % kvm_devid
2078
      utils.RemoveFile(self._InstanceNICFile(instance.name, seq))
2079
    self._CallHotplugCommand(instance.name, command)
2080
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2081
    runtime[index].remove(entry)
2082
    self._SaveKVMRuntime(instance, runtime)
2083

    
2084
    return kvm_device.pci
2085

    
2086
  def HotModDevice(self, instance, dev_type, device, _, seq):
2087
    """ Helper method for hot-mod device
2088

2089
    It gets device info from runtime file, generates the device name and
2090
    invokes the device specific method. Currently only NICs support hot-mod
2091

2092
    """
2093
    if dev_type == constants.HOTPLUG_TARGET_NIC:
2094
      # putting it back in the same pci slot
2095
      device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2096
      # TODO: remove sleep when socat gets removed
2097
      time.sleep(2)
2098
      self.HotAddDevice(instance, dev_type, device, _, seq)
2099

    
2100
  def _PassTapFd(self, instance, fd, nic):
2101
    """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2102

2103
    """
2104
    # TODO: factor out code related to unix sockets.
2105
    #       squash common parts between monitor and qmp
2106
    kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2107
    command = "getfd %s\n" % kvm_devid
2108
    fds = [fd]
2109
    logging.info("%s", fds)
2110
    try:
2111
      monsock = MonitorSocket(self._InstanceMonitor(instance.name))
2112
      monsock.connect()
2113
      fdsend.sendfds(monsock.sock, command, fds=fds)
2114
    finally:
2115
      monsock.close()
2116

    
2117
  @classmethod
2118
  def _ParseKVMVersion(cls, text):
2119
    """Parse the KVM version from the --help output.
2120

2121
    @type text: string
2122
    @param text: output of kvm --help
2123
    @return: (version, v_maj, v_min, v_rev)
2124
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2125

2126
    """
2127
    match = cls._VERSION_RE.search(text.splitlines()[0])
2128
    if not match:
2129
      raise errors.HypervisorError("Unable to get KVM version")
2130

    
2131
    v_all = match.group(0)
2132
    v_maj = int(match.group(1))
2133
    v_min = int(match.group(2))
2134
    if match.group(4):
2135
      v_rev = int(match.group(4))
2136
    else:
2137
      v_rev = 0
2138
    return (v_all, v_maj, v_min, v_rev)
2139

    
2140
  @classmethod
2141
  def _GetKVMOutput(cls, kvm_path, option):
2142
    """Return the output of a kvm invocation
2143

2144
    @type kvm_path: string
2145
    @param kvm_path: path to the kvm executable
2146
    @type option: a key of _KVMOPTS_CMDS
2147
    @param option: kvm option to fetch the output from
2148
    @return: output a supported kvm invocation
2149
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2150

2151
    """
2152
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2153

    
2154
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
2155

    
2156
    result = utils.RunCmd([kvm_path] + optlist)
2157
    if result.failed and not can_fail:
2158
      raise errors.HypervisorError("Unable to get KVM %s output" %
2159
                                    " ".join(optlist))
2160
    return result.output
2161

    
2162
  @classmethod
2163
  def _GetKVMVersion(cls, kvm_path):
2164
    """Return the installed KVM version.
2165

2166
    @return: (version, v_maj, v_min, v_rev)
2167
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2168

2169
    """
2170
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2171

    
2172
  @classmethod
2173
  def _GetDefaultMachineVersion(cls, kvm_path):
2174
    """Return the default hardware revision (e.g. pc-1.1)
2175

2176
    """
2177
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2178
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2179
    if match:
2180
      return match.group(1)
2181
    else:
2182
      return "pc"
2183

    
2184
  def StopInstance(self, instance, force=False, retry=False, name=None,
2185
                   timeout=None):
2186
    """Stop an instance.
2187

2188
    """
2189
    assert(timeout is None or force is not None)
2190

    
2191
    if name is not None and not force:
2192
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2193
    if name is None:
2194
      name = instance.name
2195
      acpi = instance.hvparams[constants.HV_ACPI]
2196
    else:
2197
      acpi = False
2198
    _, pid, alive = self._InstancePidAlive(name)
2199
    if pid > 0 and alive:
2200
      if force or not acpi:
2201
        utils.KillProcess(pid)
2202
      else:
2203
        self._CallMonitorCommand(name, "system_powerdown", timeout)
2204

    
2205
  def CleanupInstance(self, instance_name):
2206
    """Cleanup after a stopped instance
2207

2208
    """
2209
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
2210
    if pid > 0 and alive:
2211
      raise errors.HypervisorError("Cannot cleanup a live instance")
2212
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2213

    
2214
  def RebootInstance(self, instance):
2215
    """Reboot an instance.
2216

2217
    """
2218
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2219
    # socket the instance will stop, but now power up again. So we'll resort
2220
    # to shutdown and restart.
2221
    _, _, alive = self._InstancePidAlive(instance.name)
2222
    if not alive:
2223
      raise errors.HypervisorError("Failed to reboot instance %s:"
2224
                                   " not running" % instance.name)
2225
    # StopInstance will delete the saved KVM runtime so:
2226
    # ...first load it...
2227
    kvm_runtime = self._LoadKVMRuntime(instance)
2228
    # ...now we can safely call StopInstance...
2229
    if not self.StopInstance(instance):
2230
      self.StopInstance(instance, force=True)
2231
    # ...and finally we can save it again, and execute it...
2232
    self._SaveKVMRuntime(instance, kvm_runtime)
2233
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2234
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2235
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2236

    
2237
  def MigrationInfo(self, instance):
2238
    """Get instance information to perform a migration.
2239

2240
    @type instance: L{objects.Instance}
2241
    @param instance: instance to be migrated
2242
    @rtype: string
2243
    @return: content of the KVM runtime file
2244

2245
    """
2246
    return self._ReadKVMRuntime(instance.name)
2247

    
2248
  def AcceptInstance(self, instance, info, target):
2249
    """Prepare to accept an instance.
2250

2251
    @type instance: L{objects.Instance}
2252
    @param instance: instance to be accepted
2253
    @type info: string
2254
    @param info: content of the KVM runtime file on the source node
2255
    @type target: string
2256
    @param target: target host (usually ip), on this node
2257

2258
    """
2259
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2260
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2261
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2262
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2263
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2264
                            incoming=incoming_address)
2265

    
2266
  def FinalizeMigrationDst(self, instance, info, success):
2267
    """Finalize the instance migration on the target node.
2268

2269
    Stop the incoming mode KVM.
2270

2271
    @type instance: L{objects.Instance}
2272
    @param instance: instance whose migration is being finalized
2273

2274
    """
2275
    if success:
2276
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2277
      kvm_nics = kvm_runtime[1]
2278

    
2279
      for nic_seq, nic in enumerate(kvm_nics):
2280
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2281
          # Bridged interfaces have already been configured
2282
          continue
2283
        try:
2284
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2285
        except EnvironmentError, err:
2286
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
2287
                          instance.name, nic_seq, str(err))
2288
          continue
2289
        try:
2290
          self._ConfigureNIC(instance, nic_seq, nic, tap)
2291
        except errors.HypervisorError, err:
2292
          logging.warning(str(err))
2293

    
2294
      self._WriteKVMRuntime(instance.name, info)
2295
    else:
2296
      self.StopInstance(instance, force=True)
2297

    
2298
  def MigrateInstance(self, instance, target, live):
2299
    """Migrate an instance to a target node.
2300

2301
    The migration will not be attempted if the instance is not
2302
    currently running.
2303

2304
    @type instance: L{objects.Instance}
2305
    @param instance: the instance to be migrated
2306
    @type target: string
2307
    @param target: ip address of the target node
2308
    @type live: boolean
2309
    @param live: perform a live migration
2310

2311
    """
2312
    instance_name = instance.name
2313
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
2314
    _, _, alive = self._InstancePidAlive(instance_name)
2315
    if not alive:
2316
      raise errors.HypervisorError("Instance not running, cannot migrate")
2317

    
2318
    if not live:
2319
      self._CallMonitorCommand(instance_name, "stop")
2320

    
2321
    migrate_command = ("migrate_set_speed %dm" %
2322
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2323
    self._CallMonitorCommand(instance_name, migrate_command)
2324

    
2325
    migrate_command = ("migrate_set_downtime %dms" %
2326
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2327
    self._CallMonitorCommand(instance_name, migrate_command)
2328

    
2329
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2330
    self._CallMonitorCommand(instance_name, migrate_command)
2331

    
2332
  def FinalizeMigrationSource(self, instance, success, live):
2333
    """Finalize the instance migration on the source node.
2334

2335
    @type instance: L{objects.Instance}
2336
    @param instance: the instance that was migrated
2337
    @type success: bool
2338
    @param success: whether the migration succeeded or not
2339
    @type live: bool
2340
    @param live: whether the user requested a live migration or not
2341

2342
    """
2343
    if success:
2344
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2345
      utils.KillProcess(pid)
2346
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2347
    elif live:
2348
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2349

    
2350
  def GetMigrationStatus(self, instance):
2351
    """Get the migration status
2352

2353
    @type instance: L{objects.Instance}
2354
    @param instance: the instance that is being migrated
2355
    @rtype: L{objects.MigrationStatus}
2356
    @return: the status of the current migration (one of
2357
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2358
             progress info that can be retrieved from the hypervisor
2359

2360
    """
2361
    info_command = "info migrate"
2362
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2363
      result = self._CallMonitorCommand(instance.name, info_command)
2364
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
2365
      if not match:
2366
        if not result.stdout:
2367
          logging.info("KVM: empty 'info migrate' result")
2368
        else:
2369
          logging.warning("KVM: unknown 'info migrate' result: %s",
2370
                          result.stdout)
2371
      else:
2372
        status = match.group(1)
2373
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2374
          migration_status = objects.MigrationStatus(status=status)
2375
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2376
          if match:
2377
            migration_status.transferred_ram = match.group("transferred")
2378
            migration_status.total_ram = match.group("total")
2379

    
2380
          return migration_status
2381

    
2382
        logging.warning("KVM: unknown migration status '%s'", status)
2383

    
2384
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2385

    
2386
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2387

    
2388
  def BalloonInstanceMemory(self, instance, mem):
2389
    """Balloon an instance memory to a certain value.
2390

2391
    @type instance: L{objects.Instance}
2392
    @param instance: instance to be accepted
2393
    @type mem: int
2394
    @param mem: actual memory size to use for instance runtime
2395

2396
    """
2397
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2398

    
2399
  def GetNodeInfo(self):
2400
    """Return information about the node.
2401

2402
    @return: a dict with the following keys (values in MiB):
2403
          - memory_total: the total memory size on the node
2404
          - memory_free: the available memory on the node for instances
2405
          - memory_dom0: the memory used by the node itself, if available
2406
          - hv_version: the hypervisor version in the form (major, minor,
2407
                        revision)
2408

2409
    """
2410
    result = self.GetLinuxNodeInfo()
2411
    # FIXME: this is the global kvm version, but the actual version can be
2412
    # customized as an hv parameter. we should use the nodegroup's default kvm
2413
    # path parameter here.
2414
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2415
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2416
    return result
2417

    
2418
  @classmethod
2419
  def GetInstanceConsole(cls, instance, hvparams, beparams):
2420
    """Return a command for connecting to the console of an instance.
2421

2422
    """
2423
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2424
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2425
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2426
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2427
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2428
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2429
      return objects.InstanceConsole(instance=instance.name,
2430
                                     kind=constants.CONS_SSH,
2431
                                     host=instance.primary_node,
2432
                                     user=constants.SSH_CONSOLE_USER,
2433
                                     command=cmd)
2434

    
2435
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2436
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2437
      display = instance.network_port - constants.VNC_BASE_PORT
2438
      return objects.InstanceConsole(instance=instance.name,
2439
                                     kind=constants.CONS_VNC,
2440
                                     host=vnc_bind_address,
2441
                                     port=instance.network_port,
2442
                                     display=display)
2443

    
2444
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2445
    if spice_bind:
2446
      return objects.InstanceConsole(instance=instance.name,
2447
                                     kind=constants.CONS_SPICE,
2448
                                     host=spice_bind,
2449
                                     port=instance.network_port)
2450

    
2451
    return objects.InstanceConsole(instance=instance.name,
2452
                                   kind=constants.CONS_MESSAGE,
2453
                                   message=("No serial shell for instance %s" %
2454
                                            instance.name))
2455

    
2456
  def Verify(self):
2457
    """Verify the hypervisor.
2458

2459
    Check that the required binaries exist.
2460

2461
    @return: Problem description if something is wrong, C{None} otherwise
2462

2463
    """
2464
    msgs = []
2465
    # FIXME: this is the global kvm binary, but the actual path can be
2466
    # customized as an hv parameter; we should use the nodegroup's
2467
    # default kvm path parameter here.
2468
    if not os.path.exists(constants.KVM_PATH):
2469
      msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2470
    if not os.path.exists(constants.SOCAT_PATH):
2471
      msgs.append("The socat binary ('%s') does not exist" %
2472
                  constants.SOCAT_PATH)
2473

    
2474
    return self._FormatVerifyResults(msgs)
2475

    
2476
  @classmethod
2477
  def CheckParameterSyntax(cls, hvparams):
2478
    """Check the given parameters for validity.
2479

2480
    @type hvparams:  dict
2481
    @param hvparams: dictionary with parameter names/value
2482
    @raise errors.HypervisorError: when a parameter is not valid
2483

2484
    """
2485
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2486

    
2487
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2488
    if kernel_path:
2489
      if not hvparams[constants.HV_ROOT_PATH]:
2490
        raise errors.HypervisorError("Need a root partition for the instance,"
2491
                                     " if a kernel is defined")
2492

    
2493
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2494
        not hvparams[constants.HV_VNC_X509]):
2495
      raise errors.HypervisorError("%s must be defined, if %s is" %
2496
                                   (constants.HV_VNC_X509,
2497
                                    constants.HV_VNC_X509_VERIFY))
2498

    
2499
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2500
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2501
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2502
      if not serial_speed or serial_speed not in valid_speeds:
2503
        raise errors.HypervisorError("Invalid serial console speed, must be"
2504
                                     " one of: %s" %
2505
                                     utils.CommaJoin(valid_speeds))
2506

    
2507
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2508
    if (boot_order == constants.HT_BO_CDROM and
2509
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2510
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2511
                                   " ISO path")
2512

    
2513
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2514
    if security_model == constants.HT_SM_USER:
2515
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2516
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2517
                                     " must be specified")
2518
    elif (security_model == constants.HT_SM_NONE or
2519
          security_model == constants.HT_SM_POOL):
2520
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2521
        raise errors.HypervisorError("Cannot have a security domain when the"
2522
                                     " security model is 'none' or 'pool'")
2523

    
2524
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2525
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2526
    if spice_bind:
2527
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2528
        # if an IP version is specified, the spice_bind parameter must be an
2529
        # IP of that family
2530
        if (netutils.IP4Address.IsValid(spice_bind) and
2531
            spice_ip_version != constants.IP4_VERSION):
2532
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2533
                                       " the specified IP version is %s" %
2534
                                       (spice_bind, spice_ip_version))
2535

    
2536
        if (netutils.IP6Address.IsValid(spice_bind) and
2537
            spice_ip_version != constants.IP6_VERSION):
2538
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2539
                                       " the specified IP version is %s" %
2540
                                       (spice_bind, spice_ip_version))
2541
    else:
2542
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2543
      # error if any of them is set without it.
2544
      for param in _SPICE_ADDITIONAL_PARAMS:
2545
        if hvparams[param]:
2546
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2547
                                       (param, constants.HV_KVM_SPICE_BIND))
2548

    
2549
  @classmethod
2550
  def ValidateParameters(cls, hvparams):
2551
    """Check the given parameters for validity.
2552

2553
    @type hvparams:  dict
2554
    @param hvparams: dictionary with parameter names/value
2555
    @raise errors.HypervisorError: when a parameter is not valid
2556

2557
    """
2558
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2559

    
2560
    kvm_path = hvparams[constants.HV_KVM_PATH]
2561

    
2562
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2563
    if security_model == constants.HT_SM_USER:
2564
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2565
      try:
2566
        pwd.getpwnam(username)
2567
      except KeyError:
2568
        raise errors.HypervisorError("Unknown security domain user %s"
2569
                                     % username)
2570

    
2571
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2572
    if spice_bind:
2573
      # only one of VNC and SPICE can be used currently.
2574
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2575
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2576
                                     " only one of them can be used at a"
2577
                                     " given time")
2578

    
2579
      # check that KVM supports SPICE
2580
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2581
      if not cls._SPICE_RE.search(kvmhelp):
2582
        raise errors.HypervisorError("SPICE is configured, but it is not"
2583
                                     " supported according to 'kvm --help'")
2584

    
2585
      # if spice_bind is not an IP address, it must be a valid interface
2586
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2587
                       netutils.IP6Address.IsValid(spice_bind))
2588
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2589
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2590
                                     " a valid IP address or interface name" %
2591
                                     constants.HV_KVM_SPICE_BIND)
2592

    
2593
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2594
    if machine_version:
2595
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2596
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2597
        raise errors.HypervisorError("Unsupported machine version: %s" %
2598
                                     machine_version)
2599

    
2600
  @classmethod
2601
  def PowercycleNode(cls):
2602
    """KVM powercycle, just a wrapper over Linux powercycle.
2603

2604
    """
2605
    cls.LinuxPowercycle()