Statistics
| Branch: | Tag: | Revision:

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

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

    
541
  _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
542
                                    re.M | re.I)
543
  _MIGRATION_PROGRESS_RE = \
544
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
545
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
546
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
547

    
548
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
549
  _MIGRATION_INFO_RETRY_DELAY = 2
550

    
551
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
552

    
553
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
554
  _CPU_INFO_CMD = "info cpus"
555
  _CONT_CMD = "cont"
556

    
557
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
558

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

    
570
  ANCILLARY_FILES = [
571
    _KVM_NETWORK_SCRIPT,
572
    ]
573
  ANCILLARY_FILES_OPT = [
574
    _KVM_NETWORK_SCRIPT,
575
    ]
576

    
577
  def __init__(self):
578
    hv_base.BaseHypervisor.__init__(self)
579
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
580
    # in a tmpfs filesystem or has been otherwise wiped out.
581
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
582
    utils.EnsureDirs(dirs)
583

    
584
  @classmethod
585
  def _InstancePidFile(cls, instance_name):
586
    """Returns the instance pidfile.
587

588
    """
589
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
590

    
591
  @classmethod
592
  def _InstanceUidFile(cls, instance_name):
593
    """Returns the instance uidfile.
594

595
    """
596
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
597

    
598
  @classmethod
599
  def _InstancePidInfo(cls, pid):
600
    """Check pid file for instance information.
601

602
    Check that a pid file is associated with an instance, and retrieve
603
    information from its command line.
604

605
    @type pid: string or int
606
    @param pid: process id of the instance to check
607
    @rtype: tuple
608
    @return: (instance_name, memory, vcpus)
609
    @raise errors.HypervisorError: when an instance cannot be found
610

611
    """
612
    alive = utils.IsProcessAlive(pid)
613
    if not alive:
614
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
615

    
616
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
617
    try:
618
      cmdline = utils.ReadFile(cmdline_file)
619
    except EnvironmentError, err:
620
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
621
                                   (pid, err))
622

    
623
    instance = None
624
    memory = 0
625
    vcpus = 0
626

    
627
    arg_list = cmdline.split("\x00")
628
    while arg_list:
629
      arg = arg_list.pop(0)
630
      if arg == "-name":
631
        instance = arg_list.pop(0)
632
      elif arg == "-m":
633
        memory = int(arg_list.pop(0))
634
      elif arg == "-smp":
635
        vcpus = int(arg_list.pop(0).split(",")[0])
636

    
637
    if instance is None:
638
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
639
                                   " instance" % pid)
640

    
641
    return (instance, memory, vcpus)
642

    
643
  def _InstancePidAlive(self, instance_name):
644
    """Returns the instance pidfile, pid, and liveness.
645

646
    @type instance_name: string
647
    @param instance_name: instance name
648
    @rtype: tuple
649
    @return: (pid file name, pid, liveness)
650

651
    """
652
    pidfile = self._InstancePidFile(instance_name)
653
    pid = utils.ReadPidFile(pidfile)
654

    
655
    alive = False
656
    try:
657
      cmd_instance = self._InstancePidInfo(pid)[0]
658
      alive = (cmd_instance == instance_name)
659
    except errors.HypervisorError:
660
      pass
661

    
662
    return (pidfile, pid, alive)
663

    
664
  def _CheckDown(self, instance_name):
665
    """Raises an error unless the given instance is down.
666

667
    """
668
    alive = self._InstancePidAlive(instance_name)[2]
669
    if alive:
670
      raise errors.HypervisorError("Failed to start instance %s: %s" %
671
                                   (instance_name, "already running"))
672

    
673
  @classmethod
674
  def _InstanceMonitor(cls, instance_name):
675
    """Returns the instance monitor socket name
676

677
    """
678
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
679

    
680
  @classmethod
681
  def _InstanceSerial(cls, instance_name):
682
    """Returns the instance serial socket name
683

684
    """
685
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
686

    
687
  @classmethod
688
  def _InstanceQmpMonitor(cls, instance_name):
689
    """Returns the instance serial QMP socket name
690

691
    """
692
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
693

    
694
  @staticmethod
695
  def _SocatUnixConsoleParams():
696
    """Returns the correct parameters for socat
697

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

700
    """
701
    if constants.SOCAT_USE_ESCAPE:
702
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
703
    else:
704
      return "echo=0,icanon=0"
705

    
706
  @classmethod
707
  def _InstanceKVMRuntime(cls, instance_name):
708
    """Returns the instance KVM runtime filename
709

710
    """
711
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
712

    
713
  @classmethod
714
  def _InstanceChrootDir(cls, instance_name):
715
    """Returns the name of the KVM chroot dir of the instance
716

717
    """
718
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
719

    
720
  @classmethod
721
  def _InstanceNICDir(cls, instance_name):
722
    """Returns the name of the directory holding the tap device files for a
723
    given instance.
724

725
    """
726
    return utils.PathJoin(cls._NICS_DIR, instance_name)
727

    
728
  @classmethod
729
  def _InstanceNICFile(cls, instance_name, seq):
730
    """Returns the name of the file containing the tap device for a given NIC
731

732
    """
733
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
734

    
735
  @classmethod
736
  def _InstanceKeymapFile(cls, instance_name):
737
    """Returns the name of the file containing the keymap for a given instance
738

739
    """
740
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
741

    
742
  @classmethod
743
  def _TryReadUidFile(cls, uid_file):
744
    """Try to read a uid file
745

746
    """
747
    if os.path.exists(uid_file):
748
      try:
749
        uid = int(utils.ReadOneLineFile(uid_file))
750
        return uid
751
      except EnvironmentError:
752
        logging.warning("Can't read uid file", exc_info=True)
753
      except (TypeError, ValueError):
754
        logging.warning("Can't parse uid file contents", exc_info=True)
755
    return None
756

    
757
  @classmethod
758
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
759
    """Removes an instance's rutime sockets/files/dirs.
760

761
    """
762
    utils.RemoveFile(pidfile)
763
    utils.RemoveFile(cls._InstanceMonitor(instance_name))
764
    utils.RemoveFile(cls._InstanceSerial(instance_name))
765
    utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
766
    utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
767
    utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
768
    uid_file = cls._InstanceUidFile(instance_name)
769
    uid = cls._TryReadUidFile(uid_file)
770
    utils.RemoveFile(uid_file)
771
    if uid is not None:
772
      uidpool.ReleaseUid(uid)
773
    try:
774
      shutil.rmtree(cls._InstanceNICDir(instance_name))
775
    except OSError, err:
776
      if err.errno != errno.ENOENT:
777
        raise
778
    try:
779
      chroot_dir = cls._InstanceChrootDir(instance_name)
780
      utils.RemoveDir(chroot_dir)
781
    except OSError, err:
782
      if err.errno == errno.ENOTEMPTY:
783
        # The chroot directory is expected to be empty, but it isn't.
784
        new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
785
                                          prefix="%s-%s-" %
786
                                          (instance_name,
787
                                           utils.TimestampForFilename()))
788
        logging.warning("The chroot directory of instance %s can not be"
789
                        " removed as it is not empty. Moving it to the"
790
                        " quarantine instead. Please investigate the"
791
                        " contents (%s) and clean up manually",
792
                        instance_name, new_chroot_dir)
793
        utils.RenameFile(chroot_dir, new_chroot_dir)
794
      else:
795
        raise
796

    
797
  @staticmethod
798
  def _ConfigureNIC(instance, seq, nic, tap):
799
    """Run the network configuration script for a specified NIC
800

801
    @param instance: instance we're acting on
802
    @type instance: instance object
803
    @param seq: nic sequence number
804
    @type seq: int
805
    @param nic: nic we're acting on
806
    @type nic: nic object
807
    @param tap: the host's tap interface this NIC corresponds to
808
    @type tap: str
809

810
    """
811
    if instance.tags:
812
      tags = " ".join(instance.tags)
813
    else:
814
      tags = ""
815

    
816
    env = {
817
      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
818
      "INSTANCE": instance.name,
819
      "MAC": nic.mac,
820
      "MODE": nic.nicparams[constants.NIC_MODE],
821
      "INTERFACE": tap,
822
      "INTERFACE_INDEX": str(seq),
823
      "TAGS": tags,
824
    }
825

    
826
    if nic.ip:
827
      env["IP"] = nic.ip
828

    
829
    if nic.nicparams[constants.NIC_LINK]:
830
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
831

    
832
    if nic.network:
833
      n = objects.Network.FromDict(nic.netinfo)
834
      _BuildNetworkEnv(nic.network, n.network, n.gateway,
835
                       n.network6, n.gateway6, n.network_type,
836
                       n.mac_prefix, n.tags, env)
837

    
838
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
839
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
840

    
841
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
842
    if result.failed:
843
      raise errors.HypervisorError("Failed to configure interface %s: %s."
844
                                   " Network configuration script output: %s" %
845
                                   (tap, result.fail_reason, result.output))
846

    
847
  @staticmethod
848
  def _VerifyAffinityPackage():
849
    if affinity is None:
850
      raise errors.HypervisorError("affinity Python package not"
851
                                   " found; cannot use CPU pinning under KVM")
852

    
853
  @staticmethod
854
  def _BuildAffinityCpuMask(cpu_list):
855
    """Create a CPU mask suitable for sched_setaffinity from a list of
856
    CPUs.
857

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

861
    @type cpu_list: list of int
862
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
863
    @rtype: int
864
    @return: a bit mask of CPU affinities
865

866
    """
867
    if cpu_list == constants.CPU_PINNING_OFF:
868
      return constants.CPU_PINNING_ALL_KVM
869
    else:
870
      return sum(2 ** cpu for cpu in cpu_list)
871

    
872
  @classmethod
873
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
874
    """Change CPU affinity for running VM according to given CPU mask.
875

876
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
877
    @type cpu_mask: string
878
    @param process_id: process ID of KVM process. Used to pin entire VM
879
                       to physical CPUs.
880
    @type process_id: int
881
    @param thread_dict: map of virtual CPUs to KVM thread IDs
882
    @type thread_dict: dict int:int
883

884
    """
885
    # Convert the string CPU mask to a list of list of int's
886
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
887

    
888
    if len(cpu_list) == 1:
889
      all_cpu_mapping = cpu_list[0]
890
      if all_cpu_mapping == constants.CPU_PINNING_OFF:
891
        # If CPU pinning has 1 entry that's "all", then do nothing
892
        pass
893
      else:
894
        # If CPU pinning has one non-all entry, map the entire VM to
895
        # one set of physical CPUs
896
        cls._VerifyAffinityPackage()
897
        affinity.set_process_affinity_mask(
898
          process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
899
    else:
900
      # The number of vCPUs mapped should match the number of vCPUs
901
      # reported by KVM. This was already verified earlier, so
902
      # here only as a sanity check.
903
      assert len(thread_dict) == len(cpu_list)
904
      cls._VerifyAffinityPackage()
905

    
906
      # For each vCPU, map it to the proper list of physical CPUs
907
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
908
        affinity.set_process_affinity_mask(thread_dict[i],
909
                                           cls._BuildAffinityCpuMask(vcpu))
910

    
911
  def _GetVcpuThreadIds(self, instance_name):
912
    """Get a mapping of vCPU no. to thread IDs for the instance
913

914
    @type instance_name: string
915
    @param instance_name: instance in question
916
    @rtype: dictionary of int:int
917
    @return: a dictionary mapping vCPU numbers to thread IDs
918

919
    """
920
    result = {}
921
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
922
    for line in output.stdout.splitlines():
923
      match = self._CPU_INFO_RE.search(line)
924
      if not match:
925
        continue
926
      grp = map(int, match.groups())
927
      result[grp[0]] = grp[1]
928

    
929
    return result
930

    
931
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
932
    """Complete CPU pinning.
933

934
    @type instance_name: string
935
    @param instance_name: name of instance
936
    @type cpu_mask: string
937
    @param cpu_mask: CPU pinning mask as entered by user
938

939
    """
940
    # Get KVM process ID, to be used if need to pin entire VM
941
    _, pid, _ = self._InstancePidAlive(instance_name)
942
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
943
    thread_dict = self._GetVcpuThreadIds(instance_name)
944
    # Run CPU pinning, based on configured mask
945
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
946

    
947
  def ListInstances(self):
948
    """Get the list of running instances.
949

950
    We can do this by listing our live instances directory and
951
    checking whether the associated kvm process is still alive.
952

953
    """
954
    result = []
955
    for name in os.listdir(self._PIDS_DIR):
956
      if self._InstancePidAlive(name)[2]:
957
        result.append(name)
958
    return result
959

    
960
  def GetInstanceInfo(self, instance_name):
961
    """Get instance properties.
962

963
    @type instance_name: string
964
    @param instance_name: the instance name
965
    @rtype: tuple of strings
966
    @return: (name, id, memory, vcpus, stat, times)
967

968
    """
969
    _, pid, alive = self._InstancePidAlive(instance_name)
970
    if not alive:
971
      return None
972

    
973
    _, memory, vcpus = self._InstancePidInfo(pid)
974
    istat = "---b-"
975
    times = "0"
976

    
977
    try:
978
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
979
      qmp.connect()
980
      vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
981
      # Will fail if ballooning is not enabled, but we can then just resort to
982
      # the value above.
983
      mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
984
      memory = mem_bytes / 1048576
985
    except errors.HypervisorError:
986
      pass
987

    
988
    return (instance_name, pid, memory, vcpus, istat, times)
989

    
990
  def GetAllInstancesInfo(self):
991
    """Get properties of all instances.
992

993
    @return: list of tuples (name, id, memory, vcpus, stat, times)
994

995
    """
996
    data = []
997
    for name in os.listdir(self._PIDS_DIR):
998
      try:
999
        info = self.GetInstanceInfo(name)
1000
      except errors.HypervisorError:
1001
        # Ignore exceptions due to instances being shut down
1002
        continue
1003
      if info:
1004
        data.append(info)
1005
    return data
1006

    
1007
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused):
1008
    """Generate KVM information to start an instance.
1009

1010
    @attention: this function must not have any side-effects; for
1011
        example, it must not write to the filesystem, or read values
1012
        from the current system the are expected to differ between
1013
        nodes, since it is only run once at instance startup;
1014
        actions/kvm arguments that can vary between systems should be
1015
        done in L{_ExecuteKVMRuntime}
1016

1017
    """
1018
    # pylint: disable=R0912,R0914,R0915
1019
    kvmhelp = self._GetKVMHelpOutput()
1020
    hvp = instance.hvparams
1021

    
1022
    pidfile = self._InstancePidFile(instance.name)
1023
    kvm = constants.KVM_PATH
1024
    kvm_cmd = [kvm]
1025
    kvm_cmd.extend(["-M", self._GetDefaultMachineVersion()])
1026
    # used just by the vnc server, if enabled
1027
    kvm_cmd.extend(["-name", instance.name])
1028
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1029

    
1030
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1031
    if hvp[constants.HV_CPU_CORES]:
1032
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1033
    if hvp[constants.HV_CPU_THREADS]:
1034
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1035
    if hvp[constants.HV_CPU_SOCKETS]:
1036
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1037

    
1038
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1039

    
1040
    kvm_cmd.extend(["-pidfile", pidfile])
1041
    kvm_cmd.extend(["-balloon", "virtio"])
1042
    kvm_cmd.extend(["-daemonize"])
1043
    if not instance.hvparams[constants.HV_ACPI]:
1044
      kvm_cmd.extend(["-no-acpi"])
1045
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1046
        constants.INSTANCE_REBOOT_EXIT:
1047
      kvm_cmd.extend(["-no-reboot"])
1048

    
1049
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1050
    if kernel_path:
1051
      boot_disk = boot_cdrom = boot_floppy = boot_network = False
1052
    else:
1053
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1054
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1055
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1056
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1057

    
1058
    self.ValidateParameters(hvp)
1059

    
1060
    if startup_paused:
1061
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1062

    
1063
    if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1064
        self._ENABLE_KVM_RE.search(kvmhelp)):
1065
      kvm_cmd.extend(["-enable-kvm"])
1066
    elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1067
          self._DISABLE_KVM_RE.search(kvmhelp)):
1068
      kvm_cmd.extend(["-disable-kvm"])
1069

    
1070
    if boot_network:
1071
      kvm_cmd.extend(["-boot", "n"])
1072

    
1073
    # whether this is an older KVM version that uses the boot=on flag
1074
    # on devices
1075
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1076

    
1077
    disk_type = hvp[constants.HV_DISK_TYPE]
1078
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
1079
      if_val = ",if=virtio"
1080
    else:
1081
      if_val = ",if=%s" % disk_type
1082
    # Cache mode
1083
    disk_cache = hvp[constants.HV_DISK_CACHE]
1084
    if instance.disk_template in constants.DTS_EXT_MIRROR:
1085
      if disk_cache != "none":
1086
        # TODO: make this a hard error, instead of a silent overwrite
1087
        logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1088
                        " to prevent shared storage corruption on migration",
1089
                        disk_cache)
1090
      cache_val = ",cache=none"
1091
    elif disk_cache != constants.HT_CACHE_DEFAULT:
1092
      cache_val = ",cache=%s" % disk_cache
1093
    else:
1094
      cache_val = ""
1095
    for cfdev, dev_path in block_devices:
1096
      if cfdev.mode != constants.DISK_RDWR:
1097
        raise errors.HypervisorError("Instance has read-only disks which"
1098
                                     " are not supported by KVM")
1099
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
1100
      boot_val = ""
1101
      if boot_disk:
1102
        kvm_cmd.extend(["-boot", "c"])
1103
        boot_disk = False
1104
        if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1105
          boot_val = ",boot=on"
1106

    
1107
      drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
1108
                                                cache_val)
1109
      kvm_cmd.extend(["-drive", drive_val])
1110

    
1111
    #Now we can specify a different device type for CDROM devices.
1112
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1113
    if not cdrom_disk_type:
1114
      cdrom_disk_type = disk_type
1115

    
1116
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1117
    if iso_image:
1118
      options = ",format=raw,media=cdrom"
1119
      # set cdrom 'if' type
1120
      if boot_cdrom:
1121
        actual_cdrom_type = constants.HT_DISK_IDE
1122
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1123
        actual_cdrom_type = "virtio"
1124
      else:
1125
        actual_cdrom_type = cdrom_disk_type
1126
      if_val = ",if=%s" % actual_cdrom_type
1127
      # set boot flag, if needed
1128
      boot_val = ""
1129
      if boot_cdrom:
1130
        kvm_cmd.extend(["-boot", "d"])
1131
        if needs_boot_flag:
1132
          boot_val = ",boot=on"
1133
      # and finally build the entire '-drive' value
1134
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1135
      kvm_cmd.extend(["-drive", drive_val])
1136

    
1137
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1138
    if iso_image2:
1139
      options = ",format=raw,media=cdrom"
1140
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1141
        if_val = ",if=virtio"
1142
      else:
1143
        if_val = ",if=%s" % cdrom_disk_type
1144
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1145
      kvm_cmd.extend(["-drive", drive_val])
1146

    
1147
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1148
    if floppy_image:
1149
      options = ",format=raw,media=disk"
1150
      if boot_floppy:
1151
        kvm_cmd.extend(["-boot", "a"])
1152
        options = "%s,boot=on" % options
1153
      if_val = ",if=floppy"
1154
      options = "%s%s" % (options, if_val)
1155
      drive_val = "file=%s%s" % (floppy_image, options)
1156
      kvm_cmd.extend(["-drive", drive_val])
1157

    
1158
    if kernel_path:
1159
      kvm_cmd.extend(["-kernel", kernel_path])
1160
      initrd_path = hvp[constants.HV_INITRD_PATH]
1161
      if initrd_path:
1162
        kvm_cmd.extend(["-initrd", initrd_path])
1163
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1164
                     hvp[constants.HV_KERNEL_ARGS]]
1165
      if hvp[constants.HV_SERIAL_CONSOLE]:
1166
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1167
        root_append.append("console=ttyS0,%s" % serial_speed)
1168
      kvm_cmd.extend(["-append", " ".join(root_append)])
1169

    
1170
    mem_path = hvp[constants.HV_MEM_PATH]
1171
    if mem_path:
1172
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1173

    
1174
    monitor_dev = ("unix:%s,server,nowait" %
1175
                   self._InstanceMonitor(instance.name))
1176
    kvm_cmd.extend(["-monitor", monitor_dev])
1177
    if hvp[constants.HV_SERIAL_CONSOLE]:
1178
      serial_dev = ("unix:%s,server,nowait" %
1179
                    self._InstanceSerial(instance.name))
1180
      kvm_cmd.extend(["-serial", serial_dev])
1181
    else:
1182
      kvm_cmd.extend(["-serial", "none"])
1183

    
1184
    mouse_type = hvp[constants.HV_USB_MOUSE]
1185
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1186
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1187
    spice_ip_version = None
1188

    
1189
    kvm_cmd.extend(["-usb"])
1190

    
1191
    if mouse_type:
1192
      kvm_cmd.extend(["-usbdevice", mouse_type])
1193
    elif vnc_bind_address:
1194
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1195

    
1196
    if vnc_bind_address:
1197
      if netutils.IP4Address.IsValid(vnc_bind_address):
1198
        if instance.network_port > constants.VNC_BASE_PORT:
1199
          display = instance.network_port - constants.VNC_BASE_PORT
1200
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1201
            vnc_arg = ":%d" % (display)
1202
          else:
1203
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1204
        else:
1205
          logging.error("Network port is not a valid VNC display (%d < %d)."
1206
                        " Not starting VNC", instance.network_port,
1207
                        constants.VNC_BASE_PORT)
1208
          vnc_arg = "none"
1209

    
1210
        # Only allow tls and other option when not binding to a file, for now.
1211
        # kvm/qemu gets confused otherwise about the filename to use.
1212
        vnc_append = ""
1213
        if hvp[constants.HV_VNC_TLS]:
1214
          vnc_append = "%s,tls" % vnc_append
1215
          if hvp[constants.HV_VNC_X509_VERIFY]:
1216
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1217
                                               hvp[constants.HV_VNC_X509])
1218
          elif hvp[constants.HV_VNC_X509]:
1219
            vnc_append = "%s,x509=%s" % (vnc_append,
1220
                                         hvp[constants.HV_VNC_X509])
1221
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1222
          vnc_append = "%s,password" % vnc_append
1223

    
1224
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1225

    
1226
      else:
1227
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1228

    
1229
      kvm_cmd.extend(["-vnc", vnc_arg])
1230
    elif spice_bind:
1231
      # FIXME: this is wrong here; the iface ip address differs
1232
      # between systems, so it should be done in _ExecuteKVMRuntime
1233
      if netutils.IsValidInterface(spice_bind):
1234
        # The user specified a network interface, we have to figure out the IP
1235
        # address.
1236
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1237
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1238

    
1239
        # if the user specified an IP version and the interface does not
1240
        # have that kind of IP addresses, throw an exception
1241
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1242
          if not addresses[spice_ip_version]:
1243
            raise errors.HypervisorError("spice: unable to get an IPv%s address"
1244
                                         " for %s" % (spice_ip_version,
1245
                                                      spice_bind))
1246

    
1247
        # the user did not specify an IP version, we have to figure it out
1248
        elif (addresses[constants.IP4_VERSION] and
1249
              addresses[constants.IP6_VERSION]):
1250
          # we have both ipv4 and ipv6, let's use the cluster default IP
1251
          # version
1252
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1253
          spice_ip_version = \
1254
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1255
        elif addresses[constants.IP4_VERSION]:
1256
          spice_ip_version = constants.IP4_VERSION
1257
        elif addresses[constants.IP6_VERSION]:
1258
          spice_ip_version = constants.IP6_VERSION
1259
        else:
1260
          raise errors.HypervisorError("spice: unable to get an IP address"
1261
                                       " for %s" % (spice_bind))
1262

    
1263
        spice_address = addresses[spice_ip_version][0]
1264

    
1265
      else:
1266
        # spice_bind is known to be a valid IP address, because
1267
        # ValidateParameters checked it.
1268
        spice_address = spice_bind
1269

    
1270
      spice_arg = "addr=%s" % spice_address
1271
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1272
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1273
                     (spice_arg, instance.network_port,
1274
                      pathutils.SPICE_CACERT_FILE))
1275
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1276
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1277
                      pathutils.SPICE_CERT_FILE))
1278
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1279
        if tls_ciphers:
1280
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1281
      else:
1282
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1283

    
1284
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1285
        spice_arg = "%s,disable-ticketing" % spice_arg
1286

    
1287
      if spice_ip_version:
1288
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1289

    
1290
      # Image compression options
1291
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1292
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1293
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1294
      if img_lossless:
1295
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1296
      if img_jpeg:
1297
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1298
      if img_zlib_glz:
1299
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1300

    
1301
      # Video stream detection
1302
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1303
      if video_streaming:
1304
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1305

    
1306
      # Audio compression, by default in qemu-kvm it is on
1307
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1308
        spice_arg = "%s,playback-compression=off" % spice_arg
1309
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1310
        spice_arg = "%s,agent-mouse=off" % spice_arg
1311
      else:
1312
        # Enable the spice agent communication channel between the host and the
1313
        # agent.
1314
        kvm_cmd.extend(["-device", "virtio-serial-pci"])
1315
        kvm_cmd.extend(["-device", "virtserialport,chardev=spicechannel0,"
1316
                                                   "name=com.redhat.spice.0"])
1317
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1318

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

    
1322
      # Tell kvm to use the paravirtualized graphic card, optimized for SPICE
1323
      kvm_cmd.extend(["-vga", "qxl"])
1324

    
1325
    else:
1326
      kvm_cmd.extend(["-nographic"])
1327

    
1328
    if hvp[constants.HV_USE_LOCALTIME]:
1329
      kvm_cmd.extend(["-localtime"])
1330

    
1331
    if hvp[constants.HV_KVM_USE_CHROOT]:
1332
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1333

    
1334
    # Add qemu-KVM -cpu param
1335
    if hvp[constants.HV_CPU_TYPE]:
1336
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1337

    
1338
    # As requested by music lovers
1339
    if hvp[constants.HV_SOUNDHW]:
1340
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1341

    
1342
    # Save the current instance nics, but defer their expansion as parameters,
1343
    # as we'll need to generate executable temp files for them.
1344
    kvm_nics = instance.nics
1345
    hvparams = hvp
1346

    
1347
    return (kvm_cmd, kvm_nics, hvparams)
1348

    
1349
  def _WriteKVMRuntime(self, instance_name, data):
1350
    """Write an instance's KVM runtime
1351

1352
    """
1353
    try:
1354
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1355
                      data=data)
1356
    except EnvironmentError, err:
1357
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1358

    
1359
  def _ReadKVMRuntime(self, instance_name):
1360
    """Read an instance's KVM runtime
1361

1362
    """
1363
    try:
1364
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1365
    except EnvironmentError, err:
1366
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1367
    return file_content
1368

    
1369
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1370
    """Save an instance's KVM runtime
1371

1372
    """
1373
    kvm_cmd, kvm_nics, hvparams = kvm_runtime
1374
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1375
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1376
    self._WriteKVMRuntime(instance.name, serialized_form)
1377

    
1378
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1379
    """Load an instance's KVM runtime
1380

1381
    """
1382
    if not serialized_runtime:
1383
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1384
    loaded_runtime = serializer.Load(serialized_runtime)
1385
    kvm_cmd, serialized_nics, hvparams = loaded_runtime
1386
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1387
    return (kvm_cmd, kvm_nics, hvparams)
1388

    
1389
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1390
    """Run the KVM cmd and check for errors
1391

1392
    @type name: string
1393
    @param name: instance name
1394
    @type kvm_cmd: list of strings
1395
    @param kvm_cmd: runcmd input for kvm
1396
    @type tap_fds: list of int
1397
    @param tap_fds: fds of tap devices opened by Ganeti
1398

1399
    """
1400
    try:
1401
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1402
    finally:
1403
      for fd in tap_fds:
1404
        utils_wrapper.CloseFdNoError(fd)
1405

    
1406
    if result.failed:
1407
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1408
                                   (name, result.fail_reason, result.output))
1409
    if not self._InstancePidAlive(name)[2]:
1410
      raise errors.HypervisorError("Failed to start instance %s" % name)
1411

    
1412
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
1413
    """Execute a KVM cmd, after completing it with some last minute data.
1414

1415
    @type incoming: tuple of strings
1416
    @param incoming: (target_host_ip, port)
1417

1418
    """
1419
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1420
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1421
    #    have changed since the instance started; only use them if the change
1422
    #    won't affect the inside of the instance (which hasn't been rebooted).
1423
    #  - up_hvp contains the parameters as they were when the instance was
1424
    #    started, plus any new parameter which has been added between ganeti
1425
    #    versions: it is paramount that those default to a value which won't
1426
    #    affect the inside of the instance as well.
1427
    conf_hvp = instance.hvparams
1428
    name = instance.name
1429
    self._CheckDown(name)
1430

    
1431
    temp_files = []
1432

    
1433
    kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1434
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1435

    
1436
    kvmhelp = self._GetKVMHelpOutput()
1437
    _, v_major, v_min, _ = self._ParseKVMVersion(kvmhelp)
1438

    
1439
    # We know it's safe to run as a different user upon migration, so we'll use
1440
    # the latest conf, from conf_hvp.
1441
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1442
    if security_model == constants.HT_SM_USER:
1443
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1444

    
1445
    keymap = conf_hvp[constants.HV_KEYMAP]
1446
    if keymap:
1447
      keymap_path = self._InstanceKeymapFile(name)
1448
      # If a keymap file is specified, KVM won't use its internal defaults. By
1449
      # first including the "en-us" layout, an error on loading the actual
1450
      # layout (e.g. because it can't be found) won't lead to a non-functional
1451
      # keyboard. A keyboard with incorrect keys is still better than none.
1452
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1453
      kvm_cmd.extend(["-k", keymap_path])
1454

    
1455
    # We have reasons to believe changing something like the nic driver/type
1456
    # upon migration won't exactly fly with the instance kernel, so for nic
1457
    # related parameters we'll use up_hvp
1458
    tapfds = []
1459
    taps = []
1460
    if not kvm_nics:
1461
      kvm_cmd.extend(["-net", "none"])
1462
    else:
1463
      vnet_hdr = False
1464
      tap_extra = ""
1465
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1466
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1467
        # From version 0.12.0, kvm uses a new sintax for network configuration.
1468
        if (v_major, v_min) >= (0, 12):
1469
          nic_model = "virtio-net-pci"
1470
          vnet_hdr = True
1471
        else:
1472
          nic_model = "virtio"
1473

    
1474
        if up_hvp[constants.HV_VHOST_NET]:
1475
          # vhost_net is only available from version 0.13.0 or newer
1476
          if self._VHOST_RE.search(kvmhelp):
1477
            tap_extra = ",vhost=on"
1478
          else:
1479
            raise errors.HypervisorError("vhost_net is configured"
1480
                                         " but it is not available")
1481
      else:
1482
        nic_model = nic_type
1483

    
1484
      for nic_seq, nic in enumerate(kvm_nics):
1485
        tapname, tapfd = _OpenTap(vnet_hdr)
1486
        tapfds.append(tapfd)
1487
        taps.append(tapname)
1488
        if self._NETDEV_RE.search(kvmhelp):
1489
          nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1490
          tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1491
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1492
        else:
1493
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1494
                                                         nic.mac, nic_model)
1495
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1496
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1497

    
1498
    if incoming:
1499
      target, port = incoming
1500
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1501

    
1502
    # Changing the vnc password doesn't bother the guest that much. At most it
1503
    # will surprise people who connect to it. Whether positively or negatively
1504
    # it's debatable.
1505
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1506
    vnc_pwd = None
1507
    if vnc_pwd_file:
1508
      try:
1509
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1510
      except EnvironmentError, err:
1511
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1512
                                     % (vnc_pwd_file, err))
1513

    
1514
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1515
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1516
                         constants.SECURE_DIR_MODE)])
1517

    
1518
    # Automatically enable QMP if version is >= 0.14
1519
    if self._QMP_RE.search(kvmhelp):
1520
      logging.debug("Enabling QMP")
1521
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1522
                      self._InstanceQmpMonitor(instance.name)])
1523

    
1524
    # Configure the network now for starting instances and bridged interfaces,
1525
    # during FinalizeMigration for incoming instances' routed interfaces
1526
    for nic_seq, nic in enumerate(kvm_nics):
1527
      if (incoming and
1528
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1529
        continue
1530
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1531

    
1532
    # CPU affinity requires kvm to start paused, so we set this flag if the
1533
    # instance is not already paused and if we are not going to accept a
1534
    # migrating instance. In the latter case, pausing is not needed.
1535
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1536
    if start_kvm_paused:
1537
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1538

    
1539
    # Note: CPU pinning is using up_hvp since changes take effect
1540
    # during instance startup anyway, and to avoid problems when soft
1541
    # rebooting the instance.
1542
    cpu_pinning = False
1543
    if up_hvp.get(constants.HV_CPU_MASK, None):
1544
      cpu_pinning = True
1545

    
1546
    if security_model == constants.HT_SM_POOL:
1547
      ss = ssconf.SimpleStore()
1548
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1549
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1550
      uid = uidpool.RequestUnusedUid(all_uids)
1551
      try:
1552
        username = pwd.getpwuid(uid.GetUid()).pw_name
1553
        kvm_cmd.extend(["-runas", username])
1554
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1555
      except:
1556
        uidpool.ReleaseUid(uid)
1557
        raise
1558
      else:
1559
        uid.Unlock()
1560
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1561
    else:
1562
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1563

    
1564
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1565
                     constants.RUN_DIRS_MODE)])
1566
    for nic_seq, tap in enumerate(taps):
1567
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1568
                      data=tap)
1569

    
1570
    if vnc_pwd:
1571
      change_cmd = "change vnc password %s" % vnc_pwd
1572
      self._CallMonitorCommand(instance.name, change_cmd)
1573

    
1574
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1575
    # connection attempts because SPICE by default does not allow connections
1576
    # if neither a password nor the "disable_ticketing" options are specified.
1577
    # As soon as we send the password via QMP, that password is a valid ticket
1578
    # for connection.
1579
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1580
    if spice_password_file:
1581
      spice_pwd = ""
1582
      try:
1583
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1584
      except EnvironmentError, err:
1585
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1586
                                     % (spice_password_file, err))
1587

    
1588
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1589
      qmp.connect()
1590
      arguments = {
1591
          "protocol": "spice",
1592
          "password": spice_pwd,
1593
      }
1594
      qmp.Execute("set_password", arguments)
1595

    
1596
    for filename in temp_files:
1597
      utils.RemoveFile(filename)
1598

    
1599
    # If requested, set CPU affinity and resume instance execution
1600
    if cpu_pinning:
1601
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1602

    
1603
    start_memory = self._InstanceStartupMemory(instance)
1604
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1605
      self.BalloonInstanceMemory(instance, start_memory)
1606

    
1607
    if start_kvm_paused:
1608
      # To control CPU pinning, ballooning, and vnc/spice passwords
1609
      # the VM was started in a frozen state. If freezing was not
1610
      # explicitly requested resume the vm status.
1611
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1612

    
1613
  def StartInstance(self, instance, block_devices, startup_paused):
1614
    """Start an instance.
1615

1616
    """
1617
    self._CheckDown(instance.name)
1618
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1619
                                           startup_paused)
1620
    self._SaveKVMRuntime(instance, kvm_runtime)
1621
    self._ExecuteKVMRuntime(instance, kvm_runtime)
1622

    
1623
  def _CallMonitorCommand(self, instance_name, command):
1624
    """Invoke a command on the instance monitor.
1625

1626
    """
1627
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1628
             (utils.ShellQuote(command),
1629
              constants.SOCAT_PATH,
1630
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1631
    result = utils.RunCmd(socat)
1632
    if result.failed:
1633
      msg = ("Failed to send command '%s' to instance %s."
1634
             " output: %s, error: %s, fail_reason: %s" %
1635
             (command, instance_name,
1636
              result.stdout, result.stderr, result.fail_reason))
1637
      raise errors.HypervisorError(msg)
1638

    
1639
    return result
1640

    
1641
  @classmethod
1642
  def _ParseKVMVersion(cls, text):
1643
    """Parse the KVM version from the --help output.
1644

1645
    @type text: string
1646
    @param text: output of kvm --help
1647
    @return: (version, v_maj, v_min, v_rev)
1648
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1649

1650
    """
1651
    match = cls._VERSION_RE.search(text.splitlines()[0])
1652
    if not match:
1653
      raise errors.HypervisorError("Unable to get KVM version")
1654

    
1655
    v_all = match.group(0)
1656
    v_maj = int(match.group(1))
1657
    v_min = int(match.group(2))
1658
    if match.group(4):
1659
      v_rev = int(match.group(4))
1660
    else:
1661
      v_rev = 0
1662
    return (v_all, v_maj, v_min, v_rev)
1663

    
1664
  @classmethod
1665
  def _GetKVMHelpOutput(cls):
1666
    """Return the KVM help output.
1667

1668
    @return: output of kvm --help
1669
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1670

1671
    """
1672
    result = utils.RunCmd([constants.KVM_PATH, "--help"])
1673
    if result.failed:
1674
      raise errors.HypervisorError("Unable to get KVM help output")
1675
    return result.output
1676

    
1677
  @classmethod
1678
  def _GetKVMVersion(cls):
1679
    """Return the installed KVM version.
1680

1681
    @return: (version, v_maj, v_min, v_rev)
1682
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1683

1684
    """
1685
    return cls._ParseKVMVersion(cls._GetKVMHelpOutput())
1686

    
1687
  def StopInstance(self, instance, force=False, retry=False, name=None):
1688
    """Stop an instance.
1689

1690
    """
1691
    if name is not None and not force:
1692
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1693
    if name is None:
1694
      name = instance.name
1695
      acpi = instance.hvparams[constants.HV_ACPI]
1696
    else:
1697
      acpi = False
1698
    _, pid, alive = self._InstancePidAlive(name)
1699
    if pid > 0 and alive:
1700
      if force or not acpi:
1701
        utils.KillProcess(pid)
1702
      else:
1703
        self._CallMonitorCommand(name, "system_powerdown")
1704

    
1705
  @classmethod
1706
  def _GetDefaultMachineVersion(cls):
1707
    """Return the default hardware revision (e.g. pc-1.1)
1708

1709
    """
1710
    result = utils.RunCmd([constants.KVM_PATH, "-M", "?"])
1711
    if result.failed:
1712
      raise errors.HypervisorError("Unable to get default hardware revision")
1713
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(result.output)
1714
    if match:
1715
      return match.group(1)
1716
    else:
1717
      return "pc"
1718

    
1719
  def CleanupInstance(self, instance_name):
1720
    """Cleanup after a stopped instance
1721

1722
    """
1723
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
1724
    if pid > 0 and alive:
1725
      raise errors.HypervisorError("Cannot cleanup a live instance")
1726
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1727

    
1728
  def RebootInstance(self, instance):
1729
    """Reboot an instance.
1730

1731
    """
1732
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1733
    # socket the instance will stop, but now power up again. So we'll resort
1734
    # to shutdown and restart.
1735
    _, _, alive = self._InstancePidAlive(instance.name)
1736
    if not alive:
1737
      raise errors.HypervisorError("Failed to reboot instance %s:"
1738
                                   " not running" % instance.name)
1739
    # StopInstance will delete the saved KVM runtime so:
1740
    # ...first load it...
1741
    kvm_runtime = self._LoadKVMRuntime(instance)
1742
    # ...now we can safely call StopInstance...
1743
    if not self.StopInstance(instance):
1744
      self.StopInstance(instance, force=True)
1745
    # ...and finally we can save it again, and execute it...
1746
    self._SaveKVMRuntime(instance, kvm_runtime)
1747
    self._ExecuteKVMRuntime(instance, kvm_runtime)
1748

    
1749
  def MigrationInfo(self, instance):
1750
    """Get instance information to perform a migration.
1751

1752
    @type instance: L{objects.Instance}
1753
    @param instance: instance to be migrated
1754
    @rtype: string
1755
    @return: content of the KVM runtime file
1756

1757
    """
1758
    return self._ReadKVMRuntime(instance.name)
1759

    
1760
  def AcceptInstance(self, instance, info, target):
1761
    """Prepare to accept an instance.
1762

1763
    @type instance: L{objects.Instance}
1764
    @param instance: instance to be accepted
1765
    @type info: string
1766
    @param info: content of the KVM runtime file on the source node
1767
    @type target: string
1768
    @param target: target host (usually ip), on this node
1769

1770
    """
1771
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1772
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1773
    self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
1774

    
1775
  def FinalizeMigrationDst(self, instance, info, success):
1776
    """Finalize the instance migration on the target node.
1777

1778
    Stop the incoming mode KVM.
1779

1780
    @type instance: L{objects.Instance}
1781
    @param instance: instance whose migration is being finalized
1782

1783
    """
1784
    if success:
1785
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1786
      kvm_nics = kvm_runtime[1]
1787

    
1788
      for nic_seq, nic in enumerate(kvm_nics):
1789
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1790
          # Bridged interfaces have already been configured
1791
          continue
1792
        try:
1793
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1794
        except EnvironmentError, err:
1795
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
1796
                          instance.name, nic_seq, str(err))
1797
          continue
1798
        try:
1799
          self._ConfigureNIC(instance, nic_seq, nic, tap)
1800
        except errors.HypervisorError, err:
1801
          logging.warning(str(err))
1802

    
1803
      self._WriteKVMRuntime(instance.name, info)
1804
    else:
1805
      self.StopInstance(instance, force=True)
1806

    
1807
  def MigrateInstance(self, instance, target, live):
1808
    """Migrate an instance to a target node.
1809

1810
    The migration will not be attempted if the instance is not
1811
    currently running.
1812

1813
    @type instance: L{objects.Instance}
1814
    @param instance: the instance to be migrated
1815
    @type target: string
1816
    @param target: ip address of the target node
1817
    @type live: boolean
1818
    @param live: perform a live migration
1819

1820
    """
1821
    instance_name = instance.name
1822
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
1823
    _, _, alive = self._InstancePidAlive(instance_name)
1824
    if not alive:
1825
      raise errors.HypervisorError("Instance not running, cannot migrate")
1826

    
1827
    if not live:
1828
      self._CallMonitorCommand(instance_name, "stop")
1829

    
1830
    migrate_command = ("migrate_set_speed %dm" %
1831
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1832
    self._CallMonitorCommand(instance_name, migrate_command)
1833

    
1834
    migrate_command = ("migrate_set_downtime %dms" %
1835
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1836
    self._CallMonitorCommand(instance_name, migrate_command)
1837

    
1838
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1839
    self._CallMonitorCommand(instance_name, migrate_command)
1840

    
1841
  def FinalizeMigrationSource(self, instance, success, live):
1842
    """Finalize the instance migration on the source node.
1843

1844
    @type instance: L{objects.Instance}
1845
    @param instance: the instance that was migrated
1846
    @type success: bool
1847
    @param success: whether the migration succeeded or not
1848
    @type live: bool
1849
    @param live: whether the user requested a live migration or not
1850

1851
    """
1852
    if success:
1853
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
1854
      utils.KillProcess(pid)
1855
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1856
    elif live:
1857
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1858

    
1859
  def GetMigrationStatus(self, instance):
1860
    """Get the migration status
1861

1862
    @type instance: L{objects.Instance}
1863
    @param instance: the instance that is being migrated
1864
    @rtype: L{objects.MigrationStatus}
1865
    @return: the status of the current migration (one of
1866
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1867
             progress info that can be retrieved from the hypervisor
1868

1869
    """
1870
    info_command = "info migrate"
1871
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
1872
      result = self._CallMonitorCommand(instance.name, info_command)
1873
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
1874
      if not match:
1875
        if not result.stdout:
1876
          logging.info("KVM: empty 'info migrate' result")
1877
        else:
1878
          logging.warning("KVM: unknown 'info migrate' result: %s",
1879
                          result.stdout)
1880
      else:
1881
        status = match.group(1)
1882
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
1883
          migration_status = objects.MigrationStatus(status=status)
1884
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
1885
          if match:
1886
            migration_status.transferred_ram = match.group("transferred")
1887
            migration_status.total_ram = match.group("total")
1888

    
1889
          return migration_status
1890

    
1891
        logging.warning("KVM: unknown migration status '%s'", status)
1892

    
1893
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1894

    
1895
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
1896

    
1897
  def BalloonInstanceMemory(self, instance, mem):
1898
    """Balloon an instance memory to a certain value.
1899

1900
    @type instance: L{objects.Instance}
1901
    @param instance: instance to be accepted
1902
    @type mem: int
1903
    @param mem: actual memory size to use for instance runtime
1904

1905
    """
1906
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
1907

    
1908
  def GetNodeInfo(self):
1909
    """Return information about the node.
1910

1911
    @return: a dict with the following keys (values in MiB):
1912
          - memory_total: the total memory size on the node
1913
          - memory_free: the available memory on the node for instances
1914
          - memory_dom0: the memory used by the node itself, if available
1915
          - hv_version: the hypervisor version in the form (major, minor,
1916
                        revision)
1917

1918
    """
1919
    result = self.GetLinuxNodeInfo()
1920
    _, v_major, v_min, v_rev = self._GetKVMVersion()
1921
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
1922
    return result
1923

    
1924
  @classmethod
1925
  def GetInstanceConsole(cls, instance, hvparams, beparams):
1926
    """Return a command for connecting to the console of an instance.
1927

1928
    """
1929
    if hvparams[constants.HV_SERIAL_CONSOLE]:
1930
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
1931
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1932
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1933
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
1934
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1935
      return objects.InstanceConsole(instance=instance.name,
1936
                                     kind=constants.CONS_SSH,
1937
                                     host=instance.primary_node,
1938
                                     user=constants.SSH_CONSOLE_USER,
1939
                                     command=cmd)
1940

    
1941
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1942
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1943
      display = instance.network_port - constants.VNC_BASE_PORT
1944
      return objects.InstanceConsole(instance=instance.name,
1945
                                     kind=constants.CONS_VNC,
1946
                                     host=vnc_bind_address,
1947
                                     port=instance.network_port,
1948
                                     display=display)
1949

    
1950
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1951
    if spice_bind:
1952
      return objects.InstanceConsole(instance=instance.name,
1953
                                     kind=constants.CONS_SPICE,
1954
                                     host=spice_bind,
1955
                                     port=instance.network_port)
1956

    
1957
    return objects.InstanceConsole(instance=instance.name,
1958
                                   kind=constants.CONS_MESSAGE,
1959
                                   message=("No serial shell for instance %s" %
1960
                                            instance.name))
1961

    
1962
  def Verify(self):
1963
    """Verify the hypervisor.
1964

1965
    Check that the binary exists.
1966

1967
    """
1968
    if not os.path.exists(constants.KVM_PATH):
1969
      return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
1970
    if not os.path.exists(constants.SOCAT_PATH):
1971
      return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
1972

    
1973
  @classmethod
1974
  def CheckParameterSyntax(cls, hvparams):
1975
    """Check the given parameters for validity.
1976

1977
    @type hvparams:  dict
1978
    @param hvparams: dictionary with parameter names/value
1979
    @raise errors.HypervisorError: when a parameter is not valid
1980

1981
    """
1982
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
1983

    
1984
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
1985
    if kernel_path:
1986
      if not hvparams[constants.HV_ROOT_PATH]:
1987
        raise errors.HypervisorError("Need a root partition for the instance,"
1988
                                     " if a kernel is defined")
1989

    
1990
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
1991
        not hvparams[constants.HV_VNC_X509]):
1992
      raise errors.HypervisorError("%s must be defined, if %s is" %
1993
                                   (constants.HV_VNC_X509,
1994
                                    constants.HV_VNC_X509_VERIFY))
1995

    
1996
    if hvparams[constants.HV_SERIAL_CONSOLE]:
1997
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
1998
      valid_speeds = constants.VALID_SERIAL_SPEEDS
1999
      if not serial_speed or serial_speed not in valid_speeds:
2000
        raise errors.HypervisorError("Invalid serial console speed, must be"
2001
                                     " one of: %s" %
2002
                                     utils.CommaJoin(valid_speeds))
2003

    
2004
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2005
    if (boot_order == constants.HT_BO_CDROM and
2006
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2007
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2008
                                   " ISO path")
2009

    
2010
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2011
    if security_model == constants.HT_SM_USER:
2012
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2013
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2014
                                     " must be specified")
2015
    elif (security_model == constants.HT_SM_NONE or
2016
          security_model == constants.HT_SM_POOL):
2017
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2018
        raise errors.HypervisorError("Cannot have a security domain when the"
2019
                                     " security model is 'none' or 'pool'")
2020

    
2021
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2022
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2023
    if spice_bind:
2024
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2025
        # if an IP version is specified, the spice_bind parameter must be an
2026
        # IP of that family
2027
        if (netutils.IP4Address.IsValid(spice_bind) and
2028
            spice_ip_version != constants.IP4_VERSION):
2029
          raise errors.HypervisorError("spice: got an IPv4 address (%s), but"
2030
                                       " the specified IP version is %s" %
2031
                                       (spice_bind, spice_ip_version))
2032

    
2033
        if (netutils.IP6Address.IsValid(spice_bind) and
2034
            spice_ip_version != constants.IP6_VERSION):
2035
          raise errors.HypervisorError("spice: got an IPv6 address (%s), but"
2036
                                       " the specified IP version is %s" %
2037
                                       (spice_bind, spice_ip_version))
2038
    else:
2039
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2040
      # error if any of them is set without it.
2041
      for param in _SPICE_ADDITIONAL_PARAMS:
2042
        if hvparams[param]:
2043
          raise errors.HypervisorError("spice: %s requires %s to be set" %
2044
                                       (param, constants.HV_KVM_SPICE_BIND))
2045

    
2046
  @classmethod
2047
  def ValidateParameters(cls, hvparams):
2048
    """Check the given parameters for validity.
2049

2050
    @type hvparams:  dict
2051
    @param hvparams: dictionary with parameter names/value
2052
    @raise errors.HypervisorError: when a parameter is not valid
2053

2054
    """
2055
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2056

    
2057
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2058
    if security_model == constants.HT_SM_USER:
2059
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2060
      try:
2061
        pwd.getpwnam(username)
2062
      except KeyError:
2063
        raise errors.HypervisorError("Unknown security domain user %s"
2064
                                     % username)
2065

    
2066
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2067
    if spice_bind:
2068
      # only one of VNC and SPICE can be used currently.
2069
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2070
        raise errors.HypervisorError("both SPICE and VNC are configured, but"
2071
                                     " only one of them can be used at a"
2072
                                     " given time.")
2073

    
2074
      # KVM version should be >= 0.14.0
2075
      kvmhelp = cls._GetKVMHelpOutput()
2076
      if not cls._SPICE_RE.search(kvmhelp):
2077
        raise errors.HypervisorError("spice is configured, but it is not"
2078
                                     " supported according to kvm --help")
2079

    
2080
      # if spice_bind is not an IP address, it must be a valid interface
2081
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind)
2082
                       or netutils.IP6Address.IsValid(spice_bind))
2083
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2084
        raise errors.HypervisorError("spice: the %s parameter must be either"
2085
                                     " a valid IP address or interface name" %
2086
                                     constants.HV_KVM_SPICE_BIND)
2087

    
2088
  @classmethod
2089
  def PowercycleNode(cls):
2090
    """KVM powercycle, just a wrapper over Linux powercycle.
2091

2092
    """
2093
    cls.LinuxPowercycle()