Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 96f82929

History | View | Annotate | Download (84.9 kB)

1
#
2
#
3

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

    
21

    
22
"""KVM hypervisor
23

24
"""
25

    
26
import errno
27
import os
28
import os.path
29
import re
30
import tempfile
31
import time
32
import logging
33
import pwd
34
import struct
35
import fcntl
36
import shutil
37
import socket
38
import stat
39
import StringIO
40
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) for (d, l) 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)
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 _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
135
  """Retrieves supported TUN features from file descriptor.
136

137
  @see: L{_ProbeTapVnetHdr}
138

139
  """
140
  req = struct.pack("I", 0)
141
  try:
142
    buf = _ioctl(fd, TUNGETFEATURES, req)
143
  except EnvironmentError, err:
144
    logging.warning("ioctl(TUNGETFEATURES) failed: %s", err)
145
    return None
146
  else:
147
    (flags, ) = struct.unpack("I", buf)
148
    return flags
149

    
150

    
151
def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
152
  """Check whether to enable the IFF_VNET_HDR flag.
153

154
  To do this, _all_ of the following conditions must be met:
155
   1. TUNGETFEATURES ioctl() *must* be implemented
156
   2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
157
   3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
158
      drivers/net/tun.c there is no way to test this until after the tap device
159
      has been created using TUNSETIFF, and there is no way to change the
160
      IFF_VNET_HDR flag after creating the interface, catch-22! However both
161
      TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
162
      thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
163

164
   @type fd: int
165
   @param fd: the file descriptor of /dev/net/tun
166

167
  """
168
  flags = _features_fn(fd)
169

    
170
  if flags is None:
171
    # Not supported
172
    return False
173

    
174
  result = bool(flags & IFF_VNET_HDR)
175

    
176
  if not result:
177
    logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
178

    
179
  return result
180

    
181

    
182
def _OpenTap(vnet_hdr=True):
183
  """Open a new tap device and return its file descriptor.
184

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

188
  @type vnet_hdr: boolean
189
  @param vnet_hdr: Enable the VNET Header
190
  @return: (ifname, tapfd)
191
  @rtype: tuple
192

193
  """
194
  try:
195
    tapfd = os.open("/dev/net/tun", os.O_RDWR)
196
  except EnvironmentError:
197
    raise errors.HypervisorError("Failed to open /dev/net/tun")
198

    
199
  flags = IFF_TAP | IFF_NO_PI
200

    
201
  if vnet_hdr and _ProbeTapVnetHdr(tapfd):
202
    flags |= IFF_VNET_HDR
203

    
204
  # The struct ifreq ioctl request (see netdevice(7))
205
  ifr = struct.pack("16sh", "", flags)
206

    
207
  try:
208
    res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
209
  except EnvironmentError, err:
210
    raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
211
                                 err)
212

    
213
  # Get the interface name from the ioctl
214
  ifname = struct.unpack("16sh", res)[0].strip("\x00")
215
  return (ifname, tapfd)
216

    
217

    
218
class QmpMessage:
219
  """QEMU Messaging Protocol (QMP) message.
220

221
  """
222
  def __init__(self, data):
223
    """Creates a new QMP message based on the passed data.
224

225
    """
226
    if not isinstance(data, dict):
227
      raise TypeError("QmpMessage must be initialized with a dict")
228

    
229
    self.data = data
230

    
231
  def __getitem__(self, field_name):
232
    """Get the value of the required field if present, or None.
233

234
    Overrides the [] operator to provide access to the message data,
235
    returning None if the required item is not in the message
236
    @return: the value of the field_name field, or None if field_name
237
             is not contained in the message
238

239
    """
240
    return self.data.get(field_name, None)
241

    
242
  def __setitem__(self, field_name, field_value):
243
    """Set the value of the required field_name to field_value.
244

245
    """
246
    self.data[field_name] = field_value
247

    
248
  @staticmethod
249
  def BuildFromJsonString(json_string):
250
    """Build a QmpMessage from a JSON encoded string.
251

252
    @type json_string: str
253
    @param json_string: JSON string representing the message
254
    @rtype: L{QmpMessage}
255
    @return: a L{QmpMessage} built from json_string
256

257
    """
258
    # Parse the string
259
    data = serializer.LoadJson(json_string)
260
    return QmpMessage(data)
261

    
262
  def __str__(self):
263
    # The protocol expects the JSON object to be sent as a single line.
264
    return serializer.DumpJson(self.data)
265

    
266
  def __eq__(self, other):
267
    # When comparing two QmpMessages, we are interested in comparing
268
    # their internal representation of the message data
269
    return self.data == other.data
270

    
271

    
272
class QmpConnection:
273
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
274

275
  """
276
  _FIRST_MESSAGE_KEY = "QMP"
277
  _EVENT_KEY = "event"
278
  _ERROR_KEY = "error"
279
  _RETURN_KEY = RETURN_KEY = "return"
280
  _ACTUAL_KEY = ACTUAL_KEY = "actual"
281
  _ERROR_CLASS_KEY = "class"
282
  _ERROR_DATA_KEY = "data"
283
  _ERROR_DESC_KEY = "desc"
284
  _EXECUTE_KEY = "execute"
285
  _ARGUMENTS_KEY = "arguments"
286
  _CAPABILITIES_COMMAND = "qmp_capabilities"
287
  _MESSAGE_END_TOKEN = "\r\n"
288
  _SOCKET_TIMEOUT = 5
289

    
290
  def __init__(self, monitor_filename):
291
    """Instantiates the QmpConnection object.
292

293
    @type monitor_filename: string
294
    @param monitor_filename: the filename of the UNIX raw socket on which the
295
                             QMP monitor is listening
296

297
    """
298
    self.monitor_filename = monitor_filename
299
    self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
300
    # We want to fail if the server doesn't send a complete message
301
    # in a reasonable amount of time
302
    self.sock.settimeout(self._SOCKET_TIMEOUT)
303
    self._connected = False
304
    self._buf = ""
305

    
306
  def _check_socket(self):
307
    sock_stat = None
308
    try:
309
      sock_stat = os.stat(self.monitor_filename)
310
    except EnvironmentError, err:
311
      if err.errno == errno.ENOENT:
312
        raise errors.HypervisorError("No qmp socket found")
313
      else:
314
        raise errors.HypervisorError("Error checking qmp socket: %s",
315
                                     utils.ErrnoOrStr(err))
316
    if not stat.S_ISSOCK(sock_stat.st_mode):
317
      raise errors.HypervisorError("Qmp socket is not a socket")
318

    
319
  def _check_connection(self):
320
    """Make sure that the connection is established.
321

322
    """
323
    if not self._connected:
324
      raise errors.ProgrammerError("To use a QmpConnection you need to first"
325
                                   " invoke connect() on it")
326

    
327
  def connect(self):
328
    """Connects to the QMP monitor.
329

330
    Connects to the UNIX socket and makes sure that we can actually send and
331
    receive data to the kvm instance via QMP.
332

333
    @raise errors.HypervisorError: when there are communication errors
334
    @raise errors.ProgrammerError: when there are data serialization errors
335

336
    """
337
    if self._connected:
338
      raise errors.ProgrammerError("Cannot connect twice")
339

    
340
    self._check_socket()
341

    
342
    # Check file existance/stuff
343
    try:
344
      self.sock.connect(self.monitor_filename)
345
    except EnvironmentError:
346
      raise errors.HypervisorError("Can't connect to qmp socket")
347
    self._connected = True
348

    
349
    # Check if we receive a correct greeting message from the server
350
    # (As per the QEMU Protocol Specification 0.1 - section 2.2)
351
    greeting = self._Recv()
352
    if not greeting[self._FIRST_MESSAGE_KEY]:
353
      self._connected = False
354
      raise errors.HypervisorError("kvm: QMP communication error (wrong"
355
                                   " server greeting")
356

    
357
    # Let's put the monitor in command mode using the qmp_capabilities
358
    # command, or else no command will be executable.
359
    # (As per the QEMU Protocol Specification 0.1 - section 4)
360
    self.Execute(self._CAPABILITIES_COMMAND)
361

    
362
  def _ParseMessage(self, buf):
363
    """Extract and parse a QMP message from the given buffer.
364

365
    Seeks for a QMP message in the given buf. If found, it parses it and
366
    returns it together with the rest of the characters in the buf.
367
    If no message is found, returns None and the whole buffer.
368

369
    @raise errors.ProgrammerError: when there are data serialization errors
370

371
    """
372
    message = None
373
    # Check if we got the message end token (CRLF, as per the QEMU Protocol
374
    # Specification 0.1 - Section 2.1.1)
375
    pos = buf.find(self._MESSAGE_END_TOKEN)
376
    if pos >= 0:
377
      try:
378
        message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
379
      except Exception, err:
380
        raise errors.ProgrammerError("QMP data serialization error: %s" % err)
381
      buf = buf[pos + 1:]
382

    
383
    return (message, buf)
384

    
385
  def _Recv(self):
386
    """Receives a message from QMP and decodes the received JSON object.
387

388
    @rtype: QmpMessage
389
    @return: the received message
390
    @raise errors.HypervisorError: when there are communication errors
391
    @raise errors.ProgrammerError: when there are data serialization errors
392

393
    """
394
    self._check_connection()
395

    
396
    # Check if there is already a message in the buffer
397
    (message, self._buf) = self._ParseMessage(self._buf)
398
    if message:
399
      return message
400

    
401
    recv_buffer = StringIO.StringIO(self._buf)
402
    recv_buffer.seek(len(self._buf))
403
    try:
404
      while True:
405
        data = self.sock.recv(4096)
406
        if not data:
407
          break
408
        recv_buffer.write(data)
409

    
410
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
411
        if message:
412
          return message
413

    
414
    except socket.timeout, err:
415
      raise errors.HypervisorError("Timeout while receiving a QMP message: "
416
                                   "%s" % (err))
417
    except socket.error, err:
418
      raise errors.HypervisorError("Unable to receive data from KVM using the"
419
                                   " QMP protocol: %s" % err)
420

    
421
  def _Send(self, message):
422
    """Encodes and sends a message to KVM using QMP.
423

424
    @type message: QmpMessage
425
    @param message: message to send to KVM
426
    @raise errors.HypervisorError: when there are communication errors
427
    @raise errors.ProgrammerError: when there are data serialization errors
428

429
    """
430
    self._check_connection()
431
    try:
432
      message_str = str(message)
433
    except Exception, err:
434
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
435

    
436
    try:
437
      self.sock.sendall(message_str)
438
    except socket.timeout, err:
439
      raise errors.HypervisorError("Timeout while sending a QMP message: "
440
                                   "%s (%s)" % (err.string, err.errno))
441
    except socket.error, err:
442
      raise errors.HypervisorError("Unable to send data from KVM using the"
443
                                   " QMP protocol: %s" % err)
444

    
445
  def Execute(self, command, arguments=None):
446
    """Executes a QMP command and returns the response of the server.
447

448
    @type command: str
449
    @param command: the command to execute
450
    @type arguments: dict
451
    @param arguments: dictionary of arguments to be passed to the command
452
    @rtype: dict
453
    @return: dictionary representing the received JSON object
454
    @raise errors.HypervisorError: when there are communication errors
455
    @raise errors.ProgrammerError: when there are data serialization errors
456

457
    """
458
    self._check_connection()
459
    message = QmpMessage({self._EXECUTE_KEY: command})
460
    if arguments:
461
      message[self._ARGUMENTS_KEY] = arguments
462
    self._Send(message)
463

    
464
    # Events can occur between the sending of the command and the reception
465
    # of the response, so we need to filter out messages with the event key.
466
    while True:
467
      response = self._Recv()
468
      err = response[self._ERROR_KEY]
469
      if err:
470
        raise errors.HypervisorError("kvm: error executing the %s"
471
                                     " command: %s (%s, %s):" %
472
                                     (command,
473
                                      err[self._ERROR_DESC_KEY],
474
                                      err[self._ERROR_CLASS_KEY],
475
                                      err[self._ERROR_DATA_KEY]))
476

    
477
      elif not response[self._EVENT_KEY]:
478
        return response
479

    
480

    
481
class KVMHypervisor(hv_base.BaseHypervisor):
482
  """KVM hypervisor interface
483

484
  """
485
  CAN_MIGRATE = True
486

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

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

    
586
  _VIRTIO = "virtio"
587
  _VIRTIO_NET_PCI = "virtio-net-pci"
588
  _VIRTIO_BLK_PCI = "virtio-blk-pci"
589

    
590
  _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
591
                                    re.M | re.I)
592
  _MIGRATION_PROGRESS_RE = \
593
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
594
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
595
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
596

    
597
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
598
  _MIGRATION_INFO_RETRY_DELAY = 2
599

    
600
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
601

    
602
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
603
  _CPU_INFO_CMD = "info cpus"
604
  _CONT_CMD = "cont"
605

    
606
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
607
  _CHECK_MACHINE_VERSION_RE = \
608
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
609

    
610
  _QMP_RE = re.compile(r"^-qmp\s", re.M)
611
  _SPICE_RE = re.compile(r"^-spice\s", re.M)
612
  _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
613
  _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
614
  _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
615
  _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
616
  _DISPLAY_RE = re.compile(r"^-display\s", re.M)
617
  _MACHINE_RE = re.compile(r"^-machine\s", re.M)
618
  _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
619
  _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M)
620
  # match  -drive.*boot=on|off on different lines, but in between accept only
621
  # dashes not preceeded by a new line (which would mean another option
622
  # different than -drive is starting)
623
  _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
624
  _UUID_RE = re.compile(r"^-uuid\s", re.M)
625

    
626
  ANCILLARY_FILES = [
627
    _KVM_NETWORK_SCRIPT,
628
    ]
629
  ANCILLARY_FILES_OPT = [
630
    _KVM_NETWORK_SCRIPT,
631
    ]
632

    
633
  # Supported kvm options to get output from
634
  _KVMOPT_HELP = "help"
635
  _KVMOPT_MLIST = "mlist"
636
  _KVMOPT_DEVICELIST = "devicelist"
637

    
638
  # Command to execute to get the output from kvm, and whether to
639
  # accept the output even on failure.
640
  _KVMOPTS_CMDS = {
641
    _KVMOPT_HELP: (["--help"], False),
642
    _KVMOPT_MLIST: (["-M", "?"], False),
643
    _KVMOPT_DEVICELIST: (["-device", "?"], True),
644
  }
645

    
646
  def __init__(self):
647
    hv_base.BaseHypervisor.__init__(self)
648
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
649
    # in a tmpfs filesystem or has been otherwise wiped out.
650
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
651
    utils.EnsureDirs(dirs)
652

    
653
  @classmethod
654
  def _InstancePidFile(cls, instance_name):
655
    """Returns the instance pidfile.
656

657
    """
658
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
659

    
660
  @classmethod
661
  def _InstanceUidFile(cls, instance_name):
662
    """Returns the instance uidfile.
663

664
    """
665
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
666

    
667
  @classmethod
668
  def _InstancePidInfo(cls, pid):
669
    """Check pid file for instance information.
670

671
    Check that a pid file is associated with an instance, and retrieve
672
    information from its command line.
673

674
    @type pid: string or int
675
    @param pid: process id of the instance to check
676
    @rtype: tuple
677
    @return: (instance_name, memory, vcpus)
678
    @raise errors.HypervisorError: when an instance cannot be found
679

680
    """
681
    alive = utils.IsProcessAlive(pid)
682
    if not alive:
683
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
684

    
685
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
686
    try:
687
      cmdline = utils.ReadFile(cmdline_file)
688
    except EnvironmentError, err:
689
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
690
                                   (pid, err))
691

    
692
    instance = None
693
    memory = 0
694
    vcpus = 0
695

    
696
    arg_list = cmdline.split("\x00")
697
    while arg_list:
698
      arg = arg_list.pop(0)
699
      if arg == "-name":
700
        instance = arg_list.pop(0)
701
      elif arg == "-m":
702
        memory = int(arg_list.pop(0))
703
      elif arg == "-smp":
704
        vcpus = int(arg_list.pop(0).split(",")[0])
705

    
706
    if instance is None:
707
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
708
                                   " instance" % pid)
709

    
710
    return (instance, memory, vcpus)
711

    
712
  def _InstancePidAlive(self, instance_name):
713
    """Returns the instance pidfile, pid, and liveness.
714

715
    @type instance_name: string
716
    @param instance_name: instance name
717
    @rtype: tuple
718
    @return: (pid file name, pid, liveness)
719

720
    """
721
    pidfile = self._InstancePidFile(instance_name)
722
    pid = utils.ReadPidFile(pidfile)
723

    
724
    alive = False
725
    try:
726
      cmd_instance = self._InstancePidInfo(pid)[0]
727
      alive = (cmd_instance == instance_name)
728
    except errors.HypervisorError:
729
      pass
730

    
731
    return (pidfile, pid, alive)
732

    
733
  def _CheckDown(self, instance_name):
734
    """Raises an error unless the given instance is down.
735

736
    """
737
    alive = self._InstancePidAlive(instance_name)[2]
738
    if alive:
739
      raise errors.HypervisorError("Failed to start instance %s: %s" %
740
                                   (instance_name, "already running"))
741

    
742
  @classmethod
743
  def _InstanceMonitor(cls, instance_name):
744
    """Returns the instance monitor socket name
745

746
    """
747
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
748

    
749
  @classmethod
750
  def _InstanceSerial(cls, instance_name):
751
    """Returns the instance serial socket name
752

753
    """
754
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
755

    
756
  @classmethod
757
  def _InstanceQmpMonitor(cls, instance_name):
758
    """Returns the instance serial QMP socket name
759

760
    """
761
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
762

    
763
  @staticmethod
764
  def _SocatUnixConsoleParams():
765
    """Returns the correct parameters for socat
766

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

769
    """
770
    if constants.SOCAT_USE_ESCAPE:
771
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
772
    else:
773
      return "echo=0,icanon=0"
774

    
775
  @classmethod
776
  def _InstanceKVMRuntime(cls, instance_name):
777
    """Returns the instance KVM runtime filename
778

779
    """
780
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
781

    
782
  @classmethod
783
  def _InstanceChrootDir(cls, instance_name):
784
    """Returns the name of the KVM chroot dir of the instance
785

786
    """
787
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
788

    
789
  @classmethod
790
  def _InstanceNICDir(cls, instance_name):
791
    """Returns the name of the directory holding the tap device files for a
792
    given instance.
793

794
    """
795
    return utils.PathJoin(cls._NICS_DIR, instance_name)
796

    
797
  @classmethod
798
  def _InstanceNICFile(cls, instance_name, seq):
799
    """Returns the name of the file containing the tap device for a given NIC
800

801
    """
802
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
803

    
804
  @classmethod
805
  def _InstanceKeymapFile(cls, instance_name):
806
    """Returns the name of the file containing the keymap for a given instance
807

808
    """
809
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
810

    
811
  @classmethod
812
  def _TryReadUidFile(cls, uid_file):
813
    """Try to read a uid file
814

815
    """
816
    if os.path.exists(uid_file):
817
      try:
818
        uid = int(utils.ReadOneLineFile(uid_file))
819
        return uid
820
      except EnvironmentError:
821
        logging.warning("Can't read uid file", exc_info=True)
822
      except (TypeError, ValueError):
823
        logging.warning("Can't parse uid file contents", exc_info=True)
824
    return None
825

    
826
  @classmethod
827
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
828
    """Removes an instance's rutime sockets/files/dirs.
829

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

    
866
  @staticmethod
867
  def _ConfigureNIC(instance, seq, nic, tap):
868
    """Run the network configuration script for a specified NIC
869

870
    @param instance: instance we're acting on
871
    @type instance: instance object
872
    @param seq: nic sequence number
873
    @type seq: int
874
    @param nic: nic we're acting on
875
    @type nic: nic object
876
    @param tap: the host's tap interface this NIC corresponds to
877
    @type tap: str
878

879
    """
880
    if instance.tags:
881
      tags = " ".join(instance.tags)
882
    else:
883
      tags = ""
884

    
885
    env = {
886
      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
887
      "INSTANCE": instance.name,
888
      "MAC": nic.mac,
889
      "MODE": nic.nicparams[constants.NIC_MODE],
890
      "INTERFACE": tap,
891
      "INTERFACE_INDEX": str(seq),
892
      "TAGS": tags,
893
    }
894

    
895
    if nic.ip:
896
      env["IP"] = nic.ip
897

    
898
    if nic.nicparams[constants.NIC_LINK]:
899
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
900

    
901
    if nic.network:
902
      n = objects.Network.FromDict(nic.netinfo)
903
      env.update(n.HooksDict())
904

    
905
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
906
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
907

    
908
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
909
    if result.failed:
910
      raise errors.HypervisorError("Failed to configure interface %s: %s;"
911
                                   " network configuration script output: %s" %
912
                                   (tap, result.fail_reason, result.output))
913

    
914
  @staticmethod
915
  def _VerifyAffinityPackage():
916
    if affinity is None:
917
      raise errors.HypervisorError("affinity Python package not"
918
                                   " found; cannot use CPU pinning under KVM")
919

    
920
  @staticmethod
921
  def _BuildAffinityCpuMask(cpu_list):
922
    """Create a CPU mask suitable for sched_setaffinity from a list of
923
    CPUs.
924

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

928
    @type cpu_list: list of int
929
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
930
    @rtype: int
931
    @return: a bit mask of CPU affinities
932

933
    """
934
    if cpu_list == constants.CPU_PINNING_OFF:
935
      return constants.CPU_PINNING_ALL_KVM
936
    else:
937
      return sum(2 ** cpu for cpu in cpu_list)
938

    
939
  @classmethod
940
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
941
    """Change CPU affinity for running VM according to given CPU mask.
942

943
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
944
    @type cpu_mask: string
945
    @param process_id: process ID of KVM process. Used to pin entire VM
946
                       to physical CPUs.
947
    @type process_id: int
948
    @param thread_dict: map of virtual CPUs to KVM thread IDs
949
    @type thread_dict: dict int:int
950

951
    """
952
    # Convert the string CPU mask to a list of list of int's
953
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
954

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

    
973
      # For each vCPU, map it to the proper list of physical CPUs
974
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
975
        affinity.set_process_affinity_mask(thread_dict[i],
976
                                           cls._BuildAffinityCpuMask(vcpu))
977

    
978
  def _GetVcpuThreadIds(self, instance_name):
979
    """Get a mapping of vCPU no. to thread IDs for the instance
980

981
    @type instance_name: string
982
    @param instance_name: instance in question
983
    @rtype: dictionary of int:int
984
    @return: a dictionary mapping vCPU numbers to thread IDs
985

986
    """
987
    result = {}
988
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
989
    for line in output.stdout.splitlines():
990
      match = self._CPU_INFO_RE.search(line)
991
      if not match:
992
        continue
993
      grp = map(int, match.groups())
994
      result[grp[0]] = grp[1]
995

    
996
    return result
997

    
998
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
999
    """Complete CPU pinning.
1000

1001
    @type instance_name: string
1002
    @param instance_name: name of instance
1003
    @type cpu_mask: string
1004
    @param cpu_mask: CPU pinning mask as entered by user
1005

1006
    """
1007
    # Get KVM process ID, to be used if need to pin entire VM
1008
    _, pid, _ = self._InstancePidAlive(instance_name)
1009
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1010
    thread_dict = self._GetVcpuThreadIds(instance_name)
1011
    # Run CPU pinning, based on configured mask
1012
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1013

    
1014
  def ListInstances(self, hvparams=None):
1015
    """Get the list of running instances.
1016

1017
    We can do this by listing our live instances directory and
1018
    checking whether the associated kvm process is still alive.
1019

1020
    """
1021
    result = []
1022
    for name in os.listdir(self._PIDS_DIR):
1023
      if self._InstancePidAlive(name)[2]:
1024
        result.append(name)
1025
    return result
1026

    
1027
  def GetInstanceInfo(self, instance_name, hvparams=None):
1028
    """Get instance properties.
1029

1030
    @type instance_name: string
1031
    @param instance_name: the instance name
1032
    @type hvparams: dict of strings
1033
    @param hvparams: hvparams to be used with this instance
1034
    @rtype: tuple of strings
1035
    @return: (name, id, memory, vcpus, stat, times)
1036

1037
    """
1038
    _, pid, alive = self._InstancePidAlive(instance_name)
1039
    if not alive:
1040
      return None
1041

    
1042
    _, memory, vcpus = self._InstancePidInfo(pid)
1043
    istat = "---b-"
1044
    times = "0"
1045

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

    
1057
    return (instance_name, pid, memory, vcpus, istat, times)
1058

    
1059
  def GetAllInstancesInfo(self, hvparams=None):
1060
    """Get properties of all instances.
1061

1062
    @type hvparams: dict of strings
1063
    @param hvparams: hypervisor parameter
1064
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1065

1066
    """
1067
    data = []
1068
    for name in os.listdir(self._PIDS_DIR):
1069
      try:
1070
        info = self.GetInstanceInfo(name)
1071
      except errors.HypervisorError:
1072
        # Ignore exceptions due to instances being shut down
1073
        continue
1074
      if info:
1075
        data.append(info)
1076
    return data
1077

    
1078
  def _GenerateKVMBlockDevicesOptions(self, instance, block_devices, kvmhelp):
1079

    
1080
    hvp = instance.hvparams
1081
    boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1082
    kvm_path = hvp[constants.HV_KVM_PATH]
1083

    
1084
    # whether this is an older KVM version that uses the boot=on flag
1085
    # on devices
1086
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1087

    
1088
    dev_opts = []
1089
    device_driver = None
1090
    disk_type = hvp[constants.HV_DISK_TYPE]
1091
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
1092
      if_val = ",if=%s" % self._VIRTIO
1093
      try:
1094
        devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1095
        if self._VIRTIO_BLK_RE.search(devlist):
1096
          # TODO: uncomment when -device is used
1097
          # if_val = ",if=none"
1098
          # will be passed in -device option as driver
1099
          device_driver = self._VIRTIO_BLK_PCI
1100
      except errors.HypervisorError, _:
1101
        pass
1102
    else:
1103
      if_val = ",if=%s" % disk_type
1104
    # Cache mode
1105
    disk_cache = hvp[constants.HV_DISK_CACHE]
1106
    if instance.disk_template in constants.DTS_EXT_MIRROR:
1107
      if disk_cache != "none":
1108
        # TODO: make this a hard error, instead of a silent overwrite
1109
        logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1110
                        " to prevent shared storage corruption on migration",
1111
                        disk_cache)
1112
      cache_val = ",cache=none"
1113
    elif disk_cache != constants.HT_CACHE_DEFAULT:
1114
      cache_val = ",cache=%s" % disk_cache
1115
    else:
1116
      cache_val = ""
1117
    for cfdev, dev_path in block_devices:
1118
      if cfdev.mode != constants.DISK_RDWR:
1119
        raise errors.HypervisorError("Instance has read-only disks which"
1120
                                     " are not supported by KVM")
1121
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
1122
      boot_val = ""
1123
      if boot_disk:
1124
        dev_opts.extend(["-boot", "c"])
1125
        boot_disk = False
1126
        if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1127
          boot_val = ",boot=on"
1128
      drive_val = "file=%s,format=raw%s%s%s" % \
1129
                  (dev_path, if_val, boot_val, cache_val)
1130

    
1131
      if device_driver:
1132
        pass
1133
      dev_opts.extend(["-drive", drive_val])
1134

    
1135
    return dev_opts
1136

    
1137
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1138
                          kvmhelp):
1139
    """Generate KVM information to start an instance.
1140

1141
    @type kvmhelp: string
1142
    @param kvmhelp: output of kvm --help
1143
    @attention: this function must not have any side-effects; for
1144
        example, it must not write to the filesystem, or read values
1145
        from the current system the are expected to differ between
1146
        nodes, since it is only run once at instance startup;
1147
        actions/kvm arguments that can vary between systems should be
1148
        done in L{_ExecuteKVMRuntime}
1149

1150
    """
1151
    # pylint: disable=R0912,R0914,R0915
1152
    hvp = instance.hvparams
1153
    self.ValidateParameters(hvp)
1154

    
1155
    pidfile = self._InstancePidFile(instance.name)
1156
    kvm = hvp[constants.HV_KVM_PATH]
1157
    kvm_cmd = [kvm]
1158
    # used just by the vnc server, if enabled
1159
    kvm_cmd.extend(["-name", instance.name])
1160
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1161

    
1162
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1163
    if hvp[constants.HV_CPU_CORES]:
1164
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1165
    if hvp[constants.HV_CPU_THREADS]:
1166
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1167
    if hvp[constants.HV_CPU_SOCKETS]:
1168
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1169

    
1170
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1171

    
1172
    kvm_cmd.extend(["-pidfile", pidfile])
1173
    kvm_cmd.extend(["-balloon", "virtio"])
1174
    kvm_cmd.extend(["-daemonize"])
1175
    if not instance.hvparams[constants.HV_ACPI]:
1176
      kvm_cmd.extend(["-no-acpi"])
1177
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1178
        constants.INSTANCE_REBOOT_EXIT:
1179
      kvm_cmd.extend(["-no-reboot"])
1180

    
1181
    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1182
    if not mversion:
1183
      mversion = self._GetDefaultMachineVersion(kvm)
1184
    if self._MACHINE_RE.search(kvmhelp):
1185
      # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1186
      # extra hypervisor parameters. We should also investigate whether and how
1187
      # shadow_mem should be considered for the resource model.
1188
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1189
        specprop = ",accel=kvm"
1190
      else:
1191
        specprop = ""
1192
      machinespec = "%s%s" % (mversion, specprop)
1193
      kvm_cmd.extend(["-machine", machinespec])
1194
    else:
1195
      kvm_cmd.extend(["-M", mversion])
1196
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1197
          self._ENABLE_KVM_RE.search(kvmhelp)):
1198
        kvm_cmd.extend(["-enable-kvm"])
1199
      elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1200
            self._DISABLE_KVM_RE.search(kvmhelp)):
1201
        kvm_cmd.extend(["-disable-kvm"])
1202

    
1203
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1204
    if kernel_path:
1205
      boot_cdrom = boot_floppy = boot_network = False
1206
    else:
1207
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1208
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1209
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1210

    
1211
    if startup_paused:
1212
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1213

    
1214
    if boot_network:
1215
      kvm_cmd.extend(["-boot", "n"])
1216

    
1217
    # whether this is an older KVM version that uses the boot=on flag
1218
    # on devices
1219
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1220

    
1221
    disk_type = hvp[constants.HV_DISK_TYPE]
1222

    
1223
    #Now we can specify a different device type for CDROM devices.
1224
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1225
    if not cdrom_disk_type:
1226
      cdrom_disk_type = disk_type
1227

    
1228
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1229
    if iso_image:
1230
      options = ",format=raw,media=cdrom"
1231
      # set cdrom 'if' type
1232
      if boot_cdrom:
1233
        actual_cdrom_type = constants.HT_DISK_IDE
1234
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1235
        actual_cdrom_type = "virtio"
1236
      else:
1237
        actual_cdrom_type = cdrom_disk_type
1238
      if_val = ",if=%s" % actual_cdrom_type
1239
      # set boot flag, if needed
1240
      boot_val = ""
1241
      if boot_cdrom:
1242
        kvm_cmd.extend(["-boot", "d"])
1243
        if needs_boot_flag:
1244
          boot_val = ",boot=on"
1245
      # and finally build the entire '-drive' value
1246
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1247
      kvm_cmd.extend(["-drive", drive_val])
1248

    
1249
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1250
    if iso_image2:
1251
      options = ",format=raw,media=cdrom"
1252
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1253
        if_val = ",if=virtio"
1254
      else:
1255
        if_val = ",if=%s" % cdrom_disk_type
1256
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1257
      kvm_cmd.extend(["-drive", drive_val])
1258

    
1259
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1260
    if floppy_image:
1261
      options = ",format=raw,media=disk"
1262
      if boot_floppy:
1263
        kvm_cmd.extend(["-boot", "a"])
1264
        options = "%s,boot=on" % options
1265
      if_val = ",if=floppy"
1266
      options = "%s%s" % (options, if_val)
1267
      drive_val = "file=%s%s" % (floppy_image, options)
1268
      kvm_cmd.extend(["-drive", drive_val])
1269

    
1270
    if kernel_path:
1271
      kvm_cmd.extend(["-kernel", kernel_path])
1272
      initrd_path = hvp[constants.HV_INITRD_PATH]
1273
      if initrd_path:
1274
        kvm_cmd.extend(["-initrd", initrd_path])
1275
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1276
                     hvp[constants.HV_KERNEL_ARGS]]
1277
      if hvp[constants.HV_SERIAL_CONSOLE]:
1278
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1279
        root_append.append("console=ttyS0,%s" % serial_speed)
1280
      kvm_cmd.extend(["-append", " ".join(root_append)])
1281

    
1282
    mem_path = hvp[constants.HV_MEM_PATH]
1283
    if mem_path:
1284
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1285

    
1286
    monitor_dev = ("unix:%s,server,nowait" %
1287
                   self._InstanceMonitor(instance.name))
1288
    kvm_cmd.extend(["-monitor", monitor_dev])
1289
    if hvp[constants.HV_SERIAL_CONSOLE]:
1290
      serial_dev = ("unix:%s,server,nowait" %
1291
                    self._InstanceSerial(instance.name))
1292
      kvm_cmd.extend(["-serial", serial_dev])
1293
    else:
1294
      kvm_cmd.extend(["-serial", "none"])
1295

    
1296
    mouse_type = hvp[constants.HV_USB_MOUSE]
1297
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1298
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1299
    spice_ip_version = None
1300

    
1301
    kvm_cmd.extend(["-usb"])
1302

    
1303
    if mouse_type:
1304
      kvm_cmd.extend(["-usbdevice", mouse_type])
1305
    elif vnc_bind_address:
1306
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1307

    
1308
    if vnc_bind_address:
1309
      if netutils.IsValidInterface(vnc_bind_address):
1310
        if_addresses = netutils.GetInterfaceIpAddresses(vnc_bind_address)
1311
        if_ip4_addresses = if_addresses[constants.IP4_VERSION]
1312
        if len(if_ip4_addresses) < 1:
1313
          logging.error("Could not determine IPv4 address of interface %s",
1314
                        vnc_bind_address)
1315
        else:
1316
          vnc_bind_address = if_ip4_addresses[0]
1317
      if netutils.IP4Address.IsValid(vnc_bind_address):
1318
        if instance.network_port > constants.VNC_BASE_PORT:
1319
          display = instance.network_port - constants.VNC_BASE_PORT
1320
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1321
            vnc_arg = ":%d" % (display)
1322
          else:
1323
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1324
        else:
1325
          logging.error("Network port is not a valid VNC display (%d < %d),"
1326
                        " not starting VNC",
1327
                        instance.network_port, constants.VNC_BASE_PORT)
1328
          vnc_arg = "none"
1329

    
1330
        # Only allow tls and other option when not binding to a file, for now.
1331
        # kvm/qemu gets confused otherwise about the filename to use.
1332
        vnc_append = ""
1333
        if hvp[constants.HV_VNC_TLS]:
1334
          vnc_append = "%s,tls" % vnc_append
1335
          if hvp[constants.HV_VNC_X509_VERIFY]:
1336
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1337
                                               hvp[constants.HV_VNC_X509])
1338
          elif hvp[constants.HV_VNC_X509]:
1339
            vnc_append = "%s,x509=%s" % (vnc_append,
1340
                                         hvp[constants.HV_VNC_X509])
1341
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1342
          vnc_append = "%s,password" % vnc_append
1343

    
1344
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1345

    
1346
      else:
1347
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1348

    
1349
      kvm_cmd.extend(["-vnc", vnc_arg])
1350
    elif spice_bind:
1351
      # FIXME: this is wrong here; the iface ip address differs
1352
      # between systems, so it should be done in _ExecuteKVMRuntime
1353
      if netutils.IsValidInterface(spice_bind):
1354
        # The user specified a network interface, we have to figure out the IP
1355
        # address.
1356
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1357
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1358

    
1359
        # if the user specified an IP version and the interface does not
1360
        # have that kind of IP addresses, throw an exception
1361
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1362
          if not addresses[spice_ip_version]:
1363
            raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1364
                                         " for %s" % (spice_ip_version,
1365
                                                      spice_bind))
1366

    
1367
        # the user did not specify an IP version, we have to figure it out
1368
        elif (addresses[constants.IP4_VERSION] and
1369
              addresses[constants.IP6_VERSION]):
1370
          # we have both ipv4 and ipv6, let's use the cluster default IP
1371
          # version
1372
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1373
          spice_ip_version = \
1374
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1375
        elif addresses[constants.IP4_VERSION]:
1376
          spice_ip_version = constants.IP4_VERSION
1377
        elif addresses[constants.IP6_VERSION]:
1378
          spice_ip_version = constants.IP6_VERSION
1379
        else:
1380
          raise errors.HypervisorError("SPICE: Unable to get an IP address"
1381
                                       " for %s" % (spice_bind))
1382

    
1383
        spice_address = addresses[spice_ip_version][0]
1384

    
1385
      else:
1386
        # spice_bind is known to be a valid IP address, because
1387
        # ValidateParameters checked it.
1388
        spice_address = spice_bind
1389

    
1390
      spice_arg = "addr=%s" % spice_address
1391
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1392
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1393
                     (spice_arg, instance.network_port,
1394
                      pathutils.SPICE_CACERT_FILE))
1395
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1396
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1397
                      pathutils.SPICE_CERT_FILE))
1398
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1399
        if tls_ciphers:
1400
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1401
      else:
1402
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1403

    
1404
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1405
        spice_arg = "%s,disable-ticketing" % spice_arg
1406

    
1407
      if spice_ip_version:
1408
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1409

    
1410
      # Image compression options
1411
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1412
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1413
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1414
      if img_lossless:
1415
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1416
      if img_jpeg:
1417
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1418
      if img_zlib_glz:
1419
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1420

    
1421
      # Video stream detection
1422
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1423
      if video_streaming:
1424
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1425

    
1426
      # Audio compression, by default in qemu-kvm it is on
1427
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1428
        spice_arg = "%s,playback-compression=off" % spice_arg
1429
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1430
        spice_arg = "%s,agent-mouse=off" % spice_arg
1431
      else:
1432
        # Enable the spice agent communication channel between the host and the
1433
        # agent.
1434
        kvm_cmd.extend(["-device", "virtio-serial-pci"])
1435
        kvm_cmd.extend([
1436
          "-device",
1437
          "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1438
          ])
1439
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1440

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

    
1444
    else:
1445
      # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1446
      # also works in earlier versions though (tested with 1.1 and 1.3)
1447
      if self._DISPLAY_RE.search(kvmhelp):
1448
        kvm_cmd.extend(["-display", "none"])
1449
      else:
1450
        kvm_cmd.extend(["-nographic"])
1451

    
1452
    if hvp[constants.HV_USE_LOCALTIME]:
1453
      kvm_cmd.extend(["-localtime"])
1454

    
1455
    if hvp[constants.HV_KVM_USE_CHROOT]:
1456
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1457

    
1458
    # Add qemu-KVM -cpu param
1459
    if hvp[constants.HV_CPU_TYPE]:
1460
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1461

    
1462
    # As requested by music lovers
1463
    if hvp[constants.HV_SOUNDHW]:
1464
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1465

    
1466
    # Pass a -vga option if requested, or if spice is used, for backwards
1467
    # compatibility.
1468
    if hvp[constants.HV_VGA]:
1469
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1470
    elif spice_bind:
1471
      kvm_cmd.extend(["-vga", "qxl"])
1472

    
1473
    # Various types of usb devices, comma separated
1474
    if hvp[constants.HV_USB_DEVICES]:
1475
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1476
        kvm_cmd.extend(["-usbdevice", dev])
1477

    
1478
    # Set system UUID to instance UUID
1479
    if self._UUID_RE.search(kvmhelp):
1480
      kvm_cmd.extend(["-uuid", instance.uuid])
1481

    
1482
    if hvp[constants.HV_KVM_EXTRA]:
1483
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1484

    
1485
    kvm_disks = []
1486
    for disk, dev_path in block_devices:
1487
      kvm_disks.append((disk, dev_path))
1488

    
1489
    kvm_nics = []
1490
    for nic in instance.nics:
1491
      kvm_nics.append(nic)
1492

    
1493
    hvparams = hvp
1494

    
1495
    return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1496

    
1497
  def _WriteKVMRuntime(self, instance_name, data):
1498
    """Write an instance's KVM runtime
1499

1500
    """
1501
    try:
1502
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1503
                      data=data)
1504
    except EnvironmentError, err:
1505
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1506

    
1507
  def _ReadKVMRuntime(self, instance_name):
1508
    """Read an instance's KVM runtime
1509

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

    
1517
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1518
    """Save an instance's KVM runtime
1519

1520
    """
1521
    kvm_cmd, kvm_nics, hvparams, block_devices = kvm_runtime
1522

    
1523
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1524
    serialized_blockdevs = [(blk.ToDict(), link) for blk, link in block_devices]
1525
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1526
                                      serialized_blockdevs))
1527

    
1528
    self._WriteKVMRuntime(instance.name, serialized_form)
1529

    
1530
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1531
    """Load an instance's KVM runtime
1532

1533
    """
1534
    if not serialized_runtime:
1535
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1536

    
1537
    loaded_runtime = serializer.Load(serialized_runtime)
1538
    if len(loaded_runtime) == 3:
1539
      serialized_blockdevs = []
1540
      kvm_cmd, serialized_nics, hvparams = loaded_runtime
1541
    else:
1542
      kvm_cmd, serialized_nics, hvparams, serialized_blockdevs = loaded_runtime
1543

    
1544
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1545
    block_devices = [(objects.Disk.FromDict(sdisk), link)
1546
                     for sdisk, link in serialized_blockdevs]
1547

    
1548
    return (kvm_cmd, kvm_nics, hvparams, block_devices)
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(cls._KVMOPTS_CMDS[option]))
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, cluster_name, 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 cluster_name: string
2008
    @param cluster_name: name of the cluster
2009
    @type instance: L{objects.Instance}
2010
    @param instance: the instance to be migrated
2011
    @type target: string
2012
    @param target: ip address of the target node
2013
    @type live: boolean
2014
    @param live: perform a live migration
2015

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

    
2023
    if not live:
2024
      self._CallMonitorCommand(instance_name, "stop")
2025

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

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

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

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

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

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

    
2055
  def GetMigrationStatus(self, instance):
2056
    """Get the migration status
2057

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

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

    
2085
          return migration_status
2086

    
2087
        logging.warning("KVM: unknown migration status '%s'", status)
2088

    
2089
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2090

    
2091
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2092

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

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

2101
    """
2102
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2103

    
2104
  def GetNodeInfo(self, hvparams=None):
2105
    """Return information about the node.
2106

2107
    @type hvparams: dict of strings
2108
    @param hvparams: hypervisor parameters, not used in this class
2109

2110
    @return: a dict as returned by L{BaseHypervisor.GetLinuxNodeInfo} plus
2111
        the following keys:
2112
          - hv_version: the hypervisor version in the form (major, minor,
2113
                        revision)
2114

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

    
2124
  @classmethod
2125
  def GetInstanceConsole(cls, instance, primary_node, hvparams, beparams):
2126
    """Return a command for connecting to the console of an instance.
2127

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

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

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

    
2157
    return objects.InstanceConsole(instance=instance.name,
2158
                                   kind=constants.CONS_MESSAGE,
2159
                                   message=("No serial shell for instance %s" %
2160
                                            instance.name))
2161

    
2162
  def Verify(self, hvparams=None):
2163
    """Verify the hypervisor.
2164

2165
    Check that the required binaries exist.
2166

2167
    @type hvparams: dict of strings
2168
    @param hvparams: hypervisor parameters to be verified against, not used here
2169

2170
    @return: Problem description if something is wrong, C{None} otherwise
2171

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

    
2183
    return self._FormatVerifyResults(msgs)
2184

    
2185
  @classmethod
2186
  def CheckParameterSyntax(cls, hvparams):
2187
    """Check the given parameters for validity.
2188

2189
    @type hvparams:  dict
2190
    @param hvparams: dictionary with parameter names/value
2191
    @raise errors.HypervisorError: when a parameter is not valid
2192

2193
    """
2194
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2195

    
2196
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2197
    if kernel_path:
2198
      if not hvparams[constants.HV_ROOT_PATH]:
2199
        raise errors.HypervisorError("Need a root partition for the instance,"
2200
                                     " if a kernel is defined")
2201

    
2202
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2203
        not hvparams[constants.HV_VNC_X509]):
2204
      raise errors.HypervisorError("%s must be defined, if %s is" %
2205
                                   (constants.HV_VNC_X509,
2206
                                    constants.HV_VNC_X509_VERIFY))
2207

    
2208
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2209
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2210
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2211
      if not serial_speed or serial_speed not in valid_speeds:
2212
        raise errors.HypervisorError("Invalid serial console speed, must be"
2213
                                     " one of: %s" %
2214
                                     utils.CommaJoin(valid_speeds))
2215

    
2216
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2217
    if (boot_order == constants.HT_BO_CDROM and
2218
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2219
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2220
                                   " ISO path")
2221

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

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

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

    
2258
  @classmethod
2259
  def ValidateParameters(cls, hvparams):
2260
    """Check the given parameters for validity.
2261

2262
    @type hvparams:  dict
2263
    @param hvparams: dictionary with parameter names/value
2264
    @raise errors.HypervisorError: when a parameter is not valid
2265

2266
    """
2267
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2268

    
2269
    kvm_path = hvparams[constants.HV_KVM_PATH]
2270

    
2271
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2272
    if security_model == constants.HT_SM_USER:
2273
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2274
      try:
2275
        pwd.getpwnam(username)
2276
      except KeyError:
2277
        raise errors.HypervisorError("Unknown security domain user %s"
2278
                                     % username)
2279
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2280
    if vnc_bind_address:
2281
      bound_to_addr = netutils.IP4Address.IsValid(vnc_bind_address)
2282
      is_interface = netutils.IsValidInterface(vnc_bind_address)
2283
      is_path = utils.IsNormAbsPath(vnc_bind_address)
2284
      if not bound_to_addr and not is_interface and not is_path:
2285
        raise errors.HypervisorError("VNC: The %s parameter must be either"
2286
                                     " a valid IP address, an interface name,"
2287
                                     " or an absolute path" %
2288
                                     constants.HV_KVM_SPICE_BIND)
2289

    
2290
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2291
    if spice_bind:
2292
      # only one of VNC and SPICE can be used currently.
2293
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2294
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2295
                                     " only one of them can be used at a"
2296
                                     " given time")
2297

    
2298
      # check that KVM supports SPICE
2299
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2300
      if not cls._SPICE_RE.search(kvmhelp):
2301
        raise errors.HypervisorError("SPICE is configured, but it is not"
2302
                                     " supported according to 'kvm --help'")
2303

    
2304
      # if spice_bind is not an IP address, it must be a valid interface
2305
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2306
                       netutils.IP6Address.IsValid(spice_bind))
2307
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2308
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2309
                                     " a valid IP address or interface name" %
2310
                                     constants.HV_KVM_SPICE_BIND)
2311

    
2312
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2313
    if machine_version:
2314
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2315
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2316
        raise errors.HypervisorError("Unsupported machine version: %s" %
2317
                                     machine_version)
2318

    
2319
  @classmethod
2320
  def PowercycleNode(cls, hvparams=None):
2321
    """KVM powercycle, just a wrapper over Linux powercycle.
2322

2323
    @type hvparams: dict of strings
2324
    @param hvparams: hypervisor params to be used on this node
2325

2326
    """
2327
    cls.LinuxPowercycle()