Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 4f2f98f1

History | View | Annotate | Download (95.9 kB)

1
#
2
#
3

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

    
21

    
22
"""KVM hypervisor
23

24
"""
25

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

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

    
62

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

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

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

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

    
91
# below constants show the format of runtime file
92
# the nics are in second possition, while the disks in 4th (last)
93
# moreover disk entries are stored 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
     - qemu versions < 1.0
2007
     - security models and chroot (disk hotplug)
2008
     - fdsend module is missing (nic hot-add)
2009

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

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

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

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

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

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

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

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

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

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

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

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

    
2101
    return kvm_device.pci
2102

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

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

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

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

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

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

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

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

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

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

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

2168
    """
2169
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2170

    
2171
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
2172

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

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

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

2186
    """
2187
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2188

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

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

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

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

    
2219
  def CleanupInstance(self, instance_name):
2220
    """Cleanup after a stopped instance
2221

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

    
2228
  def RebootInstance(self, instance):
2229
    """Reboot an instance.
2230

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

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

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

2259
    """
2260
    return self._ReadKVMRuntime(instance.name)
2261

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

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

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

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

2283
    Stop the incoming mode KVM.
2284

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

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

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

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

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

2315
    The migration will not be attempted if the instance is not
2316
    currently running.
2317

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

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

    
2334
    if not live:
2335
      self._CallMonitorCommand(instance_name, "stop")
2336

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

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

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

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

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

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

    
2366
  def GetMigrationStatus(self, instance):
2367
    """Get the migration status
2368

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

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

    
2396
          return migration_status
2397

    
2398
        logging.warning("KVM: unknown migration status '%s'", status)
2399

    
2400
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2401

    
2402
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2403

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

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

2412
    """
2413
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2414

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

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

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

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

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

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

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

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

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

    
2473
  def Verify(self, hvparams=None):
2474
    """Verify the hypervisor.
2475

2476
    Check that the required binaries exist.
2477

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

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

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

    
2494
    return self._FormatVerifyResults(msgs)
2495

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2580
    kvm_path = hvparams[constants.HV_KVM_PATH]
2581

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

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

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

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

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

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

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

2637
    """
2638
    cls.LinuxPowercycle()