Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 2becae3f

History | View | Annotate | Download (90.5 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
import copy
41
from bitarray import bitarray
42
try:
43
  import affinity   # pylint: disable=F0401
44
except ImportError:
45
  affinity = None
46
try:
47
  import fdsend   # pylint: disable=F0401
48
except ImportError:
49
  nic_hotplug = False
50

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

    
63

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

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

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

    
88
FREE = bitarray("0")
89

    
90
def _GenerateDeviceKVMId(dev_type, dev):
91

    
92
  if not dev or not dev.pci:
93
    return None
94

    
95
  return "%s-pci-%d" % (dev_type.lower(), dev.pci)
96

    
97

    
98
def _UpdatePCISlots(dev, pci_reservations):
99
  """Update pci configuration for a stopped instance
100

101
  If dev has a pci slot the reserve it, else find first available.
102

103
  """
104
  if dev.pci:
105
    free = dev.pci
106
  else:
107
    [free] = pci_reservations.search(FREE, 1) # pylint: disable=E1103
108
    if not free:
109
      raise errors.HypervisorError("All PCI slots occupied")
110
    dev.pci = int(free)
111

    
112
  pci_reservations[free] = True
113

    
114

    
115
def _RemoveFromRuntimeEntry(devices, device, fn):
116
  [rem] = [x for x in fn(devices) if x.uuid == device.uuid]
117
  try:
118
    devices.remove(rem)
119
  except (ValueError, IndexError):
120
    logging.info("No device with uuid %s in runtime file", device.uuid)
121

    
122

    
123
def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
124
  """Retrieves supported TUN features from file descriptor.
125

126
  @see: L{_ProbeTapVnetHdr}
127

128
  """
129
  req = struct.pack("I", 0)
130
  try:
131
    buf = _ioctl(fd, TUNGETFEATURES, req)
132
  except EnvironmentError, err:
133
    logging.warning("ioctl(TUNGETFEATURES) failed: %s", err)
134
    return None
135
  else:
136
    (flags, ) = struct.unpack("I", buf)
137
    return flags
138

    
139

    
140
def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
141
  """Check whether to enable the IFF_VNET_HDR flag.
142

143
  To do this, _all_ of the following conditions must be met:
144
   1. TUNGETFEATURES ioctl() *must* be implemented
145
   2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
146
   3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
147
      drivers/net/tun.c there is no way to test this until after the tap device
148
      has been created using TUNSETIFF, and there is no way to change the
149
      IFF_VNET_HDR flag after creating the interface, catch-22! However both
150
      TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
151
      thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
152

153
   @type fd: int
154
   @param fd: the file descriptor of /dev/net/tun
155

156
  """
157
  flags = _features_fn(fd)
158

    
159
  if flags is None:
160
    # Not supported
161
    return False
162

    
163
  result = bool(flags & IFF_VNET_HDR)
164

    
165
  if not result:
166
    logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
167

    
168
  return result
169

    
170

    
171
def _OpenTap(vnet_hdr=True):
172
  """Open a new tap device and return its file descriptor.
173

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

177
  @type vnet_hdr: boolean
178
  @param vnet_hdr: Enable the VNET Header
179
  @return: (ifname, tapfd)
180
  @rtype: tuple
181

182
  """
183
  try:
184
    tapfd = os.open("/dev/net/tun", os.O_RDWR)
185
  except EnvironmentError:
186
    raise errors.HypervisorError("Failed to open /dev/net/tun")
187

    
188
  flags = IFF_TAP | IFF_NO_PI
189

    
190
  if vnet_hdr and _ProbeTapVnetHdr(tapfd):
191
    flags |= IFF_VNET_HDR
192

    
193
  # The struct ifreq ioctl request (see netdevice(7))
194
  ifr = struct.pack("16sh", "", flags)
195

    
196
  try:
197
    res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
198
  except EnvironmentError, err:
199
    raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
200
                                 err)
201

    
202
  # Get the interface name from the ioctl
203
  ifname = struct.unpack("16sh", res)[0].strip("\x00")
204
  return (ifname, tapfd)
205

    
206

    
207
class QmpMessage:
208
  """QEMU Messaging Protocol (QMP) message.
209

210
  """
211
  def __init__(self, data):
212
    """Creates a new QMP message based on the passed data.
213

214
    """
215
    if not isinstance(data, dict):
216
      raise TypeError("QmpMessage must be initialized with a dict")
217

    
218
    self.data = data
219

    
220
  def __getitem__(self, field_name):
221
    """Get the value of the required field if present, or None.
222

223
    Overrides the [] operator to provide access to the message data,
224
    returning None if the required item is not in the message
225
    @return: the value of the field_name field, or None if field_name
226
             is not contained in the message
227

228
    """
229
    return self.data.get(field_name, None)
230

    
231
  def __setitem__(self, field_name, field_value):
232
    """Set the value of the required field_name to field_value.
233

234
    """
235
    self.data[field_name] = field_value
236

    
237
  @staticmethod
238
  def BuildFromJsonString(json_string):
239
    """Build a QmpMessage from a JSON encoded string.
240

241
    @type json_string: str
242
    @param json_string: JSON string representing the message
243
    @rtype: L{QmpMessage}
244
    @return: a L{QmpMessage} built from json_string
245

246
    """
247
    # Parse the string
248
    data = serializer.LoadJson(json_string)
249
    return QmpMessage(data)
250

    
251
  def __str__(self):
252
    # The protocol expects the JSON object to be sent as a single line.
253
    return serializer.DumpJson(self.data)
254

    
255
  def __eq__(self, other):
256
    # When comparing two QmpMessages, we are interested in comparing
257
    # their internal representation of the message data
258
    return self.data == other.data
259

    
260

    
261
class QmpConnection:
262
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
263

264
  """
265
  _FIRST_MESSAGE_KEY = "QMP"
266
  _EVENT_KEY = "event"
267
  _ERROR_KEY = "error"
268
  _RETURN_KEY = RETURN_KEY = "return"
269
  _ACTUAL_KEY = ACTUAL_KEY = "actual"
270
  _ERROR_CLASS_KEY = "class"
271
  _ERROR_DATA_KEY = "data"
272
  _ERROR_DESC_KEY = "desc"
273
  _EXECUTE_KEY = "execute"
274
  _ARGUMENTS_KEY = "arguments"
275
  _CAPABILITIES_COMMAND = "qmp_capabilities"
276
  _MESSAGE_END_TOKEN = "\r\n"
277
  _SOCKET_TIMEOUT = 5
278

    
279
  def __init__(self, monitor_filename):
280
    """Instantiates the QmpConnection object.
281

282
    @type monitor_filename: string
283
    @param monitor_filename: the filename of the UNIX raw socket on which the
284
                             QMP monitor is listening
285

286
    """
287
    self.monitor_filename = monitor_filename
288
    self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
289
    # We want to fail if the server doesn't send a complete message
290
    # in a reasonable amount of time
291
    self.sock.settimeout(self._SOCKET_TIMEOUT)
292
    self._connected = False
293
    self._buf = ""
294

    
295
  def _check_socket(self):
296
    sock_stat = None
297
    try:
298
      sock_stat = os.stat(self.monitor_filename)
299
    except EnvironmentError, err:
300
      if err.errno == errno.ENOENT:
301
        raise errors.HypervisorError("No qmp socket found")
302
      else:
303
        raise errors.HypervisorError("Error checking qmp socket: %s",
304
                                     utils.ErrnoOrStr(err))
305
    if not stat.S_ISSOCK(sock_stat.st_mode):
306
      raise errors.HypervisorError("Qmp socket is not a socket")
307

    
308
  def _check_connection(self):
309
    """Make sure that the connection is established.
310

311
    """
312
    if not self._connected:
313
      raise errors.ProgrammerError("To use a QmpConnection you need to first"
314
                                   " invoke connect() on it")
315

    
316
  def connect(self):
317
    """Connects to the QMP monitor.
318

319
    Connects to the UNIX socket and makes sure that we can actually send and
320
    receive data to the kvm instance via QMP.
321

322
    @raise errors.HypervisorError: when there are communication errors
323
    @raise errors.ProgrammerError: when there are data serialization errors
324

325
    """
326
    if self._connected:
327
      raise errors.ProgrammerError("Cannot connect twice")
328

    
329
    self._check_socket()
330

    
331
    # Check file existance/stuff
332
    try:
333
      self.sock.connect(self.monitor_filename)
334
    except EnvironmentError:
335
      raise errors.HypervisorError("Can't connect to qmp socket")
336
    self._connected = True
337

    
338
    # Check if we receive a correct greeting message from the server
339
    # (As per the QEMU Protocol Specification 0.1 - section 2.2)
340
    greeting = self._Recv()
341
    if not greeting[self._FIRST_MESSAGE_KEY]:
342
      self._connected = False
343
      raise errors.HypervisorError("kvm: QMP communication error (wrong"
344
                                   " server greeting")
345

    
346
    # Let's put the monitor in command mode using the qmp_capabilities
347
    # command, or else no command will be executable.
348
    # (As per the QEMU Protocol Specification 0.1 - section 4)
349
    self.Execute(self._CAPABILITIES_COMMAND)
350

    
351
  def _ParseMessage(self, buf):
352
    """Extract and parse a QMP message from the given buffer.
353

354
    Seeks for a QMP message in the given buf. If found, it parses it and
355
    returns it together with the rest of the characters in the buf.
356
    If no message is found, returns None and the whole buffer.
357

358
    @raise errors.ProgrammerError: when there are data serialization errors
359

360
    """
361
    message = None
362
    # Check if we got the message end token (CRLF, as per the QEMU Protocol
363
    # Specification 0.1 - Section 2.1.1)
364
    pos = buf.find(self._MESSAGE_END_TOKEN)
365
    if pos >= 0:
366
      try:
367
        message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
368
      except Exception, err:
369
        raise errors.ProgrammerError("QMP data serialization error: %s" % err)
370
      buf = buf[pos + 1:]
371

    
372
    return (message, buf)
373

    
374
  def _Recv(self):
375
    """Receives a message from QMP and decodes the received JSON object.
376

377
    @rtype: QmpMessage
378
    @return: the received message
379
    @raise errors.HypervisorError: when there are communication errors
380
    @raise errors.ProgrammerError: when there are data serialization errors
381

382
    """
383
    self._check_connection()
384

    
385
    # Check if there is already a message in the buffer
386
    (message, self._buf) = self._ParseMessage(self._buf)
387
    if message:
388
      return message
389

    
390
    recv_buffer = StringIO.StringIO(self._buf)
391
    recv_buffer.seek(len(self._buf))
392
    try:
393
      while True:
394
        data = self.sock.recv(4096)
395
        if not data:
396
          break
397
        recv_buffer.write(data)
398

    
399
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
400
        if message:
401
          return message
402

    
403
    except socket.timeout, err:
404
      raise errors.HypervisorError("Timeout while receiving a QMP message: "
405
                                   "%s" % (err))
406
    except socket.error, err:
407
      raise errors.HypervisorError("Unable to receive data from KVM using the"
408
                                   " QMP protocol: %s" % err)
409

    
410
  def _Send(self, message):
411
    """Encodes and sends a message to KVM using QMP.
412

413
    @type message: QmpMessage
414
    @param message: message to send to KVM
415
    @raise errors.HypervisorError: when there are communication errors
416
    @raise errors.ProgrammerError: when there are data serialization errors
417

418
    """
419
    self._check_connection()
420
    try:
421
      message_str = str(message)
422
    except Exception, err:
423
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
424

    
425
    try:
426
      self.sock.sendall(message_str)
427
    except socket.timeout, err:
428
      raise errors.HypervisorError("Timeout while sending a QMP message: "
429
                                   "%s (%s)" % (err.string, err.errno))
430
    except socket.error, err:
431
      raise errors.HypervisorError("Unable to send data from KVM using the"
432
                                   " QMP protocol: %s" % err)
433

    
434
  def Execute(self, command, arguments=None):
435
    """Executes a QMP command and returns the response of the server.
436

437
    @type command: str
438
    @param command: the command to execute
439
    @type arguments: dict
440
    @param arguments: dictionary of arguments to be passed to the command
441
    @rtype: dict
442
    @return: dictionary representing the received JSON object
443
    @raise errors.HypervisorError: when there are communication errors
444
    @raise errors.ProgrammerError: when there are data serialization errors
445

446
    """
447
    self._check_connection()
448
    message = QmpMessage({self._EXECUTE_KEY: command})
449
    if arguments:
450
      message[self._ARGUMENTS_KEY] = arguments
451
    self._Send(message)
452

    
453
    # Events can occur between the sending of the command and the reception
454
    # of the response, so we need to filter out messages with the event key.
455
    while True:
456
      response = self._Recv()
457
      err = response[self._ERROR_KEY]
458
      if err:
459
        raise errors.HypervisorError("kvm: error executing the %s"
460
                                     " command: %s (%s, %s):" %
461
                                     (command,
462
                                      err[self._ERROR_DESC_KEY],
463
                                      err[self._ERROR_CLASS_KEY],
464
                                      err[self._ERROR_DATA_KEY]))
465

    
466
      elif not response[self._EVENT_KEY]:
467
        return response
468

    
469

    
470
class KVMHypervisor(hv_base.BaseHypervisor):
471
  """KVM hypervisor interface
472

473
  """
474
  CAN_MIGRATE = True
475

    
476
  _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
477
  _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
478
  _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
479
  _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
480
  _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
481
  _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
482
  _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
483
  # KVM instances with chroot enabled are started in empty chroot directories.
484
  _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
485
  # After an instance is stopped, its chroot directory is removed.
486
  # If the chroot directory is not empty, it can't be removed.
487
  # A non-empty chroot directory indicates a possible security incident.
488
  # To support forensics, the non-empty chroot directory is quarantined in
489
  # a separate directory, called 'chroot-quarantine'.
490
  _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
491
  _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
492
           _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
493

    
494
  PARAMETERS = {
495
    constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
496
    constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
497
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
498
    constants.HV_ROOT_PATH: hv_base.NO_CHECK,
499
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
500
    constants.HV_ACPI: hv_base.NO_CHECK,
501
    constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
502
    constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
503
    constants.HV_VNC_BIND_ADDRESS: hv_base.NO_CHECK, # will be checked later
504
    constants.HV_VNC_TLS: hv_base.NO_CHECK,
505
    constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
506
    constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
507
    constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
508
    constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
509
    constants.HV_KVM_SPICE_IP_VERSION:
510
      (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
511
                         x in constants.VALID_IP_VERSIONS),
512
       "The SPICE IP version should be 4 or 6",
513
       None, None),
514
    constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
515
    constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
516
      hv_base.ParamInSet(
517
        False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
518
    constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
519
      hv_base.ParamInSet(
520
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
521
    constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
522
      hv_base.ParamInSet(
523
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
524
    constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
525
      hv_base.ParamInSet(
526
        False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
527
    constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
528
    constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
529
    constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
530
    constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
531
    constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
532
    constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
533
    constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
534
    constants.HV_BOOT_ORDER:
535
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
536
    constants.HV_NIC_TYPE:
537
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
538
    constants.HV_DISK_TYPE:
539
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
540
    constants.HV_KVM_CDROM_DISK_TYPE:
541
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
542
    constants.HV_USB_MOUSE:
543
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
544
    constants.HV_KEYMAP: hv_base.NO_CHECK,
545
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
546
    constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
547
    constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
548
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
549
    constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
550
    constants.HV_DISK_CACHE:
551
      hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
552
    constants.HV_SECURITY_MODEL:
553
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
554
    constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
555
    constants.HV_KVM_FLAG:
556
      hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
557
    constants.HV_VHOST_NET: hv_base.NO_CHECK,
558
    constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
559
    constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
560
    constants.HV_REBOOT_BEHAVIOR:
561
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
562
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
563
    constants.HV_CPU_TYPE: hv_base.NO_CHECK,
564
    constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
565
    constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
566
    constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
567
    constants.HV_SOUNDHW: hv_base.NO_CHECK,
568
    constants.HV_USB_DEVICES: hv_base.NO_CHECK,
569
    constants.HV_VGA: hv_base.NO_CHECK,
570
    constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
571
    constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
572
    }
573

    
574
  _VIRTIO = "virtio"
575
  _VIRTIO_NET_PCI = "virtio-net-pci"
576

    
577
  _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
578
                                    re.M | re.I)
579
  _MIGRATION_PROGRESS_RE = \
580
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
581
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
582
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
583

    
584
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
585
  _MIGRATION_INFO_RETRY_DELAY = 2
586

    
587
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
588

    
589
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
590
  _CPU_INFO_CMD = "info cpus"
591
  _CONT_CMD = "cont"
592

    
593
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
594
  _CHECK_MACHINE_VERSION_RE = \
595
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
596

    
597
  _QMP_RE = re.compile(r"^-qmp\s", re.M)
598
  _SPICE_RE = re.compile(r"^-spice\s", re.M)
599
  _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
600
  _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
601
  _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
602
  _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
603
  _DISPLAY_RE = re.compile(r"^-display\s", re.M)
604
  _MACHINE_RE = re.compile(r"^-machine\s", re.M)
605
  _NEW_VIRTIO_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
606
  # match  -drive.*boot=on|off on different lines, but in between accept only
607
  # dashes not preceeded by a new line (which would mean another option
608
  # different than -drive is starting)
609
  _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
610
  _UUID_RE = re.compile(r"^-uuid\s", re.M)
611

    
612
  _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
613
  _INFO_PCI_CMD = "info pci"
614
  _INFO_VERSION_RE = \
615
    re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
616
  _INFO_VERSION_CMD = "info version"
617

    
618
  _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
619

    
620
  ANCILLARY_FILES = [
621
    _KVM_NETWORK_SCRIPT,
622
    ]
623
  ANCILLARY_FILES_OPT = [
624
    _KVM_NETWORK_SCRIPT,
625
    ]
626

    
627
  # Supported kvm options to get output from
628
  _KVMOPT_HELP = "help"
629
  _KVMOPT_MLIST = "mlist"
630
  _KVMOPT_DEVICELIST = "devicelist"
631

    
632
  # Command to execute to get the output from kvm, and whether to
633
  # accept the output even on failure.
634
  _KVMOPTS_CMDS = {
635
    _KVMOPT_HELP: (["--help"], False),
636
    _KVMOPT_MLIST: (["-M", "?"], False),
637
    _KVMOPT_DEVICELIST: (["-device", "?"], True),
638
  }
639

    
640
  def __init__(self):
641
    hv_base.BaseHypervisor.__init__(self)
642
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
643
    # in a tmpfs filesystem or has been otherwise wiped out.
644
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
645
    utils.EnsureDirs(dirs)
646

    
647
  @classmethod
648
  def _InstancePidFile(cls, instance_name):
649
    """Returns the instance pidfile.
650

651
    """
652
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
653

    
654
  @classmethod
655
  def _InstanceUidFile(cls, instance_name):
656
    """Returns the instance uidfile.
657

658
    """
659
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
660

    
661
  @classmethod
662
  def _InstancePidInfo(cls, pid):
663
    """Check pid file for instance information.
664

665
    Check that a pid file is associated with an instance, and retrieve
666
    information from its command line.
667

668
    @type pid: string or int
669
    @param pid: process id of the instance to check
670
    @rtype: tuple
671
    @return: (instance_name, memory, vcpus)
672
    @raise errors.HypervisorError: when an instance cannot be found
673

674
    """
675
    alive = utils.IsProcessAlive(pid)
676
    if not alive:
677
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
678

    
679
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
680
    try:
681
      cmdline = utils.ReadFile(cmdline_file)
682
    except EnvironmentError, err:
683
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
684
                                   (pid, err))
685

    
686
    instance = None
687
    memory = 0
688
    vcpus = 0
689

    
690
    arg_list = cmdline.split("\x00")
691
    while arg_list:
692
      arg = arg_list.pop(0)
693
      if arg == "-name":
694
        instance = arg_list.pop(0)
695
      elif arg == "-m":
696
        memory = int(arg_list.pop(0))
697
      elif arg == "-smp":
698
        vcpus = int(arg_list.pop(0).split(",")[0])
699

    
700
    if instance is None:
701
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
702
                                   " instance" % pid)
703

    
704
    return (instance, memory, vcpus)
705

    
706
  def _InstancePidAlive(self, instance_name):
707
    """Returns the instance pidfile, pid, and liveness.
708

709
    @type instance_name: string
710
    @param instance_name: instance name
711
    @rtype: tuple
712
    @return: (pid file name, pid, liveness)
713

714
    """
715
    pidfile = self._InstancePidFile(instance_name)
716
    pid = utils.ReadPidFile(pidfile)
717

    
718
    alive = False
719
    try:
720
      cmd_instance = self._InstancePidInfo(pid)[0]
721
      alive = (cmd_instance == instance_name)
722
    except errors.HypervisorError:
723
      pass
724

    
725
    return (pidfile, pid, alive)
726

    
727
  def _CheckDown(self, instance_name):
728
    """Raises an error unless the given instance is down.
729

730
    """
731
    alive = self._InstancePidAlive(instance_name)[2]
732
    if alive:
733
      raise errors.HypervisorError("Failed to start instance %s: %s" %
734
                                   (instance_name, "already running"))
735

    
736
  @classmethod
737
  def _InstanceMonitor(cls, instance_name):
738
    """Returns the instance monitor socket name
739

740
    """
741
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
742

    
743
  @classmethod
744
  def _InstanceSerial(cls, instance_name):
745
    """Returns the instance serial socket name
746

747
    """
748
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
749

    
750
  @classmethod
751
  def _InstanceQmpMonitor(cls, instance_name):
752
    """Returns the instance serial QMP socket name
753

754
    """
755
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
756

    
757
  @staticmethod
758
  def _SocatUnixConsoleParams():
759
    """Returns the correct parameters for socat
760

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

763
    """
764
    if constants.SOCAT_USE_ESCAPE:
765
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
766
    else:
767
      return "echo=0,icanon=0"
768

    
769
  @classmethod
770
  def _InstanceKVMRuntime(cls, instance_name):
771
    """Returns the instance KVM runtime filename
772

773
    """
774
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
775

    
776
  @classmethod
777
  def _InstanceChrootDir(cls, instance_name):
778
    """Returns the name of the KVM chroot dir of the instance
779

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

    
783
  @classmethod
784
  def _InstanceNICDir(cls, instance_name):
785
    """Returns the name of the directory holding the tap device files for a
786
    given instance.
787

788
    """
789
    return utils.PathJoin(cls._NICS_DIR, instance_name)
790

    
791
  @classmethod
792
  def _InstanceNICFile(cls, instance_name, seq):
793
    """Returns the name of the file containing the tap device for a given NIC
794

795
    """
796
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
797

    
798
  @classmethod
799
  def _InstanceKeymapFile(cls, instance_name):
800
    """Returns the name of the file containing the keymap for a given instance
801

802
    """
803
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
804

    
805
  @classmethod
806
  def _TryReadUidFile(cls, uid_file):
807
    """Try to read a uid file
808

809
    """
810
    if os.path.exists(uid_file):
811
      try:
812
        uid = int(utils.ReadOneLineFile(uid_file))
813
        return uid
814
      except EnvironmentError:
815
        logging.warning("Can't read uid file", exc_info=True)
816
      except (TypeError, ValueError):
817
        logging.warning("Can't parse uid file contents", exc_info=True)
818
    return None
819

    
820
  @classmethod
821
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
822
    """Removes an instance's rutime sockets/files/dirs.
823

824
    """
825
    utils.RemoveFile(pidfile)
826
    utils.RemoveFile(cls._InstanceMonitor(instance_name))
827
    utils.RemoveFile(cls._InstanceSerial(instance_name))
828
    utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
829
    utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
830
    utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
831
    uid_file = cls._InstanceUidFile(instance_name)
832
    uid = cls._TryReadUidFile(uid_file)
833
    utils.RemoveFile(uid_file)
834
    if uid is not None:
835
      uidpool.ReleaseUid(uid)
836
    try:
837
      shutil.rmtree(cls._InstanceNICDir(instance_name))
838
    except OSError, err:
839
      if err.errno != errno.ENOENT:
840
        raise
841
    try:
842
      chroot_dir = cls._InstanceChrootDir(instance_name)
843
      utils.RemoveDir(chroot_dir)
844
    except OSError, err:
845
      if err.errno == errno.ENOTEMPTY:
846
        # The chroot directory is expected to be empty, but it isn't.
847
        new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
848
                                          prefix="%s-%s-" %
849
                                          (instance_name,
850
                                           utils.TimestampForFilename()))
851
        logging.warning("The chroot directory of instance %s can not be"
852
                        " removed as it is not empty. Moving it to the"
853
                        " quarantine instead. Please investigate the"
854
                        " contents (%s) and clean up manually",
855
                        instance_name, new_chroot_dir)
856
        utils.RenameFile(chroot_dir, new_chroot_dir)
857
      else:
858
        raise
859

    
860
  @staticmethod
861
  def _ConfigureNIC(instance, seq, nic, tap):
862
    """Run the network configuration script for a specified NIC
863

864
    @param instance: instance we're acting on
865
    @type instance: instance object
866
    @param seq: nic sequence number
867
    @type seq: int
868
    @param nic: nic we're acting on
869
    @type nic: nic object
870
    @param tap: the host's tap interface this NIC corresponds to
871
    @type tap: str
872

873
    """
874
    if instance.tags:
875
      tags = " ".join(instance.tags)
876
    else:
877
      tags = ""
878

    
879
    env = {
880
      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
881
      "INSTANCE": instance.name,
882
      "MAC": nic.mac,
883
      "MODE": nic.nicparams[constants.NIC_MODE],
884
      "INTERFACE": tap,
885
      "INTERFACE_INDEX": str(seq),
886
      "TAGS": tags,
887
    }
888

    
889
    if nic.ip:
890
      env["IP"] = nic.ip
891

    
892
    if nic.nicparams[constants.NIC_LINK]:
893
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
894

    
895
    if nic.network:
896
      n = objects.Network.FromDict(nic.netinfo)
897
      env.update(n.HooksDict())
898

    
899
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
900
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
901

    
902
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
903
    if result.failed:
904
      raise errors.HypervisorError("Failed to configure interface %s: %s;"
905
                                   " network configuration script output: %s" %
906
                                   (tap, result.fail_reason, result.output))
907

    
908
  @staticmethod
909
  def _VerifyAffinityPackage():
910
    if affinity is None:
911
      raise errors.HypervisorError("affinity Python package not"
912
                                   " found; cannot use CPU pinning under KVM")
913

    
914
  @staticmethod
915
  def _BuildAffinityCpuMask(cpu_list):
916
    """Create a CPU mask suitable for sched_setaffinity from a list of
917
    CPUs.
918

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

922
    @type cpu_list: list of int
923
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
924
    @rtype: int
925
    @return: a bit mask of CPU affinities
926

927
    """
928
    if cpu_list == constants.CPU_PINNING_OFF:
929
      return constants.CPU_PINNING_ALL_KVM
930
    else:
931
      return sum(2 ** cpu for cpu in cpu_list)
932

    
933
  @classmethod
934
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
935
    """Change CPU affinity for running VM according to given CPU mask.
936

937
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
938
    @type cpu_mask: string
939
    @param process_id: process ID of KVM process. Used to pin entire VM
940
                       to physical CPUs.
941
    @type process_id: int
942
    @param thread_dict: map of virtual CPUs to KVM thread IDs
943
    @type thread_dict: dict int:int
944

945
    """
946
    # Convert the string CPU mask to a list of list of int's
947
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
948

    
949
    if len(cpu_list) == 1:
950
      all_cpu_mapping = cpu_list[0]
951
      if all_cpu_mapping == constants.CPU_PINNING_OFF:
952
        # If CPU pinning has 1 entry that's "all", then do nothing
953
        pass
954
      else:
955
        # If CPU pinning has one non-all entry, map the entire VM to
956
        # one set of physical CPUs
957
        cls._VerifyAffinityPackage()
958
        affinity.set_process_affinity_mask(
959
          process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
960
    else:
961
      # The number of vCPUs mapped should match the number of vCPUs
962
      # reported by KVM. This was already verified earlier, so
963
      # here only as a sanity check.
964
      assert len(thread_dict) == len(cpu_list)
965
      cls._VerifyAffinityPackage()
966

    
967
      # For each vCPU, map it to the proper list of physical CPUs
968
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
969
        affinity.set_process_affinity_mask(thread_dict[i],
970
                                           cls._BuildAffinityCpuMask(vcpu))
971

    
972
  def _GetVcpuThreadIds(self, instance_name):
973
    """Get a mapping of vCPU no. to thread IDs for the instance
974

975
    @type instance_name: string
976
    @param instance_name: instance in question
977
    @rtype: dictionary of int:int
978
    @return: a dictionary mapping vCPU numbers to thread IDs
979

980
    """
981
    result = {}
982
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
983
    for line in output.stdout.splitlines():
984
      match = self._CPU_INFO_RE.search(line)
985
      if not match:
986
        continue
987
      grp = map(int, match.groups())
988
      result[grp[0]] = grp[1]
989

    
990
    return result
991

    
992
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
993
    """Complete CPU pinning.
994

995
    @type instance_name: string
996
    @param instance_name: name of instance
997
    @type cpu_mask: string
998
    @param cpu_mask: CPU pinning mask as entered by user
999

1000
    """
1001
    # Get KVM process ID, to be used if need to pin entire VM
1002
    _, pid, _ = self._InstancePidAlive(instance_name)
1003
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1004
    thread_dict = self._GetVcpuThreadIds(instance_name)
1005
    # Run CPU pinning, based on configured mask
1006
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1007

    
1008
  def ListInstances(self, hvparams=None):
1009
    """Get the list of running instances.
1010

1011
    We can do this by listing our live instances directory and
1012
    checking whether the associated kvm process is still alive.
1013

1014
    """
1015
    result = []
1016
    for name in os.listdir(self._PIDS_DIR):
1017
      if self._InstancePidAlive(name)[2]:
1018
        result.append(name)
1019
    return result
1020

    
1021
  def GetInstanceInfo(self, instance_name, hvparams=None):
1022
    """Get instance properties.
1023

1024
    @type instance_name: string
1025
    @param instance_name: the instance name
1026
    @type hvparams: dict of strings
1027
    @param hvparams: hvparams to be used with this instance
1028
    @rtype: tuple of strings
1029
    @return: (name, id, memory, vcpus, stat, times)
1030

1031
    """
1032
    _, pid, alive = self._InstancePidAlive(instance_name)
1033
    if not alive:
1034
      return None
1035

    
1036
    _, memory, vcpus = self._InstancePidInfo(pid)
1037
    istat = "---b-"
1038
    times = "0"
1039

    
1040
    try:
1041
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1042
      qmp.connect()
1043
      vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1044
      # Will fail if ballooning is not enabled, but we can then just resort to
1045
      # the value above.
1046
      mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1047
      memory = mem_bytes / 1048576
1048
    except errors.HypervisorError:
1049
      pass
1050

    
1051
    return (instance_name, pid, memory, vcpus, istat, times)
1052

    
1053
  def GetAllInstancesInfo(self, hvparams=None):
1054
    """Get properties of all instances.
1055

1056
    @type hvparams: dict of strings
1057
    @param hvparams: hypervisor parameter
1058
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1059

1060
    """
1061
    data = []
1062
    for name in os.listdir(self._PIDS_DIR):
1063
      try:
1064
        info = self.GetInstanceInfo(name)
1065
      except errors.HypervisorError:
1066
        # Ignore exceptions due to instances being shut down
1067
        continue
1068
      if info:
1069
        data.append(info)
1070
    return data
1071

    
1072
  def _GetExistingDeviceKVMId(self, instance, dev_type, dev):
1073
    (_, kvm_nics, __, block_devices) = self._LoadKVMRuntime(instance)
1074
    if dev_type == "NIC":
1075
      found = [n for n in kvm_nics
1076
               if n.uuid == dev.uuid]
1077
    elif dev_type == "DISK":
1078
      found = [d for d, _ in block_devices
1079
               if d.uuid == dev.uuid]
1080
    dev_info = None
1081
    if found:
1082
      dev_info = found[0]
1083
    return _GenerateDeviceKVMId(dev_type, dev_info)
1084

    
1085
  def _GenerateKVMBlockDevicesOptions(self, instance, kvm_cmd, block_devices,
1086
                                      pci_reservations, kvmhelp):
1087

    
1088
    hvp = instance.hvparams
1089
    boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1090

    
1091
    # whether this is an older KVM version that uses the boot=on flag
1092
    # on devices
1093
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1094

    
1095
    disk_type = hvp[constants.HV_DISK_TYPE]
1096
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
1097
      #TODO: parse kvm -device ? output
1098
      disk_model = "virtio-blk-pci"
1099
      if_val = ",if=virtio"
1100
    else:
1101
      if_val = ",if=%s" % disk_type
1102
    # Cache mode
1103
    disk_cache = hvp[constants.HV_DISK_CACHE]
1104
    if instance.disk_template in constants.DTS_EXT_MIRROR:
1105
      if disk_cache != "none":
1106
        # TODO: make this a hard error, instead of a silent overwrite
1107
        logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1108
                        " to prevent shared storage corruption on migration",
1109
                        disk_cache)
1110
      cache_val = ",cache=none"
1111
    elif disk_cache != constants.HT_CACHE_DEFAULT:
1112
      cache_val = ",cache=%s" % disk_cache
1113
    else:
1114
      cache_val = ""
1115
    for cfdev, dev_path in block_devices:
1116
      if cfdev.mode != constants.DISK_RDWR:
1117
        raise errors.HypervisorError("Instance has read-only disks which"
1118
                                     " are not supported by KVM")
1119
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
1120
      boot_val = ""
1121
      if boot_disk:
1122
        kvm_cmd.extend(["-boot", "c"])
1123
        boot_disk = False
1124
        if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1125
          boot_val = ",boot=on"
1126
      drive_val = "file=%s,format=raw%s%s" % \
1127
                  (dev_path, boot_val, cache_val)
1128
      _UpdatePCISlots(cfdev, pci_reservations)
1129
      kvm_devid = _GenerateDeviceKVMId("DISK", cfdev)
1130
      if kvm_devid:
1131
        #TODO: name id after model
1132
        drive_val += (",if=none,id=%s" % kvm_devid)
1133
        drive_val += (",bus=0,unit=%d" % cfdev.pci)
1134
      else:
1135
        drive_val += if_val
1136

    
1137
      kvm_cmd.extend(["-drive", drive_val])
1138

    
1139
      if kvm_devid:
1140
        dev_val = ("%s,drive=%s,id=%s" %
1141
                    (disk_model, kvm_devid, kvm_devid))
1142
        dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci)
1143
        kvm_cmd.extend(["-device", dev_val])
1144

    
1145
    return kvm_cmd
1146

    
1147
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1148
                          kvmhelp):
1149
    """Generate KVM information to start an instance.
1150

1151
    @type kvmhelp: string
1152
    @param kvmhelp: output of kvm --help
1153
    @attention: this function must not have any side-effects; for
1154
        example, it must not write to the filesystem, or read values
1155
        from the current system the are expected to differ between
1156
        nodes, since it is only run once at instance startup;
1157
        actions/kvm arguments that can vary between systems should be
1158
        done in L{_ExecuteKVMRuntime}
1159

1160
    """
1161
    # pylint: disable=R0912,R0914,R0915
1162
    hvp = instance.hvparams
1163
    self.ValidateParameters(hvp)
1164

    
1165
    pidfile = self._InstancePidFile(instance.name)
1166
    kvm = hvp[constants.HV_KVM_PATH]
1167
    kvm_cmd = [kvm]
1168
    # used just by the vnc server, if enabled
1169
    kvm_cmd.extend(["-name", instance.name])
1170
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1171

    
1172
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1173
    if hvp[constants.HV_CPU_CORES]:
1174
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1175
    if hvp[constants.HV_CPU_THREADS]:
1176
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1177
    if hvp[constants.HV_CPU_SOCKETS]:
1178
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1179

    
1180
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1181

    
1182
    kvm_cmd.extend(["-pidfile", pidfile])
1183
    kvm_cmd.extend(["-balloon", "virtio"])
1184
    kvm_cmd.extend(["-daemonize"])
1185
    if not instance.hvparams[constants.HV_ACPI]:
1186
      kvm_cmd.extend(["-no-acpi"])
1187
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1188
        constants.INSTANCE_REBOOT_EXIT:
1189
      kvm_cmd.extend(["-no-reboot"])
1190

    
1191
    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1192
    if not mversion:
1193
      mversion = self._GetDefaultMachineVersion(kvm)
1194
    if self._MACHINE_RE.search(kvmhelp):
1195
      # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1196
      # extra hypervisor parameters. We should also investigate whether and how
1197
      # shadow_mem should be considered for the resource model.
1198
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1199
        specprop = ",accel=kvm"
1200
      else:
1201
        specprop = ""
1202
      machinespec = "%s%s" % (mversion, specprop)
1203
      kvm_cmd.extend(["-machine", machinespec])
1204
    else:
1205
      kvm_cmd.extend(["-M", mversion])
1206
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1207
          self._ENABLE_KVM_RE.search(kvmhelp)):
1208
        kvm_cmd.extend(["-enable-kvm"])
1209
      elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1210
            self._DISABLE_KVM_RE.search(kvmhelp)):
1211
        kvm_cmd.extend(["-disable-kvm"])
1212

    
1213
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1214
    if kernel_path:
1215
      boot_cdrom = boot_floppy = boot_network = False
1216
    else:
1217
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1218
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1219
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1220

    
1221
    if startup_paused:
1222
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1223

    
1224
    if boot_network:
1225
      kvm_cmd.extend(["-boot", "n"])
1226

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

    
1231
    disk_type = hvp[constants.HV_DISK_TYPE]
1232

    
1233
    #Now we can specify a different device type for CDROM devices.
1234
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1235
    if not cdrom_disk_type:
1236
      cdrom_disk_type = disk_type
1237

    
1238
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1239
    if iso_image:
1240
      options = ",format=raw,media=cdrom"
1241
      # set cdrom 'if' type
1242
      if boot_cdrom:
1243
        actual_cdrom_type = constants.HT_DISK_IDE
1244
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1245
        actual_cdrom_type = "virtio"
1246
      else:
1247
        actual_cdrom_type = cdrom_disk_type
1248
      if_val = ",if=%s" % actual_cdrom_type
1249
      # set boot flag, if needed
1250
      boot_val = ""
1251
      if boot_cdrom:
1252
        kvm_cmd.extend(["-boot", "d"])
1253
        if needs_boot_flag:
1254
          boot_val = ",boot=on"
1255
      # and finally build the entire '-drive' value
1256
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1257
      kvm_cmd.extend(["-drive", drive_val])
1258

    
1259
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1260
    if iso_image2:
1261
      options = ",format=raw,media=cdrom"
1262
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1263
        if_val = ",if=virtio"
1264
      else:
1265
        if_val = ",if=%s" % cdrom_disk_type
1266
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1267
      kvm_cmd.extend(["-drive", drive_val])
1268

    
1269
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1270
    if floppy_image:
1271
      options = ",format=raw,media=disk"
1272
      if boot_floppy:
1273
        kvm_cmd.extend(["-boot", "a"])
1274
        options = "%s,boot=on" % options
1275
      if_val = ",if=floppy"
1276
      options = "%s%s" % (options, if_val)
1277
      drive_val = "file=%s%s" % (floppy_image, options)
1278
      kvm_cmd.extend(["-drive", drive_val])
1279

    
1280
    if kernel_path:
1281
      kvm_cmd.extend(["-kernel", kernel_path])
1282
      initrd_path = hvp[constants.HV_INITRD_PATH]
1283
      if initrd_path:
1284
        kvm_cmd.extend(["-initrd", initrd_path])
1285
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1286
                     hvp[constants.HV_KERNEL_ARGS]]
1287
      if hvp[constants.HV_SERIAL_CONSOLE]:
1288
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1289
        root_append.append("console=ttyS0,%s" % serial_speed)
1290
      kvm_cmd.extend(["-append", " ".join(root_append)])
1291

    
1292
    mem_path = hvp[constants.HV_MEM_PATH]
1293
    if mem_path:
1294
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1295

    
1296
    monitor_dev = ("unix:%s,server,nowait" %
1297
                   self._InstanceMonitor(instance.name))
1298
    kvm_cmd.extend(["-monitor", monitor_dev])
1299
    if hvp[constants.HV_SERIAL_CONSOLE]:
1300
      serial_dev = ("unix:%s,server,nowait" %
1301
                    self._InstanceSerial(instance.name))
1302
      kvm_cmd.extend(["-serial", serial_dev])
1303
    else:
1304
      kvm_cmd.extend(["-serial", "none"])
1305

    
1306
    mouse_type = hvp[constants.HV_USB_MOUSE]
1307
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1308
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1309
    spice_ip_version = None
1310

    
1311
    kvm_cmd.extend(["-usb"])
1312

    
1313
    if mouse_type:
1314
      kvm_cmd.extend(["-usbdevice", mouse_type])
1315
    elif vnc_bind_address:
1316
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1317

    
1318
    if vnc_bind_address:
1319
      if netutils.IsValidInterface(vnc_bind_address):
1320
        if_addresses = netutils.GetInterfaceIpAddresses(vnc_bind_address)
1321
        if_ip4_addresses = if_addresses[constants.IP4_VERSION]
1322
        if len(if_ip4_addresses) < 1:
1323
          logging.error("Could not determine IPv4 address of interface %s",
1324
                        vnc_bind_address)
1325
        else:
1326
          vnc_bind_address = if_ip4_addresses[0]
1327
      if netutils.IP4Address.IsValid(vnc_bind_address):
1328
        if instance.network_port > constants.VNC_BASE_PORT:
1329
          display = instance.network_port - constants.VNC_BASE_PORT
1330
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1331
            vnc_arg = ":%d" % (display)
1332
          else:
1333
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1334
        else:
1335
          logging.error("Network port is not a valid VNC display (%d < %d),"
1336
                        " not starting VNC",
1337
                        instance.network_port, constants.VNC_BASE_PORT)
1338
          vnc_arg = "none"
1339

    
1340
        # Only allow tls and other option when not binding to a file, for now.
1341
        # kvm/qemu gets confused otherwise about the filename to use.
1342
        vnc_append = ""
1343
        if hvp[constants.HV_VNC_TLS]:
1344
          vnc_append = "%s,tls" % vnc_append
1345
          if hvp[constants.HV_VNC_X509_VERIFY]:
1346
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1347
                                               hvp[constants.HV_VNC_X509])
1348
          elif hvp[constants.HV_VNC_X509]:
1349
            vnc_append = "%s,x509=%s" % (vnc_append,
1350
                                         hvp[constants.HV_VNC_X509])
1351
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1352
          vnc_append = "%s,password" % vnc_append
1353

    
1354
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1355

    
1356
      else:
1357
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1358

    
1359
      kvm_cmd.extend(["-vnc", vnc_arg])
1360
    elif spice_bind:
1361
      # FIXME: this is wrong here; the iface ip address differs
1362
      # between systems, so it should be done in _ExecuteKVMRuntime
1363
      if netutils.IsValidInterface(spice_bind):
1364
        # The user specified a network interface, we have to figure out the IP
1365
        # address.
1366
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1367
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1368

    
1369
        # if the user specified an IP version and the interface does not
1370
        # have that kind of IP addresses, throw an exception
1371
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1372
          if not addresses[spice_ip_version]:
1373
            raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1374
                                         " for %s" % (spice_ip_version,
1375
                                                      spice_bind))
1376

    
1377
        # the user did not specify an IP version, we have to figure it out
1378
        elif (addresses[constants.IP4_VERSION] and
1379
              addresses[constants.IP6_VERSION]):
1380
          # we have both ipv4 and ipv6, let's use the cluster default IP
1381
          # version
1382
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1383
          spice_ip_version = \
1384
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1385
        elif addresses[constants.IP4_VERSION]:
1386
          spice_ip_version = constants.IP4_VERSION
1387
        elif addresses[constants.IP6_VERSION]:
1388
          spice_ip_version = constants.IP6_VERSION
1389
        else:
1390
          raise errors.HypervisorError("SPICE: Unable to get an IP address"
1391
                                       " for %s" % (spice_bind))
1392

    
1393
        spice_address = addresses[spice_ip_version][0]
1394

    
1395
      else:
1396
        # spice_bind is known to be a valid IP address, because
1397
        # ValidateParameters checked it.
1398
        spice_address = spice_bind
1399

    
1400
      spice_arg = "addr=%s" % spice_address
1401
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1402
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1403
                     (spice_arg, instance.network_port,
1404
                      pathutils.SPICE_CACERT_FILE))
1405
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1406
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1407
                      pathutils.SPICE_CERT_FILE))
1408
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1409
        if tls_ciphers:
1410
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1411
      else:
1412
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1413

    
1414
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1415
        spice_arg = "%s,disable-ticketing" % spice_arg
1416

    
1417
      if spice_ip_version:
1418
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1419

    
1420
      # Image compression options
1421
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1422
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1423
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1424
      if img_lossless:
1425
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1426
      if img_jpeg:
1427
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1428
      if img_zlib_glz:
1429
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1430

    
1431
      # Video stream detection
1432
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1433
      if video_streaming:
1434
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1435

    
1436
      # Audio compression, by default in qemu-kvm it is on
1437
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1438
        spice_arg = "%s,playback-compression=off" % spice_arg
1439
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1440
        spice_arg = "%s,agent-mouse=off" % spice_arg
1441
      else:
1442
        # Enable the spice agent communication channel between the host and the
1443
        # agent.
1444
        kvm_cmd.extend(["-device", "virtio-serial-pci"])
1445
        kvm_cmd.extend([
1446
          "-device",
1447
          "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1448
          ])
1449
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1450

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

    
1454
    else:
1455
      # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1456
      # also works in earlier versions though (tested with 1.1 and 1.3)
1457
      if self._DISPLAY_RE.search(kvmhelp):
1458
        kvm_cmd.extend(["-display", "none"])
1459
      else:
1460
        kvm_cmd.extend(["-nographic"])
1461

    
1462
    if hvp[constants.HV_USE_LOCALTIME]:
1463
      kvm_cmd.extend(["-localtime"])
1464

    
1465
    if hvp[constants.HV_KVM_USE_CHROOT]:
1466
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1467

    
1468
    # Add qemu-KVM -cpu param
1469
    if hvp[constants.HV_CPU_TYPE]:
1470
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1471

    
1472
    # As requested by music lovers
1473
    if hvp[constants.HV_SOUNDHW]:
1474
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1475

    
1476
    # Pass a -vga option if requested, or if spice is used, for backwards
1477
    # compatibility.
1478
    if hvp[constants.HV_VGA]:
1479
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1480
    elif spice_bind:
1481
      kvm_cmd.extend(["-vga", "qxl"])
1482

    
1483
    # Various types of usb devices, comma separated
1484
    if hvp[constants.HV_USB_DEVICES]:
1485
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1486
        kvm_cmd.extend(["-usbdevice", dev])
1487

    
1488
    # Set system UUID to instance UUID
1489
    if self._UUID_RE.search(kvmhelp):
1490
      kvm_cmd.extend(["-uuid", instance.uuid])
1491

    
1492
    if hvp[constants.HV_KVM_EXTRA]:
1493
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1494

    
1495
    # Save the current instance nics, but defer their expansion as parameters,
1496
    # as we'll need to generate executable temp files for them.
1497
    kvm_nics = instance.nics
1498
    hvparams = hvp
1499

    
1500
    return (kvm_cmd, kvm_nics, hvparams, block_devices)
1501

    
1502
  def _WriteKVMRuntime(self, instance_name, data):
1503
    """Write an instance's KVM runtime
1504

1505
    """
1506
    try:
1507
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1508
                      data=data)
1509
    except EnvironmentError, err:
1510
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1511

    
1512
  def _ReadKVMRuntime(self, instance_name):
1513
    """Read an instance's KVM runtime
1514

1515
    """
1516
    try:
1517
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1518
    except EnvironmentError, err:
1519
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1520
    return file_content
1521

    
1522
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1523
    """Save an instance's KVM runtime
1524

1525
    """
1526
    kvm_cmd, kvm_nics, hvparams, block_devices = kvm_runtime
1527

    
1528
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1529
    serialized_blockdevs = [(blk.ToDict(), link) for blk, link in block_devices]
1530
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1531
                                      serialized_blockdevs))
1532

    
1533
    self._WriteKVMRuntime(instance.name, serialized_form)
1534

    
1535
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1536
    """Load an instance's KVM runtime
1537

1538
    """
1539
    if not serialized_runtime:
1540
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1541

    
1542
    loaded_runtime = serializer.Load(serialized_runtime)
1543
    if len(loaded_runtime)==3:
1544
      serialized_blockdevs = []
1545
      kvm_cmd, serialized_nics, hvparams = loaded_runtime
1546
    else:
1547
      kvm_cmd, serialized_nics, hvparams, serialized_blockdevs = loaded_runtime
1548

    
1549
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1550
    block_devices = [(objects.Disk.FromDict(sdisk), link)
1551
                     for sdisk, link in serialized_blockdevs]
1552

    
1553
    return (kvm_cmd, kvm_nics, hvparams, block_devices)
1554

    
1555
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1556
    """Run the KVM cmd and check for errors
1557

1558
    @type name: string
1559
    @param name: instance name
1560
    @type kvm_cmd: list of strings
1561
    @param kvm_cmd: runcmd input for kvm
1562
    @type tap_fds: list of int
1563
    @param tap_fds: fds of tap devices opened by Ganeti
1564

1565
    """
1566
    try:
1567
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1568
    finally:
1569
      for fd in tap_fds:
1570
        utils_wrapper.CloseFdNoError(fd)
1571

    
1572
    if result.failed:
1573
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1574
                                   (name, result.fail_reason, result.output))
1575
    if not self._InstancePidAlive(name)[2]:
1576
      raise errors.HypervisorError("Failed to start instance %s" % name)
1577

    
1578
  # pylint: disable=R0914
1579
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1580
    """Execute a KVM cmd, after completing it with some last minute data.
1581

1582
    @type incoming: tuple of strings
1583
    @param incoming: (target_host_ip, port)
1584
    @type kvmhelp: string
1585
    @param kvmhelp: output of kvm --help
1586

1587
    """
1588
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1589
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1590
    #    have changed since the instance started; only use them if the change
1591
    #    won't affect the inside of the instance (which hasn't been rebooted).
1592
    #  - up_hvp contains the parameters as they were when the instance was
1593
    #    started, plus any new parameter which has been added between ganeti
1594
    #    versions: it is paramount that those default to a value which won't
1595
    #    affect the inside of the instance as well.
1596
    conf_hvp = instance.hvparams
1597
    name = instance.name
1598
    self._CheckDown(name)
1599

    
1600
    temp_files = []
1601

    
1602
    kvm_cmd, kvm_nics, up_hvp, block_devices = kvm_runtime
1603
    # the first element of kvm_cmd is always the path to the kvm binary
1604
    kvm_path = kvm_cmd[0]
1605

    
1606
    kvm_cmd_runtime = copy.deepcopy(kvm_cmd)
1607

    
1608
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1609

    
1610
    # We know it's safe to run as a different user upon migration, so we'll use
1611
    # the latest conf, from conf_hvp.
1612
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1613
    if security_model == constants.HT_SM_USER:
1614
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1615

    
1616
    keymap = conf_hvp[constants.HV_KEYMAP]
1617
    if keymap:
1618
      keymap_path = self._InstanceKeymapFile(name)
1619
      # If a keymap file is specified, KVM won't use its internal defaults. By
1620
      # first including the "en-us" layout, an error on loading the actual
1621
      # layout (e.g. because it can't be found) won't lead to a non-functional
1622
      # keyboard. A keyboard with incorrect keys is still better than none.
1623
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1624
      kvm_cmd.extend(["-k", keymap_path])
1625

    
1626
    pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1627

    
1628
    kvm_cmd = self._GenerateKVMBlockDevicesOptions(instance, kvm_cmd,
1629
                                                   block_devices,
1630
                                                   pci_reservations,
1631
                                                   kvmhelp)
1632

    
1633
    # We have reasons to believe changing something like the nic driver/type
1634
    # upon migration won't exactly fly with the instance kernel, so for nic
1635
    # related parameters we'll use up_hvp
1636
    tapfds = []
1637
    taps = []
1638
    if not kvm_nics:
1639
      kvm_cmd.extend(["-net", "none"])
1640
    else:
1641
      vnet_hdr = False
1642
      tap_extra = ""
1643
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1644
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1645
        nic_model = self._VIRTIO
1646
        try:
1647
          devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1648
          if self._NEW_VIRTIO_RE.search(devlist):
1649
            nic_model = self._VIRTIO_NET_PCI
1650
            vnet_hdr = True
1651
        except errors.HypervisorError, _:
1652
          # Older versions of kvm don't support DEVICE_LIST, but they don't
1653
          # have new virtio syntax either.
1654
          pass
1655

    
1656
        if up_hvp[constants.HV_VHOST_NET]:
1657
          # check for vhost_net support
1658
          if self._VHOST_RE.search(kvmhelp):
1659
            tap_extra = ",vhost=on"
1660
          else:
1661
            raise errors.HypervisorError("vhost_net is configured"
1662
                                         " but it is not available")
1663
      else:
1664
        nic_model = nic_type
1665

    
1666
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1667

    
1668
      for nic_seq, nic in enumerate(kvm_nics):
1669
        tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1670
        tapfds.append(tapfd)
1671
        taps.append(tapname)
1672
        if kvm_supports_netdev:
1673
          nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1674
          _UpdatePCISlots(nic, pci_reservations)
1675
          kvm_devid = _GenerateDeviceKVMId("NIC", nic)
1676
          netdev = kvm_devid or "netdev%d" % nic_seq
1677
          nic_val += (",netdev=%s" % netdev)
1678
          if kvm_devid:
1679
            nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1680
          tap_val = ("type=tap,id=%s,fd=%d%s" %
1681
                     (netdev, tapfd, tap_extra))
1682
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1683
        else:
1684
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1685
                                                         nic.mac, nic_model)
1686
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1687
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1688

    
1689
    if incoming:
1690
      target, port = incoming
1691
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1692

    
1693
    # Changing the vnc password doesn't bother the guest that much. At most it
1694
    # will surprise people who connect to it. Whether positively or negatively
1695
    # it's debatable.
1696
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1697
    vnc_pwd = None
1698
    if vnc_pwd_file:
1699
      try:
1700
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1701
      except EnvironmentError, err:
1702
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1703
                                     % (vnc_pwd_file, err))
1704

    
1705
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1706
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1707
                         constants.SECURE_DIR_MODE)])
1708

    
1709
    # Automatically enable QMP if version is >= 0.14
1710
    if self._QMP_RE.search(kvmhelp):
1711
      logging.debug("Enabling QMP")
1712
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1713
                      self._InstanceQmpMonitor(instance.name)])
1714

    
1715
    # Configure the network now for starting instances and bridged interfaces,
1716
    # during FinalizeMigration for incoming instances' routed interfaces
1717
    for nic_seq, nic in enumerate(kvm_nics):
1718
      if (incoming and
1719
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1720
        continue
1721
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1722

    
1723
    # CPU affinity requires kvm to start paused, so we set this flag if the
1724
    # instance is not already paused and if we are not going to accept a
1725
    # migrating instance. In the latter case, pausing is not needed.
1726
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1727
    if start_kvm_paused:
1728
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1729

    
1730
    # Note: CPU pinning is using up_hvp since changes take effect
1731
    # during instance startup anyway, and to avoid problems when soft
1732
    # rebooting the instance.
1733
    cpu_pinning = False
1734
    if up_hvp.get(constants.HV_CPU_MASK, None):
1735
      cpu_pinning = True
1736

    
1737
    if security_model == constants.HT_SM_POOL:
1738
      ss = ssconf.SimpleStore()
1739
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1740
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1741
      uid = uidpool.RequestUnusedUid(all_uids)
1742
      try:
1743
        username = pwd.getpwuid(uid.GetUid()).pw_name
1744
        kvm_cmd.extend(["-runas", username])
1745
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1746
      except:
1747
        uidpool.ReleaseUid(uid)
1748
        raise
1749
      else:
1750
        uid.Unlock()
1751
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1752
    else:
1753
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1754

    
1755
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1756
                     constants.RUN_DIRS_MODE)])
1757
    for nic_seq, tap in enumerate(taps):
1758
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1759
                      data=tap)
1760

    
1761
    if vnc_pwd:
1762
      change_cmd = "change vnc password %s" % vnc_pwd
1763
      self._CallMonitorCommand(instance.name, change_cmd)
1764

    
1765
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1766
    # connection attempts because SPICE by default does not allow connections
1767
    # if neither a password nor the "disable_ticketing" options are specified.
1768
    # As soon as we send the password via QMP, that password is a valid ticket
1769
    # for connection.
1770
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1771
    if spice_password_file:
1772
      spice_pwd = ""
1773
      try:
1774
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1775
      except EnvironmentError, err:
1776
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1777
                                     % (spice_password_file, err))
1778

    
1779
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1780
      qmp.connect()
1781
      arguments = {
1782
          "protocol": "spice",
1783
          "password": spice_pwd,
1784
      }
1785
      qmp.Execute("set_password", arguments)
1786

    
1787
    for filename in temp_files:
1788
      utils.RemoveFile(filename)
1789

    
1790
    # If requested, set CPU affinity and resume instance execution
1791
    if cpu_pinning:
1792
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1793

    
1794
    start_memory = self._InstanceStartupMemory(instance)
1795
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1796
      self.BalloonInstanceMemory(instance, start_memory)
1797

    
1798
    if start_kvm_paused:
1799
      # To control CPU pinning, ballooning, and vnc/spice passwords
1800
      # the VM was started in a frozen state. If freezing was not
1801
      # explicitly requested resume the vm status.
1802
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1803

    
1804
    kvm_runtime_with_pci_info = (kvm_cmd_runtime, kvm_nics,
1805
                                 up_hvp, block_devices)
1806
    return kvm_runtime_with_pci_info
1807

    
1808
  def StartInstance(self, instance, block_devices, startup_paused):
1809
    """Start an instance.
1810

1811
    """
1812
    self._CheckDown(instance.name)
1813
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1814
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1815
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1816
                                           startup_paused, kvmhelp)
1817
    self._SaveKVMRuntime(instance, kvm_runtime)
1818
    kvm_runtime_with_pci_info = self._ExecuteKVMRuntime(instance, kvm_runtime,
1819
                                                        kvmhelp)
1820
    self._SaveKVMRuntime(instance, kvm_runtime_with_pci_info)
1821

    
1822
  def _CallMonitorCommand(self, instance_name, command):
1823
    """Invoke a command on the instance monitor.
1824

1825
    """
1826
    # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1827
    # version. The monitor protocol is designed for human consumption, whereas
1828
    # QMP is made for programmatic usage. In the worst case QMP can also
1829
    # execute monitor commands. As it is, all calls to socat take at least
1830
    # 500ms and likely more: socat can't detect the end of the reply and waits
1831
    # for 500ms of no data received before exiting (500 ms is the default for
1832
    # the "-t" parameter).
1833
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1834
             (utils.ShellQuote(command),
1835
              constants.SOCAT_PATH,
1836
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1837
    result = utils.RunCmd(socat)
1838
    if result.failed:
1839
      msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1840
             " output: %s" %
1841
             (command, instance_name, result.fail_reason, result.output))
1842
      raise errors.HypervisorError(msg)
1843

    
1844
    return result
1845

    
1846
  def _AnnotateFreePCISlot(self, instance, dev):
1847
    """Get the first available pci slot of a runnung instance.
1848

1849
    """
1850
    slots = bitarray(32)
1851
    slots.setall(False) # pylint: disable=E1101
1852
    output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
1853
    for line in output.stdout.splitlines():
1854
      match = self._INFO_PCI_RE.search(line)
1855
      if match:
1856
        slot = int(match.group(1))
1857
        slots[slot] = True
1858

    
1859
    [free] = slots.search(FREE, 1) # pylint: disable=E1101
1860
    if not free:
1861
      raise errors.HypervisorError("All PCI slots occupied")
1862

    
1863
    dev.pci = int(free)
1864

    
1865
  def _TryHotplug(self, instance, dev_type):
1866
    """Get QEMU version from the instance's monitor.
1867

1868
    Hotplug is supported for running instances and for versions >= 1.0.
1869
    """
1870
    if dev_type == "DISK":
1871
      hvp = instance.hvparams
1872
      security_model = hvparams[constants.HV_SECURITY_MODEL]
1873
      use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
1874
      if use_chroot or security_model != constants.HT_SM_NONE:
1875
        return False
1876
    output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
1877
    #TODO: search for netdev_add, drive_add, device_add.....
1878
    match = self._INFO_VERSION_RE.search(output.stdout)
1879
    if not match:
1880
      return False
1881
    v_major, v_min, _, _ = match.groups()
1882
    return (v_major, v_min) >= (1, 0)
1883

    
1884
  def _CallMonitorHotplugCommand(self, name, cmd):
1885
    output = self._CallMonitorCommand(name, cmd)
1886
    #TODO: parse output and check if succeeded
1887
    for line in output.stdout.splitlines():
1888
      logging.info("%s", line)
1889

    
1890
  def HotplugDevice(self, instance, action, dev_type, device, extra, seq):
1891
    if self._TryHotplug(instance, dev_type):
1892
      (kvm_cmd, kvm_nics, hvparams, \
1893
        block_devices) = self._LoadKVMRuntime(instance)
1894
      if action == "ADD":
1895
        self._AnnotateFreePCISlot(instance, device)
1896
        kvm_devid = _GenerateDeviceKVMId(dev_type, device)
1897
        if dev_type == "DISK":
1898
          self._HotAddDisk(instance,
1899
                           device, extra, seq, kvm_devid, block_devices)
1900
        elif dev_type == "NIC" and nic_hotplug:
1901
          self._HotAddNic(instance, device, extra, seq, kvm_devid, kvm_nics)
1902
      elif action == "REMOVE":
1903
        kvm_devid = self._GetExistingDeviceKVMId(instance, dev_type, device)
1904
        if dev_type == "DISK":
1905
          self._HotDelDisk(instance,
1906
                           device, extra, seq, kvm_devid, block_devices)
1907
        elif dev_type == "NIC" and nic_hotplug:
1908
          self._HotDelNic(instance, device, extra, seq, kvm_devid, kvm_nics)
1909
      self._SaveKVMRuntime(instance,
1910
                          (kvm_cmd, kvm_nics, hvparams, block_devices))
1911

    
1912
  def _HotAddDisk(self, instance, disk, dev_path, _, kvm_devid, block_devices):
1913
    """Hotadd new disk to the VM
1914

1915
    """
1916
    command = ("drive_add dummy file=%s,if=none,id=%s,format=raw" %
1917
               (dev_path, kvm_devid))
1918
    self._CallMonitorHotplugCommand(instance.name, command)
1919
    command = ("device_add virtio-blk-pci,bus=pci.0,addr=%s,"
1920
               "drive=%s,id=%s"
1921
               % (hex(disk.pci), kvm_devid, kvm_devid))
1922
    self._CallMonitorHotplugCommand(instance.name, command)
1923
    block_devices.append((disk, dev_path))
1924

    
1925
  def _HotAddNic(self, instance, nic, _, seq, kvm_devid, kvm_nics):
1926
    """Hotadd new nic to the VM
1927

1928
    """
1929
    (tap, fd) = _OpenTap()
1930
    self._PassTapFd(instance, fd, nic)
1931
    command = ("netdev_add tap,id=%s,fd=%s" % (kvm_devid, kvm_devid))
1932
    self._CallMonitorHotplugCommand(instance.name, command)
1933
    command = ("device_add virtio-net-pci,bus=pci.0,addr=%s,mac=%s,"
1934
               "netdev=%s,id=%s"
1935
               % (hex(nic.pci), nic.mac, kvm_devid, kvm_devid))
1936
    self._CallMonitorHotplugCommand(instance.name, command)
1937
    self._ConfigureNIC(instance, seq, nic, tap)
1938
    utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
1939
    kvm_nics.append(nic)
1940

    
1941
  def _HotDelDisk(self, instance, disk, _, __, kvm_devid, block_devices):
1942
    """Hotdel disk to the VM
1943

1944
    """
1945
    command = "device_del %s" % kvm_devid
1946
    self._CallMonitorHotplugCommand(instance.name, command)
1947
    #command = "drive_del %s" % uuid
1948
    #self._CallMonitorHotplugCommand(instance.name, command)
1949
    _RemoveFromRuntimeEntry(block_devices, disk, lambda x: [d for d, l in x])
1950

    
1951
  def _HotDelNic(self, instance, nic, _, __, kvm_devid, kvm_nics):
1952
    """Hotadd new nic to the VM
1953

1954
    """
1955
    command = "device_del %s" % kvm_devid
1956
    self._CallMonitorHotplugCommand(instance.name, command)
1957
    command = "netdev_del %s" % kvm_devid
1958
    self._CallMonitorHotplugCommand(instance.name, command)
1959
    _RemoveFromRuntimeEntry(kvm_nics, nic, lambda x: x)
1960

    
1961
  def _PassTapFd(self, instance, fd, nic):
1962
    monsock = utils.ShellQuote(self._InstanceMonitor(instance.name))
1963
    s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
1964
    s.connect(monsock)
1965
    kvm_devid = _GenerateDeviceKVMId("NIC", nic)
1966
    command = "getfd %s\n" % kvm_devid
1967
    fds = [fd]
1968
    logging.info("%s", fds)
1969
    fdsend.sendfds(s, command, fds = fds)
1970
    s.close()
1971

    
1972
  @classmethod
1973
  def _ParseKVMVersion(cls, text):
1974
    """Parse the KVM version from the --help output.
1975

1976
    @type text: string
1977
    @param text: output of kvm --help
1978
    @return: (version, v_maj, v_min, v_rev)
1979
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1980

1981
    """
1982
    match = cls._VERSION_RE.search(text.splitlines()[0])
1983
    if not match:
1984
      raise errors.HypervisorError("Unable to get KVM version")
1985

    
1986
    v_all = match.group(0)
1987
    v_maj = int(match.group(1))
1988
    v_min = int(match.group(2))
1989
    if match.group(4):
1990
      v_rev = int(match.group(4))
1991
    else:
1992
      v_rev = 0
1993
    return (v_all, v_maj, v_min, v_rev)
1994

    
1995
  @classmethod
1996
  def _GetKVMOutput(cls, kvm_path, option):
1997
    """Return the output of a kvm invocation
1998

1999
    @type kvm_path: string
2000
    @param kvm_path: path to the kvm executable
2001
    @type option: a key of _KVMOPTS_CMDS
2002
    @param option: kvm option to fetch the output from
2003
    @return: output a supported kvm invocation
2004
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2005

2006
    """
2007
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2008

    
2009
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
2010

    
2011
    result = utils.RunCmd([kvm_path] + optlist)
2012
    if result.failed and not can_fail:
2013
      raise errors.HypervisorError("Unable to get KVM %s output" %
2014
                                    " ".join(cls._KVMOPTS_CMDS[option]))
2015
    return result.output
2016

    
2017
  @classmethod
2018
  def _GetKVMVersion(cls, kvm_path):
2019
    """Return the installed KVM version.
2020

2021
    @return: (version, v_maj, v_min, v_rev)
2022
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2023

2024
    """
2025
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2026

    
2027
  @classmethod
2028
  def _GetDefaultMachineVersion(cls, kvm_path):
2029
    """Return the default hardware revision (e.g. pc-1.1)
2030

2031
    """
2032
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2033
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2034
    if match:
2035
      return match.group(1)
2036
    else:
2037
      return "pc"
2038

    
2039
  def StopInstance(self, instance, force=False, retry=False, name=None):
2040
    """Stop an instance.
2041

2042
    """
2043
    if name is not None and not force:
2044
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2045
    if name is None:
2046
      name = instance.name
2047
      acpi = instance.hvparams[constants.HV_ACPI]
2048
    else:
2049
      acpi = False
2050
    _, pid, alive = self._InstancePidAlive(name)
2051
    if pid > 0 and alive:
2052
      if force or not acpi:
2053
        utils.KillProcess(pid)
2054
      else:
2055
        self._CallMonitorCommand(name, "system_powerdown")
2056

    
2057
  def CleanupInstance(self, instance_name):
2058
    """Cleanup after a stopped instance
2059

2060
    """
2061
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
2062
    if pid > 0 and alive:
2063
      raise errors.HypervisorError("Cannot cleanup a live instance")
2064
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2065

    
2066
  def RebootInstance(self, instance):
2067
    """Reboot an instance.
2068

2069
    """
2070
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2071
    # socket the instance will stop, but now power up again. So we'll resort
2072
    # to shutdown and restart.
2073
    _, _, alive = self._InstancePidAlive(instance.name)
2074
    if not alive:
2075
      raise errors.HypervisorError("Failed to reboot instance %s:"
2076
                                   " not running" % instance.name)
2077
    # StopInstance will delete the saved KVM runtime so:
2078
    # ...first load it...
2079
    kvm_runtime = self._LoadKVMRuntime(instance)
2080
    # ...now we can safely call StopInstance...
2081
    if not self.StopInstance(instance):
2082
      self.StopInstance(instance, force=True)
2083
    # ...and finally we can save it again, and execute it...
2084
    self._SaveKVMRuntime(instance, kvm_runtime)
2085
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2086
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2087
    kvm_runtime_with_pci_info = \
2088
      self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2089
    self._SaveKVMRuntime(instance, kvm_runtime_with_pci_info)
2090

    
2091
  def MigrationInfo(self, instance):
2092
    """Get instance information to perform a migration.
2093

2094
    @type instance: L{objects.Instance}
2095
    @param instance: instance to be migrated
2096
    @rtype: string
2097
    @return: content of the KVM runtime file
2098

2099
    """
2100
    return self._ReadKVMRuntime(instance.name)
2101

    
2102
  def AcceptInstance(self, instance, info, target):
2103
    """Prepare to accept an instance.
2104

2105
    @type instance: L{objects.Instance}
2106
    @param instance: instance to be accepted
2107
    @type info: string
2108
    @param info: content of the KVM runtime file on the source node
2109
    @type target: string
2110
    @param target: target host (usually ip), on this node
2111

2112
    """
2113
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2114
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2115
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2116
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2117
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2118
                            incoming=incoming_address)
2119

    
2120
  def FinalizeMigrationDst(self, instance, info, success):
2121
    """Finalize the instance migration on the target node.
2122

2123
    Stop the incoming mode KVM.
2124

2125
    @type instance: L{objects.Instance}
2126
    @param instance: instance whose migration is being finalized
2127

2128
    """
2129
    if success:
2130
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2131
      kvm_nics = kvm_runtime[1]
2132

    
2133
      for nic_seq, nic in enumerate(kvm_nics):
2134
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2135
          # Bridged interfaces have already been configured
2136
          continue
2137
        try:
2138
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2139
        except EnvironmentError, err:
2140
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
2141
                          instance.name, nic_seq, str(err))
2142
          continue
2143
        try:
2144
          self._ConfigureNIC(instance, nic_seq, nic, tap)
2145
        except errors.HypervisorError, err:
2146
          logging.warning(str(err))
2147

    
2148
      self._WriteKVMRuntime(instance.name, info)
2149
    else:
2150
      self.StopInstance(instance, force=True)
2151

    
2152
  def MigrateInstance(self, cluster_name, instance, target, live):
2153
    """Migrate an instance to a target node.
2154

2155
    The migration will not be attempted if the instance is not
2156
    currently running.
2157

2158
    @type cluster_name: string
2159
    @param cluster_name: name of the cluster
2160
    @type instance: L{objects.Instance}
2161
    @param instance: the instance to be migrated
2162
    @type target: string
2163
    @param target: ip address of the target node
2164
    @type live: boolean
2165
    @param live: perform a live migration
2166

2167
    """
2168
    instance_name = instance.name
2169
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
2170
    _, _, alive = self._InstancePidAlive(instance_name)
2171
    if not alive:
2172
      raise errors.HypervisorError("Instance not running, cannot migrate")
2173

    
2174
    if not live:
2175
      self._CallMonitorCommand(instance_name, "stop")
2176

    
2177
    migrate_command = ("migrate_set_speed %dm" %
2178
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2179
    self._CallMonitorCommand(instance_name, migrate_command)
2180

    
2181
    migrate_command = ("migrate_set_downtime %dms" %
2182
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2183
    self._CallMonitorCommand(instance_name, migrate_command)
2184

    
2185
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2186
    self._CallMonitorCommand(instance_name, migrate_command)
2187

    
2188
  def FinalizeMigrationSource(self, instance, success, live):
2189
    """Finalize the instance migration on the source node.
2190

2191
    @type instance: L{objects.Instance}
2192
    @param instance: the instance that was migrated
2193
    @type success: bool
2194
    @param success: whether the migration succeeded or not
2195
    @type live: bool
2196
    @param live: whether the user requested a live migration or not
2197

2198
    """
2199
    if success:
2200
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2201
      utils.KillProcess(pid)
2202
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2203
    elif live:
2204
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2205

    
2206
  def GetMigrationStatus(self, instance):
2207
    """Get the migration status
2208

2209
    @type instance: L{objects.Instance}
2210
    @param instance: the instance that is being migrated
2211
    @rtype: L{objects.MigrationStatus}
2212
    @return: the status of the current migration (one of
2213
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2214
             progress info that can be retrieved from the hypervisor
2215

2216
    """
2217
    info_command = "info migrate"
2218
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2219
      result = self._CallMonitorCommand(instance.name, info_command)
2220
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
2221
      if not match:
2222
        if not result.stdout:
2223
          logging.info("KVM: empty 'info migrate' result")
2224
        else:
2225
          logging.warning("KVM: unknown 'info migrate' result: %s",
2226
                          result.stdout)
2227
      else:
2228
        status = match.group(1)
2229
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2230
          migration_status = objects.MigrationStatus(status=status)
2231
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2232
          if match:
2233
            migration_status.transferred_ram = match.group("transferred")
2234
            migration_status.total_ram = match.group("total")
2235

    
2236
          return migration_status
2237

    
2238
        logging.warning("KVM: unknown migration status '%s'", status)
2239

    
2240
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2241

    
2242
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2243

    
2244
  def BalloonInstanceMemory(self, instance, mem):
2245
    """Balloon an instance memory to a certain value.
2246

2247
    @type instance: L{objects.Instance}
2248
    @param instance: instance to be accepted
2249
    @type mem: int
2250
    @param mem: actual memory size to use for instance runtime
2251

2252
    """
2253
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2254

    
2255
  def GetNodeInfo(self, hvparams=None):
2256
    """Return information about the node.
2257

2258
    @type hvparams: dict of strings
2259
    @param hvparams: hypervisor parameters, not used in this class
2260

2261
    @return: a dict with the following keys (values in MiB):
2262
          - memory_total: the total memory size on the node
2263
          - memory_free: the available memory on the node for instances
2264
          - memory_dom0: the memory used by the node itself, if available
2265
          - hv_version: the hypervisor version in the form (major, minor,
2266
                        revision)
2267

2268
    """
2269
    result = self.GetLinuxNodeInfo()
2270
    # FIXME: this is the global kvm version, but the actual version can be
2271
    # customized as an hv parameter. we should use the nodegroup's default kvm
2272
    # path parameter here.
2273
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2274
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2275
    return result
2276

    
2277
  @classmethod
2278
  def GetInstanceConsole(cls, instance, primary_node, hvparams, beparams):
2279
    """Return a command for connecting to the console of an instance.
2280

2281
    """
2282
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2283
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2284
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2285
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2286
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2287
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2288
      return objects.InstanceConsole(instance=instance.name,
2289
                                     kind=constants.CONS_SSH,
2290
                                     host=primary_node.name,
2291
                                     user=constants.SSH_CONSOLE_USER,
2292
                                     command=cmd)
2293

    
2294
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2295
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2296
      display = instance.network_port - constants.VNC_BASE_PORT
2297
      return objects.InstanceConsole(instance=instance.name,
2298
                                     kind=constants.CONS_VNC,
2299
                                     host=vnc_bind_address,
2300
                                     port=instance.network_port,
2301
                                     display=display)
2302

    
2303
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2304
    if spice_bind:
2305
      return objects.InstanceConsole(instance=instance.name,
2306
                                     kind=constants.CONS_SPICE,
2307
                                     host=spice_bind,
2308
                                     port=instance.network_port)
2309

    
2310
    return objects.InstanceConsole(instance=instance.name,
2311
                                   kind=constants.CONS_MESSAGE,
2312
                                   message=("No serial shell for instance %s" %
2313
                                            instance.name))
2314

    
2315
  def Verify(self, hvparams=None):
2316
    """Verify the hypervisor.
2317

2318
    Check that the required binaries exist.
2319

2320
    @type hvparams: dict of strings
2321
    @param hvparams: hypervisor parameters to be verified against, not used here
2322

2323
    @return: Problem description if something is wrong, C{None} otherwise
2324

2325
    """
2326
    msgs = []
2327
    # FIXME: this is the global kvm binary, but the actual path can be
2328
    # customized as an hv parameter; we should use the nodegroup's
2329
    # default kvm path parameter here.
2330
    if not os.path.exists(constants.KVM_PATH):
2331
      msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2332
    if not os.path.exists(constants.SOCAT_PATH):
2333
      msgs.append("The socat binary ('%s') does not exist" %
2334
                  constants.SOCAT_PATH)
2335

    
2336
    return self._FormatVerifyResults(msgs)
2337

    
2338
  @classmethod
2339
  def CheckParameterSyntax(cls, hvparams):
2340
    """Check the given parameters for validity.
2341

2342
    @type hvparams:  dict
2343
    @param hvparams: dictionary with parameter names/value
2344
    @raise errors.HypervisorError: when a parameter is not valid
2345

2346
    """
2347
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2348

    
2349
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2350
    if kernel_path:
2351
      if not hvparams[constants.HV_ROOT_PATH]:
2352
        raise errors.HypervisorError("Need a root partition for the instance,"
2353
                                     " if a kernel is defined")
2354

    
2355
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2356
        not hvparams[constants.HV_VNC_X509]):
2357
      raise errors.HypervisorError("%s must be defined, if %s is" %
2358
                                   (constants.HV_VNC_X509,
2359
                                    constants.HV_VNC_X509_VERIFY))
2360

    
2361
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2362
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2363
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2364
      if not serial_speed or serial_speed not in valid_speeds:
2365
        raise errors.HypervisorError("Invalid serial console speed, must be"
2366
                                     " one of: %s" %
2367
                                     utils.CommaJoin(valid_speeds))
2368

    
2369
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2370
    if (boot_order == constants.HT_BO_CDROM and
2371
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2372
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2373
                                   " ISO path")
2374

    
2375
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2376
    if security_model == constants.HT_SM_USER:
2377
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2378
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2379
                                     " must be specified")
2380
    elif (security_model == constants.HT_SM_NONE or
2381
          security_model == constants.HT_SM_POOL):
2382
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2383
        raise errors.HypervisorError("Cannot have a security domain when the"
2384
                                     " security model is 'none' or 'pool'")
2385

    
2386
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2387
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2388
    if spice_bind:
2389
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2390
        # if an IP version is specified, the spice_bind parameter must be an
2391
        # IP of that family
2392
        if (netutils.IP4Address.IsValid(spice_bind) and
2393
            spice_ip_version != constants.IP4_VERSION):
2394
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2395
                                       " the specified IP version is %s" %
2396
                                       (spice_bind, spice_ip_version))
2397

    
2398
        if (netutils.IP6Address.IsValid(spice_bind) and
2399
            spice_ip_version != constants.IP6_VERSION):
2400
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2401
                                       " the specified IP version is %s" %
2402
                                       (spice_bind, spice_ip_version))
2403
    else:
2404
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2405
      # error if any of them is set without it.
2406
      for param in _SPICE_ADDITIONAL_PARAMS:
2407
        if hvparams[param]:
2408
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2409
                                       (param, constants.HV_KVM_SPICE_BIND))
2410

    
2411
  @classmethod
2412
  def ValidateParameters(cls, hvparams):
2413
    """Check the given parameters for validity.
2414

2415
    @type hvparams:  dict
2416
    @param hvparams: dictionary with parameter names/value
2417
    @raise errors.HypervisorError: when a parameter is not valid
2418

2419
    """
2420
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2421

    
2422
    kvm_path = hvparams[constants.HV_KVM_PATH]
2423

    
2424
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2425
    if security_model == constants.HT_SM_USER:
2426
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2427
      try:
2428
        pwd.getpwnam(username)
2429
      except KeyError:
2430
        raise errors.HypervisorError("Unknown security domain user %s"
2431
                                     % username)
2432
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2433
    if vnc_bind_address:
2434
      bound_to_addr = netutils.IP4Address.IsValid(vnc_bind_address)
2435
      is_interface = netutils.IsValidInterface(vnc_bind_address)
2436
      is_path = utils.IsNormAbsPath(vnc_bind_address)
2437
      if not bound_to_addr and not is_interface and not is_path:
2438
        raise errors.HypervisorError("VNC: The %s parameter must be either"
2439
                                     " a valid IP address, an interface name,"
2440
                                     " or an absolute path" %
2441
                                     constants.HV_KVM_SPICE_BIND)
2442

    
2443
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2444
    if spice_bind:
2445
      # only one of VNC and SPICE can be used currently.
2446
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2447
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2448
                                     " only one of them can be used at a"
2449
                                     " given time")
2450

    
2451
      # check that KVM supports SPICE
2452
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2453
      if not cls._SPICE_RE.search(kvmhelp):
2454
        raise errors.HypervisorError("SPICE is configured, but it is not"
2455
                                     " supported according to 'kvm --help'")
2456

    
2457
      # if spice_bind is not an IP address, it must be a valid interface
2458
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2459
                       netutils.IP6Address.IsValid(spice_bind))
2460
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2461
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2462
                                     " a valid IP address or interface name" %
2463
                                     constants.HV_KVM_SPICE_BIND)
2464

    
2465
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2466
    if machine_version:
2467
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2468
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2469
        raise errors.HypervisorError("Unsupported machine version: %s" %
2470
                                     machine_version)
2471

    
2472
  @classmethod
2473
  def PowercycleNode(cls, hvparams=None):
2474
    """KVM powercycle, just a wrapper over Linux powercycle.
2475

2476
    @type hvparams: dict of strings
2477
    @param hvparams: hypervisor params to be used on this node
2478

2479
    """
2480
    cls.LinuxPowercycle()