Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 14fd6c81

History | View | Annotate | Download (73.9 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.NO_CHECK,
518
    constants.HV_MIGRATION_DOWNTIME: hv_base.NO_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
    }
536

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

    
544
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
545
  _MIGRATION_INFO_RETRY_DELAY = 2
546

    
547
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
548

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

    
553
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"(\S+).*\(default\)")
554

    
555
  ANCILLARY_FILES = [
556
    _KVM_NETWORK_SCRIPT,
557
    ]
558
  ANCILLARY_FILES_OPT = [
559
    _KVM_NETWORK_SCRIPT,
560
    ]
561

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

    
569
  @classmethod
570
  def _InstancePidFile(cls, instance_name):
571
    """Returns the instance pidfile.
572

573
    """
574
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
575

    
576
  @classmethod
577
  def _InstanceUidFile(cls, instance_name):
578
    """Returns the instance uidfile.
579

580
    """
581
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
582

    
583
  @classmethod
584
  def _InstancePidInfo(cls, pid):
585
    """Check pid file for instance information.
586

587
    Check that a pid file is associated with an instance, and retrieve
588
    information from its command line.
589

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

596
    """
597
    alive = utils.IsProcessAlive(pid)
598
    if not alive:
599
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
600

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

    
608
    instance = None
609
    memory = 0
610
    vcpus = 0
611

    
612
    arg_list = cmdline.split("\x00")
613
    while arg_list:
614
      arg = arg_list.pop(0)
615
      if arg == "-name":
616
        instance = arg_list.pop(0)
617
      elif arg == "-m":
618
        memory = int(arg_list.pop(0))
619
      elif arg == "-smp":
620
        vcpus = int(arg_list.pop(0))
621

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

    
626
    return (instance, memory, vcpus)
627

    
628
  def _InstancePidAlive(self, instance_name):
629
    """Returns the instance pidfile, pid, and liveness.
630

631
    @type instance_name: string
632
    @param instance_name: instance name
633
    @rtype: tuple
634
    @return: (pid file name, pid, liveness)
635

636
    """
637
    pidfile = self._InstancePidFile(instance_name)
638
    pid = utils.ReadPidFile(pidfile)
639

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

    
647
    return (pidfile, pid, alive)
648

    
649
  def _CheckDown(self, instance_name):
650
    """Raises an error unless the given instance is down.
651

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

    
658
  @classmethod
659
  def _InstanceMonitor(cls, instance_name):
660
    """Returns the instance monitor socket name
661

662
    """
663
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
664

    
665
  @classmethod
666
  def _InstanceSerial(cls, instance_name):
667
    """Returns the instance serial socket name
668

669
    """
670
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
671

    
672
  @classmethod
673
  def _InstanceQmpMonitor(cls, instance_name):
674
    """Returns the instance serial QMP socket name
675

676
    """
677
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
678

    
679
  @staticmethod
680
  def _SocatUnixConsoleParams():
681
    """Returns the correct parameters for socat
682

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

685
    """
686
    if constants.SOCAT_USE_ESCAPE:
687
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
688
    else:
689
      return "echo=0,icanon=0"
690

    
691
  @classmethod
692
  def _InstanceKVMRuntime(cls, instance_name):
693
    """Returns the instance KVM runtime filename
694

695
    """
696
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
697

    
698
  @classmethod
699
  def _InstanceChrootDir(cls, instance_name):
700
    """Returns the name of the KVM chroot dir of the instance
701

702
    """
703
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
704

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

710
    """
711
    return utils.PathJoin(cls._NICS_DIR, instance_name)
712

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

717
    """
718
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
719

    
720
  @classmethod
721
  def _InstanceKeymapFile(cls, instance_name):
722
    """Returns the name of the file containing the keymap for a given instance
723

724
    """
725
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
726

    
727
  @classmethod
728
  def _TryReadUidFile(cls, uid_file):
729
    """Try to read a uid file
730

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

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

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

    
782
  @staticmethod
783
  def _ConfigureNIC(instance, seq, nic, tap):
784
    """Run the network configuration script for a specified NIC
785

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

795
    """
796
    if instance.tags:
797
      tags = " ".join(instance.tags)
798
    else:
799
      tags = ""
800

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

    
811
    if nic.ip:
812
      env["IP"] = nic.ip
813

    
814
    if nic.nicparams[constants.NIC_LINK]:
815
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
816

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

    
823
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
824
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
825

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

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

    
838
  @staticmethod
839
  def _BuildAffinityCpuMask(cpu_list):
840
    """Create a CPU mask suitable for sched_setaffinity from a list of
841
    CPUs.
842

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

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

851
    """
852
    if cpu_list == constants.CPU_PINNING_OFF:
853
      return constants.CPU_PINNING_ALL_KVM
854
    else:
855
      return sum(2 ** cpu for cpu in cpu_list)
856

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

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

869
    """
870
    # Convert the string CPU mask to a list of list of int's
871
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
872

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

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

    
896
  def _GetVcpuThreadIds(self, instance_name):
897
    """Get a mapping of vCPU no. to thread IDs for the instance
898

899
    @type instance_name: string
900
    @param instance_name: instance in question
901
    @rtype: dictionary of int:int
902
    @return: a dictionary mapping vCPU numbers to thread IDs
903

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

    
914
    return result
915

    
916
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
917
    """Complete CPU pinning.
918

919
    @type instance_name: string
920
    @param instance_name: name of instance
921
    @type cpu_mask: string
922
    @param cpu_mask: CPU pinning mask as entered by user
923

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

    
932
  def ListInstances(self):
933
    """Get the list of running instances.
934

935
    We can do this by listing our live instances directory and
936
    checking whether the associated kvm process is still alive.
937

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

    
945
  def GetInstanceInfo(self, instance_name):
946
    """Get instance properties.
947

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

953
    """
954
    _, pid, alive = self._InstancePidAlive(instance_name)
955
    if not alive:
956
      return None
957

    
958
    _, memory, vcpus = self._InstancePidInfo(pid)
959
    istat = "---b-"
960
    times = "0"
961

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

    
973
    return (instance_name, pid, memory, vcpus, istat, times)
974

    
975
  def GetAllInstancesInfo(self):
976
    """Get properties of all instances.
977

978
    @return: list of tuples (name, id, memory, vcpus, stat, times)
979

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

    
992
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused):
993
    """Generate KVM information to start an instance.
994

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

1002
    """
1003
    # pylint: disable=R0914,R0915
1004
    _, v_major, v_min, _ = self._GetKVMVersion()
1005

    
1006
    pidfile = self._InstancePidFile(instance.name)
1007
    kvm = constants.KVM_PATH
1008
    kvm_cmd = [kvm]
1009
    kvm_cmd.extend(["-M", self._GetDefaultMachineVersion()])
1010
    # used just by the vnc server, if enabled
1011
    kvm_cmd.extend(["-name", instance.name])
1012
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1013
    kvm_cmd.extend(["-smp", instance.beparams[constants.BE_VCPUS]])
1014
    kvm_cmd.extend(["-pidfile", pidfile])
1015
    kvm_cmd.extend(["-balloon", "virtio"])
1016
    kvm_cmd.extend(["-daemonize"])
1017
    if not instance.hvparams[constants.HV_ACPI]:
1018
      kvm_cmd.extend(["-no-acpi"])
1019
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1020
        constants.INSTANCE_REBOOT_EXIT:
1021
      kvm_cmd.extend(["-no-reboot"])
1022

    
1023
    hvp = instance.hvparams
1024
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1025
    if kernel_path:
1026
      boot_disk = boot_cdrom = boot_floppy = boot_network = False
1027
    else:
1028
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1029
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1030
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1031
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1032

    
1033
    self.ValidateParameters(hvp)
1034

    
1035
    if startup_paused:
1036
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1037

    
1038
    if hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED:
1039
      kvm_cmd.extend(["-enable-kvm"])
1040
    elif hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED:
1041
      kvm_cmd.extend(["-disable-kvm"])
1042

    
1043
    if boot_network:
1044
      kvm_cmd.extend(["-boot", "n"])
1045

    
1046
    # whether this is an older KVM version that uses the boot=on flag
1047
    # on devices
1048
    needs_boot_flag = (v_major, v_min) < (0, 14)
1049

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

    
1080
      drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
1081
                                                cache_val)
1082
      kvm_cmd.extend(["-drive", drive_val])
1083

    
1084
    #Now we can specify a different device type for CDROM devices.
1085
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1086
    if not cdrom_disk_type:
1087
      cdrom_disk_type = disk_type
1088

    
1089
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1090
    if iso_image:
1091
      options = ",format=raw,media=cdrom"
1092
      # set cdrom 'if' type
1093
      if boot_cdrom:
1094
        actual_cdrom_type = constants.HT_DISK_IDE
1095
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1096
        actual_cdrom_type = "virtio"
1097
      else:
1098
        actual_cdrom_type = cdrom_disk_type
1099
      if_val = ",if=%s" % actual_cdrom_type
1100
      # set boot flag, if needed
1101
      boot_val = ""
1102
      if boot_cdrom:
1103
        kvm_cmd.extend(["-boot", "d"])
1104
        if needs_boot_flag:
1105
          boot_val = ",boot=on"
1106
      # and finally build the entire '-drive' value
1107
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1108
      kvm_cmd.extend(["-drive", drive_val])
1109

    
1110
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1111
    if iso_image2:
1112
      options = ",format=raw,media=cdrom"
1113
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1114
        if_val = ",if=virtio"
1115
      else:
1116
        if_val = ",if=%s" % cdrom_disk_type
1117
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1118
      kvm_cmd.extend(["-drive", drive_val])
1119

    
1120
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1121
    if floppy_image:
1122
      options = ",format=raw,media=disk"
1123
      if boot_floppy:
1124
        kvm_cmd.extend(["-boot", "a"])
1125
        options = "%s,boot=on" % options
1126
      if_val = ",if=floppy"
1127
      options = "%s%s" % (options, if_val)
1128
      drive_val = "file=%s%s" % (floppy_image, options)
1129
      kvm_cmd.extend(["-drive", drive_val])
1130

    
1131
    if kernel_path:
1132
      kvm_cmd.extend(["-kernel", kernel_path])
1133
      initrd_path = hvp[constants.HV_INITRD_PATH]
1134
      if initrd_path:
1135
        kvm_cmd.extend(["-initrd", initrd_path])
1136
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1137
                     hvp[constants.HV_KERNEL_ARGS]]
1138
      if hvp[constants.HV_SERIAL_CONSOLE]:
1139
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1140
        root_append.append("console=ttyS0,%s" % serial_speed)
1141
      kvm_cmd.extend(["-append", " ".join(root_append)])
1142

    
1143
    mem_path = hvp[constants.HV_MEM_PATH]
1144
    if mem_path:
1145
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1146

    
1147
    monitor_dev = ("unix:%s,server,nowait" %
1148
                   self._InstanceMonitor(instance.name))
1149
    kvm_cmd.extend(["-monitor", monitor_dev])
1150
    if hvp[constants.HV_SERIAL_CONSOLE]:
1151
      serial_dev = ("unix:%s,server,nowait" %
1152
                    self._InstanceSerial(instance.name))
1153
      kvm_cmd.extend(["-serial", serial_dev])
1154
    else:
1155
      kvm_cmd.extend(["-serial", "none"])
1156

    
1157
    mouse_type = hvp[constants.HV_USB_MOUSE]
1158
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1159
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1160
    spice_ip_version = None
1161

    
1162
    if mouse_type:
1163
      kvm_cmd.extend(["-usb"])
1164
      kvm_cmd.extend(["-usbdevice", mouse_type])
1165
    elif vnc_bind_address:
1166
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1167

    
1168
    if vnc_bind_address:
1169
      if netutils.IP4Address.IsValid(vnc_bind_address):
1170
        if instance.network_port > constants.VNC_BASE_PORT:
1171
          display = instance.network_port - constants.VNC_BASE_PORT
1172
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1173
            vnc_arg = ":%d" % (display)
1174
          else:
1175
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1176
        else:
1177
          logging.error("Network port is not a valid VNC display (%d < %d)."
1178
                        " Not starting VNC", instance.network_port,
1179
                        constants.VNC_BASE_PORT)
1180
          vnc_arg = "none"
1181

    
1182
        # Only allow tls and other option when not binding to a file, for now.
1183
        # kvm/qemu gets confused otherwise about the filename to use.
1184
        vnc_append = ""
1185
        if hvp[constants.HV_VNC_TLS]:
1186
          vnc_append = "%s,tls" % vnc_append
1187
          if hvp[constants.HV_VNC_X509_VERIFY]:
1188
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1189
                                               hvp[constants.HV_VNC_X509])
1190
          elif hvp[constants.HV_VNC_X509]:
1191
            vnc_append = "%s,x509=%s" % (vnc_append,
1192
                                         hvp[constants.HV_VNC_X509])
1193
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1194
          vnc_append = "%s,password" % vnc_append
1195

    
1196
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1197

    
1198
      else:
1199
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1200

    
1201
      kvm_cmd.extend(["-vnc", vnc_arg])
1202
    elif spice_bind:
1203
      # FIXME: this is wrong here; the iface ip address differs
1204
      # between systems, so it should be done in _ExecuteKVMRuntime
1205
      if netutils.IsValidInterface(spice_bind):
1206
        # The user specified a network interface, we have to figure out the IP
1207
        # address.
1208
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1209
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1210

    
1211
        # if the user specified an IP version and the interface does not
1212
        # have that kind of IP addresses, throw an exception
1213
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1214
          if not addresses[spice_ip_version]:
1215
            raise errors.HypervisorError("spice: unable to get an IPv%s address"
1216
                                         " for %s" % (spice_ip_version,
1217
                                                      spice_bind))
1218

    
1219
        # the user did not specify an IP version, we have to figure it out
1220
        elif (addresses[constants.IP4_VERSION] and
1221
              addresses[constants.IP6_VERSION]):
1222
          # we have both ipv4 and ipv6, let's use the cluster default IP
1223
          # version
1224
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1225
          spice_ip_version = \
1226
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1227
        elif addresses[constants.IP4_VERSION]:
1228
          spice_ip_version = constants.IP4_VERSION
1229
        elif addresses[constants.IP6_VERSION]:
1230
          spice_ip_version = constants.IP6_VERSION
1231
        else:
1232
          raise errors.HypervisorError("spice: unable to get an IP address"
1233
                                       " for %s" % (spice_bind))
1234

    
1235
        spice_address = addresses[spice_ip_version][0]
1236

    
1237
      else:
1238
        # spice_bind is known to be a valid IP address, because
1239
        # ValidateParameters checked it.
1240
        spice_address = spice_bind
1241

    
1242
      spice_arg = "addr=%s" % spice_address
1243
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1244
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1245
                     (spice_arg, instance.network_port,
1246
                      pathutils.SPICE_CACERT_FILE))
1247
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1248
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1249
                      pathutils.SPICE_CERT_FILE))
1250
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1251
        if tls_ciphers:
1252
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1253
      else:
1254
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1255

    
1256
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1257
        spice_arg = "%s,disable-ticketing" % spice_arg
1258

    
1259
      if spice_ip_version:
1260
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1261

    
1262
      # Image compression options
1263
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1264
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1265
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1266
      if img_lossless:
1267
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1268
      if img_jpeg:
1269
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1270
      if img_zlib_glz:
1271
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1272

    
1273
      # Video stream detection
1274
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1275
      if video_streaming:
1276
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1277

    
1278
      # Audio compression, by default in qemu-kvm it is on
1279
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1280
        spice_arg = "%s,playback-compression=off" % spice_arg
1281
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1282
        spice_arg = "%s,agent-mouse=off" % spice_arg
1283
      else:
1284
        # Enable the spice agent communication channel between the host and the
1285
        # agent.
1286
        kvm_cmd.extend(["-device", "virtio-serial-pci"])
1287
        kvm_cmd.extend(["-device", "virtserialport,chardev=spicechannel0,"
1288
                                                   "name=com.redhat.spice.0"])
1289
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1290

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

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

    
1297
    else:
1298
      kvm_cmd.extend(["-nographic"])
1299

    
1300
    if hvp[constants.HV_USE_LOCALTIME]:
1301
      kvm_cmd.extend(["-localtime"])
1302

    
1303
    if hvp[constants.HV_KVM_USE_CHROOT]:
1304
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1305

    
1306
    # Add qemu-KVM -cpu param
1307
    if hvp[constants.HV_CPU_TYPE]:
1308
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1309

    
1310
    # Save the current instance nics, but defer their expansion as parameters,
1311
    # as we'll need to generate executable temp files for them.
1312
    kvm_nics = instance.nics
1313
    hvparams = hvp
1314

    
1315
    return (kvm_cmd, kvm_nics, hvparams)
1316

    
1317
  def _WriteKVMRuntime(self, instance_name, data):
1318
    """Write an instance's KVM runtime
1319

1320
    """
1321
    try:
1322
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1323
                      data=data)
1324
    except EnvironmentError, err:
1325
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1326

    
1327
  def _ReadKVMRuntime(self, instance_name):
1328
    """Read an instance's KVM runtime
1329

1330
    """
1331
    try:
1332
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1333
    except EnvironmentError, err:
1334
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1335
    return file_content
1336

    
1337
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1338
    """Save an instance's KVM runtime
1339

1340
    """
1341
    kvm_cmd, kvm_nics, hvparams = kvm_runtime
1342
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1343
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1344
    self._WriteKVMRuntime(instance.name, serialized_form)
1345

    
1346
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1347
    """Load an instance's KVM runtime
1348

1349
    """
1350
    if not serialized_runtime:
1351
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1352
    loaded_runtime = serializer.Load(serialized_runtime)
1353
    kvm_cmd, serialized_nics, hvparams = loaded_runtime
1354
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1355
    return (kvm_cmd, kvm_nics, hvparams)
1356

    
1357
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1358
    """Run the KVM cmd and check for errors
1359

1360
    @type name: string
1361
    @param name: instance name
1362
    @type kvm_cmd: list of strings
1363
    @param kvm_cmd: runcmd input for kvm
1364
    @type tap_fds: list of int
1365
    @param tap_fds: fds of tap devices opened by Ganeti
1366

1367
    """
1368
    try:
1369
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1370
    finally:
1371
      for fd in tap_fds:
1372
        utils_wrapper.CloseFdNoError(fd)
1373

    
1374
    if result.failed:
1375
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1376
                                   (name, result.fail_reason, result.output))
1377
    if not self._InstancePidAlive(name)[2]:
1378
      raise errors.HypervisorError("Failed to start instance %s" % name)
1379

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

1383
    @type incoming: tuple of strings
1384
    @param incoming: (target_host_ip, port)
1385

1386
    """
1387
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1388
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1389
    #    have changed since the instance started; only use them if the change
1390
    #    won't affect the inside of the instance (which hasn't been rebooted).
1391
    #  - up_hvp contains the parameters as they were when the instance was
1392
    #    started, plus any new parameter which has been added between ganeti
1393
    #    versions: it is paramount that those default to a value which won't
1394
    #    affect the inside of the instance as well.
1395
    conf_hvp = instance.hvparams
1396
    name = instance.name
1397
    self._CheckDown(name)
1398

    
1399
    temp_files = []
1400

    
1401
    kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1402
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1403

    
1404
    _, v_major, v_min, _ = self._GetKVMVersion()
1405

    
1406
    # We know it's safe to run as a different user upon migration, so we'll use
1407
    # the latest conf, from conf_hvp.
1408
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1409
    if security_model == constants.HT_SM_USER:
1410
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1411

    
1412
    keymap = conf_hvp[constants.HV_KEYMAP]
1413
    if keymap:
1414
      keymap_path = self._InstanceKeymapFile(name)
1415
      # If a keymap file is specified, KVM won't use its internal defaults. By
1416
      # first including the "en-us" layout, an error on loading the actual
1417
      # layout (e.g. because it can't be found) won't lead to a non-functional
1418
      # keyboard. A keyboard with incorrect keys is still better than none.
1419
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1420
      kvm_cmd.extend(["-k", keymap_path])
1421

    
1422
    # We have reasons to believe changing something like the nic driver/type
1423
    # upon migration won't exactly fly with the instance kernel, so for nic
1424
    # related parameters we'll use up_hvp
1425
    tapfds = []
1426
    taps = []
1427
    if not kvm_nics:
1428
      kvm_cmd.extend(["-net", "none"])
1429
    else:
1430
      vnet_hdr = False
1431
      tap_extra = ""
1432
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1433
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1434
        # From version 0.12.0, kvm uses a new sintax for network configuration.
1435
        if (v_major, v_min) >= (0, 12):
1436
          nic_model = "virtio-net-pci"
1437
          vnet_hdr = True
1438
        else:
1439
          nic_model = "virtio"
1440

    
1441
        if up_hvp[constants.HV_VHOST_NET]:
1442
          # vhost_net is only available from version 0.13.0 or newer
1443
          if (v_major, v_min) >= (0, 13):
1444
            tap_extra = ",vhost=on"
1445
          else:
1446
            raise errors.HypervisorError("vhost_net is configured"
1447
                                         " but it is not available")
1448
      else:
1449
        nic_model = nic_type
1450

    
1451
      for nic_seq, nic in enumerate(kvm_nics):
1452
        tapname, tapfd = _OpenTap(vnet_hdr)
1453
        tapfds.append(tapfd)
1454
        taps.append(tapname)
1455
        if (v_major, v_min) >= (0, 12):
1456
          nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1457
          tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1458
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1459
        else:
1460
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1461
                                                         nic.mac, nic_model)
1462
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1463
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1464

    
1465
    if incoming:
1466
      target, port = incoming
1467
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1468

    
1469
    # Changing the vnc password doesn't bother the guest that much. At most it
1470
    # will surprise people who connect to it. Whether positively or negatively
1471
    # it's debatable.
1472
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1473
    vnc_pwd = None
1474
    if vnc_pwd_file:
1475
      try:
1476
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1477
      except EnvironmentError, err:
1478
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1479
                                     % (vnc_pwd_file, err))
1480

    
1481
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1482
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1483
                         constants.SECURE_DIR_MODE)])
1484

    
1485
    # Automatically enable QMP if version is >= 0.14
1486
    if (v_major, v_min) >= (0, 14):
1487
      logging.debug("Enabling QMP")
1488
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1489
                      self._InstanceQmpMonitor(instance.name)])
1490

    
1491
    # Configure the network now for starting instances and bridged interfaces,
1492
    # during FinalizeMigration for incoming instances' routed interfaces
1493
    for nic_seq, nic in enumerate(kvm_nics):
1494
      if (incoming and
1495
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1496
        continue
1497
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1498

    
1499
    # CPU affinity requires kvm to start paused, so we set this flag if the
1500
    # instance is not already paused and if we are not going to accept a
1501
    # migrating instance. In the latter case, pausing is not needed.
1502
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1503
    if start_kvm_paused:
1504
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1505

    
1506
    # Note: CPU pinning is using up_hvp since changes take effect
1507
    # during instance startup anyway, and to avoid problems when soft
1508
    # rebooting the instance.
1509
    cpu_pinning = False
1510
    if up_hvp.get(constants.HV_CPU_MASK, None):
1511
      cpu_pinning = True
1512

    
1513
    if security_model == constants.HT_SM_POOL:
1514
      ss = ssconf.SimpleStore()
1515
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1516
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1517
      uid = uidpool.RequestUnusedUid(all_uids)
1518
      try:
1519
        username = pwd.getpwuid(uid.GetUid()).pw_name
1520
        kvm_cmd.extend(["-runas", username])
1521
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1522
      except:
1523
        uidpool.ReleaseUid(uid)
1524
        raise
1525
      else:
1526
        uid.Unlock()
1527
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1528
    else:
1529
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1530

    
1531
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1532
                     constants.RUN_DIRS_MODE)])
1533
    for nic_seq, tap in enumerate(taps):
1534
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1535
                      data=tap)
1536

    
1537
    if vnc_pwd:
1538
      change_cmd = "change vnc password %s" % vnc_pwd
1539
      self._CallMonitorCommand(instance.name, change_cmd)
1540

    
1541
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1542
    # connection attempts because SPICE by default does not allow connections
1543
    # if neither a password nor the "disable_ticketing" options are specified.
1544
    # As soon as we send the password via QMP, that password is a valid ticket
1545
    # for connection.
1546
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1547
    if spice_password_file:
1548
      spice_pwd = ""
1549
      try:
1550
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1551
      except EnvironmentError, err:
1552
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1553
                                     % (spice_password_file, err))
1554

    
1555
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1556
      qmp.connect()
1557
      arguments = {
1558
          "protocol": "spice",
1559
          "password": spice_pwd,
1560
      }
1561
      qmp.Execute("set_password", arguments)
1562

    
1563
    for filename in temp_files:
1564
      utils.RemoveFile(filename)
1565

    
1566
    # If requested, set CPU affinity and resume instance execution
1567
    if cpu_pinning:
1568
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1569

    
1570
    start_memory = self._InstanceStartupMemory(instance)
1571
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1572
      self.BalloonInstanceMemory(instance, start_memory)
1573

    
1574
    if start_kvm_paused:
1575
      # To control CPU pinning, ballooning, and vnc/spice passwords
1576
      # the VM was started in a frozen state. If freezing was not
1577
      # explicitly requested resume the vm status.
1578
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1579

    
1580
  def StartInstance(self, instance, block_devices, startup_paused):
1581
    """Start an instance.
1582

1583
    """
1584
    self._CheckDown(instance.name)
1585
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1586
                                           startup_paused)
1587
    self._SaveKVMRuntime(instance, kvm_runtime)
1588
    self._ExecuteKVMRuntime(instance, kvm_runtime)
1589

    
1590
  def _CallMonitorCommand(self, instance_name, command):
1591
    """Invoke a command on the instance monitor.
1592

1593
    """
1594
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1595
             (utils.ShellQuote(command),
1596
              constants.SOCAT_PATH,
1597
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1598
    result = utils.RunCmd(socat)
1599
    if result.failed:
1600
      msg = ("Failed to send command '%s' to instance %s."
1601
             " output: %s, error: %s, fail_reason: %s" %
1602
             (command, instance_name,
1603
              result.stdout, result.stderr, result.fail_reason))
1604
      raise errors.HypervisorError(msg)
1605

    
1606
    return result
1607

    
1608
  @classmethod
1609
  def _ParseKVMVersion(cls, text):
1610
    """Parse the KVM version from the --help output.
1611

1612
    @type text: string
1613
    @param text: output of kvm --help
1614
    @return: (version, v_maj, v_min, v_rev)
1615
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1616

1617
    """
1618
    match = cls._VERSION_RE.search(text.splitlines()[0])
1619
    if not match:
1620
      raise errors.HypervisorError("Unable to get KVM version")
1621

    
1622
    v_all = match.group(0)
1623
    v_maj = int(match.group(1))
1624
    v_min = int(match.group(2))
1625
    if match.group(4):
1626
      v_rev = int(match.group(4))
1627
    else:
1628
      v_rev = 0
1629
    return (v_all, v_maj, v_min, v_rev)
1630

    
1631
  @classmethod
1632
  def _GetKVMVersion(cls):
1633
    """Return the installed KVM version.
1634

1635
    @return: (version, v_maj, v_min, v_rev)
1636
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1637

1638
    """
1639
    result = utils.RunCmd([constants.KVM_PATH, "--help"])
1640
    if result.failed:
1641
      raise errors.HypervisorError("Unable to get KVM version")
1642
    return cls._ParseKVMVersion(result.output)
1643

    
1644
  def StopInstance(self, instance, force=False, retry=False, name=None):
1645
    """Stop an instance.
1646

1647
    """
1648
    if name is not None and not force:
1649
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1650
    if name is None:
1651
      name = instance.name
1652
      acpi = instance.hvparams[constants.HV_ACPI]
1653
    else:
1654
      acpi = False
1655
    _, pid, alive = self._InstancePidAlive(name)
1656
    if pid > 0 and alive:
1657
      if force or not acpi:
1658
        utils.KillProcess(pid)
1659
      else:
1660
        self._CallMonitorCommand(name, "system_powerdown")
1661

    
1662
  @classmethod
1663
  def _GetDefaultMachineVersion(cls):
1664
    """Return the default hardware revision (e.g. pc-1.1)
1665

1666
    """
1667
    result = utils.RunCmd([constants.KVM_PATH, "-M", "?"])
1668
    if result.failed:
1669
      raise errors.HypervisorError("Unable to get default hardware revision")
1670
    for line in result.output.splitlines():
1671
      match = cls._DEFAULT_MACHINE_VERSION_RE.match(line)
1672
      if match:
1673
        return match.group(1)
1674

    
1675
    return "pc"
1676

    
1677
  def CleanupInstance(self, instance_name):
1678
    """Cleanup after a stopped instance
1679

1680
    """
1681
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
1682
    if pid > 0 and alive:
1683
      raise errors.HypervisorError("Cannot cleanup a live instance")
1684
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1685

    
1686
  def RebootInstance(self, instance):
1687
    """Reboot an instance.
1688

1689
    """
1690
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1691
    # socket the instance will stop, but now power up again. So we'll resort
1692
    # to shutdown and restart.
1693
    _, _, alive = self._InstancePidAlive(instance.name)
1694
    if not alive:
1695
      raise errors.HypervisorError("Failed to reboot instance %s:"
1696
                                   " not running" % instance.name)
1697
    # StopInstance will delete the saved KVM runtime so:
1698
    # ...first load it...
1699
    kvm_runtime = self._LoadKVMRuntime(instance)
1700
    # ...now we can safely call StopInstance...
1701
    if not self.StopInstance(instance):
1702
      self.StopInstance(instance, force=True)
1703
    # ...and finally we can save it again, and execute it...
1704
    self._SaveKVMRuntime(instance, kvm_runtime)
1705
    self._ExecuteKVMRuntime(instance, kvm_runtime)
1706

    
1707
  def MigrationInfo(self, instance):
1708
    """Get instance information to perform a migration.
1709

1710
    @type instance: L{objects.Instance}
1711
    @param instance: instance to be migrated
1712
    @rtype: string
1713
    @return: content of the KVM runtime file
1714

1715
    """
1716
    return self._ReadKVMRuntime(instance.name)
1717

    
1718
  def AcceptInstance(self, instance, info, target):
1719
    """Prepare to accept an instance.
1720

1721
    @type instance: L{objects.Instance}
1722
    @param instance: instance to be accepted
1723
    @type info: string
1724
    @param info: content of the KVM runtime file on the source node
1725
    @type target: string
1726
    @param target: target host (usually ip), on this node
1727

1728
    """
1729
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1730
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1731
    self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
1732

    
1733
  def FinalizeMigrationDst(self, instance, info, success):
1734
    """Finalize the instance migration on the target node.
1735

1736
    Stop the incoming mode KVM.
1737

1738
    @type instance: L{objects.Instance}
1739
    @param instance: instance whose migration is being finalized
1740

1741
    """
1742
    if success:
1743
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1744
      kvm_nics = kvm_runtime[1]
1745

    
1746
      for nic_seq, nic in enumerate(kvm_nics):
1747
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1748
          # Bridged interfaces have already been configured
1749
          continue
1750
        try:
1751
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1752
        except EnvironmentError, err:
1753
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
1754
                          instance.name, nic_seq, str(err))
1755
          continue
1756
        try:
1757
          self._ConfigureNIC(instance, nic_seq, nic, tap)
1758
        except errors.HypervisorError, err:
1759
          logging.warning(str(err))
1760

    
1761
      self._WriteKVMRuntime(instance.name, info)
1762
    else:
1763
      self.StopInstance(instance, force=True)
1764

    
1765
  def MigrateInstance(self, instance, target, live):
1766
    """Migrate an instance to a target node.
1767

1768
    The migration will not be attempted if the instance is not
1769
    currently running.
1770

1771
    @type instance: L{objects.Instance}
1772
    @param instance: the instance to be migrated
1773
    @type target: string
1774
    @param target: ip address of the target node
1775
    @type live: boolean
1776
    @param live: perform a live migration
1777

1778
    """
1779
    instance_name = instance.name
1780
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
1781
    _, _, alive = self._InstancePidAlive(instance_name)
1782
    if not alive:
1783
      raise errors.HypervisorError("Instance not running, cannot migrate")
1784

    
1785
    if not live:
1786
      self._CallMonitorCommand(instance_name, "stop")
1787

    
1788
    migrate_command = ("migrate_set_speed %dm" %
1789
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1790
    self._CallMonitorCommand(instance_name, migrate_command)
1791

    
1792
    migrate_command = ("migrate_set_downtime %dms" %
1793
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1794
    self._CallMonitorCommand(instance_name, migrate_command)
1795

    
1796
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1797
    self._CallMonitorCommand(instance_name, migrate_command)
1798

    
1799
  def FinalizeMigrationSource(self, instance, success, live):
1800
    """Finalize the instance migration on the source node.
1801

1802
    @type instance: L{objects.Instance}
1803
    @param instance: the instance that was migrated
1804
    @type success: bool
1805
    @param success: whether the migration succeeded or not
1806
    @type live: bool
1807
    @param live: whether the user requested a live migration or not
1808

1809
    """
1810
    if success:
1811
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
1812
      utils.KillProcess(pid)
1813
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1814
    elif live:
1815
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1816

    
1817
  def GetMigrationStatus(self, instance):
1818
    """Get the migration status
1819

1820
    @type instance: L{objects.Instance}
1821
    @param instance: the instance that is being migrated
1822
    @rtype: L{objects.MigrationStatus}
1823
    @return: the status of the current migration (one of
1824
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1825
             progress info that can be retrieved from the hypervisor
1826

1827
    """
1828
    info_command = "info migrate"
1829
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
1830
      result = self._CallMonitorCommand(instance.name, info_command)
1831
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
1832
      if not match:
1833
        if not result.stdout:
1834
          logging.info("KVM: empty 'info migrate' result")
1835
        else:
1836
          logging.warning("KVM: unknown 'info migrate' result: %s",
1837
                          result.stdout)
1838
      else:
1839
        status = match.group(1)
1840
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
1841
          migration_status = objects.MigrationStatus(status=status)
1842
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
1843
          if match:
1844
            migration_status.transferred_ram = match.group("transferred")
1845
            migration_status.total_ram = match.group("total")
1846

    
1847
          return migration_status
1848

    
1849
        logging.warning("KVM: unknown migration status '%s'", status)
1850

    
1851
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1852

    
1853
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
1854

    
1855
  def BalloonInstanceMemory(self, instance, mem):
1856
    """Balloon an instance memory to a certain value.
1857

1858
    @type instance: L{objects.Instance}
1859
    @param instance: instance to be accepted
1860
    @type mem: int
1861
    @param mem: actual memory size to use for instance runtime
1862

1863
    """
1864
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
1865

    
1866
  def GetNodeInfo(self):
1867
    """Return information about the node.
1868

1869
    @return: a dict with the following keys (values in MiB):
1870
          - memory_total: the total memory size on the node
1871
          - memory_free: the available memory on the node for instances
1872
          - memory_dom0: the memory used by the node itself, if available
1873
          - hv_version: the hypervisor version in the form (major, minor,
1874
                        revision)
1875

1876
    """
1877
    result = self.GetLinuxNodeInfo()
1878
    _, v_major, v_min, v_rev = self._GetKVMVersion()
1879
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
1880
    return result
1881

    
1882
  @classmethod
1883
  def GetInstanceConsole(cls, instance, hvparams, beparams):
1884
    """Return a command for connecting to the console of an instance.
1885

1886
    """
1887
    if hvparams[constants.HV_SERIAL_CONSOLE]:
1888
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
1889
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1890
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1891
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
1892
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1893
      return objects.InstanceConsole(instance=instance.name,
1894
                                     kind=constants.CONS_SSH,
1895
                                     host=instance.primary_node,
1896
                                     user=constants.SSH_CONSOLE_USER,
1897
                                     command=cmd)
1898

    
1899
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1900
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1901
      display = instance.network_port - constants.VNC_BASE_PORT
1902
      return objects.InstanceConsole(instance=instance.name,
1903
                                     kind=constants.CONS_VNC,
1904
                                     host=vnc_bind_address,
1905
                                     port=instance.network_port,
1906
                                     display=display)
1907

    
1908
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1909
    if spice_bind:
1910
      return objects.InstanceConsole(instance=instance.name,
1911
                                     kind=constants.CONS_SPICE,
1912
                                     host=spice_bind,
1913
                                     port=instance.network_port)
1914

    
1915
    return objects.InstanceConsole(instance=instance.name,
1916
                                   kind=constants.CONS_MESSAGE,
1917
                                   message=("No serial shell for instance %s" %
1918
                                            instance.name))
1919

    
1920
  def Verify(self):
1921
    """Verify the hypervisor.
1922

1923
    Check that the binary exists.
1924

1925
    """
1926
    if not os.path.exists(constants.KVM_PATH):
1927
      return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
1928
    if not os.path.exists(constants.SOCAT_PATH):
1929
      return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
1930

    
1931
  @classmethod
1932
  def CheckParameterSyntax(cls, hvparams):
1933
    """Check the given parameters for validity.
1934

1935
    @type hvparams:  dict
1936
    @param hvparams: dictionary with parameter names/value
1937
    @raise errors.HypervisorError: when a parameter is not valid
1938

1939
    """
1940
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
1941

    
1942
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
1943
    if kernel_path:
1944
      if not hvparams[constants.HV_ROOT_PATH]:
1945
        raise errors.HypervisorError("Need a root partition for the instance,"
1946
                                     " if a kernel is defined")
1947

    
1948
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
1949
        not hvparams[constants.HV_VNC_X509]):
1950
      raise errors.HypervisorError("%s must be defined, if %s is" %
1951
                                   (constants.HV_VNC_X509,
1952
                                    constants.HV_VNC_X509_VERIFY))
1953

    
1954
    if hvparams[constants.HV_SERIAL_CONSOLE]:
1955
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
1956
      valid_speeds = constants.VALID_SERIAL_SPEEDS
1957
      if not serial_speed or serial_speed not in valid_speeds:
1958
        raise errors.HypervisorError("Invalid serial console speed, must be"
1959
                                     " one of: %s" %
1960
                                     utils.CommaJoin(valid_speeds))
1961

    
1962
    boot_order = hvparams[constants.HV_BOOT_ORDER]
1963
    if (boot_order == constants.HT_BO_CDROM and
1964
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
1965
      raise errors.HypervisorError("Cannot boot from cdrom without an"
1966
                                   " ISO path")
1967

    
1968
    security_model = hvparams[constants.HV_SECURITY_MODEL]
1969
    if security_model == constants.HT_SM_USER:
1970
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
1971
        raise errors.HypervisorError("A security domain (user to run kvm as)"
1972
                                     " must be specified")
1973
    elif (security_model == constants.HT_SM_NONE or
1974
          security_model == constants.HT_SM_POOL):
1975
      if hvparams[constants.HV_SECURITY_DOMAIN]:
1976
        raise errors.HypervisorError("Cannot have a security domain when the"
1977
                                     " security model is 'none' or 'pool'")
1978

    
1979
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1980
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
1981
    if spice_bind:
1982
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1983
        # if an IP version is specified, the spice_bind parameter must be an
1984
        # IP of that family
1985
        if (netutils.IP4Address.IsValid(spice_bind) and
1986
            spice_ip_version != constants.IP4_VERSION):
1987
          raise errors.HypervisorError("spice: got an IPv4 address (%s), but"
1988
                                       " the specified IP version is %s" %
1989
                                       (spice_bind, spice_ip_version))
1990

    
1991
        if (netutils.IP6Address.IsValid(spice_bind) and
1992
            spice_ip_version != constants.IP6_VERSION):
1993
          raise errors.HypervisorError("spice: got an IPv6 address (%s), but"
1994
                                       " the specified IP version is %s" %
1995
                                       (spice_bind, spice_ip_version))
1996
    else:
1997
      # All the other SPICE parameters depend on spice_bind being set. Raise an
1998
      # error if any of them is set without it.
1999
      for param in _SPICE_ADDITIONAL_PARAMS:
2000
        if hvparams[param]:
2001
          raise errors.HypervisorError("spice: %s requires %s to be set" %
2002
                                       (param, constants.HV_KVM_SPICE_BIND))
2003

    
2004
  @classmethod
2005
  def ValidateParameters(cls, hvparams):
2006
    """Check the given parameters for validity.
2007

2008
    @type hvparams:  dict
2009
    @param hvparams: dictionary with parameter names/value
2010
    @raise errors.HypervisorError: when a parameter is not valid
2011

2012
    """
2013
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2014

    
2015
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2016
    if security_model == constants.HT_SM_USER:
2017
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2018
      try:
2019
        pwd.getpwnam(username)
2020
      except KeyError:
2021
        raise errors.HypervisorError("Unknown security domain user %s"
2022
                                     % username)
2023

    
2024
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2025
    if spice_bind:
2026
      # only one of VNC and SPICE can be used currently.
2027
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2028
        raise errors.HypervisorError("both SPICE and VNC are configured, but"
2029
                                     " only one of them can be used at a"
2030
                                     " given time.")
2031

    
2032
      # KVM version should be >= 0.14.0
2033
      _, v_major, v_min, _ = cls._GetKVMVersion()
2034
      if (v_major, v_min) < (0, 14):
2035
        raise errors.HypervisorError("spice is configured, but it is not"
2036
                                     " available in versions of KVM < 0.14")
2037

    
2038
      # if spice_bind is not an IP address, it must be a valid interface
2039
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind)
2040
                       or netutils.IP6Address.IsValid(spice_bind))
2041
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2042
        raise errors.HypervisorError("spice: the %s parameter must be either"
2043
                                     " a valid IP address or interface name" %
2044
                                     constants.HV_KVM_SPICE_BIND)
2045

    
2046
  @classmethod
2047
  def PowercycleNode(cls):
2048
    """KVM powercycle, just a wrapper over Linux powercycle.
2049

2050
    """
2051
    cls.LinuxPowercycle()