Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 24711492

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
    if instance.tags:
1004
      tags = " ".join(instance.tags)
1005
    else:
1006
      tags = ""
1007

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1119
    return result
1120

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1291
    return dev_opts
1292

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

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

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

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

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

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

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

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

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

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

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

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

    
1377
    disk_type = hvp[constants.HV_DISK_TYPE]
1378

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1539
        spice_address = addresses[spice_ip_version][0]
1540

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1652
    hvparams = hvp
1653

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

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

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

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

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

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

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

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

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

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

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

    
1697
    return _AnalyzeSerializedRuntime(serialized_runtime)
1698

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

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

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

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

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

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

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

    
1745
    temp_files = []
1746

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1981
    return result
1982

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

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

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

    
2000
    dev.pci = int(free)
2001

    
2002
  def VerifyHotplugSupport(self, instance, action, dev_type):
2003
    """Verifies that hotplug is supported.
2004

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

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

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

    
2023
    if (dev_type == constants.HOTPLUG_TARGET_NIC and
2024
        action == constants.HOTPLUG_ACTION_ADD and not fdsend):
2025
      raise errors.HotplugError("Cannot hot-add NIC."
2026
                                " fdsend python module is missing.")
2027

    
2028
  def HotplugSupported(self, instance):
2029
    """Checks if hotplug is generally supported.
2030

2031
    Hotplug is *not* supported in case of:
2032
     - qemu versions < 1.0
2033
     - for stopped instances
2034

2035
    @raise errors.HypervisorError: in one of the previous cases
2036

2037
    """
2038
    output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2039
    # TODO: search for netdev_add, drive_add, device_add.....
2040
    match = self._INFO_VERSION_RE.search(output.stdout)
2041
    if not match:
2042
      raise errors.HotplugError("Try hotplug only in running instances.")
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()