Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 6f4070cd

History | View | Annotate | Download (78 kB)

1
#
2
#
3

    
4
# Copyright (C) 2008, 2009, 2010, 2011, 2012 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

    
83
def _ProbeTapVnetHdr(fd):
84
  """Check whether to enable the IFF_VNET_HDR flag.
85

86
  To do this, _all_ of the following conditions must be met:
87
   1. TUNGETFEATURES ioctl() *must* be implemented
88
   2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
89
   3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
90
      drivers/net/tun.c there is no way to test this until after the tap device
91
      has been created using TUNSETIFF, and there is no way to change the
92
      IFF_VNET_HDR flag after creating the interface, catch-22! However both
93
      TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
94
      thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
95

96
   @type fd: int
97
   @param fd: the file descriptor of /dev/net/tun
98

99
  """
100
  req = struct.pack("I", 0)
101
  try:
102
    res = fcntl.ioctl(fd, TUNGETFEATURES, req)
103
  except EnvironmentError:
104
    logging.warning("TUNGETFEATURES ioctl() not implemented")
105
    return False
106

    
107
  tunflags = struct.unpack("I", res)[0]
108
  if tunflags & IFF_VNET_HDR:
109
    return True
110
  else:
111
    logging.warning("Host does not support IFF_VNET_HDR, not enabling")
112
    return False
113

    
114

    
115
def _OpenTap(vnet_hdr=True):
116
  """Open a new tap device and return its file descriptor.
117

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

121
  @type vnet_hdr: boolean
122
  @param vnet_hdr: Enable the VNET Header
123
  @return: (ifname, tapfd)
124
  @rtype: tuple
125

126
  """
127
  try:
128
    tapfd = os.open("/dev/net/tun", os.O_RDWR)
129
  except EnvironmentError:
130
    raise errors.HypervisorError("Failed to open /dev/net/tun")
131

    
132
  flags = IFF_TAP | IFF_NO_PI
133

    
134
  if vnet_hdr and _ProbeTapVnetHdr(tapfd):
135
    flags |= IFF_VNET_HDR
136

    
137
  # The struct ifreq ioctl request (see netdevice(7))
138
  ifr = struct.pack("16sh", "", flags)
139

    
140
  try:
141
    res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
142
  except EnvironmentError:
143
    raise errors.HypervisorError("Failed to allocate a new TAP device")
144

    
145
  # Get the interface name from the ioctl
146
  ifname = struct.unpack("16sh", res)[0].strip("\x00")
147
  return (ifname, tapfd)
148

    
149

    
150
def _BuildNetworkEnv(name, network, gateway, network6, gateway6,
151
                     network_type, mac_prefix, tags, env):
152
  """Build environment variables concerning a Network.
153

154
  """
155
  if name:
156
    env["NETWORK_NAME"] = name
157
  if network:
158
    env["NETWORK_SUBNET"] = network
159
  if gateway:
160
    env["NETWORK_GATEWAY"] = gateway
161
  if network6:
162
    env["NETWORK_SUBNET6"] = network6
163
  if gateway6:
164
    env["NETWORK_GATEWAY6"] = gateway6
165
  if mac_prefix:
166
    env["NETWORK_MAC_PREFIX"] = mac_prefix
167
  if network_type:
168
    env["NETWORK_TYPE"] = network_type
169
  if tags:
170
    env["NETWORK_TAGS"] = " ".join(tags)
171

    
172
  return env
173

    
174

    
175
class QmpMessage:
176
  """QEMU Messaging Protocol (QMP) message.
177

178
  """
179
  def __init__(self, data):
180
    """Creates a new QMP message based on the passed data.
181

182
    """
183
    if not isinstance(data, dict):
184
      raise TypeError("QmpMessage must be initialized with a dict")
185

    
186
    self.data = data
187

    
188
  def __getitem__(self, field_name):
189
    """Get the value of the required field if present, or None.
190

191
    Overrides the [] operator to provide access to the message data,
192
    returning None if the required item is not in the message
193
    @return: the value of the field_name field, or None if field_name
194
             is not contained in the message
195

196
    """
197
    return self.data.get(field_name, None)
198

    
199
  def __setitem__(self, field_name, field_value):
200
    """Set the value of the required field_name to field_value.
201

202
    """
203
    self.data[field_name] = field_value
204

    
205
  @staticmethod
206
  def BuildFromJsonString(json_string):
207
    """Build a QmpMessage from a JSON encoded string.
208

209
    @type json_string: str
210
    @param json_string: JSON string representing the message
211
    @rtype: L{QmpMessage}
212
    @return: a L{QmpMessage} built from json_string
213

214
    """
215
    # Parse the string
216
    data = serializer.LoadJson(json_string)
217
    return QmpMessage(data)
218

    
219
  def __str__(self):
220
    # The protocol expects the JSON object to be sent as a single line.
221
    return serializer.DumpJson(self.data)
222

    
223
  def __eq__(self, other):
224
    # When comparing two QmpMessages, we are interested in comparing
225
    # their internal representation of the message data
226
    return self.data == other.data
227

    
228

    
229
class QmpConnection:
230
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
231

232
  """
233
  _FIRST_MESSAGE_KEY = "QMP"
234
  _EVENT_KEY = "event"
235
  _ERROR_KEY = "error"
236
  _RETURN_KEY = RETURN_KEY = "return"
237
  _ACTUAL_KEY = ACTUAL_KEY = "actual"
238
  _ERROR_CLASS_KEY = "class"
239
  _ERROR_DATA_KEY = "data"
240
  _ERROR_DESC_KEY = "desc"
241
  _EXECUTE_KEY = "execute"
242
  _ARGUMENTS_KEY = "arguments"
243
  _CAPABILITIES_COMMAND = "qmp_capabilities"
244
  _MESSAGE_END_TOKEN = "\r\n"
245
  _SOCKET_TIMEOUT = 5
246

    
247
  def __init__(self, monitor_filename):
248
    """Instantiates the QmpConnection object.
249

250
    @type monitor_filename: string
251
    @param monitor_filename: the filename of the UNIX raw socket on which the
252
                             QMP monitor is listening
253

254
    """
255
    self.monitor_filename = monitor_filename
256
    self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
257
    # We want to fail if the server doesn't send a complete message
258
    # in a reasonable amount of time
259
    self.sock.settimeout(self._SOCKET_TIMEOUT)
260
    self._connected = False
261
    self._buf = ""
262

    
263
  def _check_socket(self):
264
    sock_stat = None
265
    try:
266
      sock_stat = os.stat(self.monitor_filename)
267
    except EnvironmentError, err:
268
      if err.errno == errno.ENOENT:
269
        raise errors.HypervisorError("No qmp socket found")
270
      else:
271
        raise errors.HypervisorError("Error checking qmp socket: %s",
272
                                     utils.ErrnoOrStr(err))
273
    if not stat.S_ISSOCK(sock_stat.st_mode):
274
      raise errors.HypervisorError("Qmp socket is not a socket")
275

    
276
  def _check_connection(self):
277
    """Make sure that the connection is established.
278

279
    """
280
    if not self._connected:
281
      raise errors.ProgrammerError("To use a QmpConnection you need to first"
282
                                   " invoke connect() on it")
283

    
284
  def connect(self):
285
    """Connects to the QMP monitor.
286

287
    Connects to the UNIX socket and makes sure that we can actually send and
288
    receive data to the kvm instance via QMP.
289

290
    @raise errors.HypervisorError: when there are communication errors
291
    @raise errors.ProgrammerError: when there are data serialization errors
292

293
    """
294
    if self._connected:
295
      raise errors.ProgrammerError("Cannot connect twice")
296

    
297
    self._check_socket()
298

    
299
    # Check file existance/stuff
300
    try:
301
      self.sock.connect(self.monitor_filename)
302
    except EnvironmentError:
303
      raise errors.HypervisorError("Can't connect to qmp socket")
304
    self._connected = True
305

    
306
    # Check if we receive a correct greeting message from the server
307
    # (As per the QEMU Protocol Specification 0.1 - section 2.2)
308
    greeting = self._Recv()
309
    if not greeting[self._FIRST_MESSAGE_KEY]:
310
      self._connected = False
311
      raise errors.HypervisorError("kvm: qmp communication error (wrong"
312
                                   " server greeting")
313

    
314
    # Let's put the monitor in command mode using the qmp_capabilities
315
    # command, or else no command will be executable.
316
    # (As per the QEMU Protocol Specification 0.1 - section 4)
317
    self.Execute(self._CAPABILITIES_COMMAND)
318

    
319
  def _ParseMessage(self, buf):
320
    """Extract and parse a QMP message from the given buffer.
321

322
    Seeks for a QMP message in the given buf. If found, it parses it and
323
    returns it together with the rest of the characters in the buf.
324
    If no message is found, returns None and the whole buffer.
325

326
    @raise errors.ProgrammerError: when there are data serialization errors
327

328
    """
329
    message = None
330
    # Check if we got the message end token (CRLF, as per the QEMU Protocol
331
    # Specification 0.1 - Section 2.1.1)
332
    pos = buf.find(self._MESSAGE_END_TOKEN)
333
    if pos >= 0:
334
      try:
335
        message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
336
      except Exception, err:
337
        raise errors.ProgrammerError("QMP data serialization error: %s" % err)
338
      buf = buf[pos + 1:]
339

    
340
    return (message, buf)
341

    
342
  def _Recv(self):
343
    """Receives a message from QMP and decodes the received JSON object.
344

345
    @rtype: QmpMessage
346
    @return: the received message
347
    @raise errors.HypervisorError: when there are communication errors
348
    @raise errors.ProgrammerError: when there are data serialization errors
349

350
    """
351
    self._check_connection()
352

    
353
    # Check if there is already a message in the buffer
354
    (message, self._buf) = self._ParseMessage(self._buf)
355
    if message:
356
      return message
357

    
358
    recv_buffer = StringIO.StringIO(self._buf)
359
    recv_buffer.seek(len(self._buf))
360
    try:
361
      while True:
362
        data = self.sock.recv(4096)
363
        if not data:
364
          break
365
        recv_buffer.write(data)
366

    
367
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
368
        if message:
369
          return message
370

    
371
    except socket.timeout, err:
372
      raise errors.HypervisorError("Timeout while receiving a QMP message: "
373
                                   "%s" % (err))
374
    except socket.error, err:
375
      raise errors.HypervisorError("Unable to receive data from KVM using the"
376
                                   " QMP protocol: %s" % err)
377

    
378
  def _Send(self, message):
379
    """Encodes and sends a message to KVM using QMP.
380

381
    @type message: QmpMessage
382
    @param message: message to send to KVM
383
    @raise errors.HypervisorError: when there are communication errors
384
    @raise errors.ProgrammerError: when there are data serialization errors
385

386
    """
387
    self._check_connection()
388
    try:
389
      message_str = str(message)
390
    except Exception, err:
391
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
392

    
393
    try:
394
      self.sock.sendall(message_str)
395
    except socket.timeout, err:
396
      raise errors.HypervisorError("Timeout while sending a QMP message: "
397
                                   "%s (%s)" % (err.string, err.errno))
398
    except socket.error, err:
399
      raise errors.HypervisorError("Unable to send data from KVM using the"
400
                                   " QMP protocol: %s" % err)
401

    
402
  def Execute(self, command, arguments=None):
403
    """Executes a QMP command and returns the response of the server.
404

405
    @type command: str
406
    @param command: the command to execute
407
    @type arguments: dict
408
    @param arguments: dictionary of arguments to be passed to the command
409
    @rtype: dict
410
    @return: dictionary representing the received JSON object
411
    @raise errors.HypervisorError: when there are communication errors
412
    @raise errors.ProgrammerError: when there are data serialization errors
413

414
    """
415
    self._check_connection()
416
    message = QmpMessage({self._EXECUTE_KEY: command})
417
    if arguments:
418
      message[self._ARGUMENTS_KEY] = arguments
419
    self._Send(message)
420

    
421
    # Events can occur between the sending of the command and the reception
422
    # of the response, so we need to filter out messages with the event key.
423
    while True:
424
      response = self._Recv()
425
      err = response[self._ERROR_KEY]
426
      if err:
427
        raise errors.HypervisorError("kvm: error executing the %s"
428
                                     " command: %s (%s, %s):" %
429
                                     (command,
430
                                      err[self._ERROR_DESC_KEY],
431
                                      err[self._ERROR_CLASS_KEY],
432
                                      err[self._ERROR_DATA_KEY]))
433

    
434
      elif not response[self._EVENT_KEY]:
435
        return response
436

    
437

    
438
class KVMHypervisor(hv_base.BaseHypervisor):
439
  """KVM hypervisor interface
440

441
  """
442
  CAN_MIGRATE = True
443

    
444
  _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
445
  _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
446
  _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
447
  _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
448
  _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
449
  _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
450
  _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
451
  # KVM instances with chroot enabled are started in empty chroot directories.
452
  _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
453
  # After an instance is stopped, its chroot directory is removed.
454
  # If the chroot directory is not empty, it can't be removed.
455
  # A non-empty chroot directory indicates a possible security incident.
456
  # To support forensics, the non-empty chroot directory is quarantined in
457
  # a separate directory, called 'chroot-quarantine'.
458
  _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
459
  _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
460
           _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
461

    
462
  PARAMETERS = {
463
    constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
464
    constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
465
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
466
    constants.HV_ROOT_PATH: hv_base.NO_CHECK,
467
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
468
    constants.HV_ACPI: hv_base.NO_CHECK,
469
    constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
470
    constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
471
    constants.HV_VNC_BIND_ADDRESS:
472
      (False, lambda x: (netutils.IP4Address.IsValid(x) or
473
                         utils.IsNormAbsPath(x)),
474
       "the VNC bind address must be either a valid IP address or an absolute"
475
       " pathname", None, None),
476
    constants.HV_VNC_TLS: hv_base.NO_CHECK,
477
    constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
478
    constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
479
    constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
480
    constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
481
    constants.HV_KVM_SPICE_IP_VERSION:
482
      (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
483
                         x in constants.VALID_IP_VERSIONS),
484
       "the SPICE IP version should be 4 or 6",
485
       None, None),
486
    constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
487
    constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
488
      hv_base.ParamInSet(
489
        False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
490
    constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
491
      hv_base.ParamInSet(
492
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
493
    constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
494
      hv_base.ParamInSet(
495
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
496
    constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
497
      hv_base.ParamInSet(
498
        False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
499
    constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
500
    constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
501
    constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
502
    constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
503
    constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
504
    constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
505
    constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
506
    constants.HV_BOOT_ORDER:
507
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
508
    constants.HV_NIC_TYPE:
509
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
510
    constants.HV_DISK_TYPE:
511
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
512
    constants.HV_KVM_CDROM_DISK_TYPE:
513
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
514
    constants.HV_USB_MOUSE:
515
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
516
    constants.HV_KEYMAP: hv_base.NO_CHECK,
517
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
518
    constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
519
    constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
520
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
521
    constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
522
    constants.HV_DISK_CACHE:
523
      hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
524
    constants.HV_SECURITY_MODEL:
525
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
526
    constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
527
    constants.HV_KVM_FLAG:
528
      hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
529
    constants.HV_VHOST_NET: hv_base.NO_CHECK,
530
    constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
531
    constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
532
    constants.HV_REBOOT_BEHAVIOR:
533
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
534
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
535
    constants.HV_CPU_TYPE: hv_base.NO_CHECK,
536
    constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
537
    constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
538
    constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
539
    constants.HV_SOUNDHW: hv_base.NO_CHECK,
540
    constants.HV_USB_DEVICES: hv_base.NO_CHECK,
541
    constants.HV_VGA: hv_base.NO_CHECK,
542
    constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
543
    constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
544
    }
545

    
546
  _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
547
                                    re.M | re.I)
548
  _MIGRATION_PROGRESS_RE = \
549
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
550
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
551
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
552

    
553
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
554
  _MIGRATION_INFO_RETRY_DELAY = 2
555

    
556
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
557

    
558
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
559
  _CPU_INFO_CMD = "info cpus"
560
  _CONT_CMD = "cont"
561

    
562
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
563
  _CHECK_MACHINE_VERSION_RE = \
564
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
565

    
566
  _QMP_RE = re.compile(r"^-qmp\s", re.M)
567
  _SPICE_RE = re.compile(r"^-spice\s", re.M)
568
  _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
569
  _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
570
  _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
571
  _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
572
  # match  -drive.*boot=on|off on different lines, but in between accept only
573
  # dashes not preceeded by a new line (which would mean another option
574
  # different than -drive is starting)
575
  _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
576

    
577
  ANCILLARY_FILES = [
578
    _KVM_NETWORK_SCRIPT,
579
    ]
580
  ANCILLARY_FILES_OPT = [
581
    _KVM_NETWORK_SCRIPT,
582
    ]
583

    
584
  # Supported kvm options to get output from
585
  _KVMOPT_HELP = "help"
586
  _KVMOPT_MLIST = "mlist"
587
  _KVMOPTS_CMDS = {
588
    _KVMOPT_HELP: ["--help"],
589
    _KVMOPT_MLIST: ["-M", "?"],
590
  }
591

    
592
  def __init__(self):
593
    hv_base.BaseHypervisor.__init__(self)
594
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
595
    # in a tmpfs filesystem or has been otherwise wiped out.
596
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
597
    utils.EnsureDirs(dirs)
598

    
599
  @classmethod
600
  def _InstancePidFile(cls, instance_name):
601
    """Returns the instance pidfile.
602

603
    """
604
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
605

    
606
  @classmethod
607
  def _InstanceUidFile(cls, instance_name):
608
    """Returns the instance uidfile.
609

610
    """
611
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
612

    
613
  @classmethod
614
  def _InstancePidInfo(cls, pid):
615
    """Check pid file for instance information.
616

617
    Check that a pid file is associated with an instance, and retrieve
618
    information from its command line.
619

620
    @type pid: string or int
621
    @param pid: process id of the instance to check
622
    @rtype: tuple
623
    @return: (instance_name, memory, vcpus)
624
    @raise errors.HypervisorError: when an instance cannot be found
625

626
    """
627
    alive = utils.IsProcessAlive(pid)
628
    if not alive:
629
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
630

    
631
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
632
    try:
633
      cmdline = utils.ReadFile(cmdline_file)
634
    except EnvironmentError, err:
635
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
636
                                   (pid, err))
637

    
638
    instance = None
639
    memory = 0
640
    vcpus = 0
641

    
642
    arg_list = cmdline.split("\x00")
643
    while arg_list:
644
      arg = arg_list.pop(0)
645
      if arg == "-name":
646
        instance = arg_list.pop(0)
647
      elif arg == "-m":
648
        memory = int(arg_list.pop(0))
649
      elif arg == "-smp":
650
        vcpus = int(arg_list.pop(0).split(",")[0])
651

    
652
    if instance is None:
653
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
654
                                   " instance" % pid)
655

    
656
    return (instance, memory, vcpus)
657

    
658
  def _InstancePidAlive(self, instance_name):
659
    """Returns the instance pidfile, pid, and liveness.
660

661
    @type instance_name: string
662
    @param instance_name: instance name
663
    @rtype: tuple
664
    @return: (pid file name, pid, liveness)
665

666
    """
667
    pidfile = self._InstancePidFile(instance_name)
668
    pid = utils.ReadPidFile(pidfile)
669

    
670
    alive = False
671
    try:
672
      cmd_instance = self._InstancePidInfo(pid)[0]
673
      alive = (cmd_instance == instance_name)
674
    except errors.HypervisorError:
675
      pass
676

    
677
    return (pidfile, pid, alive)
678

    
679
  def _CheckDown(self, instance_name):
680
    """Raises an error unless the given instance is down.
681

682
    """
683
    alive = self._InstancePidAlive(instance_name)[2]
684
    if alive:
685
      raise errors.HypervisorError("Failed to start instance %s: %s" %
686
                                   (instance_name, "already running"))
687

    
688
  @classmethod
689
  def _InstanceMonitor(cls, instance_name):
690
    """Returns the instance monitor socket name
691

692
    """
693
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
694

    
695
  @classmethod
696
  def _InstanceSerial(cls, instance_name):
697
    """Returns the instance serial socket name
698

699
    """
700
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
701

    
702
  @classmethod
703
  def _InstanceQmpMonitor(cls, instance_name):
704
    """Returns the instance serial QMP socket name
705

706
    """
707
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
708

    
709
  @staticmethod
710
  def _SocatUnixConsoleParams():
711
    """Returns the correct parameters for socat
712

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

715
    """
716
    if constants.SOCAT_USE_ESCAPE:
717
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
718
    else:
719
      return "echo=0,icanon=0"
720

    
721
  @classmethod
722
  def _InstanceKVMRuntime(cls, instance_name):
723
    """Returns the instance KVM runtime filename
724

725
    """
726
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
727

    
728
  @classmethod
729
  def _InstanceChrootDir(cls, instance_name):
730
    """Returns the name of the KVM chroot dir of the instance
731

732
    """
733
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
734

    
735
  @classmethod
736
  def _InstanceNICDir(cls, instance_name):
737
    """Returns the name of the directory holding the tap device files for a
738
    given instance.
739

740
    """
741
    return utils.PathJoin(cls._NICS_DIR, instance_name)
742

    
743
  @classmethod
744
  def _InstanceNICFile(cls, instance_name, seq):
745
    """Returns the name of the file containing the tap device for a given NIC
746

747
    """
748
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
749

    
750
  @classmethod
751
  def _InstanceKeymapFile(cls, instance_name):
752
    """Returns the name of the file containing the keymap for a given instance
753

754
    """
755
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
756

    
757
  @classmethod
758
  def _TryReadUidFile(cls, uid_file):
759
    """Try to read a uid file
760

761
    """
762
    if os.path.exists(uid_file):
763
      try:
764
        uid = int(utils.ReadOneLineFile(uid_file))
765
        return uid
766
      except EnvironmentError:
767
        logging.warning("Can't read uid file", exc_info=True)
768
      except (TypeError, ValueError):
769
        logging.warning("Can't parse uid file contents", exc_info=True)
770
    return None
771

    
772
  @classmethod
773
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
774
    """Removes an instance's rutime sockets/files/dirs.
775

776
    """
777
    utils.RemoveFile(pidfile)
778
    utils.RemoveFile(cls._InstanceMonitor(instance_name))
779
    utils.RemoveFile(cls._InstanceSerial(instance_name))
780
    utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
781
    utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
782
    utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
783
    uid_file = cls._InstanceUidFile(instance_name)
784
    uid = cls._TryReadUidFile(uid_file)
785
    utils.RemoveFile(uid_file)
786
    if uid is not None:
787
      uidpool.ReleaseUid(uid)
788
    try:
789
      shutil.rmtree(cls._InstanceNICDir(instance_name))
790
    except OSError, err:
791
      if err.errno != errno.ENOENT:
792
        raise
793
    try:
794
      chroot_dir = cls._InstanceChrootDir(instance_name)
795
      utils.RemoveDir(chroot_dir)
796
    except OSError, err:
797
      if err.errno == errno.ENOTEMPTY:
798
        # The chroot directory is expected to be empty, but it isn't.
799
        new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
800
                                          prefix="%s-%s-" %
801
                                          (instance_name,
802
                                           utils.TimestampForFilename()))
803
        logging.warning("The chroot directory of instance %s can not be"
804
                        " removed as it is not empty. Moving it to the"
805
                        " quarantine instead. Please investigate the"
806
                        " contents (%s) and clean up manually",
807
                        instance_name, new_chroot_dir)
808
        utils.RenameFile(chroot_dir, new_chroot_dir)
809
      else:
810
        raise
811

    
812
  @staticmethod
813
  def _ConfigureNIC(instance, seq, nic, tap):
814
    """Run the network configuration script for a specified NIC
815

816
    @param instance: instance we're acting on
817
    @type instance: instance object
818
    @param seq: nic sequence number
819
    @type seq: int
820
    @param nic: nic we're acting on
821
    @type nic: nic object
822
    @param tap: the host's tap interface this NIC corresponds to
823
    @type tap: str
824

825
    """
826
    if instance.tags:
827
      tags = " ".join(instance.tags)
828
    else:
829
      tags = ""
830

    
831
    env = {
832
      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
833
      "INSTANCE": instance.name,
834
      "MAC": nic.mac,
835
      "MODE": nic.nicparams[constants.NIC_MODE],
836
      "INTERFACE": tap,
837
      "INTERFACE_INDEX": str(seq),
838
      "TAGS": tags,
839
    }
840

    
841
    if nic.ip:
842
      env["IP"] = nic.ip
843

    
844
    if nic.nicparams[constants.NIC_LINK]:
845
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
846

    
847
    if nic.network:
848
      n = objects.Network.FromDict(nic.netinfo)
849
      _BuildNetworkEnv(nic.network, n.network, n.gateway,
850
                       n.network6, n.gateway6, n.network_type,
851
                       n.mac_prefix, n.tags, env)
852

    
853
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
854
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
855

    
856
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
857
    if result.failed:
858
      raise errors.HypervisorError("Failed to configure interface %s: %s."
859
                                   " Network configuration script output: %s" %
860
                                   (tap, result.fail_reason, result.output))
861

    
862
  @staticmethod
863
  def _VerifyAffinityPackage():
864
    if affinity is None:
865
      raise errors.HypervisorError("affinity Python package not"
866
                                   " found; cannot use CPU pinning under KVM")
867

    
868
  @staticmethod
869
  def _BuildAffinityCpuMask(cpu_list):
870
    """Create a CPU mask suitable for sched_setaffinity from a list of
871
    CPUs.
872

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

876
    @type cpu_list: list of int
877
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
878
    @rtype: int
879
    @return: a bit mask of CPU affinities
880

881
    """
882
    if cpu_list == constants.CPU_PINNING_OFF:
883
      return constants.CPU_PINNING_ALL_KVM
884
    else:
885
      return sum(2 ** cpu for cpu in cpu_list)
886

    
887
  @classmethod
888
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
889
    """Change CPU affinity for running VM according to given CPU mask.
890

891
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
892
    @type cpu_mask: string
893
    @param process_id: process ID of KVM process. Used to pin entire VM
894
                       to physical CPUs.
895
    @type process_id: int
896
    @param thread_dict: map of virtual CPUs to KVM thread IDs
897
    @type thread_dict: dict int:int
898

899
    """
900
    # Convert the string CPU mask to a list of list of int's
901
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
902

    
903
    if len(cpu_list) == 1:
904
      all_cpu_mapping = cpu_list[0]
905
      if all_cpu_mapping == constants.CPU_PINNING_OFF:
906
        # If CPU pinning has 1 entry that's "all", then do nothing
907
        pass
908
      else:
909
        # If CPU pinning has one non-all entry, map the entire VM to
910
        # one set of physical CPUs
911
        cls._VerifyAffinityPackage()
912
        affinity.set_process_affinity_mask(
913
          process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
914
    else:
915
      # The number of vCPUs mapped should match the number of vCPUs
916
      # reported by KVM. This was already verified earlier, so
917
      # here only as a sanity check.
918
      assert len(thread_dict) == len(cpu_list)
919
      cls._VerifyAffinityPackage()
920

    
921
      # For each vCPU, map it to the proper list of physical CPUs
922
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
923
        affinity.set_process_affinity_mask(thread_dict[i],
924
                                           cls._BuildAffinityCpuMask(vcpu))
925

    
926
  def _GetVcpuThreadIds(self, instance_name):
927
    """Get a mapping of vCPU no. to thread IDs for the instance
928

929
    @type instance_name: string
930
    @param instance_name: instance in question
931
    @rtype: dictionary of int:int
932
    @return: a dictionary mapping vCPU numbers to thread IDs
933

934
    """
935
    result = {}
936
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
937
    for line in output.stdout.splitlines():
938
      match = self._CPU_INFO_RE.search(line)
939
      if not match:
940
        continue
941
      grp = map(int, match.groups())
942
      result[grp[0]] = grp[1]
943

    
944
    return result
945

    
946
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
947
    """Complete CPU pinning.
948

949
    @type instance_name: string
950
    @param instance_name: name of instance
951
    @type cpu_mask: string
952
    @param cpu_mask: CPU pinning mask as entered by user
953

954
    """
955
    # Get KVM process ID, to be used if need to pin entire VM
956
    _, pid, _ = self._InstancePidAlive(instance_name)
957
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
958
    thread_dict = self._GetVcpuThreadIds(instance_name)
959
    # Run CPU pinning, based on configured mask
960
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
961

    
962
  def ListInstances(self):
963
    """Get the list of running instances.
964

965
    We can do this by listing our live instances directory and
966
    checking whether the associated kvm process is still alive.
967

968
    """
969
    result = []
970
    for name in os.listdir(self._PIDS_DIR):
971
      if self._InstancePidAlive(name)[2]:
972
        result.append(name)
973
    return result
974

    
975
  def GetInstanceInfo(self, instance_name):
976
    """Get instance properties.
977

978
    @type instance_name: string
979
    @param instance_name: the instance name
980
    @rtype: tuple of strings
981
    @return: (name, id, memory, vcpus, stat, times)
982

983
    """
984
    _, pid, alive = self._InstancePidAlive(instance_name)
985
    if not alive:
986
      return None
987

    
988
    _, memory, vcpus = self._InstancePidInfo(pid)
989
    istat = "---b-"
990
    times = "0"
991

    
992
    try:
993
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
994
      qmp.connect()
995
      vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
996
      # Will fail if ballooning is not enabled, but we can then just resort to
997
      # the value above.
998
      mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
999
      memory = mem_bytes / 1048576
1000
    except errors.HypervisorError:
1001
      pass
1002

    
1003
    return (instance_name, pid, memory, vcpus, istat, times)
1004

    
1005
  def GetAllInstancesInfo(self):
1006
    """Get properties of all instances.
1007

1008
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1009

1010
    """
1011
    data = []
1012
    for name in os.listdir(self._PIDS_DIR):
1013
      try:
1014
        info = self.GetInstanceInfo(name)
1015
      except errors.HypervisorError:
1016
        # Ignore exceptions due to instances being shut down
1017
        continue
1018
      if info:
1019
        data.append(info)
1020
    return data
1021

    
1022
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1023
                          kvmhelp):
1024
    """Generate KVM information to start an instance.
1025

1026
    @type kvmhelp: string
1027
    @param kvmhelp: output of kvm --help
1028
    @attention: this function must not have any side-effects; for
1029
        example, it must not write to the filesystem, or read values
1030
        from the current system the are expected to differ between
1031
        nodes, since it is only run once at instance startup;
1032
        actions/kvm arguments that can vary between systems should be
1033
        done in L{_ExecuteKVMRuntime}
1034

1035
    """
1036
    # pylint: disable=R0912,R0914,R0915
1037
    hvp = instance.hvparams
1038

    
1039
    pidfile = self._InstancePidFile(instance.name)
1040
    kvm = hvp[constants.HV_KVM_PATH]
1041
    kvm_cmd = [kvm]
1042
    # used just by the vnc server, if enabled
1043
    kvm_cmd.extend(["-name", instance.name])
1044
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1045

    
1046
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1047
    if hvp[constants.HV_CPU_CORES]:
1048
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1049
    if hvp[constants.HV_CPU_THREADS]:
1050
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1051
    if hvp[constants.HV_CPU_SOCKETS]:
1052
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1053

    
1054
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1055

    
1056
    kvm_cmd.extend(["-pidfile", pidfile])
1057
    kvm_cmd.extend(["-balloon", "virtio"])
1058
    kvm_cmd.extend(["-daemonize"])
1059
    if not instance.hvparams[constants.HV_ACPI]:
1060
      kvm_cmd.extend(["-no-acpi"])
1061
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1062
        constants.INSTANCE_REBOOT_EXIT:
1063
      kvm_cmd.extend(["-no-reboot"])
1064

    
1065
    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1066
    if not mversion:
1067
      mversion = self._GetDefaultMachineVersion(kvm)
1068
    kvm_cmd.extend(["-M", mversion])
1069

    
1070
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1071
    if kernel_path:
1072
      boot_disk = boot_cdrom = boot_floppy = boot_network = False
1073
    else:
1074
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1075
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1076
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1077
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1078

    
1079
    self.ValidateParameters(hvp)
1080

    
1081
    if startup_paused:
1082
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1083

    
1084
    if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1085
        self._ENABLE_KVM_RE.search(kvmhelp)):
1086
      kvm_cmd.extend(["-enable-kvm"])
1087
    elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1088
          self._DISABLE_KVM_RE.search(kvmhelp)):
1089
      kvm_cmd.extend(["-disable-kvm"])
1090

    
1091
    if boot_network:
1092
      kvm_cmd.extend(["-boot", "n"])
1093

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

    
1098
    disk_type = hvp[constants.HV_DISK_TYPE]
1099
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
1100
      if_val = ",if=virtio"
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
        kvm_cmd.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

    
1128
      drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
1129
                                                cache_val)
1130
      kvm_cmd.extend(["-drive", drive_val])
1131

    
1132
    #Now we can specify a different device type for CDROM devices.
1133
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1134
    if not cdrom_disk_type:
1135
      cdrom_disk_type = disk_type
1136

    
1137
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1138
    if iso_image:
1139
      options = ",format=raw,media=cdrom"
1140
      # set cdrom 'if' type
1141
      if boot_cdrom:
1142
        actual_cdrom_type = constants.HT_DISK_IDE
1143
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1144
        actual_cdrom_type = "virtio"
1145
      else:
1146
        actual_cdrom_type = cdrom_disk_type
1147
      if_val = ",if=%s" % actual_cdrom_type
1148
      # set boot flag, if needed
1149
      boot_val = ""
1150
      if boot_cdrom:
1151
        kvm_cmd.extend(["-boot", "d"])
1152
        if needs_boot_flag:
1153
          boot_val = ",boot=on"
1154
      # and finally build the entire '-drive' value
1155
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1156
      kvm_cmd.extend(["-drive", drive_val])
1157

    
1158
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1159
    if iso_image2:
1160
      options = ",format=raw,media=cdrom"
1161
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1162
        if_val = ",if=virtio"
1163
      else:
1164
        if_val = ",if=%s" % cdrom_disk_type
1165
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1166
      kvm_cmd.extend(["-drive", drive_val])
1167

    
1168
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1169
    if floppy_image:
1170
      options = ",format=raw,media=disk"
1171
      if boot_floppy:
1172
        kvm_cmd.extend(["-boot", "a"])
1173
        options = "%s,boot=on" % options
1174
      if_val = ",if=floppy"
1175
      options = "%s%s" % (options, if_val)
1176
      drive_val = "file=%s%s" % (floppy_image, options)
1177
      kvm_cmd.extend(["-drive", drive_val])
1178

    
1179
    if kernel_path:
1180
      kvm_cmd.extend(["-kernel", kernel_path])
1181
      initrd_path = hvp[constants.HV_INITRD_PATH]
1182
      if initrd_path:
1183
        kvm_cmd.extend(["-initrd", initrd_path])
1184
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1185
                     hvp[constants.HV_KERNEL_ARGS]]
1186
      if hvp[constants.HV_SERIAL_CONSOLE]:
1187
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1188
        root_append.append("console=ttyS0,%s" % serial_speed)
1189
      kvm_cmd.extend(["-append", " ".join(root_append)])
1190

    
1191
    mem_path = hvp[constants.HV_MEM_PATH]
1192
    if mem_path:
1193
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1194

    
1195
    monitor_dev = ("unix:%s,server,nowait" %
1196
                   self._InstanceMonitor(instance.name))
1197
    kvm_cmd.extend(["-monitor", monitor_dev])
1198
    if hvp[constants.HV_SERIAL_CONSOLE]:
1199
      serial_dev = ("unix:%s,server,nowait" %
1200
                    self._InstanceSerial(instance.name))
1201
      kvm_cmd.extend(["-serial", serial_dev])
1202
    else:
1203
      kvm_cmd.extend(["-serial", "none"])
1204

    
1205
    mouse_type = hvp[constants.HV_USB_MOUSE]
1206
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1207
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1208
    spice_ip_version = None
1209

    
1210
    kvm_cmd.extend(["-usb"])
1211

    
1212
    if mouse_type:
1213
      kvm_cmd.extend(["-usbdevice", mouse_type])
1214
    elif vnc_bind_address:
1215
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1216

    
1217
    if vnc_bind_address:
1218
      if netutils.IP4Address.IsValid(vnc_bind_address):
1219
        if instance.network_port > constants.VNC_BASE_PORT:
1220
          display = instance.network_port - constants.VNC_BASE_PORT
1221
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1222
            vnc_arg = ":%d" % (display)
1223
          else:
1224
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1225
        else:
1226
          logging.error("Network port is not a valid VNC display (%d < %d)."
1227
                        " Not starting VNC", instance.network_port,
1228
                        constants.VNC_BASE_PORT)
1229
          vnc_arg = "none"
1230

    
1231
        # Only allow tls and other option when not binding to a file, for now.
1232
        # kvm/qemu gets confused otherwise about the filename to use.
1233
        vnc_append = ""
1234
        if hvp[constants.HV_VNC_TLS]:
1235
          vnc_append = "%s,tls" % vnc_append
1236
          if hvp[constants.HV_VNC_X509_VERIFY]:
1237
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1238
                                               hvp[constants.HV_VNC_X509])
1239
          elif hvp[constants.HV_VNC_X509]:
1240
            vnc_append = "%s,x509=%s" % (vnc_append,
1241
                                         hvp[constants.HV_VNC_X509])
1242
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1243
          vnc_append = "%s,password" % vnc_append
1244

    
1245
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1246

    
1247
      else:
1248
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1249

    
1250
      kvm_cmd.extend(["-vnc", vnc_arg])
1251
    elif spice_bind:
1252
      # FIXME: this is wrong here; the iface ip address differs
1253
      # between systems, so it should be done in _ExecuteKVMRuntime
1254
      if netutils.IsValidInterface(spice_bind):
1255
        # The user specified a network interface, we have to figure out the IP
1256
        # address.
1257
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1258
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1259

    
1260
        # if the user specified an IP version and the interface does not
1261
        # have that kind of IP addresses, throw an exception
1262
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1263
          if not addresses[spice_ip_version]:
1264
            raise errors.HypervisorError("spice: unable to get an IPv%s address"
1265
                                         " for %s" % (spice_ip_version,
1266
                                                      spice_bind))
1267

    
1268
        # the user did not specify an IP version, we have to figure it out
1269
        elif (addresses[constants.IP4_VERSION] and
1270
              addresses[constants.IP6_VERSION]):
1271
          # we have both ipv4 and ipv6, let's use the cluster default IP
1272
          # version
1273
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1274
          spice_ip_version = \
1275
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1276
        elif addresses[constants.IP4_VERSION]:
1277
          spice_ip_version = constants.IP4_VERSION
1278
        elif addresses[constants.IP6_VERSION]:
1279
          spice_ip_version = constants.IP6_VERSION
1280
        else:
1281
          raise errors.HypervisorError("spice: unable to get an IP address"
1282
                                       " for %s" % (spice_bind))
1283

    
1284
        spice_address = addresses[spice_ip_version][0]
1285

    
1286
      else:
1287
        # spice_bind is known to be a valid IP address, because
1288
        # ValidateParameters checked it.
1289
        spice_address = spice_bind
1290

    
1291
      spice_arg = "addr=%s" % spice_address
1292
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1293
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1294
                     (spice_arg, instance.network_port,
1295
                      pathutils.SPICE_CACERT_FILE))
1296
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1297
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1298
                      pathutils.SPICE_CERT_FILE))
1299
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1300
        if tls_ciphers:
1301
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1302
      else:
1303
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1304

    
1305
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1306
        spice_arg = "%s,disable-ticketing" % spice_arg
1307

    
1308
      if spice_ip_version:
1309
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1310

    
1311
      # Image compression options
1312
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1313
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1314
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1315
      if img_lossless:
1316
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1317
      if img_jpeg:
1318
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1319
      if img_zlib_glz:
1320
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1321

    
1322
      # Video stream detection
1323
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1324
      if video_streaming:
1325
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1326

    
1327
      # Audio compression, by default in qemu-kvm it is on
1328
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1329
        spice_arg = "%s,playback-compression=off" % spice_arg
1330
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1331
        spice_arg = "%s,agent-mouse=off" % spice_arg
1332
      else:
1333
        # Enable the spice agent communication channel between the host and the
1334
        # agent.
1335
        kvm_cmd.extend(["-device", "virtio-serial-pci"])
1336
        kvm_cmd.extend(["-device", "virtserialport,chardev=spicechannel0,"
1337
                                                   "name=com.redhat.spice.0"])
1338
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1339

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

    
1343
    else:
1344
      kvm_cmd.extend(["-nographic"])
1345

    
1346
    if hvp[constants.HV_USE_LOCALTIME]:
1347
      kvm_cmd.extend(["-localtime"])
1348

    
1349
    if hvp[constants.HV_KVM_USE_CHROOT]:
1350
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1351

    
1352
    # Add qemu-KVM -cpu param
1353
    if hvp[constants.HV_CPU_TYPE]:
1354
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1355

    
1356
    # As requested by music lovers
1357
    if hvp[constants.HV_SOUNDHW]:
1358
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1359

    
1360
    # Pass a -vga option if requested, or if spice is used, for backwards
1361
    # compatibility.
1362
    if hvp[constants.HV_VGA]:
1363
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1364
    elif spice_bind:
1365
      kvm_cmd.extend(["-vga", "qxl"])
1366

    
1367
    # Various types of usb devices, comma separated
1368
    if hvp[constants.HV_USB_DEVICES]:
1369
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1370
        kvm_cmd.extend(["-usbdevice", dev])
1371

    
1372
    if hvp[constants.HV_KVM_EXTRA]:
1373
      kvm_cmd.extend([hvp[constants.HV_KVM_EXTRA]])
1374

    
1375
    # Save the current instance nics, but defer their expansion as parameters,
1376
    # as we'll need to generate executable temp files for them.
1377
    kvm_nics = instance.nics
1378
    hvparams = hvp
1379

    
1380
    return (kvm_cmd, kvm_nics, hvparams)
1381

    
1382
  def _WriteKVMRuntime(self, instance_name, data):
1383
    """Write an instance's KVM runtime
1384

1385
    """
1386
    try:
1387
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1388
                      data=data)
1389
    except EnvironmentError, err:
1390
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1391

    
1392
  def _ReadKVMRuntime(self, instance_name):
1393
    """Read an instance's KVM runtime
1394

1395
    """
1396
    try:
1397
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1398
    except EnvironmentError, err:
1399
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1400
    return file_content
1401

    
1402
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1403
    """Save an instance's KVM runtime
1404

1405
    """
1406
    kvm_cmd, kvm_nics, hvparams = kvm_runtime
1407
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1408
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1409
    self._WriteKVMRuntime(instance.name, serialized_form)
1410

    
1411
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1412
    """Load an instance's KVM runtime
1413

1414
    """
1415
    if not serialized_runtime:
1416
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1417
    loaded_runtime = serializer.Load(serialized_runtime)
1418
    kvm_cmd, serialized_nics, hvparams = loaded_runtime
1419
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1420
    return (kvm_cmd, kvm_nics, hvparams)
1421

    
1422
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1423
    """Run the KVM cmd and check for errors
1424

1425
    @type name: string
1426
    @param name: instance name
1427
    @type kvm_cmd: list of strings
1428
    @param kvm_cmd: runcmd input for kvm
1429
    @type tap_fds: list of int
1430
    @param tap_fds: fds of tap devices opened by Ganeti
1431

1432
    """
1433
    try:
1434
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1435
    finally:
1436
      for fd in tap_fds:
1437
        utils_wrapper.CloseFdNoError(fd)
1438

    
1439
    if result.failed:
1440
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1441
                                   (name, result.fail_reason, result.output))
1442
    if not self._InstancePidAlive(name)[2]:
1443
      raise errors.HypervisorError("Failed to start instance %s" % name)
1444

    
1445
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1446
    """Execute a KVM cmd, after completing it with some last minute data.
1447

1448
    @type incoming: tuple of strings
1449
    @param incoming: (target_host_ip, port)
1450
    @type kvmhelp: string
1451
    @param kvmhelp: output of kvm --help
1452

1453
    """
1454
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1455
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1456
    #    have changed since the instance started; only use them if the change
1457
    #    won't affect the inside of the instance (which hasn't been rebooted).
1458
    #  - up_hvp contains the parameters as they were when the instance was
1459
    #    started, plus any new parameter which has been added between ganeti
1460
    #    versions: it is paramount that those default to a value which won't
1461
    #    affect the inside of the instance as well.
1462
    conf_hvp = instance.hvparams
1463
    name = instance.name
1464
    self._CheckDown(name)
1465

    
1466
    temp_files = []
1467

    
1468
    kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1469
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1470

    
1471
    _, v_major, v_min, _ = self._ParseKVMVersion(kvmhelp)
1472

    
1473
    # We know it's safe to run as a different user upon migration, so we'll use
1474
    # the latest conf, from conf_hvp.
1475
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1476
    if security_model == constants.HT_SM_USER:
1477
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1478

    
1479
    keymap = conf_hvp[constants.HV_KEYMAP]
1480
    if keymap:
1481
      keymap_path = self._InstanceKeymapFile(name)
1482
      # If a keymap file is specified, KVM won't use its internal defaults. By
1483
      # first including the "en-us" layout, an error on loading the actual
1484
      # layout (e.g. because it can't be found) won't lead to a non-functional
1485
      # keyboard. A keyboard with incorrect keys is still better than none.
1486
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1487
      kvm_cmd.extend(["-k", keymap_path])
1488

    
1489
    # We have reasons to believe changing something like the nic driver/type
1490
    # upon migration won't exactly fly with the instance kernel, so for nic
1491
    # related parameters we'll use up_hvp
1492
    tapfds = []
1493
    taps = []
1494
    if not kvm_nics:
1495
      kvm_cmd.extend(["-net", "none"])
1496
    else:
1497
      vnet_hdr = False
1498
      tap_extra = ""
1499
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1500
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1501
        # From version 0.12.0, kvm uses a new sintax for network configuration.
1502
        if (v_major, v_min) >= (0, 12):
1503
          nic_model = "virtio-net-pci"
1504
          vnet_hdr = True
1505
        else:
1506
          nic_model = "virtio"
1507

    
1508
        if up_hvp[constants.HV_VHOST_NET]:
1509
          # check for vhost_net support
1510
          if self._VHOST_RE.search(kvmhelp):
1511
            tap_extra = ",vhost=on"
1512
          else:
1513
            raise errors.HypervisorError("vhost_net is configured"
1514
                                         " but it is not available")
1515
      else:
1516
        nic_model = nic_type
1517

    
1518
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1519

    
1520
      for nic_seq, nic in enumerate(kvm_nics):
1521
        tapname, tapfd = _OpenTap(vnet_hdr)
1522
        tapfds.append(tapfd)
1523
        taps.append(tapname)
1524
        if kvm_supports_netdev:
1525
          nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1526
          tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1527
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1528
        else:
1529
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1530
                                                         nic.mac, nic_model)
1531
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1532
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1533

    
1534
    if incoming:
1535
      target, port = incoming
1536
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1537

    
1538
    # Changing the vnc password doesn't bother the guest that much. At most it
1539
    # will surprise people who connect to it. Whether positively or negatively
1540
    # it's debatable.
1541
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1542
    vnc_pwd = None
1543
    if vnc_pwd_file:
1544
      try:
1545
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1546
      except EnvironmentError, err:
1547
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1548
                                     % (vnc_pwd_file, err))
1549

    
1550
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1551
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1552
                         constants.SECURE_DIR_MODE)])
1553

    
1554
    # Automatically enable QMP if version is >= 0.14
1555
    if self._QMP_RE.search(kvmhelp):
1556
      logging.debug("Enabling QMP")
1557
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1558
                      self._InstanceQmpMonitor(instance.name)])
1559

    
1560
    # Configure the network now for starting instances and bridged interfaces,
1561
    # during FinalizeMigration for incoming instances' routed interfaces
1562
    for nic_seq, nic in enumerate(kvm_nics):
1563
      if (incoming and
1564
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1565
        continue
1566
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1567

    
1568
    # CPU affinity requires kvm to start paused, so we set this flag if the
1569
    # instance is not already paused and if we are not going to accept a
1570
    # migrating instance. In the latter case, pausing is not needed.
1571
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1572
    if start_kvm_paused:
1573
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1574

    
1575
    # Note: CPU pinning is using up_hvp since changes take effect
1576
    # during instance startup anyway, and to avoid problems when soft
1577
    # rebooting the instance.
1578
    cpu_pinning = False
1579
    if up_hvp.get(constants.HV_CPU_MASK, None):
1580
      cpu_pinning = True
1581

    
1582
    if security_model == constants.HT_SM_POOL:
1583
      ss = ssconf.SimpleStore()
1584
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1585
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1586
      uid = uidpool.RequestUnusedUid(all_uids)
1587
      try:
1588
        username = pwd.getpwuid(uid.GetUid()).pw_name
1589
        kvm_cmd.extend(["-runas", username])
1590
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1591
      except:
1592
        uidpool.ReleaseUid(uid)
1593
        raise
1594
      else:
1595
        uid.Unlock()
1596
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1597
    else:
1598
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1599

    
1600
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1601
                     constants.RUN_DIRS_MODE)])
1602
    for nic_seq, tap in enumerate(taps):
1603
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1604
                      data=tap)
1605

    
1606
    if vnc_pwd:
1607
      change_cmd = "change vnc password %s" % vnc_pwd
1608
      self._CallMonitorCommand(instance.name, change_cmd)
1609

    
1610
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1611
    # connection attempts because SPICE by default does not allow connections
1612
    # if neither a password nor the "disable_ticketing" options are specified.
1613
    # As soon as we send the password via QMP, that password is a valid ticket
1614
    # for connection.
1615
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1616
    if spice_password_file:
1617
      spice_pwd = ""
1618
      try:
1619
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1620
      except EnvironmentError, err:
1621
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1622
                                     % (spice_password_file, err))
1623

    
1624
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1625
      qmp.connect()
1626
      arguments = {
1627
          "protocol": "spice",
1628
          "password": spice_pwd,
1629
      }
1630
      qmp.Execute("set_password", arguments)
1631

    
1632
    for filename in temp_files:
1633
      utils.RemoveFile(filename)
1634

    
1635
    # If requested, set CPU affinity and resume instance execution
1636
    if cpu_pinning:
1637
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1638

    
1639
    start_memory = self._InstanceStartupMemory(instance)
1640
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1641
      self.BalloonInstanceMemory(instance, start_memory)
1642

    
1643
    if start_kvm_paused:
1644
      # To control CPU pinning, ballooning, and vnc/spice passwords
1645
      # the VM was started in a frozen state. If freezing was not
1646
      # explicitly requested resume the vm status.
1647
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1648

    
1649
  def StartInstance(self, instance, block_devices, startup_paused):
1650
    """Start an instance.
1651

1652
    """
1653
    self._CheckDown(instance.name)
1654
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1655
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1656
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1657
                                           startup_paused, kvmhelp)
1658
    self._SaveKVMRuntime(instance, kvm_runtime)
1659
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1660

    
1661
  def _CallMonitorCommand(self, instance_name, command):
1662
    """Invoke a command on the instance monitor.
1663

1664
    """
1665
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1666
             (utils.ShellQuote(command),
1667
              constants.SOCAT_PATH,
1668
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1669
    result = utils.RunCmd(socat)
1670
    if result.failed:
1671
      msg = ("Failed to send command '%s' to instance %s."
1672
             " output: %s, error: %s, fail_reason: %s" %
1673
             (command, instance_name,
1674
              result.stdout, result.stderr, result.fail_reason))
1675
      raise errors.HypervisorError(msg)
1676

    
1677
    return result
1678

    
1679
  @classmethod
1680
  def _ParseKVMVersion(cls, text):
1681
    """Parse the KVM version from the --help output.
1682

1683
    @type text: string
1684
    @param text: output of kvm --help
1685
    @return: (version, v_maj, v_min, v_rev)
1686
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1687

1688
    """
1689
    match = cls._VERSION_RE.search(text.splitlines()[0])
1690
    if not match:
1691
      raise errors.HypervisorError("Unable to get KVM version")
1692

    
1693
    v_all = match.group(0)
1694
    v_maj = int(match.group(1))
1695
    v_min = int(match.group(2))
1696
    if match.group(4):
1697
      v_rev = int(match.group(4))
1698
    else:
1699
      v_rev = 0
1700
    return (v_all, v_maj, v_min, v_rev)
1701

    
1702
  @classmethod
1703
  def _GetKVMOutput(cls, kvm_path, option):
1704
    """Return the output of a kvm invocation
1705

1706
    @return: output a supported kvm invocation
1707
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1708

1709
    """
1710
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
1711

    
1712
    result = utils.RunCmd([kvm_path] + cls._KVMOPTS_CMDS[option])
1713
    if result.failed:
1714
      raise errors.HypervisorError("Unable to get KVM % output" %
1715
                                    ' '.join(cls._KVMOPTS_CMDS[option]))
1716
    return result.output
1717

    
1718
  @classmethod
1719
  def _GetKVMVersion(cls, kvm_path):
1720
    """Return the installed KVM version.
1721

1722
    @return: (version, v_maj, v_min, v_rev)
1723
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1724

1725
    """
1726
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
1727

    
1728
  @classmethod
1729
  def _GetDefaultMachineVersion(cls, kvm_path):
1730
    """Return the default hardware revision (e.g. pc-1.1)
1731

1732
    """
1733
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
1734
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
1735
    if match:
1736
      return match.group(1)
1737
    else:
1738
      return "pc"
1739

    
1740
  def StopInstance(self, instance, force=False, retry=False, name=None):
1741
    """Stop an instance.
1742

1743
    """
1744
    if name is not None and not force:
1745
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1746
    if name is None:
1747
      name = instance.name
1748
      acpi = instance.hvparams[constants.HV_ACPI]
1749
    else:
1750
      acpi = False
1751
    _, pid, alive = self._InstancePidAlive(name)
1752
    if pid > 0 and alive:
1753
      if force or not acpi:
1754
        utils.KillProcess(pid)
1755
      else:
1756
        self._CallMonitorCommand(name, "system_powerdown")
1757

    
1758
  def CleanupInstance(self, instance_name):
1759
    """Cleanup after a stopped instance
1760

1761
    """
1762
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
1763
    if pid > 0 and alive:
1764
      raise errors.HypervisorError("Cannot cleanup a live instance")
1765
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1766

    
1767
  def RebootInstance(self, instance):
1768
    """Reboot an instance.
1769

1770
    """
1771
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1772
    # socket the instance will stop, but now power up again. So we'll resort
1773
    # to shutdown and restart.
1774
    _, _, alive = self._InstancePidAlive(instance.name)
1775
    if not alive:
1776
      raise errors.HypervisorError("Failed to reboot instance %s:"
1777
                                   " not running" % instance.name)
1778
    # StopInstance will delete the saved KVM runtime so:
1779
    # ...first load it...
1780
    kvm_runtime = self._LoadKVMRuntime(instance)
1781
    # ...now we can safely call StopInstance...
1782
    if not self.StopInstance(instance):
1783
      self.StopInstance(instance, force=True)
1784
    # ...and finally we can save it again, and execute it...
1785
    self._SaveKVMRuntime(instance, kvm_runtime)
1786
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1787
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1788
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1789

    
1790
  def MigrationInfo(self, instance):
1791
    """Get instance information to perform a migration.
1792

1793
    @type instance: L{objects.Instance}
1794
    @param instance: instance to be migrated
1795
    @rtype: string
1796
    @return: content of the KVM runtime file
1797

1798
    """
1799
    return self._ReadKVMRuntime(instance.name)
1800

    
1801
  def AcceptInstance(self, instance, info, target):
1802
    """Prepare to accept an instance.
1803

1804
    @type instance: L{objects.Instance}
1805
    @param instance: instance to be accepted
1806
    @type info: string
1807
    @param info: content of the KVM runtime file on the source node
1808
    @type target: string
1809
    @param target: target host (usually ip), on this node
1810

1811
    """
1812
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1813
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1814
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1815
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1816
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
1817
                            incoming=incoming_address)
1818

    
1819
  def FinalizeMigrationDst(self, instance, info, success):
1820
    """Finalize the instance migration on the target node.
1821

1822
    Stop the incoming mode KVM.
1823

1824
    @type instance: L{objects.Instance}
1825
    @param instance: instance whose migration is being finalized
1826

1827
    """
1828
    if success:
1829
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1830
      kvm_nics = kvm_runtime[1]
1831

    
1832
      for nic_seq, nic in enumerate(kvm_nics):
1833
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1834
          # Bridged interfaces have already been configured
1835
          continue
1836
        try:
1837
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1838
        except EnvironmentError, err:
1839
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
1840
                          instance.name, nic_seq, str(err))
1841
          continue
1842
        try:
1843
          self._ConfigureNIC(instance, nic_seq, nic, tap)
1844
        except errors.HypervisorError, err:
1845
          logging.warning(str(err))
1846

    
1847
      self._WriteKVMRuntime(instance.name, info)
1848
    else:
1849
      self.StopInstance(instance, force=True)
1850

    
1851
  def MigrateInstance(self, instance, target, live):
1852
    """Migrate an instance to a target node.
1853

1854
    The migration will not be attempted if the instance is not
1855
    currently running.
1856

1857
    @type instance: L{objects.Instance}
1858
    @param instance: the instance to be migrated
1859
    @type target: string
1860
    @param target: ip address of the target node
1861
    @type live: boolean
1862
    @param live: perform a live migration
1863

1864
    """
1865
    instance_name = instance.name
1866
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
1867
    _, _, alive = self._InstancePidAlive(instance_name)
1868
    if not alive:
1869
      raise errors.HypervisorError("Instance not running, cannot migrate")
1870

    
1871
    if not live:
1872
      self._CallMonitorCommand(instance_name, "stop")
1873

    
1874
    migrate_command = ("migrate_set_speed %dm" %
1875
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1876
    self._CallMonitorCommand(instance_name, migrate_command)
1877

    
1878
    migrate_command = ("migrate_set_downtime %dms" %
1879
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1880
    self._CallMonitorCommand(instance_name, migrate_command)
1881

    
1882
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1883
    self._CallMonitorCommand(instance_name, migrate_command)
1884

    
1885
  def FinalizeMigrationSource(self, instance, success, live):
1886
    """Finalize the instance migration on the source node.
1887

1888
    @type instance: L{objects.Instance}
1889
    @param instance: the instance that was migrated
1890
    @type success: bool
1891
    @param success: whether the migration succeeded or not
1892
    @type live: bool
1893
    @param live: whether the user requested a live migration or not
1894

1895
    """
1896
    if success:
1897
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
1898
      utils.KillProcess(pid)
1899
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1900
    elif live:
1901
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1902

    
1903
  def GetMigrationStatus(self, instance):
1904
    """Get the migration status
1905

1906
    @type instance: L{objects.Instance}
1907
    @param instance: the instance that is being migrated
1908
    @rtype: L{objects.MigrationStatus}
1909
    @return: the status of the current migration (one of
1910
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1911
             progress info that can be retrieved from the hypervisor
1912

1913
    """
1914
    info_command = "info migrate"
1915
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
1916
      result = self._CallMonitorCommand(instance.name, info_command)
1917
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
1918
      if not match:
1919
        if not result.stdout:
1920
          logging.info("KVM: empty 'info migrate' result")
1921
        else:
1922
          logging.warning("KVM: unknown 'info migrate' result: %s",
1923
                          result.stdout)
1924
      else:
1925
        status = match.group(1)
1926
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
1927
          migration_status = objects.MigrationStatus(status=status)
1928
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
1929
          if match:
1930
            migration_status.transferred_ram = match.group("transferred")
1931
            migration_status.total_ram = match.group("total")
1932

    
1933
          return migration_status
1934

    
1935
        logging.warning("KVM: unknown migration status '%s'", status)
1936

    
1937
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1938

    
1939
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
1940

    
1941
  def BalloonInstanceMemory(self, instance, mem):
1942
    """Balloon an instance memory to a certain value.
1943

1944
    @type instance: L{objects.Instance}
1945
    @param instance: instance to be accepted
1946
    @type mem: int
1947
    @param mem: actual memory size to use for instance runtime
1948

1949
    """
1950
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
1951

    
1952
  def GetNodeInfo(self):
1953
    """Return information about the node.
1954

1955
    @return: a dict with the following keys (values in MiB):
1956
          - memory_total: the total memory size on the node
1957
          - memory_free: the available memory on the node for instances
1958
          - memory_dom0: the memory used by the node itself, if available
1959
          - hv_version: the hypervisor version in the form (major, minor,
1960
                        revision)
1961

1962
    """
1963
    result = self.GetLinuxNodeInfo()
1964
    # FIXME: this is the global kvm version, but the actual version can be
1965
    # customized as an hv parameter. we should use the nodegroup's default kvm
1966
    # path parameter here.
1967
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
1968
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
1969
    return result
1970

    
1971
  @classmethod
1972
  def GetInstanceConsole(cls, instance, hvparams, beparams):
1973
    """Return a command for connecting to the console of an instance.
1974

1975
    """
1976
    if hvparams[constants.HV_SERIAL_CONSOLE]:
1977
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
1978
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1979
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1980
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
1981
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1982
      return objects.InstanceConsole(instance=instance.name,
1983
                                     kind=constants.CONS_SSH,
1984
                                     host=instance.primary_node,
1985
                                     user=constants.SSH_CONSOLE_USER,
1986
                                     command=cmd)
1987

    
1988
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1989
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1990
      display = instance.network_port - constants.VNC_BASE_PORT
1991
      return objects.InstanceConsole(instance=instance.name,
1992
                                     kind=constants.CONS_VNC,
1993
                                     host=vnc_bind_address,
1994
                                     port=instance.network_port,
1995
                                     display=display)
1996

    
1997
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1998
    if spice_bind:
1999
      return objects.InstanceConsole(instance=instance.name,
2000
                                     kind=constants.CONS_SPICE,
2001
                                     host=spice_bind,
2002
                                     port=instance.network_port)
2003

    
2004
    return objects.InstanceConsole(instance=instance.name,
2005
                                   kind=constants.CONS_MESSAGE,
2006
                                   message=("No serial shell for instance %s" %
2007
                                            instance.name))
2008

    
2009
  def Verify(self):
2010
    """Verify the hypervisor.
2011

2012
    Check that the binary exists.
2013

2014
    """
2015
    # FIXME: this is the global kvm version, but the actual version can be
2016
    # customized as an hv parameter. we should use the nodegroup's default kvm
2017
    # path parameter here.
2018
    if not os.path.exists(constants.KVM_PATH):
2019
      return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
2020
    if not os.path.exists(constants.SOCAT_PATH):
2021
      return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
2022

    
2023
  @classmethod
2024
  def CheckParameterSyntax(cls, hvparams):
2025
    """Check the given parameters for validity.
2026

2027
    @type hvparams:  dict
2028
    @param hvparams: dictionary with parameter names/value
2029
    @raise errors.HypervisorError: when a parameter is not valid
2030

2031
    """
2032
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2033

    
2034
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2035
    if kernel_path:
2036
      if not hvparams[constants.HV_ROOT_PATH]:
2037
        raise errors.HypervisorError("Need a root partition for the instance,"
2038
                                     " if a kernel is defined")
2039

    
2040
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2041
        not hvparams[constants.HV_VNC_X509]):
2042
      raise errors.HypervisorError("%s must be defined, if %s is" %
2043
                                   (constants.HV_VNC_X509,
2044
                                    constants.HV_VNC_X509_VERIFY))
2045

    
2046
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2047
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2048
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2049
      if not serial_speed or serial_speed not in valid_speeds:
2050
        raise errors.HypervisorError("Invalid serial console speed, must be"
2051
                                     " one of: %s" %
2052
                                     utils.CommaJoin(valid_speeds))
2053

    
2054
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2055
    if (boot_order == constants.HT_BO_CDROM and
2056
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2057
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2058
                                   " ISO path")
2059

    
2060
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2061
    if security_model == constants.HT_SM_USER:
2062
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2063
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2064
                                     " must be specified")
2065
    elif (security_model == constants.HT_SM_NONE or
2066
          security_model == constants.HT_SM_POOL):
2067
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2068
        raise errors.HypervisorError("Cannot have a security domain when the"
2069
                                     " security model is 'none' or 'pool'")
2070

    
2071
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2072
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2073
    if spice_bind:
2074
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2075
        # if an IP version is specified, the spice_bind parameter must be an
2076
        # IP of that family
2077
        if (netutils.IP4Address.IsValid(spice_bind) and
2078
            spice_ip_version != constants.IP4_VERSION):
2079
          raise errors.HypervisorError("spice: got an IPv4 address (%s), but"
2080
                                       " the specified IP version is %s" %
2081
                                       (spice_bind, spice_ip_version))
2082

    
2083
        if (netutils.IP6Address.IsValid(spice_bind) and
2084
            spice_ip_version != constants.IP6_VERSION):
2085
          raise errors.HypervisorError("spice: got an IPv6 address (%s), but"
2086
                                       " the specified IP version is %s" %
2087
                                       (spice_bind, spice_ip_version))
2088
    else:
2089
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2090
      # error if any of them is set without it.
2091
      for param in _SPICE_ADDITIONAL_PARAMS:
2092
        if hvparams[param]:
2093
          raise errors.HypervisorError("spice: %s requires %s to be set" %
2094
                                       (param, constants.HV_KVM_SPICE_BIND))
2095

    
2096
  @classmethod
2097
  def ValidateParameters(cls, hvparams):
2098
    """Check the given parameters for validity.
2099

2100
    @type hvparams:  dict
2101
    @param hvparams: dictionary with parameter names/value
2102
    @raise errors.HypervisorError: when a parameter is not valid
2103

2104
    """
2105
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2106

    
2107
    kvm_path = hvparams[constants.HV_KVM_PATH]
2108

    
2109
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2110
    if security_model == constants.HT_SM_USER:
2111
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2112
      try:
2113
        pwd.getpwnam(username)
2114
      except KeyError:
2115
        raise errors.HypervisorError("Unknown security domain user %s"
2116
                                     % username)
2117

    
2118
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2119
    if spice_bind:
2120
      # only one of VNC and SPICE can be used currently.
2121
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2122
        raise errors.HypervisorError("both SPICE and VNC are configured, but"
2123
                                     " only one of them can be used at a"
2124
                                     " given time.")
2125

    
2126
      # check that KVM supports SPICE
2127
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2128
      if not cls._SPICE_RE.search(kvmhelp):
2129
        raise errors.HypervisorError("spice is configured, but it is not"
2130
                                     " supported according to kvm --help")
2131

    
2132
      # if spice_bind is not an IP address, it must be a valid interface
2133
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind)
2134
                       or netutils.IP6Address.IsValid(spice_bind))
2135
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2136
        raise errors.HypervisorError("spice: the %s parameter must be either"
2137
                                     " a valid IP address or interface name" %
2138
                                     constants.HV_KVM_SPICE_BIND)
2139

    
2140
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2141
    if machine_version:
2142
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2143
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2144
        raise errors.HypervisorError("Unsupported machine version: %s" %
2145
                                     machine_version)
2146

    
2147
  @classmethod
2148
  def PowercycleNode(cls):
2149
    """KVM powercycle, just a wrapper over Linux powercycle.
2150

2151
    """
2152
    cls.LinuxPowercycle()