Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ c8cd2315

History | View | Annotate | Download (95.9 kB)

1
#
2
#
3

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

    
21

    
22
"""KVM hypervisor
23

24
"""
25

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

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

    
62

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

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

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

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

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

    
116

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

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

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

130
  """
131

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

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

    
138

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

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

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

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

    
161
  pci_reservations[free] = True
162

    
163

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

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

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

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

    
187
  return found[0]
188

    
189

    
190
def _AnalyzeSerializedRuntime(serialized_runtime):
191
  """Return runtime entries for a serialized runtime file
192

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

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

    
206
  kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
207
  block_devices = [(objects.Disk.FromDict(sdisk), link, uri)
208
                   for sdisk, link, uri in serialized_blockdevs]
209

    
210
  return (kvm_cmd, kvm_nics, hvparams, block_devices)
211

    
212

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

216
  @see: L{_ProbeTapVnetHdr}
217

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

    
229

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

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

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

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

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

    
253
  result = bool(flags & IFF_VNET_HDR)
254

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

    
258
  return result
259

    
260

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

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

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

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

    
278
  flags = IFF_TAP | IFF_NO_PI
279

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

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

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

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

    
296

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

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

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

    
308
    self.data = data
309

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

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

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

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

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

    
327
  def __len__(self):
328
    """Return the number of fields stored in this QmpMessage.
329

330
    """
331
    return len(self.data)
332

    
333
  def __delitem__(self, key):
334
    """Delete the specified element from the QmpMessage.
335

336
    """
337
    del(self.data[key])
338

    
339
  @staticmethod
340
  def BuildFromJsonString(json_string):
341
    """Build a QmpMessage from a JSON encoded string.
342

343
    @type json_string: str
344
    @param json_string: JSON string representing the message
345
    @rtype: L{QmpMessage}
346
    @return: a L{QmpMessage} built from json_string
347

348
    """
349
    # Parse the string
350
    data = serializer.LoadJson(json_string)
351
    return QmpMessage(data)
352

    
353
  def __str__(self):
354
    # The protocol expects the JSON object to be sent as a single line.
355
    return serializer.DumpJson(self.data)
356

    
357
  def __eq__(self, other):
358
    # When comparing two QmpMessages, we are interested in comparing
359
    # their internal representation of the message data
360
    return self.data == other.data
361

    
362

    
363
class MonitorSocket(object):
364
  _SOCKET_TIMEOUT = 5
365

    
366
  def __init__(self, monitor_filename):
367
    """Instantiates the MonitorSocket object.
368

369
    @type monitor_filename: string
370
    @param monitor_filename: the filename of the UNIX raw socket on which the
371
                             monitor (QMP or simple one) is listening
372

373
    """
374
    self.monitor_filename = monitor_filename
375
    self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
376
    # We want to fail if the server doesn't send a complete message
377
    # in a reasonable amount of time
378
    self.sock.settimeout(self._SOCKET_TIMEOUT)
379
    self._connected = False
380

    
381
  def _check_socket(self):
382
    sock_stat = None
383
    try:
384
      sock_stat = os.stat(self.monitor_filename)
385
    except EnvironmentError, err:
386
      if err.errno == errno.ENOENT:
387
        raise errors.HypervisorError("No monitor socket found")
388
      else:
389
        raise errors.HypervisorError("Error checking monitor socket: %s",
390
                                     utils.ErrnoOrStr(err))
391
    if not stat.S_ISSOCK(sock_stat.st_mode):
392
      raise errors.HypervisorError("Monitor socket is not a socket")
393

    
394
  def _check_connection(self):
395
    """Make sure that the connection is established.
396

397
    """
398
    if not self._connected:
399
      raise errors.ProgrammerError("To use a MonitorSocket you need to first"
400
                                   " invoke connect() on it")
401

    
402
  def connect(self):
403
    """Connects to the monitor.
404

405
    Connects to the UNIX socket
406

407
    @raise errors.HypervisorError: when there are communication errors
408

409
    """
410
    if self._connected:
411
      raise errors.ProgrammerError("Cannot connect twice")
412

    
413
    self._check_socket()
414

    
415
    # Check file existance/stuff
416
    try:
417
      self.sock.connect(self.monitor_filename)
418
    except EnvironmentError:
419
      raise errors.HypervisorError("Can't connect to qmp socket")
420
    self._connected = True
421

    
422
  def close(self):
423
    """Closes the socket
424

425
    It cannot be used after this call.
426

427
    """
428
    self.sock.close()
429

    
430

    
431
class QmpConnection(MonitorSocket):
432
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
433

434
  """
435
  _FIRST_MESSAGE_KEY = "QMP"
436
  _EVENT_KEY = "event"
437
  _ERROR_KEY = "error"
438
  _RETURN_KEY = RETURN_KEY = "return"
439
  _ACTUAL_KEY = ACTUAL_KEY = "actual"
440
  _ERROR_CLASS_KEY = "class"
441
  _ERROR_DATA_KEY = "data"
442
  _ERROR_DESC_KEY = "desc"
443
  _EXECUTE_KEY = "execute"
444
  _ARGUMENTS_KEY = "arguments"
445
  _CAPABILITIES_COMMAND = "qmp_capabilities"
446
  _MESSAGE_END_TOKEN = "\r\n"
447

    
448
  def __init__(self, monitor_filename):
449
    super(QmpConnection, self).__init__(monitor_filename)
450
    self._buf = ""
451

    
452
  def connect(self):
453
    """Connects to the QMP monitor.
454

455
    Connects to the UNIX socket and makes sure that we can actually send and
456
    receive data to the kvm instance via QMP.
457

458
    @raise errors.HypervisorError: when there are communication errors
459
    @raise errors.ProgrammerError: when there are data serialization errors
460

461
    """
462
    super(QmpConnection, self).connect()
463
    # Check if we receive a correct greeting message from the server
464
    # (As per the QEMU Protocol Specification 0.1 - section 2.2)
465
    greeting = self._Recv()
466
    if not greeting[self._FIRST_MESSAGE_KEY]:
467
      self._connected = False
468
      raise errors.HypervisorError("kvm: QMP communication error (wrong"
469
                                   " server greeting")
470

    
471
    # Let's put the monitor in command mode using the qmp_capabilities
472
    # command, or else no command will be executable.
473
    # (As per the QEMU Protocol Specification 0.1 - section 4)
474
    self.Execute(self._CAPABILITIES_COMMAND)
475

    
476
  def _ParseMessage(self, buf):
477
    """Extract and parse a QMP message from the given buffer.
478

479
    Seeks for a QMP message in the given buf. If found, it parses it and
480
    returns it together with the rest of the characters in the buf.
481
    If no message is found, returns None and the whole buffer.
482

483
    @raise errors.ProgrammerError: when there are data serialization errors
484

485
    """
486
    message = None
487
    # Check if we got the message end token (CRLF, as per the QEMU Protocol
488
    # Specification 0.1 - Section 2.1.1)
489
    pos = buf.find(self._MESSAGE_END_TOKEN)
490
    if pos >= 0:
491
      try:
492
        message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
493
      except Exception, err:
494
        raise errors.ProgrammerError("QMP data serialization error: %s" % err)
495
      buf = buf[pos + 1:]
496

    
497
    return (message, buf)
498

    
499
  def _Recv(self):
500
    """Receives a message from QMP and decodes the received JSON object.
501

502
    @rtype: QmpMessage
503
    @return: the received message
504
    @raise errors.HypervisorError: when there are communication errors
505
    @raise errors.ProgrammerError: when there are data serialization errors
506

507
    """
508
    self._check_connection()
509

    
510
    # Check if there is already a message in the buffer
511
    (message, self._buf) = self._ParseMessage(self._buf)
512
    if message:
513
      return message
514

    
515
    recv_buffer = StringIO.StringIO(self._buf)
516
    recv_buffer.seek(len(self._buf))
517
    try:
518
      while True:
519
        data = self.sock.recv(4096)
520
        if not data:
521
          break
522
        recv_buffer.write(data)
523

    
524
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
525
        if message:
526
          return message
527

    
528
    except socket.timeout, err:
529
      raise errors.HypervisorError("Timeout while receiving a QMP message: "
530
                                   "%s" % (err))
531
    except socket.error, err:
532
      raise errors.HypervisorError("Unable to receive data from KVM using the"
533
                                   " QMP protocol: %s" % err)
534

    
535
  def _Send(self, message):
536
    """Encodes and sends a message to KVM using QMP.
537

538
    @type message: QmpMessage
539
    @param message: message to send to KVM
540
    @raise errors.HypervisorError: when there are communication errors
541
    @raise errors.ProgrammerError: when there are data serialization errors
542

543
    """
544
    self._check_connection()
545
    try:
546
      message_str = str(message)
547
    except Exception, err:
548
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
549

    
550
    try:
551
      self.sock.sendall(message_str)
552
    except socket.timeout, err:
553
      raise errors.HypervisorError("Timeout while sending a QMP message: "
554
                                   "%s (%s)" % (err.string, err.errno))
555
    except socket.error, err:
556
      raise errors.HypervisorError("Unable to send data from KVM using the"
557
                                   " QMP protocol: %s" % err)
558

    
559
  def Execute(self, command, arguments=None):
560
    """Executes a QMP command and returns the response of the server.
561

562
    @type command: str
563
    @param command: the command to execute
564
    @type arguments: dict
565
    @param arguments: dictionary of arguments to be passed to the command
566
    @rtype: dict
567
    @return: dictionary representing the received JSON object
568
    @raise errors.HypervisorError: when there are communication errors
569
    @raise errors.ProgrammerError: when there are data serialization errors
570

571
    """
572
    self._check_connection()
573
    message = QmpMessage({self._EXECUTE_KEY: command})
574
    if arguments:
575
      message[self._ARGUMENTS_KEY] = arguments
576
    self._Send(message)
577

    
578
    # Events can occur between the sending of the command and the reception
579
    # of the response, so we need to filter out messages with the event key.
580
    while True:
581
      response = self._Recv()
582
      err = response[self._ERROR_KEY]
583
      if err:
584
        raise errors.HypervisorError("kvm: error executing the %s"
585
                                     " command: %s (%s, %s):" %
586
                                     (command,
587
                                      err[self._ERROR_DESC_KEY],
588
                                      err[self._ERROR_CLASS_KEY],
589
                                      err[self._ERROR_DATA_KEY]))
590

    
591
      elif not response[self._EVENT_KEY]:
592
        return response
593

    
594

    
595
class KVMHypervisor(hv_base.BaseHypervisor):
596
  """KVM hypervisor interface
597

598
  """
599
  CAN_MIGRATE = True
600

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

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

    
700
  _VIRTIO = "virtio"
701
  _VIRTIO_NET_PCI = "virtio-net-pci"
702
  _VIRTIO_BLK_PCI = "virtio-blk-pci"
703

    
704
  _MIGRATION_STATUS_RE = re.compile(r"Migration\s+status:\s+(\w+)",
705
                                    re.M | re.I)
706
  _MIGRATION_PROGRESS_RE = \
707
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
708
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
709
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
710

    
711
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
712
  _MIGRATION_INFO_RETRY_DELAY = 2
713

    
714
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
715

    
716
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
717
  _CPU_INFO_CMD = "info cpus"
718
  _CONT_CMD = "cont"
719

    
720
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
721
  _CHECK_MACHINE_VERSION_RE = \
722
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
723

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

    
740
  _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
741
  _INFO_PCI_CMD = "info pci"
742
  _INFO_VERSION_RE = \
743
    re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
744
  _INFO_VERSION_CMD = "info version"
745

    
746
  _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
747

    
748
  ANCILLARY_FILES = [
749
    _KVM_NETWORK_SCRIPT,
750
    ]
751
  ANCILLARY_FILES_OPT = [
752
    _KVM_NETWORK_SCRIPT,
753
    ]
754

    
755
  # Supported kvm options to get output from
756
  _KVMOPT_HELP = "help"
757
  _KVMOPT_MLIST = "mlist"
758
  _KVMOPT_DEVICELIST = "devicelist"
759

    
760
  # Command to execute to get the output from kvm, and whether to
761
  # accept the output even on failure.
762
  _KVMOPTS_CMDS = {
763
    _KVMOPT_HELP: (["--help"], False),
764
    _KVMOPT_MLIST: (["-M", "?"], False),
765
    _KVMOPT_DEVICELIST: (["-device", "?"], True),
766
  }
767

    
768
  def __init__(self):
769
    hv_base.BaseHypervisor.__init__(self)
770
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
771
    # in a tmpfs filesystem or has been otherwise wiped out.
772
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
773
    utils.EnsureDirs(dirs)
774

    
775
  @classmethod
776
  def _InstancePidFile(cls, instance_name):
777
    """Returns the instance pidfile.
778

779
    """
780
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
781

    
782
  @classmethod
783
  def _InstanceUidFile(cls, instance_name):
784
    """Returns the instance uidfile.
785

786
    """
787
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
788

    
789
  @classmethod
790
  def _InstancePidInfo(cls, pid):
791
    """Check pid file for instance information.
792

793
    Check that a pid file is associated with an instance, and retrieve
794
    information from its command line.
795

796
    @type pid: string or int
797
    @param pid: process id of the instance to check
798
    @rtype: tuple
799
    @return: (instance_name, memory, vcpus)
800
    @raise errors.HypervisorError: when an instance cannot be found
801

802
    """
803
    alive = utils.IsProcessAlive(pid)
804
    if not alive:
805
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
806

    
807
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
808
    try:
809
      cmdline = utils.ReadFile(cmdline_file)
810
    except EnvironmentError, err:
811
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
812
                                   (pid, err))
813

    
814
    instance = None
815
    memory = 0
816
    vcpus = 0
817

    
818
    arg_list = cmdline.split("\x00")
819
    while arg_list:
820
      arg = arg_list.pop(0)
821
      if arg == "-name":
822
        instance = arg_list.pop(0)
823
      elif arg == "-m":
824
        memory = int(arg_list.pop(0))
825
      elif arg == "-smp":
826
        vcpus = int(arg_list.pop(0).split(",")[0])
827

    
828
    if instance is None:
829
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
830
                                   " instance" % pid)
831

    
832
    return (instance, memory, vcpus)
833

    
834
  def _InstancePidAlive(self, instance_name):
835
    """Returns the instance pidfile, pid, and liveness.
836

837
    @type instance_name: string
838
    @param instance_name: instance name
839
    @rtype: tuple
840
    @return: (pid file name, pid, liveness)
841

842
    """
843
    pidfile = self._InstancePidFile(instance_name)
844
    pid = utils.ReadPidFile(pidfile)
845

    
846
    alive = False
847
    try:
848
      cmd_instance = self._InstancePidInfo(pid)[0]
849
      alive = (cmd_instance == instance_name)
850
    except errors.HypervisorError:
851
      pass
852

    
853
    return (pidfile, pid, alive)
854

    
855
  def _CheckDown(self, instance_name):
856
    """Raises an error unless the given instance is down.
857

858
    """
859
    alive = self._InstancePidAlive(instance_name)[2]
860
    if alive:
861
      raise errors.HypervisorError("Failed to start instance %s: %s" %
862
                                   (instance_name, "already running"))
863

    
864
  @classmethod
865
  def _InstanceMonitor(cls, instance_name):
866
    """Returns the instance monitor socket name
867

868
    """
869
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
870

    
871
  @classmethod
872
  def _InstanceSerial(cls, instance_name):
873
    """Returns the instance serial socket name
874

875
    """
876
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
877

    
878
  @classmethod
879
  def _InstanceQmpMonitor(cls, instance_name):
880
    """Returns the instance serial QMP socket name
881

882
    """
883
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
884

    
885
  @staticmethod
886
  def _SocatUnixConsoleParams():
887
    """Returns the correct parameters for socat
888

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

891
    """
892
    if constants.SOCAT_USE_ESCAPE:
893
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
894
    else:
895
      return "echo=0,icanon=0"
896

    
897
  @classmethod
898
  def _InstanceKVMRuntime(cls, instance_name):
899
    """Returns the instance KVM runtime filename
900

901
    """
902
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
903

    
904
  @classmethod
905
  def _InstanceChrootDir(cls, instance_name):
906
    """Returns the name of the KVM chroot dir of the instance
907

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

    
911
  @classmethod
912
  def _InstanceNICDir(cls, instance_name):
913
    """Returns the name of the directory holding the tap device files for a
914
    given instance.
915

916
    """
917
    return utils.PathJoin(cls._NICS_DIR, instance_name)
918

    
919
  @classmethod
920
  def _InstanceNICFile(cls, instance_name, seq):
921
    """Returns the name of the file containing the tap device for a given NIC
922

923
    """
924
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
925

    
926
  @classmethod
927
  def _InstanceKeymapFile(cls, instance_name):
928
    """Returns the name of the file containing the keymap for a given instance
929

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

    
933
  @classmethod
934
  def _TryReadUidFile(cls, uid_file):
935
    """Try to read a uid file
936

937
    """
938
    if os.path.exists(uid_file):
939
      try:
940
        uid = int(utils.ReadOneLineFile(uid_file))
941
        return uid
942
      except EnvironmentError:
943
        logging.warning("Can't read uid file", exc_info=True)
944
      except (TypeError, ValueError):
945
        logging.warning("Can't parse uid file contents", exc_info=True)
946
    return None
947

    
948
  @classmethod
949
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
950
    """Removes an instance's rutime sockets/files/dirs.
951

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

    
988
  @staticmethod
989
  def _ConfigureNIC(instance, seq, nic, tap):
990
    """Run the network configuration script for a specified NIC
991

992
    @param instance: instance we're acting on
993
    @type instance: instance object
994
    @param seq: nic sequence number
995
    @type seq: int
996
    @param nic: nic we're acting on
997
    @type nic: nic object
998
    @param tap: the host's tap interface this NIC corresponds to
999
    @type tap: str
1000

1001
    """
1002
    if instance.tags:
1003
      tags = " ".join(instance.tags)
1004
    else:
1005
      tags = ""
1006

    
1007
    env = {
1008
      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
1009
      "INSTANCE": instance.name,
1010
      "MAC": nic.mac,
1011
      "MODE": nic.nicparams[constants.NIC_MODE],
1012
      "INTERFACE": tap,
1013
      "INTERFACE_INDEX": str(seq),
1014
      "TAGS": tags,
1015
    }
1016

    
1017
    if nic.ip:
1018
      env["IP"] = nic.ip
1019

    
1020
    if nic.nicparams[constants.NIC_LINK]:
1021
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
1022

    
1023
    if nic.network:
1024
      n = objects.Network.FromDict(nic.netinfo)
1025
      env.update(n.HooksDict())
1026

    
1027
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1028
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
1029

    
1030
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
1031
    if result.failed:
1032
      raise errors.HypervisorError("Failed to configure interface %s: %s;"
1033
                                   " network configuration script output: %s" %
1034
                                   (tap, result.fail_reason, result.output))
1035

    
1036
  @staticmethod
1037
  def _VerifyAffinityPackage():
1038
    if affinity is None:
1039
      raise errors.HypervisorError("affinity Python package not"
1040
                                   " found; cannot use CPU pinning under KVM")
1041

    
1042
  @staticmethod
1043
  def _BuildAffinityCpuMask(cpu_list):
1044
    """Create a CPU mask suitable for sched_setaffinity from a list of
1045
    CPUs.
1046

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

1050
    @type cpu_list: list of int
1051
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
1052
    @rtype: int
1053
    @return: a bit mask of CPU affinities
1054

1055
    """
1056
    if cpu_list == constants.CPU_PINNING_OFF:
1057
      return constants.CPU_PINNING_ALL_KVM
1058
    else:
1059
      return sum(2 ** cpu for cpu in cpu_list)
1060

    
1061
  @classmethod
1062
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
1063
    """Change CPU affinity for running VM according to given CPU mask.
1064

1065
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
1066
    @type cpu_mask: string
1067
    @param process_id: process ID of KVM process. Used to pin entire VM
1068
                       to physical CPUs.
1069
    @type process_id: int
1070
    @param thread_dict: map of virtual CPUs to KVM thread IDs
1071
    @type thread_dict: dict int:int
1072

1073
    """
1074
    # Convert the string CPU mask to a list of list of int's
1075
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
1076

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

    
1095
      # For each vCPU, map it to the proper list of physical CPUs
1096
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1097
        affinity.set_process_affinity_mask(thread_dict[i],
1098
                                           cls._BuildAffinityCpuMask(vcpu))
1099

    
1100
  def _GetVcpuThreadIds(self, instance_name):
1101
    """Get a mapping of vCPU no. to thread IDs for the instance
1102

1103
    @type instance_name: string
1104
    @param instance_name: instance in question
1105
    @rtype: dictionary of int:int
1106
    @return: a dictionary mapping vCPU numbers to thread IDs
1107

1108
    """
1109
    result = {}
1110
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1111
    for line in output.stdout.splitlines():
1112
      match = self._CPU_INFO_RE.search(line)
1113
      if not match:
1114
        continue
1115
      grp = map(int, match.groups())
1116
      result[grp[0]] = grp[1]
1117

    
1118
    return result
1119

    
1120
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1121
    """Complete CPU pinning.
1122

1123
    @type instance_name: string
1124
    @param instance_name: name of instance
1125
    @type cpu_mask: string
1126
    @param cpu_mask: CPU pinning mask as entered by user
1127

1128
    """
1129
    # Get KVM process ID, to be used if need to pin entire VM
1130
    _, pid, _ = self._InstancePidAlive(instance_name)
1131
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1132
    thread_dict = self._GetVcpuThreadIds(instance_name)
1133
    # Run CPU pinning, based on configured mask
1134
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1135

    
1136
  def ListInstances(self, hvparams=None):
1137
    """Get the list of running instances.
1138

1139
    We can do this by listing our live instances directory and
1140
    checking whether the associated kvm process is still alive.
1141

1142
    """
1143
    result = []
1144
    for name in os.listdir(self._PIDS_DIR):
1145
      if self._InstancePidAlive(name)[2]:
1146
        result.append(name)
1147
    return result
1148

    
1149
  def GetInstanceInfo(self, instance_name, hvparams=None):
1150
    """Get instance properties.
1151

1152
    @type instance_name: string
1153
    @param instance_name: the instance name
1154
    @type hvparams: dict of strings
1155
    @param hvparams: hvparams to be used with this instance
1156
    @rtype: tuple of strings
1157
    @return: (name, id, memory, vcpus, stat, times)
1158

1159
    """
1160
    _, pid, alive = self._InstancePidAlive(instance_name)
1161
    if not alive:
1162
      return None
1163

    
1164
    _, memory, vcpus = self._InstancePidInfo(pid)
1165
    istat = "---b-"
1166
    times = "0"
1167

    
1168
    try:
1169
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1170
      qmp.connect()
1171
      vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1172
      # Will fail if ballooning is not enabled, but we can then just resort to
1173
      # the value above.
1174
      mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1175
      memory = mem_bytes / 1048576
1176
    except errors.HypervisorError:
1177
      pass
1178

    
1179
    return (instance_name, pid, memory, vcpus, istat, times)
1180

    
1181
  def GetAllInstancesInfo(self, hvparams=None):
1182
    """Get properties of all instances.
1183

1184
    @type hvparams: dict of strings
1185
    @param hvparams: hypervisor parameter
1186
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1187

1188
    """
1189
    data = []
1190
    for name in os.listdir(self._PIDS_DIR):
1191
      try:
1192
        info = self.GetInstanceInfo(name)
1193
      except errors.HypervisorError:
1194
        # Ignore exceptions due to instances being shut down
1195
        continue
1196
      if info:
1197
        data.append(info)
1198
    return data
1199

    
1200
  def _GenerateKVMBlockDevicesOptions(self, instance, block_devices,
1201
                                      kvmhelp, devlist):
1202
    """Generate KVM options regarding instance's block devices.
1203

1204
    @type instance: L{objects.Instance}
1205
    @param instance: the instance object
1206
    @type block_devices: list of tuples
1207
    @param block_devices: list of tuples [(disk, link_name, uri)..]
1208
    @type kvmhelp: string
1209
    @param kvmhelp: output of kvm --help
1210
    @type devlist: string
1211
    @param devlist: output of kvm -device ?
1212
    @rtype: list
1213
    @return: list of command line options eventually used by kvm executable
1214

1215
    """
1216
    hvp = instance.hvparams
1217
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1218
    if kernel_path:
1219
      boot_disk = False
1220
    else:
1221
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1222
    kvm_path = hvp[constants.HV_KVM_PATH]
1223

    
1224
    # whether this is an older KVM version that uses the boot=on flag
1225
    # on devices
1226
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1227

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

    
1267
      access_mode = cfdev.params.get(constants.LDP_ACCESS,
1268
                                     constants.DISK_KERNELSPACE)
1269
      if (uri and access_mode == constants.DISK_USERSPACE):
1270
        drive_uri = uri
1271
      else:
1272
        drive_uri = link_name
1273

    
1274
      drive_val = "file=%s,format=raw%s%s%s" % \
1275
                  (drive_uri, if_val, boot_val, cache_val)
1276

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

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

    
1291
    return dev_opts
1292

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

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

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

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

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

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

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

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

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

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

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

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

    
1377
    disk_type = hvp[constants.HV_DISK_TYPE]
1378

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

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

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

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

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

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

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

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

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

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

    
1464
    if vnc_bind_address:
1465
      if netutils.IsValidInterface(vnc_bind_address):
1466
        if_addresses = netutils.GetInterfaceIpAddresses(vnc_bind_address)
1467
        if_ip4_addresses = if_addresses[constants.IP4_VERSION]
1468
        if len(if_ip4_addresses) < 1:
1469
          logging.error("Could not determine IPv4 address of interface %s",
1470
                        vnc_bind_address)
1471
        else:
1472
          vnc_bind_address = if_ip4_addresses[0]
1473
      if netutils.IP4Address.IsValid(vnc_bind_address):
1474
        if instance.network_port > constants.VNC_BASE_PORT:
1475
          display = instance.network_port - constants.VNC_BASE_PORT
1476
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1477
            vnc_arg = ":%d" % (display)
1478
          else:
1479
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1480
        else:
1481
          logging.error("Network port is not a valid VNC display (%d < %d),"
1482
                        " not starting VNC",
1483
                        instance.network_port, constants.VNC_BASE_PORT)
1484
          vnc_arg = "none"
1485

    
1486
        # Only allow tls and other option when not binding to a file, for now.
1487
        # kvm/qemu gets confused otherwise about the filename to use.
1488
        vnc_append = ""
1489
        if hvp[constants.HV_VNC_TLS]:
1490
          vnc_append = "%s,tls" % vnc_append
1491
          if hvp[constants.HV_VNC_X509_VERIFY]:
1492
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1493
                                               hvp[constants.HV_VNC_X509])
1494
          elif hvp[constants.HV_VNC_X509]:
1495
            vnc_append = "%s,x509=%s" % (vnc_append,
1496
                                         hvp[constants.HV_VNC_X509])
1497
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1498
          vnc_append = "%s,password" % vnc_append
1499

    
1500
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1501

    
1502
      else:
1503
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1504

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

    
1515
        # if the user specified an IP version and the interface does not
1516
        # have that kind of IP addresses, throw an exception
1517
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1518
          if not addresses[spice_ip_version]:
1519
            raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1520
                                         " for %s" % (spice_ip_version,
1521
                                                      spice_bind))
1522

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

    
1539
        spice_address = addresses[spice_ip_version][0]
1540

    
1541
      else:
1542
        # spice_bind is known to be a valid IP address, because
1543
        # ValidateParameters checked it.
1544
        spice_address = spice_bind
1545

    
1546
      spice_arg = "addr=%s" % spice_address
1547
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1548
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1549
                     (spice_arg, instance.network_port,
1550
                      pathutils.SPICE_CACERT_FILE))
1551
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1552
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1553
                      pathutils.SPICE_CERT_FILE))
1554
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1555
        if tls_ciphers:
1556
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1557
      else:
1558
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1559

    
1560
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1561
        spice_arg = "%s,disable-ticketing" % spice_arg
1562

    
1563
      if spice_ip_version:
1564
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1565

    
1566
      # Image compression options
1567
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1568
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1569
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1570
      if img_lossless:
1571
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1572
      if img_jpeg:
1573
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1574
      if img_zlib_glz:
1575
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1576

    
1577
      # Video stream detection
1578
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1579
      if video_streaming:
1580
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1581

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

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

    
1600
    else:
1601
      # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1602
      # also works in earlier versions though (tested with 1.1 and 1.3)
1603
      if self._DISPLAY_RE.search(kvmhelp):
1604
        kvm_cmd.extend(["-display", "none"])
1605
      else:
1606
        kvm_cmd.extend(["-nographic"])
1607

    
1608
    if hvp[constants.HV_USE_LOCALTIME]:
1609
      kvm_cmd.extend(["-localtime"])
1610

    
1611
    if hvp[constants.HV_KVM_USE_CHROOT]:
1612
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1613

    
1614
    # Add qemu-KVM -cpu param
1615
    if hvp[constants.HV_CPU_TYPE]:
1616
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1617

    
1618
    # As requested by music lovers
1619
    if hvp[constants.HV_SOUNDHW]:
1620
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1621

    
1622
    # Pass a -vga option if requested, or if spice is used, for backwards
1623
    # compatibility.
1624
    if hvp[constants.HV_VGA]:
1625
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1626
    elif spice_bind:
1627
      kvm_cmd.extend(["-vga", "qxl"])
1628

    
1629
    # Various types of usb devices, comma separated
1630
    if hvp[constants.HV_USB_DEVICES]:
1631
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1632
        kvm_cmd.extend(["-usbdevice", dev])
1633

    
1634
    # Set system UUID to instance UUID
1635
    if self._UUID_RE.search(kvmhelp):
1636
      kvm_cmd.extend(["-uuid", instance.uuid])
1637

    
1638
    if hvp[constants.HV_KVM_EXTRA]:
1639
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1640

    
1641
    pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1642
    kvm_disks = []
1643
    for disk, link_name, uri in block_devices:
1644
      _UpdatePCISlots(disk, pci_reservations)
1645
      kvm_disks.append((disk, link_name, uri))
1646

    
1647
    kvm_nics = []
1648
    for nic in instance.nics:
1649
      _UpdatePCISlots(nic, pci_reservations)
1650
      kvm_nics.append(nic)
1651

    
1652
    hvparams = hvp
1653

    
1654
    return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1655

    
1656
  def _WriteKVMRuntime(self, instance_name, data):
1657
    """Write an instance's KVM runtime
1658

1659
    """
1660
    try:
1661
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1662
                      data=data)
1663
    except EnvironmentError, err:
1664
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1665

    
1666
  def _ReadKVMRuntime(self, instance_name):
1667
    """Read an instance's KVM runtime
1668

1669
    """
1670
    try:
1671
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1672
    except EnvironmentError, err:
1673
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1674
    return file_content
1675

    
1676
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1677
    """Save an instance's KVM runtime
1678

1679
    """
1680
    kvm_cmd, kvm_nics, hvparams, block_devices = kvm_runtime
1681

    
1682
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1683
    serialized_blockdevs = [(blk.ToDict(), link, uri)
1684
                            for blk, link, uri in block_devices]
1685
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1686
                                      serialized_blockdevs))
1687

    
1688
    self._WriteKVMRuntime(instance.name, serialized_form)
1689

    
1690
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1691
    """Load an instance's KVM runtime
1692

1693
    """
1694
    if not serialized_runtime:
1695
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1696

    
1697
    return _AnalyzeSerializedRuntime(serialized_runtime)
1698

    
1699
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1700
    """Run the KVM cmd and check for errors
1701

1702
    @type name: string
1703
    @param name: instance name
1704
    @type kvm_cmd: list of strings
1705
    @param kvm_cmd: runcmd input for kvm
1706
    @type tap_fds: list of int
1707
    @param tap_fds: fds of tap devices opened by Ganeti
1708

1709
    """
1710
    try:
1711
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1712
    finally:
1713
      for fd in tap_fds:
1714
        utils_wrapper.CloseFdNoError(fd)
1715

    
1716
    if result.failed:
1717
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1718
                                   (name, result.fail_reason, result.output))
1719
    if not self._InstancePidAlive(name)[2]:
1720
      raise errors.HypervisorError("Failed to start instance %s" % name)
1721

    
1722
  # 52/50 local variables
1723
  # pylint: disable=R0914
1724
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1725
    """Execute a KVM cmd, after completing it with some last minute data.
1726

1727
    @type incoming: tuple of strings
1728
    @param incoming: (target_host_ip, port)
1729
    @type kvmhelp: string
1730
    @param kvmhelp: output of kvm --help
1731

1732
    """
1733
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1734
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1735
    #    have changed since the instance started; only use them if the change
1736
    #    won't affect the inside of the instance (which hasn't been rebooted).
1737
    #  - up_hvp contains the parameters as they were when the instance was
1738
    #    started, plus any new parameter which has been added between ganeti
1739
    #    versions: it is paramount that those default to a value which won't
1740
    #    affect the inside of the instance as well.
1741
    conf_hvp = instance.hvparams
1742
    name = instance.name
1743
    self._CheckDown(name)
1744

    
1745
    temp_files = []
1746

    
1747
    kvm_cmd, kvm_nics, up_hvp, block_devices = kvm_runtime
1748
    # the first element of kvm_cmd is always the path to the kvm binary
1749
    kvm_path = kvm_cmd[0]
1750
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1751

    
1752
    # We know it's safe to run as a different user upon migration, so we'll use
1753
    # the latest conf, from conf_hvp.
1754
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1755
    if security_model == constants.HT_SM_USER:
1756
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1757

    
1758
    keymap = conf_hvp[constants.HV_KEYMAP]
1759
    if keymap:
1760
      keymap_path = self._InstanceKeymapFile(name)
1761
      # If a keymap file is specified, KVM won't use its internal defaults. By
1762
      # first including the "en-us" layout, an error on loading the actual
1763
      # layout (e.g. because it can't be found) won't lead to a non-functional
1764
      # keyboard. A keyboard with incorrect keys is still better than none.
1765
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1766
      kvm_cmd.extend(["-k", keymap_path])
1767

    
1768
    # We have reasons to believe changing something like the nic driver/type
1769
    # upon migration won't exactly fly with the instance kernel, so for nic
1770
    # related parameters we'll use up_hvp
1771
    tapfds = []
1772
    taps = []
1773
    devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1774
    if not kvm_nics:
1775
      kvm_cmd.extend(["-net", "none"])
1776
    else:
1777
      vnet_hdr = False
1778
      tap_extra = ""
1779
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1780
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1781
        nic_model = self._VIRTIO
1782
        try:
1783
          if self._VIRTIO_NET_RE.search(devlist):
1784
            nic_model = self._VIRTIO_NET_PCI
1785
            vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1786
        except errors.HypervisorError, _:
1787
          # Older versions of kvm don't support DEVICE_LIST, but they don't
1788
          # have new virtio syntax either.
1789
          pass
1790

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

    
1801
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1802

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

    
1827
    if incoming:
1828
      target, port = incoming
1829
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1830

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

    
1843
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1844
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1845
                         constants.SECURE_DIR_MODE)])
1846

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

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

    
1861
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1862
                                                     block_devices,
1863
                                                     kvmhelp,
1864
                                                     devlist)
1865
    kvm_cmd.extend(bdev_opts)
1866
    # CPU affinity requires kvm to start paused, so we set this flag if the
1867
    # instance is not already paused and if we are not going to accept a
1868
    # migrating instance. In the latter case, pausing is not needed.
1869
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1870
    if start_kvm_paused:
1871
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1872

    
1873
    # Note: CPU pinning is using up_hvp since changes take effect
1874
    # during instance startup anyway, and to avoid problems when soft
1875
    # rebooting the instance.
1876
    cpu_pinning = False
1877
    if up_hvp.get(constants.HV_CPU_MASK, None):
1878
      cpu_pinning = True
1879

    
1880
    if security_model == constants.HT_SM_POOL:
1881
      ss = ssconf.SimpleStore()
1882
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1883
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1884
      uid = uidpool.RequestUnusedUid(all_uids)
1885
      try:
1886
        username = pwd.getpwuid(uid.GetUid()).pw_name
1887
        kvm_cmd.extend(["-runas", username])
1888
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1889
      except:
1890
        uidpool.ReleaseUid(uid)
1891
        raise
1892
      else:
1893
        uid.Unlock()
1894
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1895
    else:
1896
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1897

    
1898
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1899
                     constants.RUN_DIRS_MODE)])
1900
    for nic_seq, tap in enumerate(taps):
1901
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1902
                      data=tap)
1903

    
1904
    if vnc_pwd:
1905
      change_cmd = "change vnc password %s" % vnc_pwd
1906
      self._CallMonitorCommand(instance.name, change_cmd)
1907

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

    
1922
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1923
      qmp.connect()
1924
      arguments = {
1925
          "protocol": "spice",
1926
          "password": spice_pwd,
1927
      }
1928
      qmp.Execute("set_password", arguments)
1929

    
1930
    for filename in temp_files:
1931
      utils.RemoveFile(filename)
1932

    
1933
    # If requested, set CPU affinity and resume instance execution
1934
    if cpu_pinning:
1935
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1936

    
1937
    start_memory = self._InstanceStartupMemory(instance)
1938
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1939
      self.BalloonInstanceMemory(instance, start_memory)
1940

    
1941
    if start_kvm_paused:
1942
      # To control CPU pinning, ballooning, and vnc/spice passwords
1943
      # the VM was started in a frozen state. If freezing was not
1944
      # explicitly requested resume the vm status.
1945
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1946

    
1947
  def StartInstance(self, instance, block_devices, startup_paused):
1948
    """Start an instance.
1949

1950
    """
1951
    self._CheckDown(instance.name)
1952
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1953
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1954
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1955
                                           startup_paused, kvmhelp)
1956
    self._SaveKVMRuntime(instance, kvm_runtime)
1957
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1958

    
1959
  def _CallMonitorCommand(self, instance_name, command):
1960
    """Invoke a command on the instance monitor.
1961

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

    
1981
    return result
1982

    
1983
  def _GetFreePCISlot(self, instance, dev):
1984
    """Get the first available pci slot of a runnung instance.
1985

1986
    """
1987
    slots = bitarray(32)
1988
    slots.setall(False) # pylint: disable=E1101
1989
    output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
1990
    for line in output.stdout.splitlines():
1991
      match = self._INFO_PCI_RE.search(line)
1992
      if match:
1993
        slot = int(match.group(1))
1994
        slots[slot] = True
1995

    
1996
    [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
1997
    if not free:
1998
      raise errors.HypervisorError("All PCI slots occupied")
1999

    
2000
    dev.pci = int(free)
2001

    
2002
  def HotplugSupported(self, instance, action, dev_type):
2003
    """Check if hotplug is supported.
2004

2005
    Hotplug is *not* supported in case of:
2006
     - qemu versions < 1.0
2007
     - security models and chroot (disk hotplug)
2008
     - fdsend module is missing (nic hot-add)
2009

2010
    @raise errors.HypervisorError: in previous cases
2011

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

    
2022
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2023
      hvp = instance.hvparams
2024
      security_model = hvp[constants.HV_SECURITY_MODEL]
2025
      use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
2026
      if use_chroot:
2027
        raise errors.HotplugError("Disk hotplug is not supported"
2028
                                  " in case of chroot.")
2029
      if security_model != constants.HT_SM_NONE:
2030
        raise errors.HotplugError("Disk Hotplug is not supported in case"
2031
                                  " security models are used.")
2032

    
2033
    if (dev_type == constants.HOTPLUG_TARGET_NIC and
2034
        action == constants.HOTPLUG_ACTION_ADD and not fdsend):
2035
      raise errors.HotplugError("Cannot hot-add NIC."
2036
                                " fdsend python module is missing.")
2037
    return True
2038

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

    
2045
  def HotAddDevice(self, instance, dev_type, device, extra, seq):
2046
    """ Helper method to hot-add a new device
2047

2048
    It gets free pci slot generates the device name and invokes the
2049
    device specific method.
2050

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

    
2072
    self._CallHotplugCommand(instance.name, command)
2073
    # update relevant entries in runtime file
2074
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2075
    entry = _RUNTIME_ENTRY[dev_type](device, extra)
2076
    runtime[index].append(entry)
2077
    self._SaveKVMRuntime(instance, runtime)
2078

    
2079
  def HotDelDevice(self, instance, dev_type, device, _, seq):
2080
    """ Helper method for hot-del device
2081

2082
    It gets device info from runtime file, generates the device name and
2083
    invokes the device specific method.
2084

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

    
2101
    return kvm_device.pci
2102

    
2103
  def HotModDevice(self, instance, dev_type, device, _, seq):
2104
    """ Helper method for hot-mod device
2105

2106
    It gets device info from runtime file, generates the device name and
2107
    invokes the device specific method. Currently only NICs support hot-mod
2108

2109
    """
2110
    if dev_type == constants.HOTPLUG_TARGET_NIC:
2111
      # putting it back in the same pci slot
2112
      device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2113
      # TODO: remove sleep when socat gets removed
2114
      time.sleep(2)
2115
      self.HotAddDevice(instance, dev_type, device, _, seq)
2116

    
2117
  def _PassTapFd(self, instance, fd, nic):
2118
    """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2119

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

    
2132
  @classmethod
2133
  def _ParseKVMVersion(cls, text):
2134
    """Parse the KVM version from the --help output.
2135

2136
    @type text: string
2137
    @param text: output of kvm --help
2138
    @return: (version, v_maj, v_min, v_rev)
2139
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2140

2141
    """
2142
    match = cls._VERSION_RE.search(text.splitlines()[0])
2143
    if not match:
2144
      raise errors.HypervisorError("Unable to get KVM version")
2145

    
2146
    v_all = match.group(0)
2147
    v_maj = int(match.group(1))
2148
    v_min = int(match.group(2))
2149
    if match.group(4):
2150
      v_rev = int(match.group(4))
2151
    else:
2152
      v_rev = 0
2153
    return (v_all, v_maj, v_min, v_rev)
2154

    
2155
  @classmethod
2156
  def _GetKVMOutput(cls, kvm_path, option):
2157
    """Return the output of a kvm invocation
2158

2159
    @type kvm_path: string
2160
    @param kvm_path: path to the kvm executable
2161
    @type option: a key of _KVMOPTS_CMDS
2162
    @param option: kvm option to fetch the output from
2163
    @return: output a supported kvm invocation
2164
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2165

2166
    """
2167
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2168

    
2169
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
2170

    
2171
    result = utils.RunCmd([kvm_path] + optlist)
2172
    if result.failed and not can_fail:
2173
      raise errors.HypervisorError("Unable to get KVM %s output" %
2174
                                    " ".join(cls._KVMOPTS_CMDS[option]))
2175
    return result.output
2176

    
2177
  @classmethod
2178
  def _GetKVMVersion(cls, kvm_path):
2179
    """Return the installed KVM version.
2180

2181
    @return: (version, v_maj, v_min, v_rev)
2182
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2183

2184
    """
2185
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2186

    
2187
  @classmethod
2188
  def _GetDefaultMachineVersion(cls, kvm_path):
2189
    """Return the default hardware revision (e.g. pc-1.1)
2190

2191
    """
2192
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2193
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2194
    if match:
2195
      return match.group(1)
2196
    else:
2197
      return "pc"
2198

    
2199
  def StopInstance(self, instance, force=False, retry=False, name=None):
2200
    """Stop an instance.
2201

2202
    """
2203
    if name is not None and not force:
2204
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2205
    if name is None:
2206
      name = instance.name
2207
      acpi = instance.hvparams[constants.HV_ACPI]
2208
    else:
2209
      acpi = False
2210
    _, pid, alive = self._InstancePidAlive(name)
2211
    if pid > 0 and alive:
2212
      if force or not acpi:
2213
        utils.KillProcess(pid)
2214
      else:
2215
        self._CallMonitorCommand(name, "system_powerdown")
2216

    
2217
  def CleanupInstance(self, instance_name):
2218
    """Cleanup after a stopped instance
2219

2220
    """
2221
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
2222
    if pid > 0 and alive:
2223
      raise errors.HypervisorError("Cannot cleanup a live instance")
2224
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2225

    
2226
  def RebootInstance(self, instance):
2227
    """Reboot an instance.
2228

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

    
2249
  def MigrationInfo(self, instance):
2250
    """Get instance information to perform a migration.
2251

2252
    @type instance: L{objects.Instance}
2253
    @param instance: instance to be migrated
2254
    @rtype: string
2255
    @return: content of the KVM runtime file
2256

2257
    """
2258
    return self._ReadKVMRuntime(instance.name)
2259

    
2260
  def AcceptInstance(self, instance, info, target):
2261
    """Prepare to accept an instance.
2262

2263
    @type instance: L{objects.Instance}
2264
    @param instance: instance to be accepted
2265
    @type info: string
2266
    @param info: content of the KVM runtime file on the source node
2267
    @type target: string
2268
    @param target: target host (usually ip), on this node
2269

2270
    """
2271
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2272
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2273
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2274
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2275
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2276
                            incoming=incoming_address)
2277

    
2278
  def FinalizeMigrationDst(self, instance, info, success):
2279
    """Finalize the instance migration on the target node.
2280

2281
    Stop the incoming mode KVM.
2282

2283
    @type instance: L{objects.Instance}
2284
    @param instance: instance whose migration is being finalized
2285

2286
    """
2287
    if success:
2288
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2289
      kvm_nics = kvm_runtime[1]
2290

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

    
2306
      self._WriteKVMRuntime(instance.name, info)
2307
    else:
2308
      self.StopInstance(instance, force=True)
2309

    
2310
  def MigrateInstance(self, cluster_name, instance, target, live):
2311
    """Migrate an instance to a target node.
2312

2313
    The migration will not be attempted if the instance is not
2314
    currently running.
2315

2316
    @type cluster_name: string
2317
    @param cluster_name: name of the cluster
2318
    @type instance: L{objects.Instance}
2319
    @param instance: the instance to be migrated
2320
    @type target: string
2321
    @param target: ip address of the target node
2322
    @type live: boolean
2323
    @param live: perform a live migration
2324

2325
    """
2326
    instance_name = instance.name
2327
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
2328
    _, _, alive = self._InstancePidAlive(instance_name)
2329
    if not alive:
2330
      raise errors.HypervisorError("Instance not running, cannot migrate")
2331

    
2332
    if not live:
2333
      self._CallMonitorCommand(instance_name, "stop")
2334

    
2335
    migrate_command = ("migrate_set_speed %dm" %
2336
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2337
    self._CallMonitorCommand(instance_name, migrate_command)
2338

    
2339
    migrate_command = ("migrate_set_downtime %dms" %
2340
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2341
    self._CallMonitorCommand(instance_name, migrate_command)
2342

    
2343
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2344
    self._CallMonitorCommand(instance_name, migrate_command)
2345

    
2346
  def FinalizeMigrationSource(self, instance, success, live):
2347
    """Finalize the instance migration on the source node.
2348

2349
    @type instance: L{objects.Instance}
2350
    @param instance: the instance that was migrated
2351
    @type success: bool
2352
    @param success: whether the migration succeeded or not
2353
    @type live: bool
2354
    @param live: whether the user requested a live migration or not
2355

2356
    """
2357
    if success:
2358
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2359
      utils.KillProcess(pid)
2360
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2361
    elif live:
2362
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2363

    
2364
  def GetMigrationStatus(self, instance):
2365
    """Get the migration status
2366

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

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

    
2394
          return migration_status
2395

    
2396
        logging.warning("KVM: unknown migration status '%s'", status)
2397

    
2398
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2399

    
2400
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2401

    
2402
  def BalloonInstanceMemory(self, instance, mem):
2403
    """Balloon an instance memory to a certain value.
2404

2405
    @type instance: L{objects.Instance}
2406
    @param instance: instance to be accepted
2407
    @type mem: int
2408
    @param mem: actual memory size to use for instance runtime
2409

2410
    """
2411
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2412

    
2413
  def GetNodeInfo(self, hvparams=None):
2414
    """Return information about the node.
2415

2416
    @type hvparams: dict of strings
2417
    @param hvparams: hypervisor parameters, not used in this class
2418

2419
    @return: a dict as returned by L{BaseHypervisor.GetLinuxNodeInfo} plus
2420
        the following keys:
2421
          - hv_version: the hypervisor version in the form (major, minor,
2422
                        revision)
2423

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

    
2433
  @classmethod
2434
  def GetInstanceConsole(cls, instance, primary_node, hvparams, beparams):
2435
    """Return a command for connecting to the console of an instance.
2436

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

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

    
2459
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2460
    if spice_bind:
2461
      return objects.InstanceConsole(instance=instance.name,
2462
                                     kind=constants.CONS_SPICE,
2463
                                     host=spice_bind,
2464
                                     port=instance.network_port)
2465

    
2466
    return objects.InstanceConsole(instance=instance.name,
2467
                                   kind=constants.CONS_MESSAGE,
2468
                                   message=("No serial shell for instance %s" %
2469
                                            instance.name))
2470

    
2471
  def Verify(self, hvparams=None):
2472
    """Verify the hypervisor.
2473

2474
    Check that the required binaries exist.
2475

2476
    @type hvparams: dict of strings
2477
    @param hvparams: hypervisor parameters to be verified against, not used here
2478

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

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

    
2492
    return self._FormatVerifyResults(msgs)
2493

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2578
    kvm_path = hvparams[constants.HV_KVM_PATH]
2579

    
2580
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2581
    if security_model == constants.HT_SM_USER:
2582
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2583
      try:
2584
        pwd.getpwnam(username)
2585
      except KeyError:
2586
        raise errors.HypervisorError("Unknown security domain user %s"
2587
                                     % username)
2588
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2589
    if vnc_bind_address:
2590
      bound_to_addr = netutils.IP4Address.IsValid(vnc_bind_address)
2591
      is_interface = netutils.IsValidInterface(vnc_bind_address)
2592
      is_path = utils.IsNormAbsPath(vnc_bind_address)
2593
      if not bound_to_addr and not is_interface and not is_path:
2594
        raise errors.HypervisorError("VNC: The %s parameter must be either"
2595
                                     " a valid IP address, an interface name,"
2596
                                     " or an absolute path" %
2597
                                     constants.HV_KVM_SPICE_BIND)
2598

    
2599
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2600
    if spice_bind:
2601
      # only one of VNC and SPICE can be used currently.
2602
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2603
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2604
                                     " only one of them can be used at a"
2605
                                     " given time")
2606

    
2607
      # check that KVM supports SPICE
2608
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2609
      if not cls._SPICE_RE.search(kvmhelp):
2610
        raise errors.HypervisorError("SPICE is configured, but it is not"
2611
                                     " supported according to 'kvm --help'")
2612

    
2613
      # if spice_bind is not an IP address, it must be a valid interface
2614
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2615
                       netutils.IP6Address.IsValid(spice_bind))
2616
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2617
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2618
                                     " a valid IP address or interface name" %
2619
                                     constants.HV_KVM_SPICE_BIND)
2620

    
2621
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2622
    if machine_version:
2623
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2624
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2625
        raise errors.HypervisorError("Unsupported machine version: %s" %
2626
                                     machine_version)
2627

    
2628
  @classmethod
2629
  def PowercycleNode(cls, hvparams=None):
2630
    """KVM powercycle, just a wrapper over Linux powercycle.
2631

2632
    @type hvparams: dict of strings
2633
    @param hvparams: hypervisor params to be used on this node
2634

2635
    """
2636
    cls.LinuxPowercycle()