Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ f4529722

History | View | Annotate | Download (93.9 kB)

1
#
2
#
3

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

    
21

    
22
"""KVM hypervisor
23

24
"""
25

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

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

    
62

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

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

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

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

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

    
116

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

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

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

130
  """
131

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

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

    
138

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

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

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

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

    
161
  pci_reservations[free] = True
162

    
163

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

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

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

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

    
187
  return found[0]
188

    
189

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

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

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

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

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

    
212

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

216
  @see: L{_ProbeTapVnetHdr}
217

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

    
229

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

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

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

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

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

    
253
  result = bool(flags & IFF_VNET_HDR)
254

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

    
258
  return result
259

    
260

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

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

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

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

    
278
  flags = IFF_TAP | IFF_NO_PI
279

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

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

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

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

    
296

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

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

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

    
308
    self.data = data
309

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

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

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

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

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

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

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

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

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

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

    
350

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

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

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

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

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

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

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

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

393
    Connects to the UNIX socket
394

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

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

    
401
    self._check_socket()
402

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

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

413
    It cannot be used after this call.
414

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

    
418

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

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

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

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

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

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

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

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

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

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

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

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

    
485
    return (message, buf)
486

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

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

495
    """
496
    self._check_connection()
497

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

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

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

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

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

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

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

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

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

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

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

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

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

    
582

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

586
  """
587
  CAN_MIGRATE = True
588

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

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

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

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

    
703
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
704
  _MIGRATION_INFO_RETRY_DELAY = 2
705

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

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

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

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

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

    
737
  _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
738

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
823
    return (instance, memory, vcpus)
824

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

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

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

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

    
844
    return (pidfile, pid, alive)
845

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1109
    return result
1110

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1270
    return dev_opts
1271

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

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

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

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

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

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

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

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

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

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

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

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

    
1356
    disk_type = hvp[constants.HV_DISK_TYPE]
1357

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1510
        spice_address = addresses[spice_ip_version][0]
1511

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1619
    hvparams = hvp
1620

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

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

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

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

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

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

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

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

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

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

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

    
1664
    return _AnalyzeSerializedRuntime(serialized_runtime)
1665

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

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

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

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

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

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

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

    
1712
    temp_files = []
1713

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1948
    return result
1949

    
1950
  def _GetFreePCISlot(self, instance, dev):
1951
    """Get the first available pci slot of a runnung instance.
1952

1953
    """
1954
    slots = bitarray(32)
1955
    slots.setall(False) # pylint: disable=E1101
1956
    output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
1957
    for line in output.stdout.splitlines():
1958
      match = self._INFO_PCI_RE.search(line)
1959
      if match:
1960
        slot = int(match.group(1))
1961
        slots[slot] = True
1962

    
1963
    [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
1964
    if not free:
1965
      raise errors.HypervisorError("All PCI slots occupied")
1966

    
1967
    dev.pci = int(free)
1968

    
1969
  def VerifyHotplugSupport(self, instance, action, dev_type):
1970
    """Verifies that hotplug is supported.
1971

1972
    Hotplug is *not* supported in case of:
1973
     - qemu versions < 1.0
1974
     - security models and chroot (disk hotplug)
1975
     - fdsend module is missing (nic hot-add)
1976

1977
    @raise errors.HypervisorError: in one of the previous cases
1978

1979
    """
1980
    output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
1981
    # TODO: search for netdev_add, drive_add, device_add.....
1982
    match = self._INFO_VERSION_RE.search(output.stdout)
1983
    if not match:
1984
      raise errors.HotplugError("Try hotplug only in running instances.")
1985
    v_major, v_min, _, _ = match.groups()
1986
    if (int(v_major), int(v_min)) < (1, 0):
1987
      raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
1988

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

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

    
2005
  def _CallHotplugCommand(self, name, cmd):
2006
    output = self._CallMonitorCommand(name, cmd)
2007
    # TODO: parse output and check if succeeded
2008
    for line in output.stdout.splitlines():
2009
      logging.info("%s", line)
2010

    
2011
  def HotAddDevice(self, instance, dev_type, device, extra, seq):
2012
    """ Helper method to hot-add a new device
2013

2014
    It gets free pci slot generates the device name and invokes the
2015
    device specific method.
2016

2017
    """
2018
    # in case of hot-mod this is given
2019
    if device.pci is None:
2020
      self._GetFreePCISlot(instance, device)
2021
    kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2022
    runtime = self._LoadKVMRuntime(instance)
2023
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2024
      command = "drive_add dummy file=%s,if=none,id=%s,format=raw\n" % \
2025
                 (extra, kvm_devid)
2026
      command += ("device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
2027
                  (hex(device.pci), kvm_devid, kvm_devid))
2028
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
2029
      (tap, fd) = _OpenTap()
2030
      self._ConfigureNIC(instance, seq, device, tap)
2031
      self._PassTapFd(instance, fd, device)
2032
      command = "netdev_add tap,id=%s,fd=%s\n" % (kvm_devid, kvm_devid)
2033
      args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
2034
               (hex(device.pci), device.mac, kvm_devid, kvm_devid)
2035
      command += "device_add %s" % args
2036
      utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
2037

    
2038
    self._CallHotplugCommand(instance.name, command)
2039
    # update relevant entries in runtime file
2040
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2041
    entry = _RUNTIME_ENTRY[dev_type](device, extra)
2042
    runtime[index].append(entry)
2043
    self._SaveKVMRuntime(instance, runtime)
2044

    
2045
  def HotDelDevice(self, instance, dev_type, device, _, seq):
2046
    """ Helper method for hot-del device
2047

2048
    It gets device info from runtime file, generates the device name and
2049
    invokes the device specific method.
2050

2051
    """
2052
    runtime = self._LoadKVMRuntime(instance)
2053
    entry = _GetExistingDeviceInfo(dev_type, device, runtime)
2054
    kvm_device = _RUNTIME_DEVICE[dev_type](entry)
2055
    kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
2056
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2057
      command = "device_del %s" % kvm_devid
2058
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
2059
      command = "device_del %s\n" % kvm_devid
2060
      command += "netdev_del %s" % kvm_devid
2061
      utils.RemoveFile(self._InstanceNICFile(instance.name, seq))
2062
    self._CallHotplugCommand(instance.name, command)
2063
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2064
    runtime[index].remove(entry)
2065
    self._SaveKVMRuntime(instance, runtime)
2066

    
2067
    return kvm_device.pci
2068

    
2069
  def HotModDevice(self, instance, dev_type, device, _, seq):
2070
    """ Helper method for hot-mod device
2071

2072
    It gets device info from runtime file, generates the device name and
2073
    invokes the device specific method. Currently only NICs support hot-mod
2074

2075
    """
2076
    if dev_type == constants.HOTPLUG_TARGET_NIC:
2077
      # putting it back in the same pci slot
2078
      device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2079
      # TODO: remove sleep when socat gets removed
2080
      time.sleep(2)
2081
      self.HotAddDevice(instance, dev_type, device, _, seq)
2082

    
2083
  def _PassTapFd(self, instance, fd, nic):
2084
    """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2085

2086
    """
2087
    # TODO: factor out code related to unix sockets.
2088
    #       squash common parts between monitor and qmp
2089
    kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2090
    command = "getfd %s\n" % kvm_devid
2091
    fds = [fd]
2092
    logging.info("%s", fds)
2093
    try:
2094
      monsock = MonitorSocket(self._InstanceMonitor(instance.name))
2095
      monsock.connect()
2096
      fdsend.sendfds(monsock.sock, command, fds=fds)
2097
    finally:
2098
      monsock.close()
2099

    
2100
  @classmethod
2101
  def _ParseKVMVersion(cls, text):
2102
    """Parse the KVM version from the --help output.
2103

2104
    @type text: string
2105
    @param text: output of kvm --help
2106
    @return: (version, v_maj, v_min, v_rev)
2107
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2108

2109
    """
2110
    match = cls._VERSION_RE.search(text.splitlines()[0])
2111
    if not match:
2112
      raise errors.HypervisorError("Unable to get KVM version")
2113

    
2114
    v_all = match.group(0)
2115
    v_maj = int(match.group(1))
2116
    v_min = int(match.group(2))
2117
    if match.group(4):
2118
      v_rev = int(match.group(4))
2119
    else:
2120
      v_rev = 0
2121
    return (v_all, v_maj, v_min, v_rev)
2122

    
2123
  @classmethod
2124
  def _GetKVMOutput(cls, kvm_path, option):
2125
    """Return the output of a kvm invocation
2126

2127
    @type kvm_path: string
2128
    @param kvm_path: path to the kvm executable
2129
    @type option: a key of _KVMOPTS_CMDS
2130
    @param option: kvm option to fetch the output from
2131
    @return: output a supported kvm invocation
2132
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2133

2134
    """
2135
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2136

    
2137
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
2138

    
2139
    result = utils.RunCmd([kvm_path] + optlist)
2140
    if result.failed and not can_fail:
2141
      raise errors.HypervisorError("Unable to get KVM %s output" %
2142
                                    " ".join(optlist))
2143
    return result.output
2144

    
2145
  @classmethod
2146
  def _GetKVMVersion(cls, kvm_path):
2147
    """Return the installed KVM version.
2148

2149
    @return: (version, v_maj, v_min, v_rev)
2150
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2151

2152
    """
2153
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2154

    
2155
  @classmethod
2156
  def _GetDefaultMachineVersion(cls, kvm_path):
2157
    """Return the default hardware revision (e.g. pc-1.1)
2158

2159
    """
2160
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2161
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2162
    if match:
2163
      return match.group(1)
2164
    else:
2165
      return "pc"
2166

    
2167
  def StopInstance(self, instance, force=False, retry=False, name=None):
2168
    """Stop an instance.
2169

2170
    """
2171
    if name is not None and not force:
2172
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2173
    if name is None:
2174
      name = instance.name
2175
      acpi = instance.hvparams[constants.HV_ACPI]
2176
    else:
2177
      acpi = False
2178
    _, pid, alive = self._InstancePidAlive(name)
2179
    if pid > 0 and alive:
2180
      if force or not acpi:
2181
        utils.KillProcess(pid)
2182
      else:
2183
        self._CallMonitorCommand(name, "system_powerdown")
2184

    
2185
  def CleanupInstance(self, instance_name):
2186
    """Cleanup after a stopped instance
2187

2188
    """
2189
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
2190
    if pid > 0 and alive:
2191
      raise errors.HypervisorError("Cannot cleanup a live instance")
2192
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2193

    
2194
  def RebootInstance(self, instance):
2195
    """Reboot an instance.
2196

2197
    """
2198
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2199
    # socket the instance will stop, but now power up again. So we'll resort
2200
    # to shutdown and restart.
2201
    _, _, alive = self._InstancePidAlive(instance.name)
2202
    if not alive:
2203
      raise errors.HypervisorError("Failed to reboot instance %s:"
2204
                                   " not running" % instance.name)
2205
    # StopInstance will delete the saved KVM runtime so:
2206
    # ...first load it...
2207
    kvm_runtime = self._LoadKVMRuntime(instance)
2208
    # ...now we can safely call StopInstance...
2209
    if not self.StopInstance(instance):
2210
      self.StopInstance(instance, force=True)
2211
    # ...and finally we can save it again, and execute it...
2212
    self._SaveKVMRuntime(instance, kvm_runtime)
2213
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2214
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2215
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2216

    
2217
  def MigrationInfo(self, instance):
2218
    """Get instance information to perform a migration.
2219

2220
    @type instance: L{objects.Instance}
2221
    @param instance: instance to be migrated
2222
    @rtype: string
2223
    @return: content of the KVM runtime file
2224

2225
    """
2226
    return self._ReadKVMRuntime(instance.name)
2227

    
2228
  def AcceptInstance(self, instance, info, target):
2229
    """Prepare to accept an instance.
2230

2231
    @type instance: L{objects.Instance}
2232
    @param instance: instance to be accepted
2233
    @type info: string
2234
    @param info: content of the KVM runtime file on the source node
2235
    @type target: string
2236
    @param target: target host (usually ip), on this node
2237

2238
    """
2239
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2240
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2241
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2242
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2243
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2244
                            incoming=incoming_address)
2245

    
2246
  def FinalizeMigrationDst(self, instance, info, success):
2247
    """Finalize the instance migration on the target node.
2248

2249
    Stop the incoming mode KVM.
2250

2251
    @type instance: L{objects.Instance}
2252
    @param instance: instance whose migration is being finalized
2253

2254
    """
2255
    if success:
2256
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2257
      kvm_nics = kvm_runtime[1]
2258

    
2259
      for nic_seq, nic in enumerate(kvm_nics):
2260
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2261
          # Bridged interfaces have already been configured
2262
          continue
2263
        try:
2264
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2265
        except EnvironmentError, err:
2266
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
2267
                          instance.name, nic_seq, str(err))
2268
          continue
2269
        try:
2270
          self._ConfigureNIC(instance, nic_seq, nic, tap)
2271
        except errors.HypervisorError, err:
2272
          logging.warning(str(err))
2273

    
2274
      self._WriteKVMRuntime(instance.name, info)
2275
    else:
2276
      self.StopInstance(instance, force=True)
2277

    
2278
  def MigrateInstance(self, instance, target, live):
2279
    """Migrate an instance to a target node.
2280

2281
    The migration will not be attempted if the instance is not
2282
    currently running.
2283

2284
    @type instance: L{objects.Instance}
2285
    @param instance: the instance to be migrated
2286
    @type target: string
2287
    @param target: ip address of the target node
2288
    @type live: boolean
2289
    @param live: perform a live migration
2290

2291
    """
2292
    instance_name = instance.name
2293
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
2294
    _, _, alive = self._InstancePidAlive(instance_name)
2295
    if not alive:
2296
      raise errors.HypervisorError("Instance not running, cannot migrate")
2297

    
2298
    if not live:
2299
      self._CallMonitorCommand(instance_name, "stop")
2300

    
2301
    migrate_command = ("migrate_set_speed %dm" %
2302
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2303
    self._CallMonitorCommand(instance_name, migrate_command)
2304

    
2305
    migrate_command = ("migrate_set_downtime %dms" %
2306
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2307
    self._CallMonitorCommand(instance_name, migrate_command)
2308

    
2309
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2310
    self._CallMonitorCommand(instance_name, migrate_command)
2311

    
2312
  def FinalizeMigrationSource(self, instance, success, live):
2313
    """Finalize the instance migration on the source node.
2314

2315
    @type instance: L{objects.Instance}
2316
    @param instance: the instance that was migrated
2317
    @type success: bool
2318
    @param success: whether the migration succeeded or not
2319
    @type live: bool
2320
    @param live: whether the user requested a live migration or not
2321

2322
    """
2323
    if success:
2324
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2325
      utils.KillProcess(pid)
2326
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2327
    elif live:
2328
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2329

    
2330
  def GetMigrationStatus(self, instance):
2331
    """Get the migration status
2332

2333
    @type instance: L{objects.Instance}
2334
    @param instance: the instance that is being migrated
2335
    @rtype: L{objects.MigrationStatus}
2336
    @return: the status of the current migration (one of
2337
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2338
             progress info that can be retrieved from the hypervisor
2339

2340
    """
2341
    info_command = "info migrate"
2342
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2343
      result = self._CallMonitorCommand(instance.name, info_command)
2344
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
2345
      if not match:
2346
        if not result.stdout:
2347
          logging.info("KVM: empty 'info migrate' result")
2348
        else:
2349
          logging.warning("KVM: unknown 'info migrate' result: %s",
2350
                          result.stdout)
2351
      else:
2352
        status = match.group(1)
2353
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2354
          migration_status = objects.MigrationStatus(status=status)
2355
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2356
          if match:
2357
            migration_status.transferred_ram = match.group("transferred")
2358
            migration_status.total_ram = match.group("total")
2359

    
2360
          return migration_status
2361

    
2362
        logging.warning("KVM: unknown migration status '%s'", status)
2363

    
2364
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2365

    
2366
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2367

    
2368
  def BalloonInstanceMemory(self, instance, mem):
2369
    """Balloon an instance memory to a certain value.
2370

2371
    @type instance: L{objects.Instance}
2372
    @param instance: instance to be accepted
2373
    @type mem: int
2374
    @param mem: actual memory size to use for instance runtime
2375

2376
    """
2377
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2378

    
2379
  def GetNodeInfo(self):
2380
    """Return information about the node.
2381

2382
    @return: a dict with the following keys (values in MiB):
2383
          - memory_total: the total memory size on the node
2384
          - memory_free: the available memory on the node for instances
2385
          - memory_dom0: the memory used by the node itself, if available
2386
          - hv_version: the hypervisor version in the form (major, minor,
2387
                        revision)
2388

2389
    """
2390
    result = self.GetLinuxNodeInfo()
2391
    # FIXME: this is the global kvm version, but the actual version can be
2392
    # customized as an hv parameter. we should use the nodegroup's default kvm
2393
    # path parameter here.
2394
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2395
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2396
    return result
2397

    
2398
  @classmethod
2399
  def GetInstanceConsole(cls, instance, hvparams, beparams):
2400
    """Return a command for connecting to the console of an instance.
2401

2402
    """
2403
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2404
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2405
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2406
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2407
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2408
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2409
      return objects.InstanceConsole(instance=instance.name,
2410
                                     kind=constants.CONS_SSH,
2411
                                     host=instance.primary_node,
2412
                                     user=constants.SSH_CONSOLE_USER,
2413
                                     command=cmd)
2414

    
2415
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2416
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2417
      display = instance.network_port - constants.VNC_BASE_PORT
2418
      return objects.InstanceConsole(instance=instance.name,
2419
                                     kind=constants.CONS_VNC,
2420
                                     host=vnc_bind_address,
2421
                                     port=instance.network_port,
2422
                                     display=display)
2423

    
2424
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2425
    if spice_bind:
2426
      return objects.InstanceConsole(instance=instance.name,
2427
                                     kind=constants.CONS_SPICE,
2428
                                     host=spice_bind,
2429
                                     port=instance.network_port)
2430

    
2431
    return objects.InstanceConsole(instance=instance.name,
2432
                                   kind=constants.CONS_MESSAGE,
2433
                                   message=("No serial shell for instance %s" %
2434
                                            instance.name))
2435

    
2436
  def Verify(self):
2437
    """Verify the hypervisor.
2438

2439
    Check that the required binaries exist.
2440

2441
    @return: Problem description if something is wrong, C{None} otherwise
2442

2443
    """
2444
    msgs = []
2445
    # FIXME: this is the global kvm binary, but the actual path can be
2446
    # customized as an hv parameter; we should use the nodegroup's
2447
    # default kvm path parameter here.
2448
    if not os.path.exists(constants.KVM_PATH):
2449
      msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2450
    if not os.path.exists(constants.SOCAT_PATH):
2451
      msgs.append("The socat binary ('%s') does not exist" %
2452
                  constants.SOCAT_PATH)
2453

    
2454
    return self._FormatVerifyResults(msgs)
2455

    
2456
  @classmethod
2457
  def CheckParameterSyntax(cls, hvparams):
2458
    """Check the given parameters for validity.
2459

2460
    @type hvparams:  dict
2461
    @param hvparams: dictionary with parameter names/value
2462
    @raise errors.HypervisorError: when a parameter is not valid
2463

2464
    """
2465
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2466

    
2467
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2468
    if kernel_path:
2469
      if not hvparams[constants.HV_ROOT_PATH]:
2470
        raise errors.HypervisorError("Need a root partition for the instance,"
2471
                                     " if a kernel is defined")
2472

    
2473
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2474
        not hvparams[constants.HV_VNC_X509]):
2475
      raise errors.HypervisorError("%s must be defined, if %s is" %
2476
                                   (constants.HV_VNC_X509,
2477
                                    constants.HV_VNC_X509_VERIFY))
2478

    
2479
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2480
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2481
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2482
      if not serial_speed or serial_speed not in valid_speeds:
2483
        raise errors.HypervisorError("Invalid serial console speed, must be"
2484
                                     " one of: %s" %
2485
                                     utils.CommaJoin(valid_speeds))
2486

    
2487
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2488
    if (boot_order == constants.HT_BO_CDROM and
2489
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2490
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2491
                                   " ISO path")
2492

    
2493
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2494
    if security_model == constants.HT_SM_USER:
2495
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2496
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2497
                                     " must be specified")
2498
    elif (security_model == constants.HT_SM_NONE or
2499
          security_model == constants.HT_SM_POOL):
2500
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2501
        raise errors.HypervisorError("Cannot have a security domain when the"
2502
                                     " security model is 'none' or 'pool'")
2503

    
2504
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2505
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2506
    if spice_bind:
2507
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2508
        # if an IP version is specified, the spice_bind parameter must be an
2509
        # IP of that family
2510
        if (netutils.IP4Address.IsValid(spice_bind) and
2511
            spice_ip_version != constants.IP4_VERSION):
2512
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2513
                                       " the specified IP version is %s" %
2514
                                       (spice_bind, spice_ip_version))
2515

    
2516
        if (netutils.IP6Address.IsValid(spice_bind) and
2517
            spice_ip_version != constants.IP6_VERSION):
2518
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2519
                                       " the specified IP version is %s" %
2520
                                       (spice_bind, spice_ip_version))
2521
    else:
2522
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2523
      # error if any of them is set without it.
2524
      for param in _SPICE_ADDITIONAL_PARAMS:
2525
        if hvparams[param]:
2526
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2527
                                       (param, constants.HV_KVM_SPICE_BIND))
2528

    
2529
  @classmethod
2530
  def ValidateParameters(cls, hvparams):
2531
    """Check the given parameters for validity.
2532

2533
    @type hvparams:  dict
2534
    @param hvparams: dictionary with parameter names/value
2535
    @raise errors.HypervisorError: when a parameter is not valid
2536

2537
    """
2538
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2539

    
2540
    kvm_path = hvparams[constants.HV_KVM_PATH]
2541

    
2542
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2543
    if security_model == constants.HT_SM_USER:
2544
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2545
      try:
2546
        pwd.getpwnam(username)
2547
      except KeyError:
2548
        raise errors.HypervisorError("Unknown security domain user %s"
2549
                                     % username)
2550

    
2551
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2552
    if spice_bind:
2553
      # only one of VNC and SPICE can be used currently.
2554
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2555
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2556
                                     " only one of them can be used at a"
2557
                                     " given time")
2558

    
2559
      # check that KVM supports SPICE
2560
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2561
      if not cls._SPICE_RE.search(kvmhelp):
2562
        raise errors.HypervisorError("SPICE is configured, but it is not"
2563
                                     " supported according to 'kvm --help'")
2564

    
2565
      # if spice_bind is not an IP address, it must be a valid interface
2566
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2567
                       netutils.IP6Address.IsValid(spice_bind))
2568
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2569
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2570
                                     " a valid IP address or interface name" %
2571
                                     constants.HV_KVM_SPICE_BIND)
2572

    
2573
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2574
    if machine_version:
2575
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2576
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2577
        raise errors.HypervisorError("Unsupported machine version: %s" %
2578
                                     machine_version)
2579

    
2580
  @classmethod
2581
  def PowercycleNode(cls):
2582
    """KVM powercycle, just a wrapper over Linux powercycle.
2583

2584
    """
2585
    cls.LinuxPowercycle()