Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 58502c9e

History | View | Annotate | Download (83.7 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
try:
41
  import affinity   # pylint: disable=F0401
42
except ImportError:
43
  affinity = None
44

    
45
from ganeti import utils
46
from ganeti import constants
47
from ganeti import errors
48
from ganeti import serializer
49
from ganeti import objects
50
from ganeti import uidpool
51
from ganeti import ssconf
52
from ganeti import netutils
53
from ganeti import pathutils
54
from ganeti.hypervisor import hv_base
55
from ganeti.utils import wrapper as utils_wrapper
56

    
57

    
58
_KVM_NETWORK_SCRIPT = pathutils.CONF_DIR + "/kvm-vif-bridge"
59
_KVM_START_PAUSED_FLAG = "-S"
60

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

    
71
#: SPICE parameters which depend on L{constants.HV_KVM_SPICE_BIND}
72
_SPICE_ADDITIONAL_PARAMS = frozenset([
73
  constants.HV_KVM_SPICE_IP_VERSION,
74
  constants.HV_KVM_SPICE_PASSWORD_FILE,
75
  constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR,
76
  constants.HV_KVM_SPICE_JPEG_IMG_COMPR,
77
  constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR,
78
  constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION,
79
  constants.HV_KVM_SPICE_USE_TLS,
80
  ])
81

    
82
# below constants show the format of runtime file
83
# the nics are in second possition, while the disks in 4th (last)
84
# moreover disk entries are stored in tupples of L{objects.Disk}, dev_path
85
_KVM_NICS_RUNTIME_INDEX = 1
86
_KVM_DISKS_RUNTIME_INDEX = 3
87
_DEVICE_RUNTIME_INDEX = {
88
  constants.HOTPLUG_TARGET_DISK: _KVM_DISKS_RUNTIME_INDEX,
89
  constants.HOTPLUG_TARGET_NIC: _KVM_NICS_RUNTIME_INDEX
90
  }
91
_FIND_RUNTIME_ENTRY = {
92
  constants.HOTPLUG_TARGET_NIC:
93
    lambda nic, kvm_nics: [n for n in kvm_nics if n.uuid == nic.uuid],
94
  constants.HOTPLUG_TARGET_DISK:
95
    lambda disk, kvm_disks: [(d, l, u) for (d, l, u) in kvm_disks
96
                             if d.uuid == disk.uuid]
97
  }
98
_RUNTIME_DEVICE = {
99
  constants.HOTPLUG_TARGET_NIC: lambda d: d,
100
  constants.HOTPLUG_TARGET_DISK: lambda (d, e, _): d
101
  }
102
_RUNTIME_ENTRY = {
103
  constants.HOTPLUG_TARGET_NIC: lambda d, e: d,
104
  constants.HOTPLUG_TARGET_DISK: lambda d, e: (d, e, None)
105
  }
106

    
107

    
108
def _GetExistingDeviceInfo(dev_type, device, runtime):
109
  """Helper function to get an existing device inside the runtime file
110

111
  Used when an instance is running. Load kvm runtime file and search
112
  for a device based on its type and uuid.
113

114
  @type dev_type: sting
115
  @param dev_type: device type of param dev
116
  @type device: L{objects.Disk} or L{objects.NIC}
117
  @param device: the device object for which we generate a kvm name
118
  @type runtime: tuple (cmd, nics, hvparams, disks)
119
  @param runtime: the runtime data to search for the device
120
  @raise errors.HotplugError: in case the requested device does not
121
    exist (e.g. device has been added without --hotplug option) or
122
    device info has not pci slot (e.g. old devices in the cluster)
123

124
  """
125
  index = _DEVICE_RUNTIME_INDEX[dev_type]
126
  found = _FIND_RUNTIME_ENTRY[dev_type](device, runtime[index])
127
  if not found:
128
    raise errors.HotplugError("Cannot find runtime info for %s with UUID %s" %
129
                              (dev_type, device.uuid))
130

    
131
  return found[0]
132

    
133

    
134
def _AnalyzeSerializedRuntime(serialized_runtime):
135
  """Return runtime entries for a serialized runtime file
136

137
  @type serialized_runtime: string
138
  @param serialized_runtime: raw text data read from actual runtime file
139
  @return: (cmd, nics, hvparams, bdevs)
140
  @rtype: list
141

142
  """
143
  loaded_runtime = serializer.Load(serialized_runtime)
144
  if len(loaded_runtime) == 3:
145
    serialized_blockdevs = []
146
    kvm_cmd, serialized_nics, hvparams = loaded_runtime
147
  else:
148
    kvm_cmd, serialized_nics, hvparams, serialized_blockdevs = loaded_runtime
149

    
150
  kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
151
  block_devices = [(objects.Disk.FromDict(sdisk), link, uri)
152
                   for sdisk, link, uri in serialized_blockdevs]
153

    
154
  return (kvm_cmd, kvm_nics, hvparams, block_devices)
155

    
156

    
157
def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
158
  """Retrieves supported TUN features from file descriptor.
159

160
  @see: L{_ProbeTapVnetHdr}
161

162
  """
163
  req = struct.pack("I", 0)
164
  try:
165
    buf = _ioctl(fd, TUNGETFEATURES, req)
166
  except EnvironmentError, err:
167
    logging.warning("ioctl(TUNGETFEATURES) failed: %s", err)
168
    return None
169
  else:
170
    (flags, ) = struct.unpack("I", buf)
171
    return flags
172

    
173

    
174
def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
175
  """Check whether to enable the IFF_VNET_HDR flag.
176

177
  To do this, _all_ of the following conditions must be met:
178
   1. TUNGETFEATURES ioctl() *must* be implemented
179
   2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
180
   3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
181
      drivers/net/tun.c there is no way to test this until after the tap device
182
      has been created using TUNSETIFF, and there is no way to change the
183
      IFF_VNET_HDR flag after creating the interface, catch-22! However both
184
      TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
185
      thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
186

187
   @type fd: int
188
   @param fd: the file descriptor of /dev/net/tun
189

190
  """
191
  flags = _features_fn(fd)
192

    
193
  if flags is None:
194
    # Not supported
195
    return False
196

    
197
  result = bool(flags & IFF_VNET_HDR)
198

    
199
  if not result:
200
    logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
201

    
202
  return result
203

    
204

    
205
def _OpenTap(vnet_hdr=True):
206
  """Open a new tap device and return its file descriptor.
207

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

211
  @type vnet_hdr: boolean
212
  @param vnet_hdr: Enable the VNET Header
213
  @return: (ifname, tapfd)
214
  @rtype: tuple
215

216
  """
217
  try:
218
    tapfd = os.open("/dev/net/tun", os.O_RDWR)
219
  except EnvironmentError:
220
    raise errors.HypervisorError("Failed to open /dev/net/tun")
221

    
222
  flags = IFF_TAP | IFF_NO_PI
223

    
224
  if vnet_hdr and _ProbeTapVnetHdr(tapfd):
225
    flags |= IFF_VNET_HDR
226

    
227
  # The struct ifreq ioctl request (see netdevice(7))
228
  ifr = struct.pack("16sh", "", flags)
229

    
230
  try:
231
    res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
232
  except EnvironmentError, err:
233
    raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
234
                                 err)
235

    
236
  # Get the interface name from the ioctl
237
  ifname = struct.unpack("16sh", res)[0].strip("\x00")
238
  return (ifname, tapfd)
239

    
240

    
241
class QmpMessage:
242
  """QEMU Messaging Protocol (QMP) message.
243

244
  """
245
  def __init__(self, data):
246
    """Creates a new QMP message based on the passed data.
247

248
    """
249
    if not isinstance(data, dict):
250
      raise TypeError("QmpMessage must be initialized with a dict")
251

    
252
    self.data = data
253

    
254
  def __getitem__(self, field_name):
255
    """Get the value of the required field if present, or None.
256

257
    Overrides the [] operator to provide access to the message data,
258
    returning None if the required item is not in the message
259
    @return: the value of the field_name field, or None if field_name
260
             is not contained in the message
261

262
    """
263
    return self.data.get(field_name, None)
264

    
265
  def __setitem__(self, field_name, field_value):
266
    """Set the value of the required field_name to field_value.
267

268
    """
269
    self.data[field_name] = field_value
270

    
271
  @staticmethod
272
  def BuildFromJsonString(json_string):
273
    """Build a QmpMessage from a JSON encoded string.
274

275
    @type json_string: str
276
    @param json_string: JSON string representing the message
277
    @rtype: L{QmpMessage}
278
    @return: a L{QmpMessage} built from json_string
279

280
    """
281
    # Parse the string
282
    data = serializer.LoadJson(json_string)
283
    return QmpMessage(data)
284

    
285
  def __str__(self):
286
    # The protocol expects the JSON object to be sent as a single line.
287
    return serializer.DumpJson(self.data)
288

    
289
  def __eq__(self, other):
290
    # When comparing two QmpMessages, we are interested in comparing
291
    # their internal representation of the message data
292
    return self.data == other.data
293

    
294

    
295
class QmpConnection:
296
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
297

298
  """
299
  _FIRST_MESSAGE_KEY = "QMP"
300
  _EVENT_KEY = "event"
301
  _ERROR_KEY = "error"
302
  _RETURN_KEY = RETURN_KEY = "return"
303
  _ACTUAL_KEY = ACTUAL_KEY = "actual"
304
  _ERROR_CLASS_KEY = "class"
305
  _ERROR_DATA_KEY = "data"
306
  _ERROR_DESC_KEY = "desc"
307
  _EXECUTE_KEY = "execute"
308
  _ARGUMENTS_KEY = "arguments"
309
  _CAPABILITIES_COMMAND = "qmp_capabilities"
310
  _MESSAGE_END_TOKEN = "\r\n"
311
  _SOCKET_TIMEOUT = 5
312

    
313
  def __init__(self, monitor_filename):
314
    """Instantiates the QmpConnection object.
315

316
    @type monitor_filename: string
317
    @param monitor_filename: the filename of the UNIX raw socket on which the
318
                             QMP monitor is listening
319

320
    """
321
    self.monitor_filename = monitor_filename
322
    self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
323
    # We want to fail if the server doesn't send a complete message
324
    # in a reasonable amount of time
325
    self.sock.settimeout(self._SOCKET_TIMEOUT)
326
    self._connected = False
327
    self._buf = ""
328

    
329
  def _check_socket(self):
330
    sock_stat = None
331
    try:
332
      sock_stat = os.stat(self.monitor_filename)
333
    except EnvironmentError, err:
334
      if err.errno == errno.ENOENT:
335
        raise errors.HypervisorError("No qmp socket found")
336
      else:
337
        raise errors.HypervisorError("Error checking qmp socket: %s",
338
                                     utils.ErrnoOrStr(err))
339
    if not stat.S_ISSOCK(sock_stat.st_mode):
340
      raise errors.HypervisorError("Qmp socket is not a socket")
341

    
342
  def _check_connection(self):
343
    """Make sure that the connection is established.
344

345
    """
346
    if not self._connected:
347
      raise errors.ProgrammerError("To use a QmpConnection you need to first"
348
                                   " invoke connect() on it")
349

    
350
  def connect(self):
351
    """Connects to the QMP monitor.
352

353
    Connects to the UNIX socket and makes sure that we can actually send and
354
    receive data to the kvm instance via QMP.
355

356
    @raise errors.HypervisorError: when there are communication errors
357
    @raise errors.ProgrammerError: when there are data serialization errors
358

359
    """
360
    if self._connected:
361
      raise errors.ProgrammerError("Cannot connect twice")
362

    
363
    self._check_socket()
364

    
365
    # Check file existance/stuff
366
    try:
367
      self.sock.connect(self.monitor_filename)
368
    except EnvironmentError:
369
      raise errors.HypervisorError("Can't connect to qmp socket")
370
    self._connected = True
371

    
372
    # Check if we receive a correct greeting message from the server
373
    # (As per the QEMU Protocol Specification 0.1 - section 2.2)
374
    greeting = self._Recv()
375
    if not greeting[self._FIRST_MESSAGE_KEY]:
376
      self._connected = False
377
      raise errors.HypervisorError("kvm: QMP communication error (wrong"
378
                                   " server greeting")
379

    
380
    # Let's put the monitor in command mode using the qmp_capabilities
381
    # command, or else no command will be executable.
382
    # (As per the QEMU Protocol Specification 0.1 - section 4)
383
    self.Execute(self._CAPABILITIES_COMMAND)
384

    
385
  def _ParseMessage(self, buf):
386
    """Extract and parse a QMP message from the given buffer.
387

388
    Seeks for a QMP message in the given buf. If found, it parses it and
389
    returns it together with the rest of the characters in the buf.
390
    If no message is found, returns None and the whole buffer.
391

392
    @raise errors.ProgrammerError: when there are data serialization errors
393

394
    """
395
    message = None
396
    # Check if we got the message end token (CRLF, as per the QEMU Protocol
397
    # Specification 0.1 - Section 2.1.1)
398
    pos = buf.find(self._MESSAGE_END_TOKEN)
399
    if pos >= 0:
400
      try:
401
        message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
402
      except Exception, err:
403
        raise errors.ProgrammerError("QMP data serialization error: %s" % err)
404
      buf = buf[pos + 1:]
405

    
406
    return (message, buf)
407

    
408
  def _Recv(self):
409
    """Receives a message from QMP and decodes the received JSON object.
410

411
    @rtype: QmpMessage
412
    @return: the received message
413
    @raise errors.HypervisorError: when there are communication errors
414
    @raise errors.ProgrammerError: when there are data serialization errors
415

416
    """
417
    self._check_connection()
418

    
419
    # Check if there is already a message in the buffer
420
    (message, self._buf) = self._ParseMessage(self._buf)
421
    if message:
422
      return message
423

    
424
    recv_buffer = StringIO.StringIO(self._buf)
425
    recv_buffer.seek(len(self._buf))
426
    try:
427
      while True:
428
        data = self.sock.recv(4096)
429
        if not data:
430
          break
431
        recv_buffer.write(data)
432

    
433
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
434
        if message:
435
          return message
436

    
437
    except socket.timeout, err:
438
      raise errors.HypervisorError("Timeout while receiving a QMP message: "
439
                                   "%s" % (err))
440
    except socket.error, err:
441
      raise errors.HypervisorError("Unable to receive data from KVM using the"
442
                                   " QMP protocol: %s" % err)
443

    
444
  def _Send(self, message):
445
    """Encodes and sends a message to KVM using QMP.
446

447
    @type message: QmpMessage
448
    @param message: message to send to KVM
449
    @raise errors.HypervisorError: when there are communication errors
450
    @raise errors.ProgrammerError: when there are data serialization errors
451

452
    """
453
    self._check_connection()
454
    try:
455
      message_str = str(message)
456
    except Exception, err:
457
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
458

    
459
    try:
460
      self.sock.sendall(message_str)
461
    except socket.timeout, err:
462
      raise errors.HypervisorError("Timeout while sending a QMP message: "
463
                                   "%s (%s)" % (err.string, err.errno))
464
    except socket.error, err:
465
      raise errors.HypervisorError("Unable to send data from KVM using the"
466
                                   " QMP protocol: %s" % err)
467

    
468
  def Execute(self, command, arguments=None):
469
    """Executes a QMP command and returns the response of the server.
470

471
    @type command: str
472
    @param command: the command to execute
473
    @type arguments: dict
474
    @param arguments: dictionary of arguments to be passed to the command
475
    @rtype: dict
476
    @return: dictionary representing the received JSON object
477
    @raise errors.HypervisorError: when there are communication errors
478
    @raise errors.ProgrammerError: when there are data serialization errors
479

480
    """
481
    self._check_connection()
482
    message = QmpMessage({self._EXECUTE_KEY: command})
483
    if arguments:
484
      message[self._ARGUMENTS_KEY] = arguments
485
    self._Send(message)
486

    
487
    # Events can occur between the sending of the command and the reception
488
    # of the response, so we need to filter out messages with the event key.
489
    while True:
490
      response = self._Recv()
491
      err = response[self._ERROR_KEY]
492
      if err:
493
        raise errors.HypervisorError("kvm: error executing the %s"
494
                                     " command: %s (%s, %s):" %
495
                                     (command,
496
                                      err[self._ERROR_DESC_KEY],
497
                                      err[self._ERROR_CLASS_KEY],
498
                                      err[self._ERROR_DATA_KEY]))
499

    
500
      elif not response[self._EVENT_KEY]:
501
        return response
502

    
503

    
504
class KVMHypervisor(hv_base.BaseHypervisor):
505
  """KVM hypervisor interface
506

507
  """
508
  CAN_MIGRATE = True
509

    
510
  _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
511
  _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
512
  _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
513
  _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
514
  _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
515
  _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
516
  _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
517
  # KVM instances with chroot enabled are started in empty chroot directories.
518
  _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
519
  # After an instance is stopped, its chroot directory is removed.
520
  # If the chroot directory is not empty, it can't be removed.
521
  # A non-empty chroot directory indicates a possible security incident.
522
  # To support forensics, the non-empty chroot directory is quarantined in
523
  # a separate directory, called 'chroot-quarantine'.
524
  _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
525
  _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
526
           _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
527

    
528
  PARAMETERS = {
529
    constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
530
    constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
531
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
532
    constants.HV_ROOT_PATH: hv_base.NO_CHECK,
533
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
534
    constants.HV_ACPI: hv_base.NO_CHECK,
535
    constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
536
    constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
537
    constants.HV_VNC_BIND_ADDRESS:
538
      (False, lambda x: (netutils.IP4Address.IsValid(x) or
539
                         utils.IsNormAbsPath(x)),
540
       "The VNC bind address must be either a valid IP address or an absolute"
541
       " pathname", None, None),
542
    constants.HV_VNC_TLS: hv_base.NO_CHECK,
543
    constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
544
    constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
545
    constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
546
    constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
547
    constants.HV_KVM_SPICE_IP_VERSION:
548
      (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
549
                         x in constants.VALID_IP_VERSIONS),
550
       "The SPICE IP version should be 4 or 6",
551
       None, None),
552
    constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
553
    constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
554
      hv_base.ParamInSet(
555
        False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
556
    constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
557
      hv_base.ParamInSet(
558
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
559
    constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
560
      hv_base.ParamInSet(
561
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
562
    constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
563
      hv_base.ParamInSet(
564
        False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
565
    constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
566
    constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
567
    constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
568
    constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
569
    constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
570
    constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
571
    constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
572
    constants.HV_BOOT_ORDER:
573
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
574
    constants.HV_NIC_TYPE:
575
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
576
    constants.HV_DISK_TYPE:
577
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
578
    constants.HV_KVM_CDROM_DISK_TYPE:
579
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
580
    constants.HV_USB_MOUSE:
581
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
582
    constants.HV_KEYMAP: hv_base.NO_CHECK,
583
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
584
    constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
585
    constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
586
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
587
    constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
588
    constants.HV_DISK_CACHE:
589
      hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
590
    constants.HV_SECURITY_MODEL:
591
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
592
    constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
593
    constants.HV_KVM_FLAG:
594
      hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
595
    constants.HV_VHOST_NET: hv_base.NO_CHECK,
596
    constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
597
    constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
598
    constants.HV_REBOOT_BEHAVIOR:
599
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
600
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
601
    constants.HV_CPU_TYPE: hv_base.NO_CHECK,
602
    constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
603
    constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
604
    constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
605
    constants.HV_SOUNDHW: hv_base.NO_CHECK,
606
    constants.HV_USB_DEVICES: hv_base.NO_CHECK,
607
    constants.HV_VGA: hv_base.NO_CHECK,
608
    constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
609
    constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
610
    constants.HV_VNET_HDR: hv_base.NO_CHECK,
611
    }
612

    
613
  _VIRTIO = "virtio"
614
  _VIRTIO_NET_PCI = "virtio-net-pci"
615
  _VIRTIO_BLK_PCI = "virtio-blk-pci"
616

    
617
  _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
618
                                    re.M | re.I)
619
  _MIGRATION_PROGRESS_RE = \
620
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
621
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
622
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
623

    
624
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
625
  _MIGRATION_INFO_RETRY_DELAY = 2
626

    
627
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
628

    
629
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
630
  _CPU_INFO_CMD = "info cpus"
631
  _CONT_CMD = "cont"
632

    
633
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
634
  _CHECK_MACHINE_VERSION_RE = \
635
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
636

    
637
  _QMP_RE = re.compile(r"^-qmp\s", re.M)
638
  _SPICE_RE = re.compile(r"^-spice\s", re.M)
639
  _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
640
  _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
641
  _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
642
  _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
643
  _DISPLAY_RE = re.compile(r"^-display\s", re.M)
644
  _MACHINE_RE = re.compile(r"^-machine\s", re.M)
645
  _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
646
  _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M)
647
  # match  -drive.*boot=on|off on different lines, but in between accept only
648
  # dashes not preceeded by a new line (which would mean another option
649
  # different than -drive is starting)
650
  _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
651

    
652
  ANCILLARY_FILES = [
653
    _KVM_NETWORK_SCRIPT,
654
    ]
655
  ANCILLARY_FILES_OPT = [
656
    _KVM_NETWORK_SCRIPT,
657
    ]
658

    
659
  # Supported kvm options to get output from
660
  _KVMOPT_HELP = "help"
661
  _KVMOPT_MLIST = "mlist"
662
  _KVMOPT_DEVICELIST = "devicelist"
663

    
664
  # Command to execute to get the output from kvm, and whether to
665
  # accept the output even on failure.
666
  _KVMOPTS_CMDS = {
667
    _KVMOPT_HELP: (["--help"], False),
668
    _KVMOPT_MLIST: (["-M", "?"], False),
669
    _KVMOPT_DEVICELIST: (["-device", "?"], True),
670
  }
671

    
672
  def __init__(self):
673
    hv_base.BaseHypervisor.__init__(self)
674
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
675
    # in a tmpfs filesystem or has been otherwise wiped out.
676
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
677
    utils.EnsureDirs(dirs)
678

    
679
  @classmethod
680
  def _InstancePidFile(cls, instance_name):
681
    """Returns the instance pidfile.
682

683
    """
684
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
685

    
686
  @classmethod
687
  def _InstanceUidFile(cls, instance_name):
688
    """Returns the instance uidfile.
689

690
    """
691
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
692

    
693
  @classmethod
694
  def _InstancePidInfo(cls, pid):
695
    """Check pid file for instance information.
696

697
    Check that a pid file is associated with an instance, and retrieve
698
    information from its command line.
699

700
    @type pid: string or int
701
    @param pid: process id of the instance to check
702
    @rtype: tuple
703
    @return: (instance_name, memory, vcpus)
704
    @raise errors.HypervisorError: when an instance cannot be found
705

706
    """
707
    alive = utils.IsProcessAlive(pid)
708
    if not alive:
709
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
710

    
711
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
712
    try:
713
      cmdline = utils.ReadFile(cmdline_file)
714
    except EnvironmentError, err:
715
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
716
                                   (pid, err))
717

    
718
    instance = None
719
    memory = 0
720
    vcpus = 0
721

    
722
    arg_list = cmdline.split("\x00")
723
    while arg_list:
724
      arg = arg_list.pop(0)
725
      if arg == "-name":
726
        instance = arg_list.pop(0)
727
      elif arg == "-m":
728
        memory = int(arg_list.pop(0))
729
      elif arg == "-smp":
730
        vcpus = int(arg_list.pop(0).split(",")[0])
731

    
732
    if instance is None:
733
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
734
                                   " instance" % pid)
735

    
736
    return (instance, memory, vcpus)
737

    
738
  def _InstancePidAlive(self, instance_name):
739
    """Returns the instance pidfile, pid, and liveness.
740

741
    @type instance_name: string
742
    @param instance_name: instance name
743
    @rtype: tuple
744
    @return: (pid file name, pid, liveness)
745

746
    """
747
    pidfile = self._InstancePidFile(instance_name)
748
    pid = utils.ReadPidFile(pidfile)
749

    
750
    alive = False
751
    try:
752
      cmd_instance = self._InstancePidInfo(pid)[0]
753
      alive = (cmd_instance == instance_name)
754
    except errors.HypervisorError:
755
      pass
756

    
757
    return (pidfile, pid, alive)
758

    
759
  def _CheckDown(self, instance_name):
760
    """Raises an error unless the given instance is down.
761

762
    """
763
    alive = self._InstancePidAlive(instance_name)[2]
764
    if alive:
765
      raise errors.HypervisorError("Failed to start instance %s: %s" %
766
                                   (instance_name, "already running"))
767

    
768
  @classmethod
769
  def _InstanceMonitor(cls, instance_name):
770
    """Returns the instance monitor socket name
771

772
    """
773
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
774

    
775
  @classmethod
776
  def _InstanceSerial(cls, instance_name):
777
    """Returns the instance serial socket name
778

779
    """
780
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
781

    
782
  @classmethod
783
  def _InstanceQmpMonitor(cls, instance_name):
784
    """Returns the instance serial QMP socket name
785

786
    """
787
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
788

    
789
  @staticmethod
790
  def _SocatUnixConsoleParams():
791
    """Returns the correct parameters for socat
792

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

795
    """
796
    if constants.SOCAT_USE_ESCAPE:
797
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
798
    else:
799
      return "echo=0,icanon=0"
800

    
801
  @classmethod
802
  def _InstanceKVMRuntime(cls, instance_name):
803
    """Returns the instance KVM runtime filename
804

805
    """
806
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
807

    
808
  @classmethod
809
  def _InstanceChrootDir(cls, instance_name):
810
    """Returns the name of the KVM chroot dir of the instance
811

812
    """
813
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
814

    
815
  @classmethod
816
  def _InstanceNICDir(cls, instance_name):
817
    """Returns the name of the directory holding the tap device files for a
818
    given instance.
819

820
    """
821
    return utils.PathJoin(cls._NICS_DIR, instance_name)
822

    
823
  @classmethod
824
  def _InstanceNICFile(cls, instance_name, seq):
825
    """Returns the name of the file containing the tap device for a given NIC
826

827
    """
828
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
829

    
830
  @classmethod
831
  def _InstanceKeymapFile(cls, instance_name):
832
    """Returns the name of the file containing the keymap for a given instance
833

834
    """
835
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
836

    
837
  @classmethod
838
  def _TryReadUidFile(cls, uid_file):
839
    """Try to read a uid file
840

841
    """
842
    if os.path.exists(uid_file):
843
      try:
844
        uid = int(utils.ReadOneLineFile(uid_file))
845
        return uid
846
      except EnvironmentError:
847
        logging.warning("Can't read uid file", exc_info=True)
848
      except (TypeError, ValueError):
849
        logging.warning("Can't parse uid file contents", exc_info=True)
850
    return None
851

    
852
  @classmethod
853
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
854
    """Removes an instance's rutime sockets/files/dirs.
855

856
    """
857
    utils.RemoveFile(pidfile)
858
    utils.RemoveFile(cls._InstanceMonitor(instance_name))
859
    utils.RemoveFile(cls._InstanceSerial(instance_name))
860
    utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
861
    utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
862
    utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
863
    uid_file = cls._InstanceUidFile(instance_name)
864
    uid = cls._TryReadUidFile(uid_file)
865
    utils.RemoveFile(uid_file)
866
    if uid is not None:
867
      uidpool.ReleaseUid(uid)
868
    try:
869
      shutil.rmtree(cls._InstanceNICDir(instance_name))
870
    except OSError, err:
871
      if err.errno != errno.ENOENT:
872
        raise
873
    try:
874
      chroot_dir = cls._InstanceChrootDir(instance_name)
875
      utils.RemoveDir(chroot_dir)
876
    except OSError, err:
877
      if err.errno == errno.ENOTEMPTY:
878
        # The chroot directory is expected to be empty, but it isn't.
879
        new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
880
                                          prefix="%s-%s-" %
881
                                          (instance_name,
882
                                           utils.TimestampForFilename()))
883
        logging.warning("The chroot directory of instance %s can not be"
884
                        " removed as it is not empty. Moving it to the"
885
                        " quarantine instead. Please investigate the"
886
                        " contents (%s) and clean up manually",
887
                        instance_name, new_chroot_dir)
888
        utils.RenameFile(chroot_dir, new_chroot_dir)
889
      else:
890
        raise
891

    
892
  @staticmethod
893
  def _ConfigureNIC(instance, seq, nic, tap):
894
    """Run the network configuration script for a specified NIC
895

896
    @param instance: instance we're acting on
897
    @type instance: instance object
898
    @param seq: nic sequence number
899
    @type seq: int
900
    @param nic: nic we're acting on
901
    @type nic: nic object
902
    @param tap: the host's tap interface this NIC corresponds to
903
    @type tap: str
904

905
    """
906
    if instance.tags:
907
      tags = " ".join(instance.tags)
908
    else:
909
      tags = ""
910

    
911
    env = {
912
      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
913
      "INSTANCE": instance.name,
914
      "MAC": nic.mac,
915
      "MODE": nic.nicparams[constants.NIC_MODE],
916
      "INTERFACE": tap,
917
      "INTERFACE_INDEX": str(seq),
918
      "TAGS": tags,
919
    }
920

    
921
    if nic.ip:
922
      env["IP"] = nic.ip
923

    
924
    if nic.nicparams[constants.NIC_LINK]:
925
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
926

    
927
    if nic.network:
928
      n = objects.Network.FromDict(nic.netinfo)
929
      env.update(n.HooksDict())
930

    
931
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
932
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
933

    
934
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
935
    if result.failed:
936
      raise errors.HypervisorError("Failed to configure interface %s: %s;"
937
                                   " network configuration script output: %s" %
938
                                   (tap, result.fail_reason, result.output))
939

    
940
  @staticmethod
941
  def _VerifyAffinityPackage():
942
    if affinity is None:
943
      raise errors.HypervisorError("affinity Python package not"
944
                                   " found; cannot use CPU pinning under KVM")
945

    
946
  @staticmethod
947
  def _BuildAffinityCpuMask(cpu_list):
948
    """Create a CPU mask suitable for sched_setaffinity from a list of
949
    CPUs.
950

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

954
    @type cpu_list: list of int
955
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
956
    @rtype: int
957
    @return: a bit mask of CPU affinities
958

959
    """
960
    if cpu_list == constants.CPU_PINNING_OFF:
961
      return constants.CPU_PINNING_ALL_KVM
962
    else:
963
      return sum(2 ** cpu for cpu in cpu_list)
964

    
965
  @classmethod
966
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
967
    """Change CPU affinity for running VM according to given CPU mask.
968

969
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
970
    @type cpu_mask: string
971
    @param process_id: process ID of KVM process. Used to pin entire VM
972
                       to physical CPUs.
973
    @type process_id: int
974
    @param thread_dict: map of virtual CPUs to KVM thread IDs
975
    @type thread_dict: dict int:int
976

977
    """
978
    # Convert the string CPU mask to a list of list of int's
979
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
980

    
981
    if len(cpu_list) == 1:
982
      all_cpu_mapping = cpu_list[0]
983
      if all_cpu_mapping == constants.CPU_PINNING_OFF:
984
        # If CPU pinning has 1 entry that's "all", then do nothing
985
        pass
986
      else:
987
        # If CPU pinning has one non-all entry, map the entire VM to
988
        # one set of physical CPUs
989
        cls._VerifyAffinityPackage()
990
        affinity.set_process_affinity_mask(
991
          process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
992
    else:
993
      # The number of vCPUs mapped should match the number of vCPUs
994
      # reported by KVM. This was already verified earlier, so
995
      # here only as a sanity check.
996
      assert len(thread_dict) == len(cpu_list)
997
      cls._VerifyAffinityPackage()
998

    
999
      # For each vCPU, map it to the proper list of physical CPUs
1000
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1001
        affinity.set_process_affinity_mask(thread_dict[i],
1002
                                           cls._BuildAffinityCpuMask(vcpu))
1003

    
1004
  def _GetVcpuThreadIds(self, instance_name):
1005
    """Get a mapping of vCPU no. to thread IDs for the instance
1006

1007
    @type instance_name: string
1008
    @param instance_name: instance in question
1009
    @rtype: dictionary of int:int
1010
    @return: a dictionary mapping vCPU numbers to thread IDs
1011

1012
    """
1013
    result = {}
1014
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1015
    for line in output.stdout.splitlines():
1016
      match = self._CPU_INFO_RE.search(line)
1017
      if not match:
1018
        continue
1019
      grp = map(int, match.groups())
1020
      result[grp[0]] = grp[1]
1021

    
1022
    return result
1023

    
1024
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1025
    """Complete CPU pinning.
1026

1027
    @type instance_name: string
1028
    @param instance_name: name of instance
1029
    @type cpu_mask: string
1030
    @param cpu_mask: CPU pinning mask as entered by user
1031

1032
    """
1033
    # Get KVM process ID, to be used if need to pin entire VM
1034
    _, pid, _ = self._InstancePidAlive(instance_name)
1035
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1036
    thread_dict = self._GetVcpuThreadIds(instance_name)
1037
    # Run CPU pinning, based on configured mask
1038
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1039

    
1040
  def ListInstances(self):
1041
    """Get the list of running instances.
1042

1043
    We can do this by listing our live instances directory and
1044
    checking whether the associated kvm process is still alive.
1045

1046
    """
1047
    result = []
1048
    for name in os.listdir(self._PIDS_DIR):
1049
      if self._InstancePidAlive(name)[2]:
1050
        result.append(name)
1051
    return result
1052

    
1053
  def GetInstanceInfo(self, instance_name):
1054
    """Get instance properties.
1055

1056
    @type instance_name: string
1057
    @param instance_name: the instance name
1058
    @rtype: tuple of strings
1059
    @return: (name, id, memory, vcpus, stat, times)
1060

1061
    """
1062
    _, pid, alive = self._InstancePidAlive(instance_name)
1063
    if not alive:
1064
      return None
1065

    
1066
    _, memory, vcpus = self._InstancePidInfo(pid)
1067
    istat = "---b-"
1068
    times = "0"
1069

    
1070
    try:
1071
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1072
      qmp.connect()
1073
      vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1074
      # Will fail if ballooning is not enabled, but we can then just resort to
1075
      # the value above.
1076
      mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1077
      memory = mem_bytes / 1048576
1078
    except errors.HypervisorError:
1079
      pass
1080

    
1081
    return (instance_name, pid, memory, vcpus, istat, times)
1082

    
1083
  def GetAllInstancesInfo(self):
1084
    """Get properties of all instances.
1085

1086
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1087

1088
    """
1089
    data = []
1090
    for name in os.listdir(self._PIDS_DIR):
1091
      try:
1092
        info = self.GetInstanceInfo(name)
1093
      except errors.HypervisorError:
1094
        # Ignore exceptions due to instances being shut down
1095
        continue
1096
      if info:
1097
        data.append(info)
1098
    return data
1099

    
1100
  def _GenerateKVMBlockDevicesOptions(self, instance, block_devices, kvmhelp):
1101

    
1102
    hvp = instance.hvparams
1103
    boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1104
    kvm_path = hvp[constants.HV_KVM_PATH]
1105

    
1106
    # whether this is an older KVM version that uses the boot=on flag
1107
    # on devices
1108
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1109

    
1110
    dev_opts = []
1111
    device_driver = None
1112
    disk_type = hvp[constants.HV_DISK_TYPE]
1113
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
1114
      if_val = ",if=%s" % self._VIRTIO
1115
      try:
1116
        devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1117
        if self._VIRTIO_BLK_RE.search(devlist):
1118
          # TODO: uncomment when -device is used
1119
          # if_val = ",if=none"
1120
          # will be passed in -device option as driver
1121
          device_driver = self._VIRTIO_BLK_PCI
1122
      except errors.HypervisorError, _:
1123
        pass
1124
    else:
1125
      if_val = ",if=%s" % disk_type
1126
    # Cache mode
1127
    disk_cache = hvp[constants.HV_DISK_CACHE]
1128
    if instance.disk_template in constants.DTS_EXT_MIRROR:
1129
      if disk_cache != "none":
1130
        # TODO: make this a hard error, instead of a silent overwrite
1131
        logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1132
                        " to prevent shared storage corruption on migration",
1133
                        disk_cache)
1134
      cache_val = ",cache=none"
1135
    elif disk_cache != constants.HT_CACHE_DEFAULT:
1136
      cache_val = ",cache=%s" % disk_cache
1137
    else:
1138
      cache_val = ""
1139
    for cfdev, dev_path in block_devices:
1140
      if cfdev.mode != constants.DISK_RDWR:
1141
        raise errors.HypervisorError("Instance has read-only disks which"
1142
                                     " are not supported by KVM")
1143
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
1144
      boot_val = ""
1145
      if boot_disk:
1146
        dev_opts.extend(["-boot", "c"])
1147
        boot_disk = False
1148
        if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1149
          boot_val = ",boot=on"
1150
      drive_val = "file=%s,format=raw%s%s%s" % \
1151
                  (dev_path, if_val, boot_val, cache_val)
1152

    
1153
      if device_driver:
1154
        pass
1155
      dev_opts.extend(["-drive", drive_val])
1156

    
1157
    return dev_opts
1158

    
1159
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1160
                          kvmhelp):
1161
    """Generate KVM information to start an instance.
1162

1163
    @type kvmhelp: string
1164
    @param kvmhelp: output of kvm --help
1165
    @attention: this function must not have any side-effects; for
1166
        example, it must not write to the filesystem, or read values
1167
        from the current system the are expected to differ between
1168
        nodes, since it is only run once at instance startup;
1169
        actions/kvm arguments that can vary between systems should be
1170
        done in L{_ExecuteKVMRuntime}
1171

1172
    """
1173
    # pylint: disable=R0912,R0914,R0915
1174
    hvp = instance.hvparams
1175
    self.ValidateParameters(hvp)
1176

    
1177
    pidfile = self._InstancePidFile(instance.name)
1178
    kvm = hvp[constants.HV_KVM_PATH]
1179
    kvm_cmd = [kvm]
1180
    # used just by the vnc server, if enabled
1181
    kvm_cmd.extend(["-name", instance.name])
1182
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1183

    
1184
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1185
    if hvp[constants.HV_CPU_CORES]:
1186
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1187
    if hvp[constants.HV_CPU_THREADS]:
1188
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1189
    if hvp[constants.HV_CPU_SOCKETS]:
1190
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1191

    
1192
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1193

    
1194
    kvm_cmd.extend(["-pidfile", pidfile])
1195
    kvm_cmd.extend(["-balloon", "virtio"])
1196
    kvm_cmd.extend(["-daemonize"])
1197
    if not instance.hvparams[constants.HV_ACPI]:
1198
      kvm_cmd.extend(["-no-acpi"])
1199
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1200
        constants.INSTANCE_REBOOT_EXIT:
1201
      kvm_cmd.extend(["-no-reboot"])
1202

    
1203
    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1204
    if not mversion:
1205
      mversion = self._GetDefaultMachineVersion(kvm)
1206
    if self._MACHINE_RE.search(kvmhelp):
1207
      # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1208
      # extra hypervisor parameters. We should also investigate whether and how
1209
      # shadow_mem should be considered for the resource model.
1210
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1211
        specprop = ",accel=kvm"
1212
      else:
1213
        specprop = ""
1214
      machinespec = "%s%s" % (mversion, specprop)
1215
      kvm_cmd.extend(["-machine", machinespec])
1216
    else:
1217
      kvm_cmd.extend(["-M", mversion])
1218
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1219
          self._ENABLE_KVM_RE.search(kvmhelp)):
1220
        kvm_cmd.extend(["-enable-kvm"])
1221
      elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1222
            self._DISABLE_KVM_RE.search(kvmhelp)):
1223
        kvm_cmd.extend(["-disable-kvm"])
1224

    
1225
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1226
    if kernel_path:
1227
      boot_cdrom = boot_floppy = boot_network = False
1228
    else:
1229
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1230
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1231
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1232

    
1233
    if startup_paused:
1234
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1235

    
1236
    if boot_network:
1237
      kvm_cmd.extend(["-boot", "n"])
1238

    
1239
    # whether this is an older KVM version that uses the boot=on flag
1240
    # on devices
1241
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1242

    
1243
    disk_type = hvp[constants.HV_DISK_TYPE]
1244

    
1245
    #Now we can specify a different device type for CDROM devices.
1246
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1247
    if not cdrom_disk_type:
1248
      cdrom_disk_type = disk_type
1249

    
1250
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1251
    if iso_image:
1252
      options = ",format=raw,media=cdrom"
1253
      # set cdrom 'if' type
1254
      if boot_cdrom:
1255
        actual_cdrom_type = constants.HT_DISK_IDE
1256
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1257
        actual_cdrom_type = "virtio"
1258
      else:
1259
        actual_cdrom_type = cdrom_disk_type
1260
      if_val = ",if=%s" % actual_cdrom_type
1261
      # set boot flag, if needed
1262
      boot_val = ""
1263
      if boot_cdrom:
1264
        kvm_cmd.extend(["-boot", "d"])
1265
        if needs_boot_flag:
1266
          boot_val = ",boot=on"
1267
      # and finally build the entire '-drive' value
1268
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1269
      kvm_cmd.extend(["-drive", drive_val])
1270

    
1271
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1272
    if iso_image2:
1273
      options = ",format=raw,media=cdrom"
1274
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1275
        if_val = ",if=virtio"
1276
      else:
1277
        if_val = ",if=%s" % cdrom_disk_type
1278
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1279
      kvm_cmd.extend(["-drive", drive_val])
1280

    
1281
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1282
    if floppy_image:
1283
      options = ",format=raw,media=disk"
1284
      if boot_floppy:
1285
        kvm_cmd.extend(["-boot", "a"])
1286
        options = "%s,boot=on" % options
1287
      if_val = ",if=floppy"
1288
      options = "%s%s" % (options, if_val)
1289
      drive_val = "file=%s%s" % (floppy_image, options)
1290
      kvm_cmd.extend(["-drive", drive_val])
1291

    
1292
    if kernel_path:
1293
      kvm_cmd.extend(["-kernel", kernel_path])
1294
      initrd_path = hvp[constants.HV_INITRD_PATH]
1295
      if initrd_path:
1296
        kvm_cmd.extend(["-initrd", initrd_path])
1297
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1298
                     hvp[constants.HV_KERNEL_ARGS]]
1299
      if hvp[constants.HV_SERIAL_CONSOLE]:
1300
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1301
        root_append.append("console=ttyS0,%s" % serial_speed)
1302
      kvm_cmd.extend(["-append", " ".join(root_append)])
1303

    
1304
    mem_path = hvp[constants.HV_MEM_PATH]
1305
    if mem_path:
1306
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1307

    
1308
    monitor_dev = ("unix:%s,server,nowait" %
1309
                   self._InstanceMonitor(instance.name))
1310
    kvm_cmd.extend(["-monitor", monitor_dev])
1311
    if hvp[constants.HV_SERIAL_CONSOLE]:
1312
      serial_dev = ("unix:%s,server,nowait" %
1313
                    self._InstanceSerial(instance.name))
1314
      kvm_cmd.extend(["-serial", serial_dev])
1315
    else:
1316
      kvm_cmd.extend(["-serial", "none"])
1317

    
1318
    mouse_type = hvp[constants.HV_USB_MOUSE]
1319
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1320
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1321
    spice_ip_version = None
1322

    
1323
    kvm_cmd.extend(["-usb"])
1324

    
1325
    if mouse_type:
1326
      kvm_cmd.extend(["-usbdevice", mouse_type])
1327
    elif vnc_bind_address:
1328
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1329

    
1330
    if vnc_bind_address:
1331
      if netutils.IP4Address.IsValid(vnc_bind_address):
1332
        if instance.network_port > constants.VNC_BASE_PORT:
1333
          display = instance.network_port - constants.VNC_BASE_PORT
1334
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1335
            vnc_arg = ":%d" % (display)
1336
          else:
1337
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1338
        else:
1339
          logging.error("Network port is not a valid VNC display (%d < %d),"
1340
                        " not starting VNC",
1341
                        instance.network_port, constants.VNC_BASE_PORT)
1342
          vnc_arg = "none"
1343

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

    
1358
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1359

    
1360
      else:
1361
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1362

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

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

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

    
1397
        spice_address = addresses[spice_ip_version][0]
1398

    
1399
      else:
1400
        # spice_bind is known to be a valid IP address, because
1401
        # ValidateParameters checked it.
1402
        spice_address = spice_bind
1403

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

    
1418
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1419
        spice_arg = "%s,disable-ticketing" % spice_arg
1420

    
1421
      if spice_ip_version:
1422
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1423

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

    
1435
      # Video stream detection
1436
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1437
      if video_streaming:
1438
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1439

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

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

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

    
1466
    if hvp[constants.HV_USE_LOCALTIME]:
1467
      kvm_cmd.extend(["-localtime"])
1468

    
1469
    if hvp[constants.HV_KVM_USE_CHROOT]:
1470
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1471

    
1472
    # Add qemu-KVM -cpu param
1473
    if hvp[constants.HV_CPU_TYPE]:
1474
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1475

    
1476
    # As requested by music lovers
1477
    if hvp[constants.HV_SOUNDHW]:
1478
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1479

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

    
1487
    # Various types of usb devices, comma separated
1488
    if hvp[constants.HV_USB_DEVICES]:
1489
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1490
        kvm_cmd.extend(["-usbdevice", dev])
1491

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

    
1495
    kvm_disks = []
1496
    for disk, dev_path in block_devices:
1497
      kvm_disks.append((disk, dev_path))
1498

    
1499
    kvm_nics = []
1500
    for nic in instance.nics:
1501
      kvm_nics.append(nic)
1502

    
1503
    hvparams = hvp
1504

    
1505
    return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1506

    
1507
  def _WriteKVMRuntime(self, instance_name, data):
1508
    """Write an instance's KVM runtime
1509

1510
    """
1511
    try:
1512
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1513
                      data=data)
1514
    except EnvironmentError, err:
1515
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1516

    
1517
  def _ReadKVMRuntime(self, instance_name):
1518
    """Read an instance's KVM runtime
1519

1520
    """
1521
    try:
1522
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1523
    except EnvironmentError, err:
1524
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1525
    return file_content
1526

    
1527
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1528
    """Save an instance's KVM runtime
1529

1530
    """
1531
    kvm_cmd, kvm_nics, hvparams, block_devices = kvm_runtime
1532

    
1533
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1534
    serialized_blockdevs = [(blk.ToDict(), link, uri)
1535
                            for blk, link, uri in block_devices]
1536
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1537
                                      serialized_blockdevs))
1538

    
1539
    self._WriteKVMRuntime(instance.name, serialized_form)
1540

    
1541
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1542
    """Load an instance's KVM runtime
1543

1544
    """
1545
    if not serialized_runtime:
1546
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1547

    
1548
    return _AnalyzeSerializedRuntime(serialized_runtime)
1549

    
1550
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1551
    """Run the KVM cmd and check for errors
1552

1553
    @type name: string
1554
    @param name: instance name
1555
    @type kvm_cmd: list of strings
1556
    @param kvm_cmd: runcmd input for kvm
1557
    @type tap_fds: list of int
1558
    @param tap_fds: fds of tap devices opened by Ganeti
1559

1560
    """
1561
    try:
1562
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1563
    finally:
1564
      for fd in tap_fds:
1565
        utils_wrapper.CloseFdNoError(fd)
1566

    
1567
    if result.failed:
1568
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1569
                                   (name, result.fail_reason, result.output))
1570
    if not self._InstancePidAlive(name)[2]:
1571
      raise errors.HypervisorError("Failed to start instance %s" % name)
1572

    
1573
  # 52/50 local variables
1574
  # pylint: disable=R0914
1575
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1576
    """Execute a KVM cmd, after completing it with some last minute data.
1577

1578
    @type incoming: tuple of strings
1579
    @param incoming: (target_host_ip, port)
1580
    @type kvmhelp: string
1581
    @param kvmhelp: output of kvm --help
1582

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

    
1596
    temp_files = []
1597

    
1598
    kvm_cmd, kvm_nics, up_hvp, block_devices = kvm_runtime
1599
    # the first element of kvm_cmd is always the path to the kvm binary
1600
    kvm_path = kvm_cmd[0]
1601
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1602

    
1603
    # We know it's safe to run as a different user upon migration, so we'll use
1604
    # the latest conf, from conf_hvp.
1605
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1606
    if security_model == constants.HT_SM_USER:
1607
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1608

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

    
1619
    # We have reasons to believe changing something like the nic driver/type
1620
    # upon migration won't exactly fly with the instance kernel, so for nic
1621
    # related parameters we'll use up_hvp
1622
    tapfds = []
1623
    taps = []
1624
    if not kvm_nics:
1625
      kvm_cmd.extend(["-net", "none"])
1626
    else:
1627
      vnet_hdr = False
1628
      tap_extra = ""
1629
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1630
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1631
        nic_model = self._VIRTIO
1632
        try:
1633
          devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1634
          if self._VIRTIO_NET_RE.search(devlist):
1635
            nic_model = self._VIRTIO_NET_PCI
1636
            vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1637
        except errors.HypervisorError, _:
1638
          # Older versions of kvm don't support DEVICE_LIST, but they don't
1639
          # have new virtio syntax either.
1640
          pass
1641

    
1642
        if up_hvp[constants.HV_VHOST_NET]:
1643
          # check for vhost_net support
1644
          if self._VHOST_RE.search(kvmhelp):
1645
            tap_extra = ",vhost=on"
1646
          else:
1647
            raise errors.HypervisorError("vhost_net is configured"
1648
                                         " but it is not available")
1649
      else:
1650
        nic_model = nic_type
1651

    
1652
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1653

    
1654
      for nic_seq, nic in enumerate(kvm_nics):
1655
        tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1656
        tapfds.append(tapfd)
1657
        taps.append(tapname)
1658
        if kvm_supports_netdev:
1659
          nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1660
          tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1661
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1662
        else:
1663
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1664
                                                         nic.mac, nic_model)
1665
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1666
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1667

    
1668
    if incoming:
1669
      target, port = incoming
1670
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1671

    
1672
    # Changing the vnc password doesn't bother the guest that much. At most it
1673
    # will surprise people who connect to it. Whether positively or negatively
1674
    # it's debatable.
1675
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1676
    vnc_pwd = None
1677
    if vnc_pwd_file:
1678
      try:
1679
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1680
      except EnvironmentError, err:
1681
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1682
                                     % (vnc_pwd_file, err))
1683

    
1684
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1685
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1686
                         constants.SECURE_DIR_MODE)])
1687

    
1688
    # Automatically enable QMP if version is >= 0.14
1689
    if self._QMP_RE.search(kvmhelp):
1690
      logging.debug("Enabling QMP")
1691
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1692
                      self._InstanceQmpMonitor(instance.name)])
1693

    
1694
    # Configure the network now for starting instances and bridged interfaces,
1695
    # during FinalizeMigration for incoming instances' routed interfaces
1696
    for nic_seq, nic in enumerate(kvm_nics):
1697
      if (incoming and
1698
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1699
        continue
1700
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1701

    
1702
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1703
                                                     block_devices,
1704
                                                     kvmhelp)
1705
    kvm_cmd.extend(bdev_opts)
1706
    # CPU affinity requires kvm to start paused, so we set this flag if the
1707
    # instance is not already paused and if we are not going to accept a
1708
    # migrating instance. In the latter case, pausing is not needed.
1709
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1710
    if start_kvm_paused:
1711
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1712

    
1713
    # Note: CPU pinning is using up_hvp since changes take effect
1714
    # during instance startup anyway, and to avoid problems when soft
1715
    # rebooting the instance.
1716
    cpu_pinning = False
1717
    if up_hvp.get(constants.HV_CPU_MASK, None):
1718
      cpu_pinning = True
1719

    
1720
    if security_model == constants.HT_SM_POOL:
1721
      ss = ssconf.SimpleStore()
1722
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1723
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1724
      uid = uidpool.RequestUnusedUid(all_uids)
1725
      try:
1726
        username = pwd.getpwuid(uid.GetUid()).pw_name
1727
        kvm_cmd.extend(["-runas", username])
1728
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1729
      except:
1730
        uidpool.ReleaseUid(uid)
1731
        raise
1732
      else:
1733
        uid.Unlock()
1734
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1735
    else:
1736
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1737

    
1738
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1739
                     constants.RUN_DIRS_MODE)])
1740
    for nic_seq, tap in enumerate(taps):
1741
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1742
                      data=tap)
1743

    
1744
    if vnc_pwd:
1745
      change_cmd = "change vnc password %s" % vnc_pwd
1746
      self._CallMonitorCommand(instance.name, change_cmd)
1747

    
1748
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1749
    # connection attempts because SPICE by default does not allow connections
1750
    # if neither a password nor the "disable_ticketing" options are specified.
1751
    # As soon as we send the password via QMP, that password is a valid ticket
1752
    # for connection.
1753
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1754
    if spice_password_file:
1755
      spice_pwd = ""
1756
      try:
1757
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1758
      except EnvironmentError, err:
1759
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1760
                                     % (spice_password_file, err))
1761

    
1762
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1763
      qmp.connect()
1764
      arguments = {
1765
          "protocol": "spice",
1766
          "password": spice_pwd,
1767
      }
1768
      qmp.Execute("set_password", arguments)
1769

    
1770
    for filename in temp_files:
1771
      utils.RemoveFile(filename)
1772

    
1773
    # If requested, set CPU affinity and resume instance execution
1774
    if cpu_pinning:
1775
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1776

    
1777
    start_memory = self._InstanceStartupMemory(instance)
1778
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1779
      self.BalloonInstanceMemory(instance, start_memory)
1780

    
1781
    if start_kvm_paused:
1782
      # To control CPU pinning, ballooning, and vnc/spice passwords
1783
      # the VM was started in a frozen state. If freezing was not
1784
      # explicitly requested resume the vm status.
1785
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1786

    
1787
  def StartInstance(self, instance, block_devices, startup_paused):
1788
    """Start an instance.
1789

1790
    """
1791
    self._CheckDown(instance.name)
1792
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1793
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1794
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1795
                                           startup_paused, kvmhelp)
1796
    self._SaveKVMRuntime(instance, kvm_runtime)
1797
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1798

    
1799
  def _CallMonitorCommand(self, instance_name, command):
1800
    """Invoke a command on the instance monitor.
1801

1802
    """
1803
    # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1804
    # version. The monitor protocol is designed for human consumption, whereas
1805
    # QMP is made for programmatic usage. In the worst case QMP can also
1806
    # execute monitor commands. As it is, all calls to socat take at least
1807
    # 500ms and likely more: socat can't detect the end of the reply and waits
1808
    # for 500ms of no data received before exiting (500 ms is the default for
1809
    # the "-t" parameter).
1810
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1811
             (utils.ShellQuote(command),
1812
              constants.SOCAT_PATH,
1813
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1814
    result = utils.RunCmd(socat)
1815
    if result.failed:
1816
      msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1817
             " output: %s" %
1818
             (command, instance_name, result.fail_reason, result.output))
1819
      raise errors.HypervisorError(msg)
1820

    
1821
    return result
1822

    
1823
  @classmethod
1824
  def _ParseKVMVersion(cls, text):
1825
    """Parse the KVM version from the --help output.
1826

1827
    @type text: string
1828
    @param text: output of kvm --help
1829
    @return: (version, v_maj, v_min, v_rev)
1830
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1831

1832
    """
1833
    match = cls._VERSION_RE.search(text.splitlines()[0])
1834
    if not match:
1835
      raise errors.HypervisorError("Unable to get KVM version")
1836

    
1837
    v_all = match.group(0)
1838
    v_maj = int(match.group(1))
1839
    v_min = int(match.group(2))
1840
    if match.group(4):
1841
      v_rev = int(match.group(4))
1842
    else:
1843
      v_rev = 0
1844
    return (v_all, v_maj, v_min, v_rev)
1845

    
1846
  @classmethod
1847
  def _GetKVMOutput(cls, kvm_path, option):
1848
    """Return the output of a kvm invocation
1849

1850
    @type kvm_path: string
1851
    @param kvm_path: path to the kvm executable
1852
    @type option: a key of _KVMOPTS_CMDS
1853
    @param option: kvm option to fetch the output from
1854
    @return: output a supported kvm invocation
1855
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1856

1857
    """
1858
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
1859

    
1860
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
1861

    
1862
    result = utils.RunCmd([kvm_path] + optlist)
1863
    if result.failed and not can_fail:
1864
      raise errors.HypervisorError("Unable to get KVM %s output" %
1865
                                    " ".join(optlist))
1866
    return result.output
1867

    
1868
  @classmethod
1869
  def _GetKVMVersion(cls, kvm_path):
1870
    """Return the installed KVM version.
1871

1872
    @return: (version, v_maj, v_min, v_rev)
1873
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1874

1875
    """
1876
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
1877

    
1878
  @classmethod
1879
  def _GetDefaultMachineVersion(cls, kvm_path):
1880
    """Return the default hardware revision (e.g. pc-1.1)
1881

1882
    """
1883
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
1884
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
1885
    if match:
1886
      return match.group(1)
1887
    else:
1888
      return "pc"
1889

    
1890
  def StopInstance(self, instance, force=False, retry=False, name=None):
1891
    """Stop an instance.
1892

1893
    """
1894
    if name is not None and not force:
1895
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1896
    if name is None:
1897
      name = instance.name
1898
      acpi = instance.hvparams[constants.HV_ACPI]
1899
    else:
1900
      acpi = False
1901
    _, pid, alive = self._InstancePidAlive(name)
1902
    if pid > 0 and alive:
1903
      if force or not acpi:
1904
        utils.KillProcess(pid)
1905
      else:
1906
        self._CallMonitorCommand(name, "system_powerdown")
1907

    
1908
  def CleanupInstance(self, instance_name):
1909
    """Cleanup after a stopped instance
1910

1911
    """
1912
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
1913
    if pid > 0 and alive:
1914
      raise errors.HypervisorError("Cannot cleanup a live instance")
1915
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1916

    
1917
  def RebootInstance(self, instance):
1918
    """Reboot an instance.
1919

1920
    """
1921
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1922
    # socket the instance will stop, but now power up again. So we'll resort
1923
    # to shutdown and restart.
1924
    _, _, alive = self._InstancePidAlive(instance.name)
1925
    if not alive:
1926
      raise errors.HypervisorError("Failed to reboot instance %s:"
1927
                                   " not running" % instance.name)
1928
    # StopInstance will delete the saved KVM runtime so:
1929
    # ...first load it...
1930
    kvm_runtime = self._LoadKVMRuntime(instance)
1931
    # ...now we can safely call StopInstance...
1932
    if not self.StopInstance(instance):
1933
      self.StopInstance(instance, force=True)
1934
    # ...and finally we can save it again, and execute it...
1935
    self._SaveKVMRuntime(instance, kvm_runtime)
1936
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1937
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1938
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1939

    
1940
  def MigrationInfo(self, instance):
1941
    """Get instance information to perform a migration.
1942

1943
    @type instance: L{objects.Instance}
1944
    @param instance: instance to be migrated
1945
    @rtype: string
1946
    @return: content of the KVM runtime file
1947

1948
    """
1949
    return self._ReadKVMRuntime(instance.name)
1950

    
1951
  def AcceptInstance(self, instance, info, target):
1952
    """Prepare to accept an instance.
1953

1954
    @type instance: L{objects.Instance}
1955
    @param instance: instance to be accepted
1956
    @type info: string
1957
    @param info: content of the KVM runtime file on the source node
1958
    @type target: string
1959
    @param target: target host (usually ip), on this node
1960

1961
    """
1962
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1963
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1964
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1965
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1966
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
1967
                            incoming=incoming_address)
1968

    
1969
  def FinalizeMigrationDst(self, instance, info, success):
1970
    """Finalize the instance migration on the target node.
1971

1972
    Stop the incoming mode KVM.
1973

1974
    @type instance: L{objects.Instance}
1975
    @param instance: instance whose migration is being finalized
1976

1977
    """
1978
    if success:
1979
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1980
      kvm_nics = kvm_runtime[1]
1981

    
1982
      for nic_seq, nic in enumerate(kvm_nics):
1983
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1984
          # Bridged interfaces have already been configured
1985
          continue
1986
        try:
1987
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1988
        except EnvironmentError, err:
1989
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
1990
                          instance.name, nic_seq, str(err))
1991
          continue
1992
        try:
1993
          self._ConfigureNIC(instance, nic_seq, nic, tap)
1994
        except errors.HypervisorError, err:
1995
          logging.warning(str(err))
1996

    
1997
      self._WriteKVMRuntime(instance.name, info)
1998
    else:
1999
      self.StopInstance(instance, force=True)
2000

    
2001
  def MigrateInstance(self, instance, target, live):
2002
    """Migrate an instance to a target node.
2003

2004
    The migration will not be attempted if the instance is not
2005
    currently running.
2006

2007
    @type instance: L{objects.Instance}
2008
    @param instance: the instance to be migrated
2009
    @type target: string
2010
    @param target: ip address of the target node
2011
    @type live: boolean
2012
    @param live: perform a live migration
2013

2014
    """
2015
    instance_name = instance.name
2016
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
2017
    _, _, alive = self._InstancePidAlive(instance_name)
2018
    if not alive:
2019
      raise errors.HypervisorError("Instance not running, cannot migrate")
2020

    
2021
    if not live:
2022
      self._CallMonitorCommand(instance_name, "stop")
2023

    
2024
    migrate_command = ("migrate_set_speed %dm" %
2025
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2026
    self._CallMonitorCommand(instance_name, migrate_command)
2027

    
2028
    migrate_command = ("migrate_set_downtime %dms" %
2029
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2030
    self._CallMonitorCommand(instance_name, migrate_command)
2031

    
2032
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2033
    self._CallMonitorCommand(instance_name, migrate_command)
2034

    
2035
  def FinalizeMigrationSource(self, instance, success, live):
2036
    """Finalize the instance migration on the source node.
2037

2038
    @type instance: L{objects.Instance}
2039
    @param instance: the instance that was migrated
2040
    @type success: bool
2041
    @param success: whether the migration succeeded or not
2042
    @type live: bool
2043
    @param live: whether the user requested a live migration or not
2044

2045
    """
2046
    if success:
2047
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2048
      utils.KillProcess(pid)
2049
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2050
    elif live:
2051
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2052

    
2053
  def GetMigrationStatus(self, instance):
2054
    """Get the migration status
2055

2056
    @type instance: L{objects.Instance}
2057
    @param instance: the instance that is being migrated
2058
    @rtype: L{objects.MigrationStatus}
2059
    @return: the status of the current migration (one of
2060
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2061
             progress info that can be retrieved from the hypervisor
2062

2063
    """
2064
    info_command = "info migrate"
2065
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2066
      result = self._CallMonitorCommand(instance.name, info_command)
2067
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
2068
      if not match:
2069
        if not result.stdout:
2070
          logging.info("KVM: empty 'info migrate' result")
2071
        else:
2072
          logging.warning("KVM: unknown 'info migrate' result: %s",
2073
                          result.stdout)
2074
      else:
2075
        status = match.group(1)
2076
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2077
          migration_status = objects.MigrationStatus(status=status)
2078
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2079
          if match:
2080
            migration_status.transferred_ram = match.group("transferred")
2081
            migration_status.total_ram = match.group("total")
2082

    
2083
          return migration_status
2084

    
2085
        logging.warning("KVM: unknown migration status '%s'", status)
2086

    
2087
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2088

    
2089
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2090

    
2091
  def BalloonInstanceMemory(self, instance, mem):
2092
    """Balloon an instance memory to a certain value.
2093

2094
    @type instance: L{objects.Instance}
2095
    @param instance: instance to be accepted
2096
    @type mem: int
2097
    @param mem: actual memory size to use for instance runtime
2098

2099
    """
2100
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2101

    
2102
  def GetNodeInfo(self):
2103
    """Return information about the node.
2104

2105
    @return: a dict with the following keys (values in MiB):
2106
          - memory_total: the total memory size on the node
2107
          - memory_free: the available memory on the node for instances
2108
          - memory_dom0: the memory used by the node itself, if available
2109
          - hv_version: the hypervisor version in the form (major, minor,
2110
                        revision)
2111

2112
    """
2113
    result = self.GetLinuxNodeInfo()
2114
    # FIXME: this is the global kvm version, but the actual version can be
2115
    # customized as an hv parameter. we should use the nodegroup's default kvm
2116
    # path parameter here.
2117
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2118
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2119
    return result
2120

    
2121
  @classmethod
2122
  def GetInstanceConsole(cls, instance, hvparams, beparams):
2123
    """Return a command for connecting to the console of an instance.
2124

2125
    """
2126
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2127
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2128
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2129
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2130
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2131
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2132
      return objects.InstanceConsole(instance=instance.name,
2133
                                     kind=constants.CONS_SSH,
2134
                                     host=instance.primary_node,
2135
                                     user=constants.SSH_CONSOLE_USER,
2136
                                     command=cmd)
2137

    
2138
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2139
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2140
      display = instance.network_port - constants.VNC_BASE_PORT
2141
      return objects.InstanceConsole(instance=instance.name,
2142
                                     kind=constants.CONS_VNC,
2143
                                     host=vnc_bind_address,
2144
                                     port=instance.network_port,
2145
                                     display=display)
2146

    
2147
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2148
    if spice_bind:
2149
      return objects.InstanceConsole(instance=instance.name,
2150
                                     kind=constants.CONS_SPICE,
2151
                                     host=spice_bind,
2152
                                     port=instance.network_port)
2153

    
2154
    return objects.InstanceConsole(instance=instance.name,
2155
                                   kind=constants.CONS_MESSAGE,
2156
                                   message=("No serial shell for instance %s" %
2157
                                            instance.name))
2158

    
2159
  def Verify(self):
2160
    """Verify the hypervisor.
2161

2162
    Check that the required binaries exist.
2163

2164
    @return: Problem description if something is wrong, C{None} otherwise
2165

2166
    """
2167
    msgs = []
2168
    # FIXME: this is the global kvm binary, but the actual path can be
2169
    # customized as an hv parameter; we should use the nodegroup's
2170
    # default kvm path parameter here.
2171
    if not os.path.exists(constants.KVM_PATH):
2172
      msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2173
    if not os.path.exists(constants.SOCAT_PATH):
2174
      msgs.append("The socat binary ('%s') does not exist" %
2175
                  constants.SOCAT_PATH)
2176

    
2177
    return self._FormatVerifyResults(msgs)
2178

    
2179
  @classmethod
2180
  def CheckParameterSyntax(cls, hvparams):
2181
    """Check the given parameters for validity.
2182

2183
    @type hvparams:  dict
2184
    @param hvparams: dictionary with parameter names/value
2185
    @raise errors.HypervisorError: when a parameter is not valid
2186

2187
    """
2188
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2189

    
2190
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2191
    if kernel_path:
2192
      if not hvparams[constants.HV_ROOT_PATH]:
2193
        raise errors.HypervisorError("Need a root partition for the instance,"
2194
                                     " if a kernel is defined")
2195

    
2196
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2197
        not hvparams[constants.HV_VNC_X509]):
2198
      raise errors.HypervisorError("%s must be defined, if %s is" %
2199
                                   (constants.HV_VNC_X509,
2200
                                    constants.HV_VNC_X509_VERIFY))
2201

    
2202
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2203
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2204
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2205
      if not serial_speed or serial_speed not in valid_speeds:
2206
        raise errors.HypervisorError("Invalid serial console speed, must be"
2207
                                     " one of: %s" %
2208
                                     utils.CommaJoin(valid_speeds))
2209

    
2210
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2211
    if (boot_order == constants.HT_BO_CDROM and
2212
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2213
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2214
                                   " ISO path")
2215

    
2216
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2217
    if security_model == constants.HT_SM_USER:
2218
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2219
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2220
                                     " must be specified")
2221
    elif (security_model == constants.HT_SM_NONE or
2222
          security_model == constants.HT_SM_POOL):
2223
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2224
        raise errors.HypervisorError("Cannot have a security domain when the"
2225
                                     " security model is 'none' or 'pool'")
2226

    
2227
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2228
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2229
    if spice_bind:
2230
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2231
        # if an IP version is specified, the spice_bind parameter must be an
2232
        # IP of that family
2233
        if (netutils.IP4Address.IsValid(spice_bind) and
2234
            spice_ip_version != constants.IP4_VERSION):
2235
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2236
                                       " the specified IP version is %s" %
2237
                                       (spice_bind, spice_ip_version))
2238

    
2239
        if (netutils.IP6Address.IsValid(spice_bind) and
2240
            spice_ip_version != constants.IP6_VERSION):
2241
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2242
                                       " the specified IP version is %s" %
2243
                                       (spice_bind, spice_ip_version))
2244
    else:
2245
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2246
      # error if any of them is set without it.
2247
      for param in _SPICE_ADDITIONAL_PARAMS:
2248
        if hvparams[param]:
2249
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2250
                                       (param, constants.HV_KVM_SPICE_BIND))
2251

    
2252
  @classmethod
2253
  def ValidateParameters(cls, hvparams):
2254
    """Check the given parameters for validity.
2255

2256
    @type hvparams:  dict
2257
    @param hvparams: dictionary with parameter names/value
2258
    @raise errors.HypervisorError: when a parameter is not valid
2259

2260
    """
2261
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2262

    
2263
    kvm_path = hvparams[constants.HV_KVM_PATH]
2264

    
2265
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2266
    if security_model == constants.HT_SM_USER:
2267
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2268
      try:
2269
        pwd.getpwnam(username)
2270
      except KeyError:
2271
        raise errors.HypervisorError("Unknown security domain user %s"
2272
                                     % username)
2273

    
2274
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2275
    if spice_bind:
2276
      # only one of VNC and SPICE can be used currently.
2277
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2278
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2279
                                     " only one of them can be used at a"
2280
                                     " given time")
2281

    
2282
      # check that KVM supports SPICE
2283
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2284
      if not cls._SPICE_RE.search(kvmhelp):
2285
        raise errors.HypervisorError("SPICE is configured, but it is not"
2286
                                     " supported according to 'kvm --help'")
2287

    
2288
      # if spice_bind is not an IP address, it must be a valid interface
2289
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2290
                       netutils.IP6Address.IsValid(spice_bind))
2291
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2292
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2293
                                     " a valid IP address or interface name" %
2294
                                     constants.HV_KVM_SPICE_BIND)
2295

    
2296
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2297
    if machine_version:
2298
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2299
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2300
        raise errors.HypervisorError("Unsupported machine version: %s" %
2301
                                     machine_version)
2302

    
2303
  @classmethod
2304
  def PowercycleNode(cls):
2305
    """KVM powercycle, just a wrapper over Linux powercycle.
2306

2307
    """
2308
    cls.LinuxPowercycle()