Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ e3b89628

History | View | Annotate | Download (74.7 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
    kvm_cmd.extend(["-usb"])
1176

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

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

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

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

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

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

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

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

    
1249
        spice_address = addresses[spice_ip_version][0]
1250

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1329
    return (kvm_cmd, kvm_nics, hvparams)
1330

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1413
    temp_files = []
1414

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1620
    return result
1621

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

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

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

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

    
1645
  @classmethod
1646
  def _GetKVMHelpOutput(cls):
1647
    """Return the KVM help output.
1648

1649
    @return: output of kvm --help
1650
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1651

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

    
1658
  @classmethod
1659
  def _GetKVMVersion(cls):
1660
    """Return the installed KVM version.
1661

1662
    @return: (version, v_maj, v_min, v_rev)
1663
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1664

1665
    """
1666
    return cls._ParseKVMVersion(cls._GetKVMHelpOutput())
1667

    
1668
  def StopInstance(self, instance, force=False, retry=False, name=None):
1669
    """Stop an instance.
1670

1671
    """
1672
    if name is not None and not force:
1673
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1674
    if name is None:
1675
      name = instance.name
1676
      acpi = instance.hvparams[constants.HV_ACPI]
1677
    else:
1678
      acpi = False
1679
    _, pid, alive = self._InstancePidAlive(name)
1680
    if pid > 0 and alive:
1681
      if force or not acpi:
1682
        utils.KillProcess(pid)
1683
      else:
1684
        self._CallMonitorCommand(name, "system_powerdown")
1685

    
1686
  @classmethod
1687
  def _GetDefaultMachineVersion(cls):
1688
    """Return the default hardware revision (e.g. pc-1.1)
1689

1690
    """
1691
    result = utils.RunCmd([constants.KVM_PATH, "-M", "?"])
1692
    if result.failed:
1693
      raise errors.HypervisorError("Unable to get default hardware revision")
1694
    for line in result.output.splitlines():
1695
      match = cls._DEFAULT_MACHINE_VERSION_RE.match(line)
1696
      if match:
1697
        return match.group(1)
1698

    
1699
    return "pc"
1700

    
1701
  def CleanupInstance(self, instance_name):
1702
    """Cleanup after a stopped instance
1703

1704
    """
1705
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
1706
    if pid > 0 and alive:
1707
      raise errors.HypervisorError("Cannot cleanup a live instance")
1708
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1709

    
1710
  def RebootInstance(self, instance):
1711
    """Reboot an instance.
1712

1713
    """
1714
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1715
    # socket the instance will stop, but now power up again. So we'll resort
1716
    # to shutdown and restart.
1717
    _, _, alive = self._InstancePidAlive(instance.name)
1718
    if not alive:
1719
      raise errors.HypervisorError("Failed to reboot instance %s:"
1720
                                   " not running" % instance.name)
1721
    # StopInstance will delete the saved KVM runtime so:
1722
    # ...first load it...
1723
    kvm_runtime = self._LoadKVMRuntime(instance)
1724
    # ...now we can safely call StopInstance...
1725
    if not self.StopInstance(instance):
1726
      self.StopInstance(instance, force=True)
1727
    # ...and finally we can save it again, and execute it...
1728
    self._SaveKVMRuntime(instance, kvm_runtime)
1729
    self._ExecuteKVMRuntime(instance, kvm_runtime)
1730

    
1731
  def MigrationInfo(self, instance):
1732
    """Get instance information to perform a migration.
1733

1734
    @type instance: L{objects.Instance}
1735
    @param instance: instance to be migrated
1736
    @rtype: string
1737
    @return: content of the KVM runtime file
1738

1739
    """
1740
    return self._ReadKVMRuntime(instance.name)
1741

    
1742
  def AcceptInstance(self, instance, info, target):
1743
    """Prepare to accept an instance.
1744

1745
    @type instance: L{objects.Instance}
1746
    @param instance: instance to be accepted
1747
    @type info: string
1748
    @param info: content of the KVM runtime file on the source node
1749
    @type target: string
1750
    @param target: target host (usually ip), on this node
1751

1752
    """
1753
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1754
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1755
    self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
1756

    
1757
  def FinalizeMigrationDst(self, instance, info, success):
1758
    """Finalize the instance migration on the target node.
1759

1760
    Stop the incoming mode KVM.
1761

1762
    @type instance: L{objects.Instance}
1763
    @param instance: instance whose migration is being finalized
1764

1765
    """
1766
    if success:
1767
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1768
      kvm_nics = kvm_runtime[1]
1769

    
1770
      for nic_seq, nic in enumerate(kvm_nics):
1771
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1772
          # Bridged interfaces have already been configured
1773
          continue
1774
        try:
1775
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1776
        except EnvironmentError, err:
1777
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
1778
                          instance.name, nic_seq, str(err))
1779
          continue
1780
        try:
1781
          self._ConfigureNIC(instance, nic_seq, nic, tap)
1782
        except errors.HypervisorError, err:
1783
          logging.warning(str(err))
1784

    
1785
      self._WriteKVMRuntime(instance.name, info)
1786
    else:
1787
      self.StopInstance(instance, force=True)
1788

    
1789
  def MigrateInstance(self, instance, target, live):
1790
    """Migrate an instance to a target node.
1791

1792
    The migration will not be attempted if the instance is not
1793
    currently running.
1794

1795
    @type instance: L{objects.Instance}
1796
    @param instance: the instance to be migrated
1797
    @type target: string
1798
    @param target: ip address of the target node
1799
    @type live: boolean
1800
    @param live: perform a live migration
1801

1802
    """
1803
    instance_name = instance.name
1804
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
1805
    _, _, alive = self._InstancePidAlive(instance_name)
1806
    if not alive:
1807
      raise errors.HypervisorError("Instance not running, cannot migrate")
1808

    
1809
    if not live:
1810
      self._CallMonitorCommand(instance_name, "stop")
1811

    
1812
    migrate_command = ("migrate_set_speed %dm" %
1813
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1814
    self._CallMonitorCommand(instance_name, migrate_command)
1815

    
1816
    migrate_command = ("migrate_set_downtime %dms" %
1817
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1818
    self._CallMonitorCommand(instance_name, migrate_command)
1819

    
1820
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1821
    self._CallMonitorCommand(instance_name, migrate_command)
1822

    
1823
  def FinalizeMigrationSource(self, instance, success, live):
1824
    """Finalize the instance migration on the source node.
1825

1826
    @type instance: L{objects.Instance}
1827
    @param instance: the instance that was migrated
1828
    @type success: bool
1829
    @param success: whether the migration succeeded or not
1830
    @type live: bool
1831
    @param live: whether the user requested a live migration or not
1832

1833
    """
1834
    if success:
1835
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
1836
      utils.KillProcess(pid)
1837
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1838
    elif live:
1839
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1840

    
1841
  def GetMigrationStatus(self, instance):
1842
    """Get the migration status
1843

1844
    @type instance: L{objects.Instance}
1845
    @param instance: the instance that is being migrated
1846
    @rtype: L{objects.MigrationStatus}
1847
    @return: the status of the current migration (one of
1848
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1849
             progress info that can be retrieved from the hypervisor
1850

1851
    """
1852
    info_command = "info migrate"
1853
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
1854
      result = self._CallMonitorCommand(instance.name, info_command)
1855
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
1856
      if not match:
1857
        if not result.stdout:
1858
          logging.info("KVM: empty 'info migrate' result")
1859
        else:
1860
          logging.warning("KVM: unknown 'info migrate' result: %s",
1861
                          result.stdout)
1862
      else:
1863
        status = match.group(1)
1864
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
1865
          migration_status = objects.MigrationStatus(status=status)
1866
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
1867
          if match:
1868
            migration_status.transferred_ram = match.group("transferred")
1869
            migration_status.total_ram = match.group("total")
1870

    
1871
          return migration_status
1872

    
1873
        logging.warning("KVM: unknown migration status '%s'", status)
1874

    
1875
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1876

    
1877
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
1878

    
1879
  def BalloonInstanceMemory(self, instance, mem):
1880
    """Balloon an instance memory to a certain value.
1881

1882
    @type instance: L{objects.Instance}
1883
    @param instance: instance to be accepted
1884
    @type mem: int
1885
    @param mem: actual memory size to use for instance runtime
1886

1887
    """
1888
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
1889

    
1890
  def GetNodeInfo(self):
1891
    """Return information about the node.
1892

1893
    @return: a dict with the following keys (values in MiB):
1894
          - memory_total: the total memory size on the node
1895
          - memory_free: the available memory on the node for instances
1896
          - memory_dom0: the memory used by the node itself, if available
1897
          - hv_version: the hypervisor version in the form (major, minor,
1898
                        revision)
1899

1900
    """
1901
    result = self.GetLinuxNodeInfo()
1902
    _, v_major, v_min, v_rev = self._GetKVMVersion()
1903
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
1904
    return result
1905

    
1906
  @classmethod
1907
  def GetInstanceConsole(cls, instance, hvparams, beparams):
1908
    """Return a command for connecting to the console of an instance.
1909

1910
    """
1911
    if hvparams[constants.HV_SERIAL_CONSOLE]:
1912
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
1913
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1914
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1915
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
1916
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1917
      return objects.InstanceConsole(instance=instance.name,
1918
                                     kind=constants.CONS_SSH,
1919
                                     host=instance.primary_node,
1920
                                     user=constants.SSH_CONSOLE_USER,
1921
                                     command=cmd)
1922

    
1923
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1924
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1925
      display = instance.network_port - constants.VNC_BASE_PORT
1926
      return objects.InstanceConsole(instance=instance.name,
1927
                                     kind=constants.CONS_VNC,
1928
                                     host=vnc_bind_address,
1929
                                     port=instance.network_port,
1930
                                     display=display)
1931

    
1932
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1933
    if spice_bind:
1934
      return objects.InstanceConsole(instance=instance.name,
1935
                                     kind=constants.CONS_SPICE,
1936
                                     host=spice_bind,
1937
                                     port=instance.network_port)
1938

    
1939
    return objects.InstanceConsole(instance=instance.name,
1940
                                   kind=constants.CONS_MESSAGE,
1941
                                   message=("No serial shell for instance %s" %
1942
                                            instance.name))
1943

    
1944
  def Verify(self):
1945
    """Verify the hypervisor.
1946

1947
    Check that the binary exists.
1948

1949
    """
1950
    if not os.path.exists(constants.KVM_PATH):
1951
      return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
1952
    if not os.path.exists(constants.SOCAT_PATH):
1953
      return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
1954

    
1955
  @classmethod
1956
  def CheckParameterSyntax(cls, hvparams):
1957
    """Check the given parameters for validity.
1958

1959
    @type hvparams:  dict
1960
    @param hvparams: dictionary with parameter names/value
1961
    @raise errors.HypervisorError: when a parameter is not valid
1962

1963
    """
1964
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
1965

    
1966
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
1967
    if kernel_path:
1968
      if not hvparams[constants.HV_ROOT_PATH]:
1969
        raise errors.HypervisorError("Need a root partition for the instance,"
1970
                                     " if a kernel is defined")
1971

    
1972
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
1973
        not hvparams[constants.HV_VNC_X509]):
1974
      raise errors.HypervisorError("%s must be defined, if %s is" %
1975
                                   (constants.HV_VNC_X509,
1976
                                    constants.HV_VNC_X509_VERIFY))
1977

    
1978
    if hvparams[constants.HV_SERIAL_CONSOLE]:
1979
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
1980
      valid_speeds = constants.VALID_SERIAL_SPEEDS
1981
      if not serial_speed or serial_speed not in valid_speeds:
1982
        raise errors.HypervisorError("Invalid serial console speed, must be"
1983
                                     " one of: %s" %
1984
                                     utils.CommaJoin(valid_speeds))
1985

    
1986
    boot_order = hvparams[constants.HV_BOOT_ORDER]
1987
    if (boot_order == constants.HT_BO_CDROM and
1988
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
1989
      raise errors.HypervisorError("Cannot boot from cdrom without an"
1990
                                   " ISO path")
1991

    
1992
    security_model = hvparams[constants.HV_SECURITY_MODEL]
1993
    if security_model == constants.HT_SM_USER:
1994
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
1995
        raise errors.HypervisorError("A security domain (user to run kvm as)"
1996
                                     " must be specified")
1997
    elif (security_model == constants.HT_SM_NONE or
1998
          security_model == constants.HT_SM_POOL):
1999
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2000
        raise errors.HypervisorError("Cannot have a security domain when the"
2001
                                     " security model is 'none' or 'pool'")
2002

    
2003
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2004
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2005
    if spice_bind:
2006
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2007
        # if an IP version is specified, the spice_bind parameter must be an
2008
        # IP of that family
2009
        if (netutils.IP4Address.IsValid(spice_bind) and
2010
            spice_ip_version != constants.IP4_VERSION):
2011
          raise errors.HypervisorError("spice: got an IPv4 address (%s), but"
2012
                                       " the specified IP version is %s" %
2013
                                       (spice_bind, spice_ip_version))
2014

    
2015
        if (netutils.IP6Address.IsValid(spice_bind) and
2016
            spice_ip_version != constants.IP6_VERSION):
2017
          raise errors.HypervisorError("spice: got an IPv6 address (%s), but"
2018
                                       " the specified IP version is %s" %
2019
                                       (spice_bind, spice_ip_version))
2020
    else:
2021
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2022
      # error if any of them is set without it.
2023
      for param in _SPICE_ADDITIONAL_PARAMS:
2024
        if hvparams[param]:
2025
          raise errors.HypervisorError("spice: %s requires %s to be set" %
2026
                                       (param, constants.HV_KVM_SPICE_BIND))
2027

    
2028
  @classmethod
2029
  def ValidateParameters(cls, hvparams):
2030
    """Check the given parameters for validity.
2031

2032
    @type hvparams:  dict
2033
    @param hvparams: dictionary with parameter names/value
2034
    @raise errors.HypervisorError: when a parameter is not valid
2035

2036
    """
2037
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2038

    
2039
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2040
    if security_model == constants.HT_SM_USER:
2041
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2042
      try:
2043
        pwd.getpwnam(username)
2044
      except KeyError:
2045
        raise errors.HypervisorError("Unknown security domain user %s"
2046
                                     % username)
2047

    
2048
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2049
    if spice_bind:
2050
      # only one of VNC and SPICE can be used currently.
2051
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2052
        raise errors.HypervisorError("both SPICE and VNC are configured, but"
2053
                                     " only one of them can be used at a"
2054
                                     " given time.")
2055

    
2056
      # KVM version should be >= 0.14.0
2057
      _, v_major, v_min, _ = cls._GetKVMVersion()
2058
      if (v_major, v_min) < (0, 14):
2059
        raise errors.HypervisorError("spice is configured, but it is not"
2060
                                     " available in versions of KVM < 0.14")
2061

    
2062
      # if spice_bind is not an IP address, it must be a valid interface
2063
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind)
2064
                       or netutils.IP6Address.IsValid(spice_bind))
2065
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2066
        raise errors.HypervisorError("spice: the %s parameter must be either"
2067
                                     " a valid IP address or interface name" %
2068
                                     constants.HV_KVM_SPICE_BIND)
2069

    
2070
  @classmethod
2071
  def PowercycleNode(cls):
2072
    """KVM powercycle, just a wrapper over Linux powercycle.
2073

2074
    """
2075
    cls.LinuxPowercycle()