Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 5b3aa9a1

History | View | Annotate | Download (83.4 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:
515
      (False, lambda x: (netutils.IP4Address.IsValid(x) or
516
                         utils.IsNormAbsPath(x)),
517
       "The VNC bind address must be either a valid IP address or an absolute"
518
       " pathname", None, None),
519
    constants.HV_VNC_TLS: hv_base.NO_CHECK,
520
    constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
521
    constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
522
    constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
523
    constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
524
    constants.HV_KVM_SPICE_IP_VERSION:
525
      (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
526
                         x in constants.VALID_IP_VERSIONS),
527
       "The SPICE IP version should be 4 or 6",
528
       None, None),
529
    constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
530
    constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
531
      hv_base.ParamInSet(
532
        False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
533
    constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
534
      hv_base.ParamInSet(
535
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
536
    constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
537
      hv_base.ParamInSet(
538
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
539
    constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
540
      hv_base.ParamInSet(
541
        False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
542
    constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
543
    constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
544
    constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
545
    constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
546
    constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
547
    constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
548
    constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
549
    constants.HV_BOOT_ORDER:
550
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
551
    constants.HV_NIC_TYPE:
552
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
553
    constants.HV_DISK_TYPE:
554
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
555
    constants.HV_KVM_CDROM_DISK_TYPE:
556
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
557
    constants.HV_USB_MOUSE:
558
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
559
    constants.HV_KEYMAP: hv_base.NO_CHECK,
560
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
561
    constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
562
    constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
563
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
564
    constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
565
    constants.HV_DISK_CACHE:
566
      hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
567
    constants.HV_SECURITY_MODEL:
568
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
569
    constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
570
    constants.HV_KVM_FLAG:
571
      hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
572
    constants.HV_VHOST_NET: hv_base.NO_CHECK,
573
    constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
574
    constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
575
    constants.HV_REBOOT_BEHAVIOR:
576
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
577
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
578
    constants.HV_CPU_TYPE: hv_base.NO_CHECK,
579
    constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
580
    constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
581
    constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
582
    constants.HV_SOUNDHW: hv_base.NO_CHECK,
583
    constants.HV_USB_DEVICES: hv_base.NO_CHECK,
584
    constants.HV_VGA: hv_base.NO_CHECK,
585
    constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
586
    constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
587
    constants.HV_VNET_HDR: hv_base.NO_CHECK,
588
    }
589

    
590
  _VIRTIO = "virtio"
591
  _VIRTIO_NET_PCI = "virtio-net-pci"
592
  _VIRTIO_BLK_PCI = "virtio-blk-pci"
593

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

    
601
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
602
  _MIGRATION_INFO_RETRY_DELAY = 2
603

    
604
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
605

    
606
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
607
  _CPU_INFO_CMD = "info cpus"
608
  _CONT_CMD = "cont"
609

    
610
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
611
  _CHECK_MACHINE_VERSION_RE = \
612
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
613

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

    
629
  ANCILLARY_FILES = [
630
    _KVM_NETWORK_SCRIPT,
631
    ]
632
  ANCILLARY_FILES_OPT = [
633
    _KVM_NETWORK_SCRIPT,
634
    ]
635

    
636
  # Supported kvm options to get output from
637
  _KVMOPT_HELP = "help"
638
  _KVMOPT_MLIST = "mlist"
639
  _KVMOPT_DEVICELIST = "devicelist"
640

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

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

    
656
  @classmethod
657
  def _InstancePidFile(cls, instance_name):
658
    """Returns the instance pidfile.
659

660
    """
661
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
662

    
663
  @classmethod
664
  def _InstanceUidFile(cls, instance_name):
665
    """Returns the instance uidfile.
666

667
    """
668
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
669

    
670
  @classmethod
671
  def _InstancePidInfo(cls, pid):
672
    """Check pid file for instance information.
673

674
    Check that a pid file is associated with an instance, and retrieve
675
    information from its command line.
676

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

683
    """
684
    alive = utils.IsProcessAlive(pid)
685
    if not alive:
686
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
687

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

    
695
    instance = None
696
    memory = 0
697
    vcpus = 0
698

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

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

    
713
    return (instance, memory, vcpus)
714

    
715
  def _InstancePidAlive(self, instance_name):
716
    """Returns the instance pidfile, pid, and liveness.
717

718
    @type instance_name: string
719
    @param instance_name: instance name
720
    @rtype: tuple
721
    @return: (pid file name, pid, liveness)
722

723
    """
724
    pidfile = self._InstancePidFile(instance_name)
725
    pid = utils.ReadPidFile(pidfile)
726

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

    
734
    return (pidfile, pid, alive)
735

    
736
  def _CheckDown(self, instance_name):
737
    """Raises an error unless the given instance is down.
738

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

    
745
  @classmethod
746
  def _InstanceMonitor(cls, instance_name):
747
    """Returns the instance monitor socket name
748

749
    """
750
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
751

    
752
  @classmethod
753
  def _InstanceSerial(cls, instance_name):
754
    """Returns the instance serial socket name
755

756
    """
757
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
758

    
759
  @classmethod
760
  def _InstanceQmpMonitor(cls, instance_name):
761
    """Returns the instance serial QMP socket name
762

763
    """
764
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
765

    
766
  @staticmethod
767
  def _SocatUnixConsoleParams():
768
    """Returns the correct parameters for socat
769

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

772
    """
773
    if constants.SOCAT_USE_ESCAPE:
774
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
775
    else:
776
      return "echo=0,icanon=0"
777

    
778
  @classmethod
779
  def _InstanceKVMRuntime(cls, instance_name):
780
    """Returns the instance KVM runtime filename
781

782
    """
783
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
784

    
785
  @classmethod
786
  def _InstanceChrootDir(cls, instance_name):
787
    """Returns the name of the KVM chroot dir of the instance
788

789
    """
790
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
791

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

797
    """
798
    return utils.PathJoin(cls._NICS_DIR, instance_name)
799

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

804
    """
805
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
806

    
807
  @classmethod
808
  def _InstanceKeymapFile(cls, instance_name):
809
    """Returns the name of the file containing the keymap for a given instance
810

811
    """
812
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
813

    
814
  @classmethod
815
  def _TryReadUidFile(cls, uid_file):
816
    """Try to read a uid file
817

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

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

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

    
869
  @staticmethod
870
  def _ConfigureNIC(instance, seq, nic, tap):
871
    """Run the network configuration script for a specified NIC
872

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

882
    """
883
    if instance.tags:
884
      tags = " ".join(instance.tags)
885
    else:
886
      tags = ""
887

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

    
898
    if nic.ip:
899
      env["IP"] = nic.ip
900

    
901
    if nic.nicparams[constants.NIC_LINK]:
902
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
903

    
904
    if nic.network:
905
      n = objects.Network.FromDict(nic.netinfo)
906
      env.update(n.HooksDict())
907

    
908
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
909
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
910

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

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

    
923
  @staticmethod
924
  def _BuildAffinityCpuMask(cpu_list):
925
    """Create a CPU mask suitable for sched_setaffinity from a list of
926
    CPUs.
927

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

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

936
    """
937
    if cpu_list == constants.CPU_PINNING_OFF:
938
      return constants.CPU_PINNING_ALL_KVM
939
    else:
940
      return sum(2 ** cpu for cpu in cpu_list)
941

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

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

954
    """
955
    # Convert the string CPU mask to a list of list of int's
956
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
957

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

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

    
981
  def _GetVcpuThreadIds(self, instance_name):
982
    """Get a mapping of vCPU no. to thread IDs for the instance
983

984
    @type instance_name: string
985
    @param instance_name: instance in question
986
    @rtype: dictionary of int:int
987
    @return: a dictionary mapping vCPU numbers to thread IDs
988

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

    
999
    return result
1000

    
1001
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1002
    """Complete CPU pinning.
1003

1004
    @type instance_name: string
1005
    @param instance_name: name of instance
1006
    @type cpu_mask: string
1007
    @param cpu_mask: CPU pinning mask as entered by user
1008

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

    
1017
  def ListInstances(self):
1018
    """Get the list of running instances.
1019

1020
    We can do this by listing our live instances directory and
1021
    checking whether the associated kvm process is still alive.
1022

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

    
1030
  def GetInstanceInfo(self, instance_name):
1031
    """Get instance properties.
1032

1033
    @type instance_name: string
1034
    @param instance_name: the instance name
1035
    @rtype: tuple of strings
1036
    @return: (name, id, memory, vcpus, stat, times)
1037

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

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

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

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

    
1060
  def GetAllInstancesInfo(self):
1061
    """Get properties of all instances.
1062

1063
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1064

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

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

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

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

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

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

    
1134
    return dev_opts
1135

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

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

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

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

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

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

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

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

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

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

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

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

    
1220
    disk_type = hvp[constants.HV_DISK_TYPE]
1221

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

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

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

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

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

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

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

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

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

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

    
1307
    if vnc_bind_address:
1308
      if netutils.IP4Address.IsValid(vnc_bind_address):
1309
        if instance.network_port > constants.VNC_BASE_PORT:
1310
          display = instance.network_port - constants.VNC_BASE_PORT
1311
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1312
            vnc_arg = ":%d" % (display)
1313
          else:
1314
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1315
        else:
1316
          logging.error("Network port is not a valid VNC display (%d < %d),"
1317
                        " not starting VNC",
1318
                        instance.network_port, constants.VNC_BASE_PORT)
1319
          vnc_arg = "none"
1320

    
1321
        # Only allow tls and other option when not binding to a file, for now.
1322
        # kvm/qemu gets confused otherwise about the filename to use.
1323
        vnc_append = ""
1324
        if hvp[constants.HV_VNC_TLS]:
1325
          vnc_append = "%s,tls" % vnc_append
1326
          if hvp[constants.HV_VNC_X509_VERIFY]:
1327
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1328
                                               hvp[constants.HV_VNC_X509])
1329
          elif hvp[constants.HV_VNC_X509]:
1330
            vnc_append = "%s,x509=%s" % (vnc_append,
1331
                                         hvp[constants.HV_VNC_X509])
1332
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1333
          vnc_append = "%s,password" % vnc_append
1334

    
1335
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1336

    
1337
      else:
1338
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1339

    
1340
      kvm_cmd.extend(["-vnc", vnc_arg])
1341
    elif spice_bind:
1342
      # FIXME: this is wrong here; the iface ip address differs
1343
      # between systems, so it should be done in _ExecuteKVMRuntime
1344
      if netutils.IsValidInterface(spice_bind):
1345
        # The user specified a network interface, we have to figure out the IP
1346
        # address.
1347
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1348
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1349

    
1350
        # if the user specified an IP version and the interface does not
1351
        # have that kind of IP addresses, throw an exception
1352
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1353
          if not addresses[spice_ip_version]:
1354
            raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1355
                                         " for %s" % (spice_ip_version,
1356
                                                      spice_bind))
1357

    
1358
        # the user did not specify an IP version, we have to figure it out
1359
        elif (addresses[constants.IP4_VERSION] and
1360
              addresses[constants.IP6_VERSION]):
1361
          # we have both ipv4 and ipv6, let's use the cluster default IP
1362
          # version
1363
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1364
          spice_ip_version = \
1365
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1366
        elif addresses[constants.IP4_VERSION]:
1367
          spice_ip_version = constants.IP4_VERSION
1368
        elif addresses[constants.IP6_VERSION]:
1369
          spice_ip_version = constants.IP6_VERSION
1370
        else:
1371
          raise errors.HypervisorError("SPICE: Unable to get an IP address"
1372
                                       " for %s" % (spice_bind))
1373

    
1374
        spice_address = addresses[spice_ip_version][0]
1375

    
1376
      else:
1377
        # spice_bind is known to be a valid IP address, because
1378
        # ValidateParameters checked it.
1379
        spice_address = spice_bind
1380

    
1381
      spice_arg = "addr=%s" % spice_address
1382
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1383
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1384
                     (spice_arg, instance.network_port,
1385
                      pathutils.SPICE_CACERT_FILE))
1386
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1387
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1388
                      pathutils.SPICE_CERT_FILE))
1389
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1390
        if tls_ciphers:
1391
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1392
      else:
1393
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1394

    
1395
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1396
        spice_arg = "%s,disable-ticketing" % spice_arg
1397

    
1398
      if spice_ip_version:
1399
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1400

    
1401
      # Image compression options
1402
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1403
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1404
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1405
      if img_lossless:
1406
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1407
      if img_jpeg:
1408
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1409
      if img_zlib_glz:
1410
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1411

    
1412
      # Video stream detection
1413
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1414
      if video_streaming:
1415
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1416

    
1417
      # Audio compression, by default in qemu-kvm it is on
1418
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1419
        spice_arg = "%s,playback-compression=off" % spice_arg
1420
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1421
        spice_arg = "%s,agent-mouse=off" % spice_arg
1422
      else:
1423
        # Enable the spice agent communication channel between the host and the
1424
        # agent.
1425
        kvm_cmd.extend(["-device", "virtio-serial-pci"])
1426
        kvm_cmd.extend([
1427
          "-device",
1428
          "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1429
          ])
1430
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1431

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

    
1435
    else:
1436
      # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1437
      # also works in earlier versions though (tested with 1.1 and 1.3)
1438
      if self._DISPLAY_RE.search(kvmhelp):
1439
        kvm_cmd.extend(["-display", "none"])
1440
      else:
1441
        kvm_cmd.extend(["-nographic"])
1442

    
1443
    if hvp[constants.HV_USE_LOCALTIME]:
1444
      kvm_cmd.extend(["-localtime"])
1445

    
1446
    if hvp[constants.HV_KVM_USE_CHROOT]:
1447
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1448

    
1449
    # Add qemu-KVM -cpu param
1450
    if hvp[constants.HV_CPU_TYPE]:
1451
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1452

    
1453
    # As requested by music lovers
1454
    if hvp[constants.HV_SOUNDHW]:
1455
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1456

    
1457
    # Pass a -vga option if requested, or if spice is used, for backwards
1458
    # compatibility.
1459
    if hvp[constants.HV_VGA]:
1460
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1461
    elif spice_bind:
1462
      kvm_cmd.extend(["-vga", "qxl"])
1463

    
1464
    # Various types of usb devices, comma separated
1465
    if hvp[constants.HV_USB_DEVICES]:
1466
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1467
        kvm_cmd.extend(["-usbdevice", dev])
1468

    
1469
    if hvp[constants.HV_KVM_EXTRA]:
1470
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1471

    
1472
    kvm_disks = []
1473
    for disk, dev_path in block_devices:
1474
      kvm_disks.append((disk, dev_path))
1475

    
1476
    kvm_nics = []
1477
    for nic in instance.nics:
1478
      kvm_nics.append(nic)
1479

    
1480
    hvparams = hvp
1481

    
1482
    return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1483

    
1484
  def _WriteKVMRuntime(self, instance_name, data):
1485
    """Write an instance's KVM runtime
1486

1487
    """
1488
    try:
1489
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1490
                      data=data)
1491
    except EnvironmentError, err:
1492
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1493

    
1494
  def _ReadKVMRuntime(self, instance_name):
1495
    """Read an instance's KVM runtime
1496

1497
    """
1498
    try:
1499
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1500
    except EnvironmentError, err:
1501
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1502
    return file_content
1503

    
1504
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1505
    """Save an instance's KVM runtime
1506

1507
    """
1508
    kvm_cmd, kvm_nics, hvparams, block_devices = kvm_runtime
1509

    
1510
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1511
    serialized_blockdevs = [(blk.ToDict(), link) for blk, link in block_devices]
1512
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1513
                                      serialized_blockdevs))
1514

    
1515
    self._WriteKVMRuntime(instance.name, serialized_form)
1516

    
1517
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1518
    """Load an instance's KVM runtime
1519

1520
    """
1521
    if not serialized_runtime:
1522
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1523

    
1524
    loaded_runtime = serializer.Load(serialized_runtime)
1525
    if len(loaded_runtime) == 3:
1526
      serialized_blockdevs = []
1527
      kvm_cmd, serialized_nics, hvparams = loaded_runtime
1528
    else:
1529
      kvm_cmd, serialized_nics, hvparams, serialized_blockdevs = loaded_runtime
1530

    
1531
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1532
    block_devices = [(objects.Disk.FromDict(sdisk), link)
1533
                     for sdisk, link in serialized_blockdevs]
1534

    
1535
    return (kvm_cmd, kvm_nics, hvparams, block_devices)
1536

    
1537
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1538
    """Run the KVM cmd and check for errors
1539

1540
    @type name: string
1541
    @param name: instance name
1542
    @type kvm_cmd: list of strings
1543
    @param kvm_cmd: runcmd input for kvm
1544
    @type tap_fds: list of int
1545
    @param tap_fds: fds of tap devices opened by Ganeti
1546

1547
    """
1548
    try:
1549
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1550
    finally:
1551
      for fd in tap_fds:
1552
        utils_wrapper.CloseFdNoError(fd)
1553

    
1554
    if result.failed:
1555
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1556
                                   (name, result.fail_reason, result.output))
1557
    if not self._InstancePidAlive(name)[2]:
1558
      raise errors.HypervisorError("Failed to start instance %s" % name)
1559

    
1560
  # 52/50 local variables
1561
  # pylint: disable=R0914
1562
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1563
    """Execute a KVM cmd, after completing it with some last minute data.
1564

1565
    @type incoming: tuple of strings
1566
    @param incoming: (target_host_ip, port)
1567
    @type kvmhelp: string
1568
    @param kvmhelp: output of kvm --help
1569

1570
    """
1571
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1572
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1573
    #    have changed since the instance started; only use them if the change
1574
    #    won't affect the inside of the instance (which hasn't been rebooted).
1575
    #  - up_hvp contains the parameters as they were when the instance was
1576
    #    started, plus any new parameter which has been added between ganeti
1577
    #    versions: it is paramount that those default to a value which won't
1578
    #    affect the inside of the instance as well.
1579
    conf_hvp = instance.hvparams
1580
    name = instance.name
1581
    self._CheckDown(name)
1582

    
1583
    temp_files = []
1584

    
1585
    kvm_cmd, kvm_nics, up_hvp, block_devices = kvm_runtime
1586
    # the first element of kvm_cmd is always the path to the kvm binary
1587
    kvm_path = kvm_cmd[0]
1588
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1589

    
1590
    # We know it's safe to run as a different user upon migration, so we'll use
1591
    # the latest conf, from conf_hvp.
1592
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1593
    if security_model == constants.HT_SM_USER:
1594
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1595

    
1596
    keymap = conf_hvp[constants.HV_KEYMAP]
1597
    if keymap:
1598
      keymap_path = self._InstanceKeymapFile(name)
1599
      # If a keymap file is specified, KVM won't use its internal defaults. By
1600
      # first including the "en-us" layout, an error on loading the actual
1601
      # layout (e.g. because it can't be found) won't lead to a non-functional
1602
      # keyboard. A keyboard with incorrect keys is still better than none.
1603
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1604
      kvm_cmd.extend(["-k", keymap_path])
1605

    
1606
    # We have reasons to believe changing something like the nic driver/type
1607
    # upon migration won't exactly fly with the instance kernel, so for nic
1608
    # related parameters we'll use up_hvp
1609
    tapfds = []
1610
    taps = []
1611
    if not kvm_nics:
1612
      kvm_cmd.extend(["-net", "none"])
1613
    else:
1614
      vnet_hdr = False
1615
      tap_extra = ""
1616
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1617
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1618
        nic_model = self._VIRTIO
1619
        try:
1620
          devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1621
          if self._VIRTIO_NET_RE.search(devlist):
1622
            nic_model = self._VIRTIO_NET_PCI
1623
            vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1624
        except errors.HypervisorError, _:
1625
          # Older versions of kvm don't support DEVICE_LIST, but they don't
1626
          # have new virtio syntax either.
1627
          pass
1628

    
1629
        if up_hvp[constants.HV_VHOST_NET]:
1630
          # check for vhost_net support
1631
          if self._VHOST_RE.search(kvmhelp):
1632
            tap_extra = ",vhost=on"
1633
          else:
1634
            raise errors.HypervisorError("vhost_net is configured"
1635
                                         " but it is not available")
1636
      else:
1637
        nic_model = nic_type
1638

    
1639
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1640

    
1641
      for nic_seq, nic in enumerate(kvm_nics):
1642
        tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1643
        tapfds.append(tapfd)
1644
        taps.append(tapname)
1645
        if kvm_supports_netdev:
1646
          nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1647
          tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1648
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1649
        else:
1650
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1651
                                                         nic.mac, nic_model)
1652
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1653
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1654

    
1655
    if incoming:
1656
      target, port = incoming
1657
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1658

    
1659
    # Changing the vnc password doesn't bother the guest that much. At most it
1660
    # will surprise people who connect to it. Whether positively or negatively
1661
    # it's debatable.
1662
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1663
    vnc_pwd = None
1664
    if vnc_pwd_file:
1665
      try:
1666
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1667
      except EnvironmentError, err:
1668
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1669
                                     % (vnc_pwd_file, err))
1670

    
1671
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1672
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1673
                         constants.SECURE_DIR_MODE)])
1674

    
1675
    # Automatically enable QMP if version is >= 0.14
1676
    if self._QMP_RE.search(kvmhelp):
1677
      logging.debug("Enabling QMP")
1678
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1679
                      self._InstanceQmpMonitor(instance.name)])
1680

    
1681
    # Configure the network now for starting instances and bridged interfaces,
1682
    # during FinalizeMigration for incoming instances' routed interfaces
1683
    for nic_seq, nic in enumerate(kvm_nics):
1684
      if (incoming and
1685
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1686
        continue
1687
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1688

    
1689
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1690
                                                     block_devices,
1691
                                                     kvmhelp)
1692
    kvm_cmd.extend(bdev_opts)
1693
    # CPU affinity requires kvm to start paused, so we set this flag if the
1694
    # instance is not already paused and if we are not going to accept a
1695
    # migrating instance. In the latter case, pausing is not needed.
1696
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1697
    if start_kvm_paused:
1698
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1699

    
1700
    # Note: CPU pinning is using up_hvp since changes take effect
1701
    # during instance startup anyway, and to avoid problems when soft
1702
    # rebooting the instance.
1703
    cpu_pinning = False
1704
    if up_hvp.get(constants.HV_CPU_MASK, None):
1705
      cpu_pinning = True
1706

    
1707
    if security_model == constants.HT_SM_POOL:
1708
      ss = ssconf.SimpleStore()
1709
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1710
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1711
      uid = uidpool.RequestUnusedUid(all_uids)
1712
      try:
1713
        username = pwd.getpwuid(uid.GetUid()).pw_name
1714
        kvm_cmd.extend(["-runas", username])
1715
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1716
      except:
1717
        uidpool.ReleaseUid(uid)
1718
        raise
1719
      else:
1720
        uid.Unlock()
1721
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1722
    else:
1723
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1724

    
1725
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1726
                     constants.RUN_DIRS_MODE)])
1727
    for nic_seq, tap in enumerate(taps):
1728
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1729
                      data=tap)
1730

    
1731
    if vnc_pwd:
1732
      change_cmd = "change vnc password %s" % vnc_pwd
1733
      self._CallMonitorCommand(instance.name, change_cmd)
1734

    
1735
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1736
    # connection attempts because SPICE by default does not allow connections
1737
    # if neither a password nor the "disable_ticketing" options are specified.
1738
    # As soon as we send the password via QMP, that password is a valid ticket
1739
    # for connection.
1740
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1741
    if spice_password_file:
1742
      spice_pwd = ""
1743
      try:
1744
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1745
      except EnvironmentError, err:
1746
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1747
                                     % (spice_password_file, err))
1748

    
1749
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1750
      qmp.connect()
1751
      arguments = {
1752
          "protocol": "spice",
1753
          "password": spice_pwd,
1754
      }
1755
      qmp.Execute("set_password", arguments)
1756

    
1757
    for filename in temp_files:
1758
      utils.RemoveFile(filename)
1759

    
1760
    # If requested, set CPU affinity and resume instance execution
1761
    if cpu_pinning:
1762
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1763

    
1764
    start_memory = self._InstanceStartupMemory(instance)
1765
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1766
      self.BalloonInstanceMemory(instance, start_memory)
1767

    
1768
    if start_kvm_paused:
1769
      # To control CPU pinning, ballooning, and vnc/spice passwords
1770
      # the VM was started in a frozen state. If freezing was not
1771
      # explicitly requested resume the vm status.
1772
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1773

    
1774
  def StartInstance(self, instance, block_devices, startup_paused):
1775
    """Start an instance.
1776

1777
    """
1778
    self._CheckDown(instance.name)
1779
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1780
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1781
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1782
                                           startup_paused, kvmhelp)
1783
    self._SaveKVMRuntime(instance, kvm_runtime)
1784
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1785

    
1786
  def _CallMonitorCommand(self, instance_name, command):
1787
    """Invoke a command on the instance monitor.
1788

1789
    """
1790
    # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1791
    # version. The monitor protocol is designed for human consumption, whereas
1792
    # QMP is made for programmatic usage. In the worst case QMP can also
1793
    # execute monitor commands. As it is, all calls to socat take at least
1794
    # 500ms and likely more: socat can't detect the end of the reply and waits
1795
    # for 500ms of no data received before exiting (500 ms is the default for
1796
    # the "-t" parameter).
1797
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1798
             (utils.ShellQuote(command),
1799
              constants.SOCAT_PATH,
1800
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1801
    result = utils.RunCmd(socat)
1802
    if result.failed:
1803
      msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1804
             " output: %s" %
1805
             (command, instance_name, result.fail_reason, result.output))
1806
      raise errors.HypervisorError(msg)
1807

    
1808
    return result
1809

    
1810
  @classmethod
1811
  def _ParseKVMVersion(cls, text):
1812
    """Parse the KVM version from the --help output.
1813

1814
    @type text: string
1815
    @param text: output of kvm --help
1816
    @return: (version, v_maj, v_min, v_rev)
1817
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1818

1819
    """
1820
    match = cls._VERSION_RE.search(text.splitlines()[0])
1821
    if not match:
1822
      raise errors.HypervisorError("Unable to get KVM version")
1823

    
1824
    v_all = match.group(0)
1825
    v_maj = int(match.group(1))
1826
    v_min = int(match.group(2))
1827
    if match.group(4):
1828
      v_rev = int(match.group(4))
1829
    else:
1830
      v_rev = 0
1831
    return (v_all, v_maj, v_min, v_rev)
1832

    
1833
  @classmethod
1834
  def _GetKVMOutput(cls, kvm_path, option):
1835
    """Return the output of a kvm invocation
1836

1837
    @type kvm_path: string
1838
    @param kvm_path: path to the kvm executable
1839
    @type option: a key of _KVMOPTS_CMDS
1840
    @param option: kvm option to fetch the output from
1841
    @return: output a supported kvm invocation
1842
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1843

1844
    """
1845
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
1846

    
1847
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
1848

    
1849
    result = utils.RunCmd([kvm_path] + optlist)
1850
    if result.failed and not can_fail:
1851
      raise errors.HypervisorError("Unable to get KVM %s output" %
1852
                                    " ".join(cls._KVMOPTS_CMDS[option]))
1853
    return result.output
1854

    
1855
  @classmethod
1856
  def _GetKVMVersion(cls, kvm_path):
1857
    """Return the installed KVM version.
1858

1859
    @return: (version, v_maj, v_min, v_rev)
1860
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1861

1862
    """
1863
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
1864

    
1865
  @classmethod
1866
  def _GetDefaultMachineVersion(cls, kvm_path):
1867
    """Return the default hardware revision (e.g. pc-1.1)
1868

1869
    """
1870
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
1871
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
1872
    if match:
1873
      return match.group(1)
1874
    else:
1875
      return "pc"
1876

    
1877
  def StopInstance(self, instance, force=False, retry=False, name=None):
1878
    """Stop an instance.
1879

1880
    """
1881
    if name is not None and not force:
1882
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1883
    if name is None:
1884
      name = instance.name
1885
      acpi = instance.hvparams[constants.HV_ACPI]
1886
    else:
1887
      acpi = False
1888
    _, pid, alive = self._InstancePidAlive(name)
1889
    if pid > 0 and alive:
1890
      if force or not acpi:
1891
        utils.KillProcess(pid)
1892
      else:
1893
        self._CallMonitorCommand(name, "system_powerdown")
1894

    
1895
  def CleanupInstance(self, instance_name):
1896
    """Cleanup after a stopped instance
1897

1898
    """
1899
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
1900
    if pid > 0 and alive:
1901
      raise errors.HypervisorError("Cannot cleanup a live instance")
1902
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1903

    
1904
  def RebootInstance(self, instance):
1905
    """Reboot an instance.
1906

1907
    """
1908
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1909
    # socket the instance will stop, but now power up again. So we'll resort
1910
    # to shutdown and restart.
1911
    _, _, alive = self._InstancePidAlive(instance.name)
1912
    if not alive:
1913
      raise errors.HypervisorError("Failed to reboot instance %s:"
1914
                                   " not running" % instance.name)
1915
    # StopInstance will delete the saved KVM runtime so:
1916
    # ...first load it...
1917
    kvm_runtime = self._LoadKVMRuntime(instance)
1918
    # ...now we can safely call StopInstance...
1919
    if not self.StopInstance(instance):
1920
      self.StopInstance(instance, force=True)
1921
    # ...and finally we can save it again, and execute it...
1922
    self._SaveKVMRuntime(instance, kvm_runtime)
1923
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1924
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1925
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1926

    
1927
  def MigrationInfo(self, instance):
1928
    """Get instance information to perform a migration.
1929

1930
    @type instance: L{objects.Instance}
1931
    @param instance: instance to be migrated
1932
    @rtype: string
1933
    @return: content of the KVM runtime file
1934

1935
    """
1936
    return self._ReadKVMRuntime(instance.name)
1937

    
1938
  def AcceptInstance(self, instance, info, target):
1939
    """Prepare to accept an instance.
1940

1941
    @type instance: L{objects.Instance}
1942
    @param instance: instance to be accepted
1943
    @type info: string
1944
    @param info: content of the KVM runtime file on the source node
1945
    @type target: string
1946
    @param target: target host (usually ip), on this node
1947

1948
    """
1949
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1950
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1951
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1952
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1953
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
1954
                            incoming=incoming_address)
1955

    
1956
  def FinalizeMigrationDst(self, instance, info, success):
1957
    """Finalize the instance migration on the target node.
1958

1959
    Stop the incoming mode KVM.
1960

1961
    @type instance: L{objects.Instance}
1962
    @param instance: instance whose migration is being finalized
1963

1964
    """
1965
    if success:
1966
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1967
      kvm_nics = kvm_runtime[1]
1968

    
1969
      for nic_seq, nic in enumerate(kvm_nics):
1970
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1971
          # Bridged interfaces have already been configured
1972
          continue
1973
        try:
1974
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1975
        except EnvironmentError, err:
1976
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
1977
                          instance.name, nic_seq, str(err))
1978
          continue
1979
        try:
1980
          self._ConfigureNIC(instance, nic_seq, nic, tap)
1981
        except errors.HypervisorError, err:
1982
          logging.warning(str(err))
1983

    
1984
      self._WriteKVMRuntime(instance.name, info)
1985
    else:
1986
      self.StopInstance(instance, force=True)
1987

    
1988
  def MigrateInstance(self, instance, target, live):
1989
    """Migrate an instance to a target node.
1990

1991
    The migration will not be attempted if the instance is not
1992
    currently running.
1993

1994
    @type instance: L{objects.Instance}
1995
    @param instance: the instance to be migrated
1996
    @type target: string
1997
    @param target: ip address of the target node
1998
    @type live: boolean
1999
    @param live: perform a live migration
2000

2001
    """
2002
    instance_name = instance.name
2003
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
2004
    _, _, alive = self._InstancePidAlive(instance_name)
2005
    if not alive:
2006
      raise errors.HypervisorError("Instance not running, cannot migrate")
2007

    
2008
    if not live:
2009
      self._CallMonitorCommand(instance_name, "stop")
2010

    
2011
    migrate_command = ("migrate_set_speed %dm" %
2012
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2013
    self._CallMonitorCommand(instance_name, migrate_command)
2014

    
2015
    migrate_command = ("migrate_set_downtime %dms" %
2016
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2017
    self._CallMonitorCommand(instance_name, migrate_command)
2018

    
2019
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2020
    self._CallMonitorCommand(instance_name, migrate_command)
2021

    
2022
  def FinalizeMigrationSource(self, instance, success, live):
2023
    """Finalize the instance migration on the source node.
2024

2025
    @type instance: L{objects.Instance}
2026
    @param instance: the instance that was migrated
2027
    @type success: bool
2028
    @param success: whether the migration succeeded or not
2029
    @type live: bool
2030
    @param live: whether the user requested a live migration or not
2031

2032
    """
2033
    if success:
2034
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2035
      utils.KillProcess(pid)
2036
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2037
    elif live:
2038
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2039

    
2040
  def GetMigrationStatus(self, instance):
2041
    """Get the migration status
2042

2043
    @type instance: L{objects.Instance}
2044
    @param instance: the instance that is being migrated
2045
    @rtype: L{objects.MigrationStatus}
2046
    @return: the status of the current migration (one of
2047
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2048
             progress info that can be retrieved from the hypervisor
2049

2050
    """
2051
    info_command = "info migrate"
2052
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2053
      result = self._CallMonitorCommand(instance.name, info_command)
2054
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
2055
      if not match:
2056
        if not result.stdout:
2057
          logging.info("KVM: empty 'info migrate' result")
2058
        else:
2059
          logging.warning("KVM: unknown 'info migrate' result: %s",
2060
                          result.stdout)
2061
      else:
2062
        status = match.group(1)
2063
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2064
          migration_status = objects.MigrationStatus(status=status)
2065
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2066
          if match:
2067
            migration_status.transferred_ram = match.group("transferred")
2068
            migration_status.total_ram = match.group("total")
2069

    
2070
          return migration_status
2071

    
2072
        logging.warning("KVM: unknown migration status '%s'", status)
2073

    
2074
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2075

    
2076
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2077

    
2078
  def BalloonInstanceMemory(self, instance, mem):
2079
    """Balloon an instance memory to a certain value.
2080

2081
    @type instance: L{objects.Instance}
2082
    @param instance: instance to be accepted
2083
    @type mem: int
2084
    @param mem: actual memory size to use for instance runtime
2085

2086
    """
2087
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2088

    
2089
  def GetNodeInfo(self):
2090
    """Return information about the node.
2091

2092
    @return: a dict with the following keys (values in MiB):
2093
          - memory_total: the total memory size on the node
2094
          - memory_free: the available memory on the node for instances
2095
          - memory_dom0: the memory used by the node itself, if available
2096
          - hv_version: the hypervisor version in the form (major, minor,
2097
                        revision)
2098

2099
    """
2100
    result = self.GetLinuxNodeInfo()
2101
    # FIXME: this is the global kvm version, but the actual version can be
2102
    # customized as an hv parameter. we should use the nodegroup's default kvm
2103
    # path parameter here.
2104
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2105
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2106
    return result
2107

    
2108
  @classmethod
2109
  def GetInstanceConsole(cls, instance, hvparams, beparams):
2110
    """Return a command for connecting to the console of an instance.
2111

2112
    """
2113
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2114
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2115
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2116
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2117
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2118
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2119
      return objects.InstanceConsole(instance=instance.name,
2120
                                     kind=constants.CONS_SSH,
2121
                                     host=instance.primary_node,
2122
                                     user=constants.SSH_CONSOLE_USER,
2123
                                     command=cmd)
2124

    
2125
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2126
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2127
      display = instance.network_port - constants.VNC_BASE_PORT
2128
      return objects.InstanceConsole(instance=instance.name,
2129
                                     kind=constants.CONS_VNC,
2130
                                     host=vnc_bind_address,
2131
                                     port=instance.network_port,
2132
                                     display=display)
2133

    
2134
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2135
    if spice_bind:
2136
      return objects.InstanceConsole(instance=instance.name,
2137
                                     kind=constants.CONS_SPICE,
2138
                                     host=spice_bind,
2139
                                     port=instance.network_port)
2140

    
2141
    return objects.InstanceConsole(instance=instance.name,
2142
                                   kind=constants.CONS_MESSAGE,
2143
                                   message=("No serial shell for instance %s" %
2144
                                            instance.name))
2145

    
2146
  def Verify(self):
2147
    """Verify the hypervisor.
2148

2149
    Check that the required binaries exist.
2150

2151
    @return: Problem description if something is wrong, C{None} otherwise
2152

2153
    """
2154
    msgs = []
2155
    # FIXME: this is the global kvm binary, but the actual path can be
2156
    # customized as an hv parameter; we should use the nodegroup's
2157
    # default kvm path parameter here.
2158
    if not os.path.exists(constants.KVM_PATH):
2159
      msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2160
    if not os.path.exists(constants.SOCAT_PATH):
2161
      msgs.append("The socat binary ('%s') does not exist" %
2162
                  constants.SOCAT_PATH)
2163

    
2164
    return self._FormatVerifyResults(msgs)
2165

    
2166
  @classmethod
2167
  def CheckParameterSyntax(cls, hvparams):
2168
    """Check the given parameters for validity.
2169

2170
    @type hvparams:  dict
2171
    @param hvparams: dictionary with parameter names/value
2172
    @raise errors.HypervisorError: when a parameter is not valid
2173

2174
    """
2175
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2176

    
2177
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2178
    if kernel_path:
2179
      if not hvparams[constants.HV_ROOT_PATH]:
2180
        raise errors.HypervisorError("Need a root partition for the instance,"
2181
                                     " if a kernel is defined")
2182

    
2183
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2184
        not hvparams[constants.HV_VNC_X509]):
2185
      raise errors.HypervisorError("%s must be defined, if %s is" %
2186
                                   (constants.HV_VNC_X509,
2187
                                    constants.HV_VNC_X509_VERIFY))
2188

    
2189
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2190
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2191
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2192
      if not serial_speed or serial_speed not in valid_speeds:
2193
        raise errors.HypervisorError("Invalid serial console speed, must be"
2194
                                     " one of: %s" %
2195
                                     utils.CommaJoin(valid_speeds))
2196

    
2197
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2198
    if (boot_order == constants.HT_BO_CDROM and
2199
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2200
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2201
                                   " ISO path")
2202

    
2203
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2204
    if security_model == constants.HT_SM_USER:
2205
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2206
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2207
                                     " must be specified")
2208
    elif (security_model == constants.HT_SM_NONE or
2209
          security_model == constants.HT_SM_POOL):
2210
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2211
        raise errors.HypervisorError("Cannot have a security domain when the"
2212
                                     " security model is 'none' or 'pool'")
2213

    
2214
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2215
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2216
    if spice_bind:
2217
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2218
        # if an IP version is specified, the spice_bind parameter must be an
2219
        # IP of that family
2220
        if (netutils.IP4Address.IsValid(spice_bind) and
2221
            spice_ip_version != constants.IP4_VERSION):
2222
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2223
                                       " the specified IP version is %s" %
2224
                                       (spice_bind, spice_ip_version))
2225

    
2226
        if (netutils.IP6Address.IsValid(spice_bind) and
2227
            spice_ip_version != constants.IP6_VERSION):
2228
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2229
                                       " the specified IP version is %s" %
2230
                                       (spice_bind, spice_ip_version))
2231
    else:
2232
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2233
      # error if any of them is set without it.
2234
      for param in _SPICE_ADDITIONAL_PARAMS:
2235
        if hvparams[param]:
2236
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2237
                                       (param, constants.HV_KVM_SPICE_BIND))
2238

    
2239
  @classmethod
2240
  def ValidateParameters(cls, hvparams):
2241
    """Check the given parameters for validity.
2242

2243
    @type hvparams:  dict
2244
    @param hvparams: dictionary with parameter names/value
2245
    @raise errors.HypervisorError: when a parameter is not valid
2246

2247
    """
2248
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2249

    
2250
    kvm_path = hvparams[constants.HV_KVM_PATH]
2251

    
2252
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2253
    if security_model == constants.HT_SM_USER:
2254
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2255
      try:
2256
        pwd.getpwnam(username)
2257
      except KeyError:
2258
        raise errors.HypervisorError("Unknown security domain user %s"
2259
                                     % username)
2260

    
2261
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2262
    if spice_bind:
2263
      # only one of VNC and SPICE can be used currently.
2264
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2265
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2266
                                     " only one of them can be used at a"
2267
                                     " given time")
2268

    
2269
      # check that KVM supports SPICE
2270
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2271
      if not cls._SPICE_RE.search(kvmhelp):
2272
        raise errors.HypervisorError("SPICE is configured, but it is not"
2273
                                     " supported according to 'kvm --help'")
2274

    
2275
      # if spice_bind is not an IP address, it must be a valid interface
2276
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2277
                       netutils.IP6Address.IsValid(spice_bind))
2278
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2279
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2280
                                     " a valid IP address or interface name" %
2281
                                     constants.HV_KVM_SPICE_BIND)
2282

    
2283
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2284
    if machine_version:
2285
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2286
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2287
        raise errors.HypervisorError("Unsupported machine version: %s" %
2288
                                     machine_version)
2289

    
2290
  @classmethod
2291
  def PowercycleNode(cls):
2292
    """KVM powercycle, just a wrapper over Linux powercycle.
2293

2294
    """
2295
    cls.LinuxPowercycle()