Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 884ec6d4

History | View | Annotate | Download (96.1 kB)

1
#
2
#
3

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

    
21

    
22
"""KVM hypervisor
23

24
"""
25

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

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

    
62

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

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

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

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

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

    
117

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

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

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

131
  """
132

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

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

    
139

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

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

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

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

    
162
  pci_reservations[free] = True
163

    
164

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

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

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

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

    
188
  return found[0]
189

    
190

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

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

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

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

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

    
213

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

217
  @see: L{_ProbeTapVnetHdr}
218

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

    
230

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

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

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

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

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

    
254
  result = bool(flags & IFF_VNET_HDR)
255

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

    
259
  return result
260

    
261

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

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

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

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

    
279
  flags = IFF_TAP | IFF_NO_PI
280

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

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

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

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

    
297

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

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

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

    
309
    self.data = data
310

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
363

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

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

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

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

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

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

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

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

406
    Connects to the UNIX socket
407

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

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

    
414
    self._check_socket()
415

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

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

426
    It cannot be used after this call.
427

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

    
431

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

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

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

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

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

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

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

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

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

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

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

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

    
498
    return (message, buf)
499

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

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

508
    """
509
    self._check_connection()
510

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

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

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

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

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

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

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

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

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

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

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

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

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

    
595

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

599
  """
600
  CAN_MIGRATE = True
601

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

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

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

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

    
712
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
713
  _MIGRATION_INFO_RETRY_DELAY = 2
714

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

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

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

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

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

    
747
  _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
748

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
833
    return (instance, memory, vcpus)
834

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

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

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

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

    
854
    return (pidfile, pid, alive)
855

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1013
    if nic.ip:
1014
      env["IP"] = nic.ip
1015

    
1016
    if nic.nicparams[constants.NIC_LINK]:
1017
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
1018

    
1019
    if nic.network:
1020
      n = objects.Network.FromDict(nic.netinfo)
1021
      env.update(n.HooksDict())
1022

    
1023
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1024
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
1025

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

    
1032
  @staticmethod
1033
  def _VerifyAffinityPackage():
1034
    if affinity is None:
1035
      raise errors.HypervisorError("affinity Python package not"
1036
                                   " found; cannot use CPU pinning under KVM")
1037

    
1038
  @staticmethod
1039
  def _BuildAffinityCpuMask(cpu_list):
1040
    """Create a CPU mask suitable for sched_setaffinity from a list of
1041
    CPUs.
1042

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

1046
    @type cpu_list: list of int
1047
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
1048
    @rtype: int
1049
    @return: a bit mask of CPU affinities
1050

1051
    """
1052
    if cpu_list == constants.CPU_PINNING_OFF:
1053
      return constants.CPU_PINNING_ALL_KVM
1054
    else:
1055
      return sum(2 ** cpu for cpu in cpu_list)
1056

    
1057
  @classmethod
1058
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
1059
    """Change CPU affinity for running VM according to given CPU mask.
1060

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

1069
    """
1070
    # Convert the string CPU mask to a list of list of int's
1071
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
1072

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

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

    
1096
  def _GetVcpuThreadIds(self, instance_name):
1097
    """Get a mapping of vCPU no. to thread IDs for the instance
1098

1099
    @type instance_name: string
1100
    @param instance_name: instance in question
1101
    @rtype: dictionary of int:int
1102
    @return: a dictionary mapping vCPU numbers to thread IDs
1103

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

    
1114
    return result
1115

    
1116
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1117
    """Complete CPU pinning.
1118

1119
    @type instance_name: string
1120
    @param instance_name: name of instance
1121
    @type cpu_mask: string
1122
    @param cpu_mask: CPU pinning mask as entered by user
1123

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

    
1132
  def ListInstances(self, hvparams=None):
1133
    """Get the list of running instances.
1134

1135
    We can do this by listing our live instances directory and
1136
    checking whether the associated kvm process is still alive.
1137

1138
    """
1139
    result = []
1140
    for name in os.listdir(self._PIDS_DIR):
1141
      if self._InstancePidAlive(name)[2]:
1142
        result.append(name)
1143
    return result
1144

    
1145
  def GetInstanceInfo(self, instance_name, hvparams=None):
1146
    """Get instance properties.
1147

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

1155
    """
1156
    _, pid, alive = self._InstancePidAlive(instance_name)
1157
    if not alive:
1158
      return None
1159

    
1160
    _, memory, vcpus = self._InstancePidInfo(pid)
1161
    istat = "---b-"
1162
    times = "0"
1163

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

    
1175
    return (instance_name, pid, memory, vcpus, istat, times)
1176

    
1177
  def GetAllInstancesInfo(self, hvparams=None):
1178
    """Get properties of all instances.
1179

1180
    @type hvparams: dict of strings
1181
    @param hvparams: hypervisor parameter
1182
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1183

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

    
1196
  def _GenerateKVMBlockDevicesOptions(self, instance, kvm_disks,
1197
                                      kvmhelp, devlist):
1198
    """Generate KVM options regarding instance's block devices.
1199

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

1211
    """
1212
    hvp = instance.hvparams
1213
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1214
    if kernel_path:
1215
      boot_disk = False
1216
    else:
1217
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1218

    
1219
    # whether this is an older KVM version that uses the boot=on flag
1220
    # on devices
1221
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1222

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

    
1262
      access_mode = cfdev.params.get(constants.LDP_ACCESS,
1263
                                     constants.DISK_KERNELSPACE)
1264
      if (uri and access_mode == constants.DISK_USERSPACE):
1265
        drive_uri = uri
1266
      else:
1267
        drive_uri = link_name
1268

    
1269
      drive_val = "file=%s,format=raw%s%s%s" % \
1270
                  (drive_uri, if_val, boot_val, cache_val)
1271

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

    
1284
      dev_opts.extend(["-drive", drive_val])
1285

    
1286
    return dev_opts
1287

    
1288
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1289
                          kvmhelp):
1290
    """Generate KVM information to start an instance.
1291

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

1301
    """
1302
    # pylint: disable=R0912,R0914,R0915
1303
    hvp = instance.hvparams
1304
    self.ValidateParameters(hvp)
1305

    
1306
    pidfile = self._InstancePidFile(instance.name)
1307
    kvm = hvp[constants.HV_KVM_PATH]
1308
    kvm_cmd = [kvm]
1309
    # used just by the vnc server, if enabled
1310
    kvm_cmd.extend(["-name", instance.name])
1311
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1312

    
1313
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1314
    if hvp[constants.HV_CPU_CORES]:
1315
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1316
    if hvp[constants.HV_CPU_THREADS]:
1317
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1318
    if hvp[constants.HV_CPU_SOCKETS]:
1319
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1320

    
1321
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1322

    
1323
    kvm_cmd.extend(["-pidfile", pidfile])
1324
    kvm_cmd.extend(["-balloon", "virtio"])
1325
    kvm_cmd.extend(["-daemonize"])
1326
    if not instance.hvparams[constants.HV_ACPI]:
1327
      kvm_cmd.extend(["-no-acpi"])
1328
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1329
        constants.INSTANCE_REBOOT_EXIT:
1330
      kvm_cmd.extend(["-no-reboot"])
1331

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

    
1354
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1355
    if kernel_path:
1356
      boot_cdrom = boot_floppy = boot_network = False
1357
    else:
1358
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1359
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1360
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1361

    
1362
    if startup_paused:
1363
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1364

    
1365
    if boot_network:
1366
      kvm_cmd.extend(["-boot", "n"])
1367

    
1368
    # whether this is an older KVM version that uses the boot=on flag
1369
    # on devices
1370
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1371

    
1372
    disk_type = hvp[constants.HV_DISK_TYPE]
1373

    
1374
    #Now we can specify a different device type for CDROM devices.
1375
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1376
    if not cdrom_disk_type:
1377
      cdrom_disk_type = disk_type
1378

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

    
1400
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1401
    if iso_image2:
1402
      options = ",format=raw,media=cdrom"
1403
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1404
        if_val = ",if=virtio"
1405
      else:
1406
        if_val = ",if=%s" % cdrom_disk_type
1407
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1408
      kvm_cmd.extend(["-drive", drive_val])
1409

    
1410
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1411
    if floppy_image:
1412
      options = ",format=raw,media=disk"
1413
      if boot_floppy:
1414
        kvm_cmd.extend(["-boot", "a"])
1415
        options = "%s,boot=on" % options
1416
      if_val = ",if=floppy"
1417
      options = "%s%s" % (options, if_val)
1418
      drive_val = "file=%s%s" % (floppy_image, options)
1419
      kvm_cmd.extend(["-drive", drive_val])
1420

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

    
1433
    mem_path = hvp[constants.HV_MEM_PATH]
1434
    if mem_path:
1435
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1436

    
1437
    monitor_dev = ("unix:%s,server,nowait" %
1438
                   self._InstanceMonitor(instance.name))
1439
    kvm_cmd.extend(["-monitor", monitor_dev])
1440
    if hvp[constants.HV_SERIAL_CONSOLE]:
1441
      serial_dev = ("unix:%s,server,nowait" %
1442
                    self._InstanceSerial(instance.name))
1443
      kvm_cmd.extend(["-serial", serial_dev])
1444
    else:
1445
      kvm_cmd.extend(["-serial", "none"])
1446

    
1447
    mouse_type = hvp[constants.HV_USB_MOUSE]
1448
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1449
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1450
    spice_ip_version = None
1451

    
1452
    kvm_cmd.extend(["-usb"])
1453

    
1454
    if mouse_type:
1455
      kvm_cmd.extend(["-usbdevice", mouse_type])
1456
    elif vnc_bind_address:
1457
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1458

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

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

    
1495
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1496

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

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

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

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

    
1534
        spice_address = addresses[spice_ip_version][0]
1535

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

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

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

    
1558
      if spice_ip_version:
1559
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1560

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

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

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

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

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

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

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

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

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

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

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

    
1629
    # Set system UUID to instance UUID
1630
    if self._UUID_RE.search(kvmhelp):
1631
      kvm_cmd.extend(["-uuid", instance.uuid])
1632

    
1633
    if hvp[constants.HV_KVM_EXTRA]:
1634
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1635

    
1636
    pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1637
    kvm_disks = []
1638
    for disk, link_name, uri in block_devices:
1639
      _UpdatePCISlots(disk, pci_reservations)
1640
      kvm_disks.append((disk, link_name, uri))
1641

    
1642
    kvm_nics = []
1643
    for nic in instance.nics:
1644
      _UpdatePCISlots(nic, pci_reservations)
1645
      kvm_nics.append(nic)
1646

    
1647
    hvparams = hvp
1648

    
1649
    return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1650

    
1651
  def _WriteKVMRuntime(self, instance_name, data):
1652
    """Write an instance's KVM runtime
1653

1654
    """
1655
    try:
1656
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1657
                      data=data)
1658
    except EnvironmentError, err:
1659
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1660

    
1661
  def _ReadKVMRuntime(self, instance_name):
1662
    """Read an instance's KVM runtime
1663

1664
    """
1665
    try:
1666
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1667
    except EnvironmentError, err:
1668
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1669
    return file_content
1670

    
1671
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1672
    """Save an instance's KVM runtime
1673

1674
    """
1675
    kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1676

    
1677
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1678
    serialized_disks = [(blk.ToDict(), link, uri)
1679
                        for blk, link, uri in kvm_disks]
1680
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1681
                                      serialized_disks))
1682

    
1683
    self._WriteKVMRuntime(instance.name, serialized_form)
1684

    
1685
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1686
    """Load an instance's KVM runtime
1687

1688
    """
1689
    if not serialized_runtime:
1690
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1691

    
1692
    return _AnalyzeSerializedRuntime(serialized_runtime)
1693

    
1694
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1695
    """Run the KVM cmd and check for errors
1696

1697
    @type name: string
1698
    @param name: instance name
1699
    @type kvm_cmd: list of strings
1700
    @param kvm_cmd: runcmd input for kvm
1701
    @type tap_fds: list of int
1702
    @param tap_fds: fds of tap devices opened by Ganeti
1703

1704
    """
1705
    try:
1706
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1707
    finally:
1708
      for fd in tap_fds:
1709
        utils_wrapper.CloseFdNoError(fd)
1710

    
1711
    if result.failed:
1712
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1713
                                   (name, result.fail_reason, result.output))
1714
    if not self._InstancePidAlive(name)[2]:
1715
      raise errors.HypervisorError("Failed to start instance %s" % name)
1716

    
1717
  # too many local variables
1718
  # pylint: disable=R0914
1719
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1720
    """Execute a KVM cmd, after completing it with some last minute data.
1721

1722
    @type incoming: tuple of strings
1723
    @param incoming: (target_host_ip, port)
1724
    @type kvmhelp: string
1725
    @param kvmhelp: output of kvm --help
1726

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

    
1740
    temp_files = []
1741

    
1742
    kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1743
    # the first element of kvm_cmd is always the path to the kvm binary
1744
    kvm_path = kvm_cmd[0]
1745
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1746

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1893
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1894
                     constants.RUN_DIRS_MODE)])
1895
    for nic_seq, tap in enumerate(taps):
1896
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1897
                      data=tap)
1898

    
1899
    if vnc_pwd:
1900
      change_cmd = "change vnc password %s" % vnc_pwd
1901
      self._CallMonitorCommand(instance.name, change_cmd)
1902

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

    
1917
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1918
      qmp.connect()
1919
      arguments = {
1920
          "protocol": "spice",
1921
          "password": spice_pwd,
1922
      }
1923
      qmp.Execute("set_password", arguments)
1924

    
1925
    for filename in temp_files:
1926
      utils.RemoveFile(filename)
1927

    
1928
    # If requested, set CPU affinity and resume instance execution
1929
    if cpu_pinning:
1930
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1931

    
1932
    start_memory = self._InstanceStartupMemory(instance)
1933
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1934
      self.BalloonInstanceMemory(instance, start_memory)
1935

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

    
1942
  def StartInstance(self, instance, block_devices, startup_paused):
1943
    """Start an instance.
1944

1945
    """
1946
    self._CheckDown(instance.name)
1947
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1948
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1949
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1950
                                           startup_paused, kvmhelp)
1951
    self._SaveKVMRuntime(instance, kvm_runtime)
1952
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1953

    
1954
  def _CallMonitorCommand(self, instance_name, command):
1955
    """Invoke a command on the instance monitor.
1956

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

    
1976
    return result
1977

    
1978
  def _GetFreePCISlot(self, instance, dev):
1979
    """Get the first available pci slot of a runnung instance.
1980

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

    
1991
    [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
1992
    if not free:
1993
      raise errors.HypervisorError("All PCI slots occupied")
1994

    
1995
    dev.pci = int(free)
1996

    
1997
  def VerifyHotplugSupport(self, instance, action, dev_type):
1998
    """Verifies that hotplug is supported.
1999

2000
    Hotplug is *not* supported in case of:
2001
     - security models and chroot (disk hotplug)
2002
     - fdsend module is missing (nic hot-add)
2003

2004
    @raise errors.HypervisorError: in one of the previous cases
2005

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

    
2018
    if (dev_type == constants.HOTPLUG_TARGET_NIC and
2019
        action == constants.HOTPLUG_ACTION_ADD and not fdsend):
2020
      raise errors.HotplugError("Cannot hot-add NIC."
2021
                                " fdsend python module is missing.")
2022

    
2023
  def HotplugSupported(self, instance):
2024
    """Checks if hotplug is generally supported.
2025

2026
    Hotplug is *not* supported in case of:
2027
     - qemu versions < 1.0
2028
     - for stopped instances
2029

2030
    @raise errors.HypervisorError: in one of the previous cases
2031

2032
    """
2033
    try:
2034
      output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2035
    except errors.HypervisorError:
2036
      raise errors.HotplugError("Instance is probably down")
2037

    
2038
    # TODO: search for netdev_add, drive_add, device_add.....
2039
    match = self._INFO_VERSION_RE.search(output.stdout)
2040
    if not match:
2041
      raise errors.HotplugError("Cannot parse qemu version via monitor")
2042

    
2043
    v_major, v_min, _, _ = match.groups()
2044
    if (int(v_major), int(v_min)) < (1, 0):
2045
      raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2046

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

    
2053
  def HotAddDevice(self, instance, dev_type, device, extra, seq):
2054
    """ Helper method to hot-add a new device
2055

2056
    It gets free pci slot generates the device name and invokes the
2057
    device specific method.
2058

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

    
2080
    self._CallHotplugCommand(instance.name, command)
2081
    # update relevant entries in runtime file
2082
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2083
    entry = _RUNTIME_ENTRY[dev_type](device, extra)
2084
    runtime[index].append(entry)
2085
    self._SaveKVMRuntime(instance, runtime)
2086

    
2087
  def HotDelDevice(self, instance, dev_type, device, _, seq):
2088
    """ Helper method for hot-del device
2089

2090
    It gets device info from runtime file, generates the device name and
2091
    invokes the device specific method.
2092

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

    
2110
    return kvm_device.pci
2111

    
2112
  def HotModDevice(self, instance, dev_type, device, _, seq):
2113
    """ Helper method for hot-mod device
2114

2115
    It gets device info from runtime file, generates the device name and
2116
    invokes the device specific method. Currently only NICs support hot-mod
2117

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

    
2126
  def _PassTapFd(self, instance, fd, nic):
2127
    """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2128

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

    
2143
  @classmethod
2144
  def _ParseKVMVersion(cls, text):
2145
    """Parse the KVM version from the --help output.
2146

2147
    @type text: string
2148
    @param text: output of kvm --help
2149
    @return: (version, v_maj, v_min, v_rev)
2150
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2151

2152
    """
2153
    match = cls._VERSION_RE.search(text.splitlines()[0])
2154
    if not match:
2155
      raise errors.HypervisorError("Unable to get KVM version")
2156

    
2157
    v_all = match.group(0)
2158
    v_maj = int(match.group(1))
2159
    v_min = int(match.group(2))
2160
    if match.group(4):
2161
      v_rev = int(match.group(4))
2162
    else:
2163
      v_rev = 0
2164
    return (v_all, v_maj, v_min, v_rev)
2165

    
2166
  @classmethod
2167
  def _GetKVMOutput(cls, kvm_path, option):
2168
    """Return the output of a kvm invocation
2169

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

2177
    """
2178
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2179

    
2180
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
2181

    
2182
    result = utils.RunCmd([kvm_path] + optlist)
2183
    if result.failed and not can_fail:
2184
      raise errors.HypervisorError("Unable to get KVM %s output" %
2185
                                    " ".join(cls._KVMOPTS_CMDS[option]))
2186
    return result.output
2187

    
2188
  @classmethod
2189
  def _GetKVMVersion(cls, kvm_path):
2190
    """Return the installed KVM version.
2191

2192
    @return: (version, v_maj, v_min, v_rev)
2193
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2194

2195
    """
2196
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2197

    
2198
  @classmethod
2199
  def _GetDefaultMachineVersion(cls, kvm_path):
2200
    """Return the default hardware revision (e.g. pc-1.1)
2201

2202
    """
2203
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2204
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2205
    if match:
2206
      return match.group(1)
2207
    else:
2208
      return "pc"
2209

    
2210
  def StopInstance(self, instance, force=False, retry=False, name=None):
2211
    """Stop an instance.
2212

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

    
2228
  def CleanupInstance(self, instance_name):
2229
    """Cleanup after a stopped instance
2230

2231
    """
2232
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
2233
    if pid > 0 and alive:
2234
      raise errors.HypervisorError("Cannot cleanup a live instance")
2235
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2236

    
2237
  def RebootInstance(self, instance):
2238
    """Reboot an instance.
2239

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

    
2260
  def MigrationInfo(self, instance):
2261
    """Get instance information to perform a migration.
2262

2263
    @type instance: L{objects.Instance}
2264
    @param instance: instance to be migrated
2265
    @rtype: string
2266
    @return: content of the KVM runtime file
2267

2268
    """
2269
    return self._ReadKVMRuntime(instance.name)
2270

    
2271
  def AcceptInstance(self, instance, info, target):
2272
    """Prepare to accept an instance.
2273

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

2281
    """
2282
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2283
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2284
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2285
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2286
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2287
                            incoming=incoming_address)
2288

    
2289
  def FinalizeMigrationDst(self, instance, info, success):
2290
    """Finalize the instance migration on the target node.
2291

2292
    Stop the incoming mode KVM.
2293

2294
    @type instance: L{objects.Instance}
2295
    @param instance: instance whose migration is being finalized
2296

2297
    """
2298
    if success:
2299
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2300
      kvm_nics = kvm_runtime[1]
2301

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

    
2317
      self._WriteKVMRuntime(instance.name, info)
2318
    else:
2319
      self.StopInstance(instance, force=True)
2320

    
2321
  def MigrateInstance(self, cluster_name, instance, target, live):
2322
    """Migrate an instance to a target node.
2323

2324
    The migration will not be attempted if the instance is not
2325
    currently running.
2326

2327
    @type cluster_name: string
2328
    @param cluster_name: name of the cluster
2329
    @type instance: L{objects.Instance}
2330
    @param instance: the instance to be migrated
2331
    @type target: string
2332
    @param target: ip address of the target node
2333
    @type live: boolean
2334
    @param live: perform a live migration
2335

2336
    """
2337
    instance_name = instance.name
2338
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
2339
    _, _, alive = self._InstancePidAlive(instance_name)
2340
    if not alive:
2341
      raise errors.HypervisorError("Instance not running, cannot migrate")
2342

    
2343
    if not live:
2344
      self._CallMonitorCommand(instance_name, "stop")
2345

    
2346
    migrate_command = ("migrate_set_speed %dm" %
2347
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2348
    self._CallMonitorCommand(instance_name, migrate_command)
2349

    
2350
    migrate_command = ("migrate_set_downtime %dms" %
2351
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2352
    self._CallMonitorCommand(instance_name, migrate_command)
2353

    
2354
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2355
    self._CallMonitorCommand(instance_name, migrate_command)
2356

    
2357
  def FinalizeMigrationSource(self, instance, success, live):
2358
    """Finalize the instance migration on the source node.
2359

2360
    @type instance: L{objects.Instance}
2361
    @param instance: the instance that was migrated
2362
    @type success: bool
2363
    @param success: whether the migration succeeded or not
2364
    @type live: bool
2365
    @param live: whether the user requested a live migration or not
2366

2367
    """
2368
    if success:
2369
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2370
      utils.KillProcess(pid)
2371
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2372
    elif live:
2373
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2374

    
2375
  def GetMigrationStatus(self, instance):
2376
    """Get the migration status
2377

2378
    @type instance: L{objects.Instance}
2379
    @param instance: the instance that is being migrated
2380
    @rtype: L{objects.MigrationStatus}
2381
    @return: the status of the current migration (one of
2382
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2383
             progress info that can be retrieved from the hypervisor
2384

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

    
2405
          return migration_status
2406

    
2407
        logging.warning("KVM: unknown migration status '%s'", status)
2408

    
2409
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2410

    
2411
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2412

    
2413
  def BalloonInstanceMemory(self, instance, mem):
2414
    """Balloon an instance memory to a certain value.
2415

2416
    @type instance: L{objects.Instance}
2417
    @param instance: instance to be accepted
2418
    @type mem: int
2419
    @param mem: actual memory size to use for instance runtime
2420

2421
    """
2422
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2423

    
2424
  def GetNodeInfo(self, hvparams=None):
2425
    """Return information about the node.
2426

2427
    @type hvparams: dict of strings
2428
    @param hvparams: hypervisor parameters, not used in this class
2429

2430
    @return: a dict as returned by L{BaseHypervisor.GetLinuxNodeInfo} plus
2431
        the following keys:
2432
          - hv_version: the hypervisor version in the form (major, minor,
2433
                        revision)
2434

2435
    """
2436
    result = self.GetLinuxNodeInfo()
2437
    # FIXME: this is the global kvm version, but the actual version can be
2438
    # customized as an hv parameter. we should use the nodegroup's default kvm
2439
    # path parameter here.
2440
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2441
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2442
    return result
2443

    
2444
  @classmethod
2445
  def GetInstanceConsole(cls, instance, primary_node, hvparams, beparams):
2446
    """Return a command for connecting to the console of an instance.
2447

2448
    """
2449
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2450
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2451
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2452
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2453
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2454
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2455
      return objects.InstanceConsole(instance=instance.name,
2456
                                     kind=constants.CONS_SSH,
2457
                                     host=primary_node.name,
2458
                                     user=constants.SSH_CONSOLE_USER,
2459
                                     command=cmd)
2460

    
2461
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2462
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2463
      display = instance.network_port - constants.VNC_BASE_PORT
2464
      return objects.InstanceConsole(instance=instance.name,
2465
                                     kind=constants.CONS_VNC,
2466
                                     host=vnc_bind_address,
2467
                                     port=instance.network_port,
2468
                                     display=display)
2469

    
2470
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2471
    if spice_bind:
2472
      return objects.InstanceConsole(instance=instance.name,
2473
                                     kind=constants.CONS_SPICE,
2474
                                     host=spice_bind,
2475
                                     port=instance.network_port)
2476

    
2477
    return objects.InstanceConsole(instance=instance.name,
2478
                                   kind=constants.CONS_MESSAGE,
2479
                                   message=("No serial shell for instance %s" %
2480
                                            instance.name))
2481

    
2482
  def Verify(self, hvparams=None):
2483
    """Verify the hypervisor.
2484

2485
    Check that the required binaries exist.
2486

2487
    @type hvparams: dict of strings
2488
    @param hvparams: hypervisor parameters to be verified against, not used here
2489

2490
    @return: Problem description if something is wrong, C{None} otherwise
2491

2492
    """
2493
    msgs = []
2494
    # FIXME: this is the global kvm binary, but the actual path can be
2495
    # customized as an hv parameter; we should use the nodegroup's
2496
    # default kvm path parameter here.
2497
    if not os.path.exists(constants.KVM_PATH):
2498
      msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2499
    if not os.path.exists(constants.SOCAT_PATH):
2500
      msgs.append("The socat binary ('%s') does not exist" %
2501
                  constants.SOCAT_PATH)
2502

    
2503
    return self._FormatVerifyResults(msgs)
2504

    
2505
  @classmethod
2506
  def CheckParameterSyntax(cls, hvparams):
2507
    """Check the given parameters for validity.
2508

2509
    @type hvparams:  dict
2510
    @param hvparams: dictionary with parameter names/value
2511
    @raise errors.HypervisorError: when a parameter is not valid
2512

2513
    """
2514
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2515

    
2516
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2517
    if kernel_path:
2518
      if not hvparams[constants.HV_ROOT_PATH]:
2519
        raise errors.HypervisorError("Need a root partition for the instance,"
2520
                                     " if a kernel is defined")
2521

    
2522
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2523
        not hvparams[constants.HV_VNC_X509]):
2524
      raise errors.HypervisorError("%s must be defined, if %s is" %
2525
                                   (constants.HV_VNC_X509,
2526
                                    constants.HV_VNC_X509_VERIFY))
2527

    
2528
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2529
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2530
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2531
      if not serial_speed or serial_speed not in valid_speeds:
2532
        raise errors.HypervisorError("Invalid serial console speed, must be"
2533
                                     " one of: %s" %
2534
                                     utils.CommaJoin(valid_speeds))
2535

    
2536
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2537
    if (boot_order == constants.HT_BO_CDROM and
2538
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2539
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2540
                                   " ISO path")
2541

    
2542
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2543
    if security_model == constants.HT_SM_USER:
2544
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2545
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2546
                                     " must be specified")
2547
    elif (security_model == constants.HT_SM_NONE or
2548
          security_model == constants.HT_SM_POOL):
2549
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2550
        raise errors.HypervisorError("Cannot have a security domain when the"
2551
                                     " security model is 'none' or 'pool'")
2552

    
2553
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2554
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2555
    if spice_bind:
2556
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2557
        # if an IP version is specified, the spice_bind parameter must be an
2558
        # IP of that family
2559
        if (netutils.IP4Address.IsValid(spice_bind) and
2560
            spice_ip_version != constants.IP4_VERSION):
2561
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2562
                                       " the specified IP version is %s" %
2563
                                       (spice_bind, spice_ip_version))
2564

    
2565
        if (netutils.IP6Address.IsValid(spice_bind) and
2566
            spice_ip_version != constants.IP6_VERSION):
2567
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2568
                                       " the specified IP version is %s" %
2569
                                       (spice_bind, spice_ip_version))
2570
    else:
2571
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2572
      # error if any of them is set without it.
2573
      for param in _SPICE_ADDITIONAL_PARAMS:
2574
        if hvparams[param]:
2575
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2576
                                       (param, constants.HV_KVM_SPICE_BIND))
2577

    
2578
  @classmethod
2579
  def ValidateParameters(cls, hvparams):
2580
    """Check the given parameters for validity.
2581

2582
    @type hvparams:  dict
2583
    @param hvparams: dictionary with parameter names/value
2584
    @raise errors.HypervisorError: when a parameter is not valid
2585

2586
    """
2587
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2588

    
2589
    kvm_path = hvparams[constants.HV_KVM_PATH]
2590

    
2591
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2592
    if security_model == constants.HT_SM_USER:
2593
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2594
      try:
2595
        pwd.getpwnam(username)
2596
      except KeyError:
2597
        raise errors.HypervisorError("Unknown security domain user %s"
2598
                                     % username)
2599
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2600
    if vnc_bind_address:
2601
      bound_to_addr = netutils.IP4Address.IsValid(vnc_bind_address)
2602
      is_interface = netutils.IsValidInterface(vnc_bind_address)
2603
      is_path = utils.IsNormAbsPath(vnc_bind_address)
2604
      if not bound_to_addr and not is_interface and not is_path:
2605
        raise errors.HypervisorError("VNC: The %s parameter must be either"
2606
                                     " a valid IP address, an interface name,"
2607
                                     " or an absolute path" %
2608
                                     constants.HV_KVM_SPICE_BIND)
2609

    
2610
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2611
    if spice_bind:
2612
      # only one of VNC and SPICE can be used currently.
2613
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2614
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2615
                                     " only one of them can be used at a"
2616
                                     " given time")
2617

    
2618
      # check that KVM supports SPICE
2619
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2620
      if not cls._SPICE_RE.search(kvmhelp):
2621
        raise errors.HypervisorError("SPICE is configured, but it is not"
2622
                                     " supported according to 'kvm --help'")
2623

    
2624
      # if spice_bind is not an IP address, it must be a valid interface
2625
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2626
                       netutils.IP6Address.IsValid(spice_bind))
2627
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2628
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2629
                                     " a valid IP address or interface name" %
2630
                                     constants.HV_KVM_SPICE_BIND)
2631

    
2632
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2633
    if machine_version:
2634
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2635
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2636
        raise errors.HypervisorError("Unsupported machine version: %s" %
2637
                                     machine_version)
2638

    
2639
  @classmethod
2640
  def PowercycleNode(cls, hvparams=None):
2641
    """KVM powercycle, just a wrapper over Linux powercycle.
2642

2643
    @type hvparams: dict of strings
2644
    @param hvparams: hypervisor params to be used on this node
2645

2646
    """
2647
    cls.LinuxPowercycle()