Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (74.5 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
    }
539

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

    
547
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
548
  _MIGRATION_INFO_RETRY_DELAY = 2
549

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

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

    
556
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"(\S+).*\(default\)")
557

    
558
  ANCILLARY_FILES = [
559
    _KVM_NETWORK_SCRIPT,
560
    ]
561
  ANCILLARY_FILES_OPT = [
562
    _KVM_NETWORK_SCRIPT,
563
    ]
564

    
565
  def __init__(self):
566
    hv_base.BaseHypervisor.__init__(self)
567
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
568
    # in a tmpfs filesystem or has been otherwise wiped out.
569
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
570
    utils.EnsureDirs(dirs)
571

    
572
  @classmethod
573
  def _InstancePidFile(cls, instance_name):
574
    """Returns the instance pidfile.
575

576
    """
577
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
578

    
579
  @classmethod
580
  def _InstanceUidFile(cls, instance_name):
581
    """Returns the instance uidfile.
582

583
    """
584
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
585

    
586
  @classmethod
587
  def _InstancePidInfo(cls, pid):
588
    """Check pid file for instance information.
589

590
    Check that a pid file is associated with an instance, and retrieve
591
    information from its command line.
592

593
    @type pid: string or int
594
    @param pid: process id of the instance to check
595
    @rtype: tuple
596
    @return: (instance_name, memory, vcpus)
597
    @raise errors.HypervisorError: when an instance cannot be found
598

599
    """
600
    alive = utils.IsProcessAlive(pid)
601
    if not alive:
602
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
603

    
604
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
605
    try:
606
      cmdline = utils.ReadFile(cmdline_file)
607
    except EnvironmentError, err:
608
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
609
                                   (pid, err))
610

    
611
    instance = None
612
    memory = 0
613
    vcpus = 0
614

    
615
    arg_list = cmdline.split("\x00")
616
    while arg_list:
617
      arg = arg_list.pop(0)
618
      if arg == "-name":
619
        instance = arg_list.pop(0)
620
      elif arg == "-m":
621
        memory = int(arg_list.pop(0))
622
      elif arg == "-smp":
623
        vcpus = int(arg_list.pop(0).split(",")[0])
624

    
625
    if instance is None:
626
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
627
                                   " instance" % pid)
628

    
629
    return (instance, memory, vcpus)
630

    
631
  def _InstancePidAlive(self, instance_name):
632
    """Returns the instance pidfile, pid, and liveness.
633

634
    @type instance_name: string
635
    @param instance_name: instance name
636
    @rtype: tuple
637
    @return: (pid file name, pid, liveness)
638

639
    """
640
    pidfile = self._InstancePidFile(instance_name)
641
    pid = utils.ReadPidFile(pidfile)
642

    
643
    alive = False
644
    try:
645
      cmd_instance = self._InstancePidInfo(pid)[0]
646
      alive = (cmd_instance == instance_name)
647
    except errors.HypervisorError:
648
      pass
649

    
650
    return (pidfile, pid, alive)
651

    
652
  def _CheckDown(self, instance_name):
653
    """Raises an error unless the given instance is down.
654

655
    """
656
    alive = self._InstancePidAlive(instance_name)[2]
657
    if alive:
658
      raise errors.HypervisorError("Failed to start instance %s: %s" %
659
                                   (instance_name, "already running"))
660

    
661
  @classmethod
662
  def _InstanceMonitor(cls, instance_name):
663
    """Returns the instance monitor socket name
664

665
    """
666
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
667

    
668
  @classmethod
669
  def _InstanceSerial(cls, instance_name):
670
    """Returns the instance serial socket name
671

672
    """
673
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
674

    
675
  @classmethod
676
  def _InstanceQmpMonitor(cls, instance_name):
677
    """Returns the instance serial QMP socket name
678

679
    """
680
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
681

    
682
  @staticmethod
683
  def _SocatUnixConsoleParams():
684
    """Returns the correct parameters for socat
685

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

688
    """
689
    if constants.SOCAT_USE_ESCAPE:
690
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
691
    else:
692
      return "echo=0,icanon=0"
693

    
694
  @classmethod
695
  def _InstanceKVMRuntime(cls, instance_name):
696
    """Returns the instance KVM runtime filename
697

698
    """
699
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
700

    
701
  @classmethod
702
  def _InstanceChrootDir(cls, instance_name):
703
    """Returns the name of the KVM chroot dir of the instance
704

705
    """
706
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
707

    
708
  @classmethod
709
  def _InstanceNICDir(cls, instance_name):
710
    """Returns the name of the directory holding the tap device files for a
711
    given instance.
712

713
    """
714
    return utils.PathJoin(cls._NICS_DIR, instance_name)
715

    
716
  @classmethod
717
  def _InstanceNICFile(cls, instance_name, seq):
718
    """Returns the name of the file containing the tap device for a given NIC
719

720
    """
721
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
722

    
723
  @classmethod
724
  def _InstanceKeymapFile(cls, instance_name):
725
    """Returns the name of the file containing the keymap for a given instance
726

727
    """
728
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
729

    
730
  @classmethod
731
  def _TryReadUidFile(cls, uid_file):
732
    """Try to read a uid file
733

734
    """
735
    if os.path.exists(uid_file):
736
      try:
737
        uid = int(utils.ReadOneLineFile(uid_file))
738
        return uid
739
      except EnvironmentError:
740
        logging.warning("Can't read uid file", exc_info=True)
741
      except (TypeError, ValueError):
742
        logging.warning("Can't parse uid file contents", exc_info=True)
743
    return None
744

    
745
  @classmethod
746
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
747
    """Removes an instance's rutime sockets/files/dirs.
748

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

    
785
  @staticmethod
786
  def _ConfigureNIC(instance, seq, nic, tap):
787
    """Run the network configuration script for a specified NIC
788

789
    @param instance: instance we're acting on
790
    @type instance: instance object
791
    @param seq: nic sequence number
792
    @type seq: int
793
    @param nic: nic we're acting on
794
    @type nic: nic object
795
    @param tap: the host's tap interface this NIC corresponds to
796
    @type tap: str
797

798
    """
799
    if instance.tags:
800
      tags = " ".join(instance.tags)
801
    else:
802
      tags = ""
803

    
804
    env = {
805
      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
806
      "INSTANCE": instance.name,
807
      "MAC": nic.mac,
808
      "MODE": nic.nicparams[constants.NIC_MODE],
809
      "INTERFACE": tap,
810
      "INTERFACE_INDEX": str(seq),
811
      "TAGS": tags,
812
    }
813

    
814
    if nic.ip:
815
      env["IP"] = nic.ip
816

    
817
    if nic.nicparams[constants.NIC_LINK]:
818
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
819

    
820
    if nic.network:
821
      n = objects.Network.FromDict(nic.netinfo)
822
      _BuildNetworkEnv(nic.network, n.network, n.gateway,
823
                       n.network6, n.gateway6, n.network_type,
824
                       n.mac_prefix, n.tags, env)
825

    
826
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
827
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
828

    
829
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
830
    if result.failed:
831
      raise errors.HypervisorError("Failed to configure interface %s: %s."
832
                                   " Network configuration script output: %s" %
833
                                   (tap, result.fail_reason, result.output))
834

    
835
  @staticmethod
836
  def _VerifyAffinityPackage():
837
    if affinity is None:
838
      raise errors.HypervisorError("affinity Python package not"
839
                                   " found; cannot use CPU pinning under KVM")
840

    
841
  @staticmethod
842
  def _BuildAffinityCpuMask(cpu_list):
843
    """Create a CPU mask suitable for sched_setaffinity from a list of
844
    CPUs.
845

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

849
    @type cpu_list: list of int
850
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
851
    @rtype: int
852
    @return: a bit mask of CPU affinities
853

854
    """
855
    if cpu_list == constants.CPU_PINNING_OFF:
856
      return constants.CPU_PINNING_ALL_KVM
857
    else:
858
      return sum(2 ** cpu for cpu in cpu_list)
859

    
860
  @classmethod
861
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
862
    """Change CPU affinity for running VM according to given CPU mask.
863

864
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
865
    @type cpu_mask: string
866
    @param process_id: process ID of KVM process. Used to pin entire VM
867
                       to physical CPUs.
868
    @type process_id: int
869
    @param thread_dict: map of virtual CPUs to KVM thread IDs
870
    @type thread_dict: dict int:int
871

872
    """
873
    # Convert the string CPU mask to a list of list of int's
874
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
875

    
876
    if len(cpu_list) == 1:
877
      all_cpu_mapping = cpu_list[0]
878
      if all_cpu_mapping == constants.CPU_PINNING_OFF:
879
        # If CPU pinning has 1 entry that's "all", then do nothing
880
        pass
881
      else:
882
        # If CPU pinning has one non-all entry, map the entire VM to
883
        # one set of physical CPUs
884
        cls._VerifyAffinityPackage()
885
        affinity.set_process_affinity_mask(
886
          process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
887
    else:
888
      # The number of vCPUs mapped should match the number of vCPUs
889
      # reported by KVM. This was already verified earlier, so
890
      # here only as a sanity check.
891
      assert len(thread_dict) == len(cpu_list)
892
      cls._VerifyAffinityPackage()
893

    
894
      # For each vCPU, map it to the proper list of physical CPUs
895
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
896
        affinity.set_process_affinity_mask(thread_dict[i],
897
                                           cls._BuildAffinityCpuMask(vcpu))
898

    
899
  def _GetVcpuThreadIds(self, instance_name):
900
    """Get a mapping of vCPU no. to thread IDs for the instance
901

902
    @type instance_name: string
903
    @param instance_name: instance in question
904
    @rtype: dictionary of int:int
905
    @return: a dictionary mapping vCPU numbers to thread IDs
906

907
    """
908
    result = {}
909
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
910
    for line in output.stdout.splitlines():
911
      match = self._CPU_INFO_RE.search(line)
912
      if not match:
913
        continue
914
      grp = map(int, match.groups())
915
      result[grp[0]] = grp[1]
916

    
917
    return result
918

    
919
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
920
    """Complete CPU pinning.
921

922
    @type instance_name: string
923
    @param instance_name: name of instance
924
    @type cpu_mask: string
925
    @param cpu_mask: CPU pinning mask as entered by user
926

927
    """
928
    # Get KVM process ID, to be used if need to pin entire VM
929
    _, pid, _ = self._InstancePidAlive(instance_name)
930
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
931
    thread_dict = self._GetVcpuThreadIds(instance_name)
932
    # Run CPU pinning, based on configured mask
933
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
934

    
935
  def ListInstances(self):
936
    """Get the list of running instances.
937

938
    We can do this by listing our live instances directory and
939
    checking whether the associated kvm process is still alive.
940

941
    """
942
    result = []
943
    for name in os.listdir(self._PIDS_DIR):
944
      if self._InstancePidAlive(name)[2]:
945
        result.append(name)
946
    return result
947

    
948
  def GetInstanceInfo(self, instance_name):
949
    """Get instance properties.
950

951
    @type instance_name: string
952
    @param instance_name: the instance name
953
    @rtype: tuple of strings
954
    @return: (name, id, memory, vcpus, stat, times)
955

956
    """
957
    _, pid, alive = self._InstancePidAlive(instance_name)
958
    if not alive:
959
      return None
960

    
961
    _, memory, vcpus = self._InstancePidInfo(pid)
962
    istat = "---b-"
963
    times = "0"
964

    
965
    try:
966
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
967
      qmp.connect()
968
      vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
969
      # Will fail if ballooning is not enabled, but we can then just resort to
970
      # the value above.
971
      mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
972
      memory = mem_bytes / 1048576
973
    except errors.HypervisorError:
974
      pass
975

    
976
    return (instance_name, pid, memory, vcpus, istat, times)
977

    
978
  def GetAllInstancesInfo(self):
979
    """Get properties of all instances.
980

981
    @return: list of tuples (name, id, memory, vcpus, stat, times)
982

983
    """
984
    data = []
985
    for name in os.listdir(self._PIDS_DIR):
986
      try:
987
        info = self.GetInstanceInfo(name)
988
      except errors.HypervisorError:
989
        # Ignore exceptions due to instances being shut down
990
        continue
991
      if info:
992
        data.append(info)
993
    return data
994

    
995
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused):
996
    """Generate KVM information to start an instance.
997

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

1005
    """
1006
    # pylint: disable=R0912,R0914,R0915
1007
    _, v_major, v_min, _ = self._GetKVMVersion()
1008
    hvp = instance.hvparams
1009

    
1010
    pidfile = self._InstancePidFile(instance.name)
1011
    kvm = constants.KVM_PATH
1012
    kvm_cmd = [kvm]
1013
    kvm_cmd.extend(["-M", self._GetDefaultMachineVersion()])
1014
    # used just by the vnc server, if enabled
1015
    kvm_cmd.extend(["-name", instance.name])
1016
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1017

    
1018
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1019
    if hvp[constants.HV_CPU_CORES]:
1020
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1021
    if hvp[constants.HV_CPU_THREADS]:
1022
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1023
    if hvp[constants.HV_CPU_SOCKETS]:
1024
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1025

    
1026
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1027

    
1028
    kvm_cmd.extend(["-pidfile", pidfile])
1029
    kvm_cmd.extend(["-balloon", "virtio"])
1030
    kvm_cmd.extend(["-daemonize"])
1031
    if not instance.hvparams[constants.HV_ACPI]:
1032
      kvm_cmd.extend(["-no-acpi"])
1033
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1034
        constants.INSTANCE_REBOOT_EXIT:
1035
      kvm_cmd.extend(["-no-reboot"])
1036

    
1037
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1038
    if kernel_path:
1039
      boot_disk = boot_cdrom = boot_floppy = boot_network = False
1040
    else:
1041
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1042
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1043
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1044
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1045

    
1046
    self.ValidateParameters(hvp)
1047

    
1048
    if startup_paused:
1049
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1050

    
1051
    if hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED:
1052
      kvm_cmd.extend(["-enable-kvm"])
1053
    elif hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED:
1054
      kvm_cmd.extend(["-disable-kvm"])
1055

    
1056
    if boot_network:
1057
      kvm_cmd.extend(["-boot", "n"])
1058

    
1059
    # whether this is an older KVM version that uses the boot=on flag
1060
    # on devices
1061
    needs_boot_flag = (v_major, v_min) < (0, 14)
1062

    
1063
    disk_type = hvp[constants.HV_DISK_TYPE]
1064
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
1065
      if_val = ",if=virtio"
1066
    else:
1067
      if_val = ",if=%s" % disk_type
1068
    # Cache mode
1069
    disk_cache = hvp[constants.HV_DISK_CACHE]
1070
    if instance.disk_template in constants.DTS_EXT_MIRROR:
1071
      if disk_cache != "none":
1072
        # TODO: make this a hard error, instead of a silent overwrite
1073
        logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1074
                        " to prevent shared storage corruption on migration",
1075
                        disk_cache)
1076
      cache_val = ",cache=none"
1077
    elif disk_cache != constants.HT_CACHE_DEFAULT:
1078
      cache_val = ",cache=%s" % disk_cache
1079
    else:
1080
      cache_val = ""
1081
    for cfdev, dev_path in block_devices:
1082
      if cfdev.mode != constants.DISK_RDWR:
1083
        raise errors.HypervisorError("Instance has read-only disks which"
1084
                                     " are not supported by KVM")
1085
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
1086
      boot_val = ""
1087
      if boot_disk:
1088
        kvm_cmd.extend(["-boot", "c"])
1089
        boot_disk = False
1090
        if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1091
          boot_val = ",boot=on"
1092

    
1093
      drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
1094
                                                cache_val)
1095
      kvm_cmd.extend(["-drive", drive_val])
1096

    
1097
    #Now we can specify a different device type for CDROM devices.
1098
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1099
    if not cdrom_disk_type:
1100
      cdrom_disk_type = disk_type
1101

    
1102
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1103
    if iso_image:
1104
      options = ",format=raw,media=cdrom"
1105
      # set cdrom 'if' type
1106
      if boot_cdrom:
1107
        actual_cdrom_type = constants.HT_DISK_IDE
1108
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1109
        actual_cdrom_type = "virtio"
1110
      else:
1111
        actual_cdrom_type = cdrom_disk_type
1112
      if_val = ",if=%s" % actual_cdrom_type
1113
      # set boot flag, if needed
1114
      boot_val = ""
1115
      if boot_cdrom:
1116
        kvm_cmd.extend(["-boot", "d"])
1117
        if needs_boot_flag:
1118
          boot_val = ",boot=on"
1119
      # and finally build the entire '-drive' value
1120
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1121
      kvm_cmd.extend(["-drive", drive_val])
1122

    
1123
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1124
    if iso_image2:
1125
      options = ",format=raw,media=cdrom"
1126
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1127
        if_val = ",if=virtio"
1128
      else:
1129
        if_val = ",if=%s" % cdrom_disk_type
1130
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1131
      kvm_cmd.extend(["-drive", drive_val])
1132

    
1133
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1134
    if floppy_image:
1135
      options = ",format=raw,media=disk"
1136
      if boot_floppy:
1137
        kvm_cmd.extend(["-boot", "a"])
1138
        options = "%s,boot=on" % options
1139
      if_val = ",if=floppy"
1140
      options = "%s%s" % (options, if_val)
1141
      drive_val = "file=%s%s" % (floppy_image, options)
1142
      kvm_cmd.extend(["-drive", drive_val])
1143

    
1144
    if kernel_path:
1145
      kvm_cmd.extend(["-kernel", kernel_path])
1146
      initrd_path = hvp[constants.HV_INITRD_PATH]
1147
      if initrd_path:
1148
        kvm_cmd.extend(["-initrd", initrd_path])
1149
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1150
                     hvp[constants.HV_KERNEL_ARGS]]
1151
      if hvp[constants.HV_SERIAL_CONSOLE]:
1152
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1153
        root_append.append("console=ttyS0,%s" % serial_speed)
1154
      kvm_cmd.extend(["-append", " ".join(root_append)])
1155

    
1156
    mem_path = hvp[constants.HV_MEM_PATH]
1157
    if mem_path:
1158
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1159

    
1160
    monitor_dev = ("unix:%s,server,nowait" %
1161
                   self._InstanceMonitor(instance.name))
1162
    kvm_cmd.extend(["-monitor", monitor_dev])
1163
    if hvp[constants.HV_SERIAL_CONSOLE]:
1164
      serial_dev = ("unix:%s,server,nowait" %
1165
                    self._InstanceSerial(instance.name))
1166
      kvm_cmd.extend(["-serial", serial_dev])
1167
    else:
1168
      kvm_cmd.extend(["-serial", "none"])
1169

    
1170
    mouse_type = hvp[constants.HV_USB_MOUSE]
1171
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1172
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1173
    spice_ip_version = None
1174

    
1175
    if mouse_type:
1176
      kvm_cmd.extend(["-usb"])
1177
      kvm_cmd.extend(["-usbdevice", mouse_type])
1178
    elif vnc_bind_address:
1179
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1180

    
1181
    if vnc_bind_address:
1182
      if netutils.IP4Address.IsValid(vnc_bind_address):
1183
        if instance.network_port > constants.VNC_BASE_PORT:
1184
          display = instance.network_port - constants.VNC_BASE_PORT
1185
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1186
            vnc_arg = ":%d" % (display)
1187
          else:
1188
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1189
        else:
1190
          logging.error("Network port is not a valid VNC display (%d < %d)."
1191
                        " Not starting VNC", instance.network_port,
1192
                        constants.VNC_BASE_PORT)
1193
          vnc_arg = "none"
1194

    
1195
        # Only allow tls and other option when not binding to a file, for now.
1196
        # kvm/qemu gets confused otherwise about the filename to use.
1197
        vnc_append = ""
1198
        if hvp[constants.HV_VNC_TLS]:
1199
          vnc_append = "%s,tls" % vnc_append
1200
          if hvp[constants.HV_VNC_X509_VERIFY]:
1201
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1202
                                               hvp[constants.HV_VNC_X509])
1203
          elif hvp[constants.HV_VNC_X509]:
1204
            vnc_append = "%s,x509=%s" % (vnc_append,
1205
                                         hvp[constants.HV_VNC_X509])
1206
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1207
          vnc_append = "%s,password" % vnc_append
1208

    
1209
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1210

    
1211
      else:
1212
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1213

    
1214
      kvm_cmd.extend(["-vnc", vnc_arg])
1215
    elif spice_bind:
1216
      # FIXME: this is wrong here; the iface ip address differs
1217
      # between systems, so it should be done in _ExecuteKVMRuntime
1218
      if netutils.IsValidInterface(spice_bind):
1219
        # The user specified a network interface, we have to figure out the IP
1220
        # address.
1221
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1222
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1223

    
1224
        # if the user specified an IP version and the interface does not
1225
        # have that kind of IP addresses, throw an exception
1226
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1227
          if not addresses[spice_ip_version]:
1228
            raise errors.HypervisorError("spice: unable to get an IPv%s address"
1229
                                         " for %s" % (spice_ip_version,
1230
                                                      spice_bind))
1231

    
1232
        # the user did not specify an IP version, we have to figure it out
1233
        elif (addresses[constants.IP4_VERSION] and
1234
              addresses[constants.IP6_VERSION]):
1235
          # we have both ipv4 and ipv6, let's use the cluster default IP
1236
          # version
1237
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1238
          spice_ip_version = \
1239
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1240
        elif addresses[constants.IP4_VERSION]:
1241
          spice_ip_version = constants.IP4_VERSION
1242
        elif addresses[constants.IP6_VERSION]:
1243
          spice_ip_version = constants.IP6_VERSION
1244
        else:
1245
          raise errors.HypervisorError("spice: unable to get an IP address"
1246
                                       " for %s" % (spice_bind))
1247

    
1248
        spice_address = addresses[spice_ip_version][0]
1249

    
1250
      else:
1251
        # spice_bind is known to be a valid IP address, because
1252
        # ValidateParameters checked it.
1253
        spice_address = spice_bind
1254

    
1255
      spice_arg = "addr=%s" % spice_address
1256
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1257
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1258
                     (spice_arg, instance.network_port,
1259
                      pathutils.SPICE_CACERT_FILE))
1260
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1261
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1262
                      pathutils.SPICE_CERT_FILE))
1263
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1264
        if tls_ciphers:
1265
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1266
      else:
1267
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1268

    
1269
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1270
        spice_arg = "%s,disable-ticketing" % spice_arg
1271

    
1272
      if spice_ip_version:
1273
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1274

    
1275
      # Image compression options
1276
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1277
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1278
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1279
      if img_lossless:
1280
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1281
      if img_jpeg:
1282
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1283
      if img_zlib_glz:
1284
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1285

    
1286
      # Video stream detection
1287
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1288
      if video_streaming:
1289
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1290

    
1291
      # Audio compression, by default in qemu-kvm it is on
1292
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1293
        spice_arg = "%s,playback-compression=off" % spice_arg
1294
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1295
        spice_arg = "%s,agent-mouse=off" % spice_arg
1296
      else:
1297
        # Enable the spice agent communication channel between the host and the
1298
        # agent.
1299
        kvm_cmd.extend(["-device", "virtio-serial-pci"])
1300
        kvm_cmd.extend(["-device", "virtserialport,chardev=spicechannel0,"
1301
                                                   "name=com.redhat.spice.0"])
1302
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1303

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

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

    
1310
    else:
1311
      kvm_cmd.extend(["-nographic"])
1312

    
1313
    if hvp[constants.HV_USE_LOCALTIME]:
1314
      kvm_cmd.extend(["-localtime"])
1315

    
1316
    if hvp[constants.HV_KVM_USE_CHROOT]:
1317
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1318

    
1319
    # Add qemu-KVM -cpu param
1320
    if hvp[constants.HV_CPU_TYPE]:
1321
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1322

    
1323
    # Save the current instance nics, but defer their expansion as parameters,
1324
    # as we'll need to generate executable temp files for them.
1325
    kvm_nics = instance.nics
1326
    hvparams = hvp
1327

    
1328
    return (kvm_cmd, kvm_nics, hvparams)
1329

    
1330
  def _WriteKVMRuntime(self, instance_name, data):
1331
    """Write an instance's KVM runtime
1332

1333
    """
1334
    try:
1335
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1336
                      data=data)
1337
    except EnvironmentError, err:
1338
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1339

    
1340
  def _ReadKVMRuntime(self, instance_name):
1341
    """Read an instance's KVM runtime
1342

1343
    """
1344
    try:
1345
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1346
    except EnvironmentError, err:
1347
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1348
    return file_content
1349

    
1350
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1351
    """Save an instance's KVM runtime
1352

1353
    """
1354
    kvm_cmd, kvm_nics, hvparams = kvm_runtime
1355
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1356
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1357
    self._WriteKVMRuntime(instance.name, serialized_form)
1358

    
1359
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1360
    """Load an instance's KVM runtime
1361

1362
    """
1363
    if not serialized_runtime:
1364
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1365
    loaded_runtime = serializer.Load(serialized_runtime)
1366
    kvm_cmd, serialized_nics, hvparams = loaded_runtime
1367
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1368
    return (kvm_cmd, kvm_nics, hvparams)
1369

    
1370
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1371
    """Run the KVM cmd and check for errors
1372

1373
    @type name: string
1374
    @param name: instance name
1375
    @type kvm_cmd: list of strings
1376
    @param kvm_cmd: runcmd input for kvm
1377
    @type tap_fds: list of int
1378
    @param tap_fds: fds of tap devices opened by Ganeti
1379

1380
    """
1381
    try:
1382
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1383
    finally:
1384
      for fd in tap_fds:
1385
        utils_wrapper.CloseFdNoError(fd)
1386

    
1387
    if result.failed:
1388
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1389
                                   (name, result.fail_reason, result.output))
1390
    if not self._InstancePidAlive(name)[2]:
1391
      raise errors.HypervisorError("Failed to start instance %s" % name)
1392

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

1396
    @type incoming: tuple of strings
1397
    @param incoming: (target_host_ip, port)
1398

1399
    """
1400
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1401
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1402
    #    have changed since the instance started; only use them if the change
1403
    #    won't affect the inside of the instance (which hasn't been rebooted).
1404
    #  - up_hvp contains the parameters as they were when the instance was
1405
    #    started, plus any new parameter which has been added between ganeti
1406
    #    versions: it is paramount that those default to a value which won't
1407
    #    affect the inside of the instance as well.
1408
    conf_hvp = instance.hvparams
1409
    name = instance.name
1410
    self._CheckDown(name)
1411

    
1412
    temp_files = []
1413

    
1414
    kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1415
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1416

    
1417
    _, v_major, v_min, _ = self._GetKVMVersion()
1418

    
1419
    # We know it's safe to run as a different user upon migration, so we'll use
1420
    # the latest conf, from conf_hvp.
1421
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1422
    if security_model == constants.HT_SM_USER:
1423
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1424

    
1425
    keymap = conf_hvp[constants.HV_KEYMAP]
1426
    if keymap:
1427
      keymap_path = self._InstanceKeymapFile(name)
1428
      # If a keymap file is specified, KVM won't use its internal defaults. By
1429
      # first including the "en-us" layout, an error on loading the actual
1430
      # layout (e.g. because it can't be found) won't lead to a non-functional
1431
      # keyboard. A keyboard with incorrect keys is still better than none.
1432
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1433
      kvm_cmd.extend(["-k", keymap_path])
1434

    
1435
    # We have reasons to believe changing something like the nic driver/type
1436
    # upon migration won't exactly fly with the instance kernel, so for nic
1437
    # related parameters we'll use up_hvp
1438
    tapfds = []
1439
    taps = []
1440
    if not kvm_nics:
1441
      kvm_cmd.extend(["-net", "none"])
1442
    else:
1443
      vnet_hdr = False
1444
      tap_extra = ""
1445
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1446
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1447
        # From version 0.12.0, kvm uses a new sintax for network configuration.
1448
        if (v_major, v_min) >= (0, 12):
1449
          nic_model = "virtio-net-pci"
1450
          vnet_hdr = True
1451
        else:
1452
          nic_model = "virtio"
1453

    
1454
        if up_hvp[constants.HV_VHOST_NET]:
1455
          # vhost_net is only available from version 0.13.0 or newer
1456
          if (v_major, v_min) >= (0, 13):
1457
            tap_extra = ",vhost=on"
1458
          else:
1459
            raise errors.HypervisorError("vhost_net is configured"
1460
                                         " but it is not available")
1461
      else:
1462
        nic_model = nic_type
1463

    
1464
      for nic_seq, nic in enumerate(kvm_nics):
1465
        tapname, tapfd = _OpenTap(vnet_hdr)
1466
        tapfds.append(tapfd)
1467
        taps.append(tapname)
1468
        if (v_major, v_min) >= (0, 12):
1469
          nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1470
          tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1471
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1472
        else:
1473
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1474
                                                         nic.mac, nic_model)
1475
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1476
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1477

    
1478
    if incoming:
1479
      target, port = incoming
1480
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1481

    
1482
    # Changing the vnc password doesn't bother the guest that much. At most it
1483
    # will surprise people who connect to it. Whether positively or negatively
1484
    # it's debatable.
1485
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1486
    vnc_pwd = None
1487
    if vnc_pwd_file:
1488
      try:
1489
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1490
      except EnvironmentError, err:
1491
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1492
                                     % (vnc_pwd_file, err))
1493

    
1494
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1495
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1496
                         constants.SECURE_DIR_MODE)])
1497

    
1498
    # Automatically enable QMP if version is >= 0.14
1499
    if (v_major, v_min) >= (0, 14):
1500
      logging.debug("Enabling QMP")
1501
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1502
                      self._InstanceQmpMonitor(instance.name)])
1503

    
1504
    # Configure the network now for starting instances and bridged interfaces,
1505
    # during FinalizeMigration for incoming instances' routed interfaces
1506
    for nic_seq, nic in enumerate(kvm_nics):
1507
      if (incoming and
1508
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1509
        continue
1510
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1511

    
1512
    # CPU affinity requires kvm to start paused, so we set this flag if the
1513
    # instance is not already paused and if we are not going to accept a
1514
    # migrating instance. In the latter case, pausing is not needed.
1515
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1516
    if start_kvm_paused:
1517
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1518

    
1519
    # Note: CPU pinning is using up_hvp since changes take effect
1520
    # during instance startup anyway, and to avoid problems when soft
1521
    # rebooting the instance.
1522
    cpu_pinning = False
1523
    if up_hvp.get(constants.HV_CPU_MASK, None):
1524
      cpu_pinning = True
1525

    
1526
    if security_model == constants.HT_SM_POOL:
1527
      ss = ssconf.SimpleStore()
1528
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1529
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1530
      uid = uidpool.RequestUnusedUid(all_uids)
1531
      try:
1532
        username = pwd.getpwuid(uid.GetUid()).pw_name
1533
        kvm_cmd.extend(["-runas", username])
1534
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1535
      except:
1536
        uidpool.ReleaseUid(uid)
1537
        raise
1538
      else:
1539
        uid.Unlock()
1540
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1541
    else:
1542
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1543

    
1544
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1545
                     constants.RUN_DIRS_MODE)])
1546
    for nic_seq, tap in enumerate(taps):
1547
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1548
                      data=tap)
1549

    
1550
    if vnc_pwd:
1551
      change_cmd = "change vnc password %s" % vnc_pwd
1552
      self._CallMonitorCommand(instance.name, change_cmd)
1553

    
1554
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1555
    # connection attempts because SPICE by default does not allow connections
1556
    # if neither a password nor the "disable_ticketing" options are specified.
1557
    # As soon as we send the password via QMP, that password is a valid ticket
1558
    # for connection.
1559
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1560
    if spice_password_file:
1561
      spice_pwd = ""
1562
      try:
1563
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1564
      except EnvironmentError, err:
1565
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1566
                                     % (spice_password_file, err))
1567

    
1568
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1569
      qmp.connect()
1570
      arguments = {
1571
          "protocol": "spice",
1572
          "password": spice_pwd,
1573
      }
1574
      qmp.Execute("set_password", arguments)
1575

    
1576
    for filename in temp_files:
1577
      utils.RemoveFile(filename)
1578

    
1579
    # If requested, set CPU affinity and resume instance execution
1580
    if cpu_pinning:
1581
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1582

    
1583
    start_memory = self._InstanceStartupMemory(instance)
1584
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1585
      self.BalloonInstanceMemory(instance, start_memory)
1586

    
1587
    if start_kvm_paused:
1588
      # To control CPU pinning, ballooning, and vnc/spice passwords
1589
      # the VM was started in a frozen state. If freezing was not
1590
      # explicitly requested resume the vm status.
1591
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1592

    
1593
  def StartInstance(self, instance, block_devices, startup_paused):
1594
    """Start an instance.
1595

1596
    """
1597
    self._CheckDown(instance.name)
1598
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1599
                                           startup_paused)
1600
    self._SaveKVMRuntime(instance, kvm_runtime)
1601
    self._ExecuteKVMRuntime(instance, kvm_runtime)
1602

    
1603
  def _CallMonitorCommand(self, instance_name, command):
1604
    """Invoke a command on the instance monitor.
1605

1606
    """
1607
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1608
             (utils.ShellQuote(command),
1609
              constants.SOCAT_PATH,
1610
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1611
    result = utils.RunCmd(socat)
1612
    if result.failed:
1613
      msg = ("Failed to send command '%s' to instance %s."
1614
             " output: %s, error: %s, fail_reason: %s" %
1615
             (command, instance_name,
1616
              result.stdout, result.stderr, result.fail_reason))
1617
      raise errors.HypervisorError(msg)
1618

    
1619
    return result
1620

    
1621
  @classmethod
1622
  def _ParseKVMVersion(cls, text):
1623
    """Parse the KVM version from the --help output.
1624

1625
    @type text: string
1626
    @param text: output of kvm --help
1627
    @return: (version, v_maj, v_min, v_rev)
1628
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1629

1630
    """
1631
    match = cls._VERSION_RE.search(text.splitlines()[0])
1632
    if not match:
1633
      raise errors.HypervisorError("Unable to get KVM version")
1634

    
1635
    v_all = match.group(0)
1636
    v_maj = int(match.group(1))
1637
    v_min = int(match.group(2))
1638
    if match.group(4):
1639
      v_rev = int(match.group(4))
1640
    else:
1641
      v_rev = 0
1642
    return (v_all, v_maj, v_min, v_rev)
1643

    
1644
  @classmethod
1645
  def _GetKVMVersion(cls):
1646
    """Return the installed KVM version.
1647

1648
    @return: (version, v_maj, v_min, v_rev)
1649
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1650

1651
    """
1652
    result = utils.RunCmd([constants.KVM_PATH, "--help"])
1653
    if result.failed:
1654
      raise errors.HypervisorError("Unable to get KVM version")
1655
    return cls._ParseKVMVersion(result.output)
1656

    
1657
  def StopInstance(self, instance, force=False, retry=False, name=None):
1658
    """Stop an instance.
1659

1660
    """
1661
    if name is not None and not force:
1662
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1663
    if name is None:
1664
      name = instance.name
1665
      acpi = instance.hvparams[constants.HV_ACPI]
1666
    else:
1667
      acpi = False
1668
    _, pid, alive = self._InstancePidAlive(name)
1669
    if pid > 0 and alive:
1670
      if force or not acpi:
1671
        utils.KillProcess(pid)
1672
      else:
1673
        self._CallMonitorCommand(name, "system_powerdown")
1674

    
1675
  @classmethod
1676
  def _GetDefaultMachineVersion(cls):
1677
    """Return the default hardware revision (e.g. pc-1.1)
1678

1679
    """
1680
    result = utils.RunCmd([constants.KVM_PATH, "-M", "?"])
1681
    if result.failed:
1682
      raise errors.HypervisorError("Unable to get default hardware revision")
1683
    for line in result.output.splitlines():
1684
      match = cls._DEFAULT_MACHINE_VERSION_RE.match(line)
1685
      if match:
1686
        return match.group(1)
1687

    
1688
    return "pc"
1689

    
1690
  def CleanupInstance(self, instance_name):
1691
    """Cleanup after a stopped instance
1692

1693
    """
1694
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
1695
    if pid > 0 and alive:
1696
      raise errors.HypervisorError("Cannot cleanup a live instance")
1697
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1698

    
1699
  def RebootInstance(self, instance):
1700
    """Reboot an instance.
1701

1702
    """
1703
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1704
    # socket the instance will stop, but now power up again. So we'll resort
1705
    # to shutdown and restart.
1706
    _, _, alive = self._InstancePidAlive(instance.name)
1707
    if not alive:
1708
      raise errors.HypervisorError("Failed to reboot instance %s:"
1709
                                   " not running" % instance.name)
1710
    # StopInstance will delete the saved KVM runtime so:
1711
    # ...first load it...
1712
    kvm_runtime = self._LoadKVMRuntime(instance)
1713
    # ...now we can safely call StopInstance...
1714
    if not self.StopInstance(instance):
1715
      self.StopInstance(instance, force=True)
1716
    # ...and finally we can save it again, and execute it...
1717
    self._SaveKVMRuntime(instance, kvm_runtime)
1718
    self._ExecuteKVMRuntime(instance, kvm_runtime)
1719

    
1720
  def MigrationInfo(self, instance):
1721
    """Get instance information to perform a migration.
1722

1723
    @type instance: L{objects.Instance}
1724
    @param instance: instance to be migrated
1725
    @rtype: string
1726
    @return: content of the KVM runtime file
1727

1728
    """
1729
    return self._ReadKVMRuntime(instance.name)
1730

    
1731
  def AcceptInstance(self, instance, info, target):
1732
    """Prepare to accept an instance.
1733

1734
    @type instance: L{objects.Instance}
1735
    @param instance: instance to be accepted
1736
    @type info: string
1737
    @param info: content of the KVM runtime file on the source node
1738
    @type target: string
1739
    @param target: target host (usually ip), on this node
1740

1741
    """
1742
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1743
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1744
    self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
1745

    
1746
  def FinalizeMigrationDst(self, instance, info, success):
1747
    """Finalize the instance migration on the target node.
1748

1749
    Stop the incoming mode KVM.
1750

1751
    @type instance: L{objects.Instance}
1752
    @param instance: instance whose migration is being finalized
1753

1754
    """
1755
    if success:
1756
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1757
      kvm_nics = kvm_runtime[1]
1758

    
1759
      for nic_seq, nic in enumerate(kvm_nics):
1760
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1761
          # Bridged interfaces have already been configured
1762
          continue
1763
        try:
1764
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1765
        except EnvironmentError, err:
1766
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
1767
                          instance.name, nic_seq, str(err))
1768
          continue
1769
        try:
1770
          self._ConfigureNIC(instance, nic_seq, nic, tap)
1771
        except errors.HypervisorError, err:
1772
          logging.warning(str(err))
1773

    
1774
      self._WriteKVMRuntime(instance.name, info)
1775
    else:
1776
      self.StopInstance(instance, force=True)
1777

    
1778
  def MigrateInstance(self, instance, target, live):
1779
    """Migrate an instance to a target node.
1780

1781
    The migration will not be attempted if the instance is not
1782
    currently running.
1783

1784
    @type instance: L{objects.Instance}
1785
    @param instance: the instance to be migrated
1786
    @type target: string
1787
    @param target: ip address of the target node
1788
    @type live: boolean
1789
    @param live: perform a live migration
1790

1791
    """
1792
    instance_name = instance.name
1793
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
1794
    _, _, alive = self._InstancePidAlive(instance_name)
1795
    if not alive:
1796
      raise errors.HypervisorError("Instance not running, cannot migrate")
1797

    
1798
    if not live:
1799
      self._CallMonitorCommand(instance_name, "stop")
1800

    
1801
    migrate_command = ("migrate_set_speed %dm" %
1802
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1803
    self._CallMonitorCommand(instance_name, migrate_command)
1804

    
1805
    migrate_command = ("migrate_set_downtime %dms" %
1806
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1807
    self._CallMonitorCommand(instance_name, migrate_command)
1808

    
1809
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1810
    self._CallMonitorCommand(instance_name, migrate_command)
1811

    
1812
  def FinalizeMigrationSource(self, instance, success, live):
1813
    """Finalize the instance migration on the source node.
1814

1815
    @type instance: L{objects.Instance}
1816
    @param instance: the instance that was migrated
1817
    @type success: bool
1818
    @param success: whether the migration succeeded or not
1819
    @type live: bool
1820
    @param live: whether the user requested a live migration or not
1821

1822
    """
1823
    if success:
1824
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
1825
      utils.KillProcess(pid)
1826
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1827
    elif live:
1828
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1829

    
1830
  def GetMigrationStatus(self, instance):
1831
    """Get the migration status
1832

1833
    @type instance: L{objects.Instance}
1834
    @param instance: the instance that is being migrated
1835
    @rtype: L{objects.MigrationStatus}
1836
    @return: the status of the current migration (one of
1837
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1838
             progress info that can be retrieved from the hypervisor
1839

1840
    """
1841
    info_command = "info migrate"
1842
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
1843
      result = self._CallMonitorCommand(instance.name, info_command)
1844
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
1845
      if not match:
1846
        if not result.stdout:
1847
          logging.info("KVM: empty 'info migrate' result")
1848
        else:
1849
          logging.warning("KVM: unknown 'info migrate' result: %s",
1850
                          result.stdout)
1851
      else:
1852
        status = match.group(1)
1853
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
1854
          migration_status = objects.MigrationStatus(status=status)
1855
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
1856
          if match:
1857
            migration_status.transferred_ram = match.group("transferred")
1858
            migration_status.total_ram = match.group("total")
1859

    
1860
          return migration_status
1861

    
1862
        logging.warning("KVM: unknown migration status '%s'", status)
1863

    
1864
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1865

    
1866
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
1867

    
1868
  def BalloonInstanceMemory(self, instance, mem):
1869
    """Balloon an instance memory to a certain value.
1870

1871
    @type instance: L{objects.Instance}
1872
    @param instance: instance to be accepted
1873
    @type mem: int
1874
    @param mem: actual memory size to use for instance runtime
1875

1876
    """
1877
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
1878

    
1879
  def GetNodeInfo(self):
1880
    """Return information about the node.
1881

1882
    @return: a dict with the following keys (values in MiB):
1883
          - memory_total: the total memory size on the node
1884
          - memory_free: the available memory on the node for instances
1885
          - memory_dom0: the memory used by the node itself, if available
1886
          - hv_version: the hypervisor version in the form (major, minor,
1887
                        revision)
1888

1889
    """
1890
    result = self.GetLinuxNodeInfo()
1891
    _, v_major, v_min, v_rev = self._GetKVMVersion()
1892
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
1893
    return result
1894

    
1895
  @classmethod
1896
  def GetInstanceConsole(cls, instance, hvparams, beparams):
1897
    """Return a command for connecting to the console of an instance.
1898

1899
    """
1900
    if hvparams[constants.HV_SERIAL_CONSOLE]:
1901
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
1902
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1903
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1904
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
1905
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1906
      return objects.InstanceConsole(instance=instance.name,
1907
                                     kind=constants.CONS_SSH,
1908
                                     host=instance.primary_node,
1909
                                     user=constants.SSH_CONSOLE_USER,
1910
                                     command=cmd)
1911

    
1912
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1913
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1914
      display = instance.network_port - constants.VNC_BASE_PORT
1915
      return objects.InstanceConsole(instance=instance.name,
1916
                                     kind=constants.CONS_VNC,
1917
                                     host=vnc_bind_address,
1918
                                     port=instance.network_port,
1919
                                     display=display)
1920

    
1921
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1922
    if spice_bind:
1923
      return objects.InstanceConsole(instance=instance.name,
1924
                                     kind=constants.CONS_SPICE,
1925
                                     host=spice_bind,
1926
                                     port=instance.network_port)
1927

    
1928
    return objects.InstanceConsole(instance=instance.name,
1929
                                   kind=constants.CONS_MESSAGE,
1930
                                   message=("No serial shell for instance %s" %
1931
                                            instance.name))
1932

    
1933
  def Verify(self):
1934
    """Verify the hypervisor.
1935

1936
    Check that the binary exists.
1937

1938
    """
1939
    if not os.path.exists(constants.KVM_PATH):
1940
      return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
1941
    if not os.path.exists(constants.SOCAT_PATH):
1942
      return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
1943

    
1944
  @classmethod
1945
  def CheckParameterSyntax(cls, hvparams):
1946
    """Check the given parameters for validity.
1947

1948
    @type hvparams:  dict
1949
    @param hvparams: dictionary with parameter names/value
1950
    @raise errors.HypervisorError: when a parameter is not valid
1951

1952
    """
1953
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
1954

    
1955
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
1956
    if kernel_path:
1957
      if not hvparams[constants.HV_ROOT_PATH]:
1958
        raise errors.HypervisorError("Need a root partition for the instance,"
1959
                                     " if a kernel is defined")
1960

    
1961
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
1962
        not hvparams[constants.HV_VNC_X509]):
1963
      raise errors.HypervisorError("%s must be defined, if %s is" %
1964
                                   (constants.HV_VNC_X509,
1965
                                    constants.HV_VNC_X509_VERIFY))
1966

    
1967
    if hvparams[constants.HV_SERIAL_CONSOLE]:
1968
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
1969
      valid_speeds = constants.VALID_SERIAL_SPEEDS
1970
      if not serial_speed or serial_speed not in valid_speeds:
1971
        raise errors.HypervisorError("Invalid serial console speed, must be"
1972
                                     " one of: %s" %
1973
                                     utils.CommaJoin(valid_speeds))
1974

    
1975
    boot_order = hvparams[constants.HV_BOOT_ORDER]
1976
    if (boot_order == constants.HT_BO_CDROM and
1977
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
1978
      raise errors.HypervisorError("Cannot boot from cdrom without an"
1979
                                   " ISO path")
1980

    
1981
    security_model = hvparams[constants.HV_SECURITY_MODEL]
1982
    if security_model == constants.HT_SM_USER:
1983
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
1984
        raise errors.HypervisorError("A security domain (user to run kvm as)"
1985
                                     " must be specified")
1986
    elif (security_model == constants.HT_SM_NONE or
1987
          security_model == constants.HT_SM_POOL):
1988
      if hvparams[constants.HV_SECURITY_DOMAIN]:
1989
        raise errors.HypervisorError("Cannot have a security domain when the"
1990
                                     " security model is 'none' or 'pool'")
1991

    
1992
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1993
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
1994
    if spice_bind:
1995
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1996
        # if an IP version is specified, the spice_bind parameter must be an
1997
        # IP of that family
1998
        if (netutils.IP4Address.IsValid(spice_bind) and
1999
            spice_ip_version != constants.IP4_VERSION):
2000
          raise errors.HypervisorError("spice: got an IPv4 address (%s), but"
2001
                                       " the specified IP version is %s" %
2002
                                       (spice_bind, spice_ip_version))
2003

    
2004
        if (netutils.IP6Address.IsValid(spice_bind) and
2005
            spice_ip_version != constants.IP6_VERSION):
2006
          raise errors.HypervisorError("spice: got an IPv6 address (%s), but"
2007
                                       " the specified IP version is %s" %
2008
                                       (spice_bind, spice_ip_version))
2009
    else:
2010
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2011
      # error if any of them is set without it.
2012
      for param in _SPICE_ADDITIONAL_PARAMS:
2013
        if hvparams[param]:
2014
          raise errors.HypervisorError("spice: %s requires %s to be set" %
2015
                                       (param, constants.HV_KVM_SPICE_BIND))
2016

    
2017
  @classmethod
2018
  def ValidateParameters(cls, hvparams):
2019
    """Check the given parameters for validity.
2020

2021
    @type hvparams:  dict
2022
    @param hvparams: dictionary with parameter names/value
2023
    @raise errors.HypervisorError: when a parameter is not valid
2024

2025
    """
2026
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2027

    
2028
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2029
    if security_model == constants.HT_SM_USER:
2030
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2031
      try:
2032
        pwd.getpwnam(username)
2033
      except KeyError:
2034
        raise errors.HypervisorError("Unknown security domain user %s"
2035
                                     % username)
2036

    
2037
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2038
    if spice_bind:
2039
      # only one of VNC and SPICE can be used currently.
2040
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2041
        raise errors.HypervisorError("both SPICE and VNC are configured, but"
2042
                                     " only one of them can be used at a"
2043
                                     " given time.")
2044

    
2045
      # KVM version should be >= 0.14.0
2046
      _, v_major, v_min, _ = cls._GetKVMVersion()
2047
      if (v_major, v_min) < (0, 14):
2048
        raise errors.HypervisorError("spice is configured, but it is not"
2049
                                     " available in versions of KVM < 0.14")
2050

    
2051
      # if spice_bind is not an IP address, it must be a valid interface
2052
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind)
2053
                       or netutils.IP6Address.IsValid(spice_bind))
2054
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2055
        raise errors.HypervisorError("spice: the %s parameter must be either"
2056
                                     " a valid IP address or interface name" %
2057
                                     constants.HV_KVM_SPICE_BIND)
2058

    
2059
  @classmethod
2060
  def PowercycleNode(cls):
2061
    """KVM powercycle, just a wrapper over Linux powercycle.
2062

2063
    """
2064
    cls.LinuxPowercycle()