Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 141d1489

History | View | Annotate | Download (72.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
  constants.HV_KVM_SPICE_AUDIO_COMPR,
81
  constants.HV_KVM_SPICE_TLS_CIPHERS,
82
  constants.HV_KVM_SPICE_USE_VDAGENT,
83
  ])
84

    
85

    
86
def _ProbeTapVnetHdr(fd):
87
  """Check whether to enable the IFF_VNET_HDR flag.
88

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

99
   @type fd: int
100
   @param fd: the file descriptor of /dev/net/tun
101

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

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

    
117

    
118
def _OpenTap(vnet_hdr=True):
119
  """Open a new tap device and return its file descriptor.
120

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

124
  @type vnet_hdr: boolean
125
  @param vnet_hdr: Enable the VNET Header
126
  @return: (ifname, tapfd)
127
  @rtype: tuple
128

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

    
135
  flags = IFF_TAP | IFF_NO_PI
136

    
137
  if vnet_hdr and _ProbeTapVnetHdr(tapfd):
138
    flags |= IFF_VNET_HDR
139

    
140
  # The struct ifreq ioctl request (see netdevice(7))
141
  ifr = struct.pack("16sh", "", flags)
142

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

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

    
152

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

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

    
175
  return env
176

    
177

    
178
class QmpMessage:
179
  """QEMU Messaging Protocol (QMP) message.
180

181
  """
182
  def __init__(self, data):
183
    """Creates a new QMP message based on the passed data.
184

185
    """
186
    if not isinstance(data, dict):
187
      raise TypeError("QmpMessage must be initialized with a dict")
188

    
189
    self.data = data
190

    
191
  def __getitem__(self, field_name):
192
    """Get the value of the required field if present, or None.
193

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

199
    """
200
    return self.data.get(field_name, None)
201

    
202
  def __setitem__(self, field_name, field_value):
203
    """Set the value of the required field_name to field_value.
204

205
    """
206
    self.data[field_name] = field_value
207

    
208
  @staticmethod
209
  def BuildFromJsonString(json_string):
210
    """Build a QmpMessage from a JSON encoded string.
211

212
    @type json_string: str
213
    @param json_string: JSON string representing the message
214
    @rtype: L{QmpMessage}
215
    @return: a L{QmpMessage} built from json_string
216

217
    """
218
    # Parse the string
219
    data = serializer.LoadJson(json_string)
220
    return QmpMessage(data)
221

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

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

    
231

    
232
class QmpConnection:
233
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
234

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

    
250
  def __init__(self, monitor_filename):
251
    """Instantiates the QmpConnection object.
252

253
    @type monitor_filename: string
254
    @param monitor_filename: the filename of the UNIX raw socket on which the
255
                             QMP monitor is listening
256

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

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

    
279
  def _check_connection(self):
280
    """Make sure that the connection is established.
281

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

    
287
  def connect(self):
288
    """Connects to the QMP monitor.
289

290
    Connects to the UNIX socket and makes sure that we can actually send and
291
    receive data to the kvm instance via QMP.
292

293
    @raise errors.HypervisorError: when there are communication errors
294
    @raise errors.ProgrammerError: when there are data serialization errors
295

296
    """
297
    if self._connected:
298
      raise errors.ProgrammerError("Cannot connect twice")
299

    
300
    self._check_socket()
301

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

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

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

    
322
  def _ParseMessage(self, buf):
323
    """Extract and parse a QMP message from the given buffer.
324

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

329
    @raise errors.ProgrammerError: when there are data serialization errors
330

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

    
343
    return (message, buf)
344

    
345
  def _Recv(self):
346
    """Receives a message from QMP and decodes the received JSON object.
347

348
    @rtype: QmpMessage
349
    @return: the received message
350
    @raise errors.HypervisorError: when there are communication errors
351
    @raise errors.ProgrammerError: when there are data serialization errors
352

353
    """
354
    self._check_connection()
355

    
356
    # Check if there is already a message in the buffer
357
    (message, self._buf) = self._ParseMessage(self._buf)
358
    if message:
359
      return message
360

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

    
370
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
371
        if message:
372
          return message
373

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

    
381
  def _Send(self, message):
382
    """Encodes and sends a message to KVM using QMP.
383

384
    @type message: QmpMessage
385
    @param message: message to send to KVM
386
    @raise errors.HypervisorError: when there are communication errors
387
    @raise errors.ProgrammerError: when there are data serialization errors
388

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

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

    
405
  def Execute(self, command, arguments=None):
406
    """Executes a QMP command and returns the response of the server.
407

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

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

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

    
437
      elif not response[self._EVENT_KEY]:
438
        return response
439

    
440

    
441
class KVMHypervisor(hv_base.BaseHypervisor):
442
  """KVM hypervisor interface
443

444
  """
445
  CAN_MIGRATE = True
446

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

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

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

    
546
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
547
  _MIGRATION_INFO_RETRY_DELAY = 2
548

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

    
551
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
552
  _CPU_INFO_CMD = "info cpus"
553
  _CONT_CMD = "cont"
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
    # used just by the vnc server, if enabled
1010
    kvm_cmd.extend(["-name", instance.name])
1011
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1012
    kvm_cmd.extend(["-smp", instance.beparams[constants.BE_VCPUS]])
1013
    kvm_cmd.extend(["-pidfile", pidfile])
1014
    kvm_cmd.extend(["-balloon", "virtio"])
1015
    kvm_cmd.extend(["-daemonize"])
1016
    if not instance.hvparams[constants.HV_ACPI]:
1017
      kvm_cmd.extend(["-no-acpi"])
1018
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1019
        constants.INSTANCE_REBOOT_EXIT:
1020
      kvm_cmd.extend(["-no-reboot"])
1021

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

    
1032
    self.ValidateParameters(hvp)
1033

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1194
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1195

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

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

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

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

    
1233
        spice_address = addresses[spice_ip_version][0]
1234

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

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

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

    
1257
      if spice_ip_version:
1258
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1259

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

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

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

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

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

    
1295
    else:
1296
      kvm_cmd.extend(["-nographic"])
1297

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

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

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

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

    
1313
    return (kvm_cmd, kvm_nics, hvparams)
1314

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

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

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

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

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

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

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

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

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

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

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

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

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

1381
    @type incoming: tuple of strings
1382
    @param incoming: (target_host_ip, port)
1383

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

    
1397
    temp_files = []
1398

    
1399
    kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1400
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1401

    
1402
    _, v_major, v_min, _ = self._GetKVMVersion()
1403

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1561
    for filename in temp_files:
1562
      utils.RemoveFile(filename)
1563

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

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

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

    
1578
  def StartInstance(self, instance, block_devices, startup_paused):
1579
    """Start an instance.
1580

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

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

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

    
1604
    return result
1605

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

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

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

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

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

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

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

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

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

    
1660
  def CleanupInstance(self, instance_name):
1661
    """Cleanup after a stopped instance
1662

1663
    """
1664
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
1665
    if pid > 0 and alive:
1666
      raise errors.HypervisorError("Cannot cleanup a live instance")
1667
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1668

    
1669
  def RebootInstance(self, instance):
1670
    """Reboot an instance.
1671

1672
    """
1673
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1674
    # socket the instance will stop, but now power up again. So we'll resort
1675
    # to shutdown and restart.
1676
    _, _, alive = self._InstancePidAlive(instance.name)
1677
    if not alive:
1678
      raise errors.HypervisorError("Failed to reboot instance %s:"
1679
                                   " not running" % instance.name)
1680
    # StopInstance will delete the saved KVM runtime so:
1681
    # ...first load it...
1682
    kvm_runtime = self._LoadKVMRuntime(instance)
1683
    # ...now we can safely call StopInstance...
1684
    if not self.StopInstance(instance):
1685
      self.StopInstance(instance, force=True)
1686
    # ...and finally we can save it again, and execute it...
1687
    self._SaveKVMRuntime(instance, kvm_runtime)
1688
    self._ExecuteKVMRuntime(instance, kvm_runtime)
1689

    
1690
  def MigrationInfo(self, instance):
1691
    """Get instance information to perform a migration.
1692

1693
    @type instance: L{objects.Instance}
1694
    @param instance: instance to be migrated
1695
    @rtype: string
1696
    @return: content of the KVM runtime file
1697

1698
    """
1699
    return self._ReadKVMRuntime(instance.name)
1700

    
1701
  def AcceptInstance(self, instance, info, target):
1702
    """Prepare to accept an instance.
1703

1704
    @type instance: L{objects.Instance}
1705
    @param instance: instance to be accepted
1706
    @type info: string
1707
    @param info: content of the KVM runtime file on the source node
1708
    @type target: string
1709
    @param target: target host (usually ip), on this node
1710

1711
    """
1712
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1713
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1714
    self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
1715

    
1716
  def FinalizeMigrationDst(self, instance, info, success):
1717
    """Finalize the instance migration on the target node.
1718

1719
    Stop the incoming mode KVM.
1720

1721
    @type instance: L{objects.Instance}
1722
    @param instance: instance whose migration is being finalized
1723

1724
    """
1725
    if success:
1726
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1727
      kvm_nics = kvm_runtime[1]
1728

    
1729
      for nic_seq, nic in enumerate(kvm_nics):
1730
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1731
          # Bridged interfaces have already been configured
1732
          continue
1733
        try:
1734
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1735
        except EnvironmentError, err:
1736
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
1737
                          instance.name, nic_seq, str(err))
1738
          continue
1739
        try:
1740
          self._ConfigureNIC(instance, nic_seq, nic, tap)
1741
        except errors.HypervisorError, err:
1742
          logging.warning(str(err))
1743

    
1744
      self._WriteKVMRuntime(instance.name, info)
1745
    else:
1746
      self.StopInstance(instance, force=True)
1747

    
1748
  def MigrateInstance(self, instance, target, live):
1749
    """Migrate an instance to a target node.
1750

1751
    The migration will not be attempted if the instance is not
1752
    currently running.
1753

1754
    @type instance: L{objects.Instance}
1755
    @param instance: the instance to be migrated
1756
    @type target: string
1757
    @param target: ip address of the target node
1758
    @type live: boolean
1759
    @param live: perform a live migration
1760

1761
    """
1762
    instance_name = instance.name
1763
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
1764
    _, _, alive = self._InstancePidAlive(instance_name)
1765
    if not alive:
1766
      raise errors.HypervisorError("Instance not running, cannot migrate")
1767

    
1768
    if not live:
1769
      self._CallMonitorCommand(instance_name, "stop")
1770

    
1771
    migrate_command = ("migrate_set_speed %dm" %
1772
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1773
    self._CallMonitorCommand(instance_name, migrate_command)
1774

    
1775
    migrate_command = ("migrate_set_downtime %dms" %
1776
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1777
    self._CallMonitorCommand(instance_name, migrate_command)
1778

    
1779
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1780
    self._CallMonitorCommand(instance_name, migrate_command)
1781

    
1782
  def FinalizeMigrationSource(self, instance, success, live):
1783
    """Finalize the instance migration on the source node.
1784

1785
    @type instance: L{objects.Instance}
1786
    @param instance: the instance that was migrated
1787
    @type success: bool
1788
    @param success: whether the migration succeeded or not
1789
    @type live: bool
1790
    @param live: whether the user requested a live migration or not
1791

1792
    """
1793
    if success:
1794
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
1795
      utils.KillProcess(pid)
1796
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1797
    elif live:
1798
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1799

    
1800
  def GetMigrationStatus(self, instance):
1801
    """Get the migration status
1802

1803
    @type instance: L{objects.Instance}
1804
    @param instance: the instance that is being migrated
1805
    @rtype: L{objects.MigrationStatus}
1806
    @return: the status of the current migration (one of
1807
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1808
             progress info that can be retrieved from the hypervisor
1809

1810
    """
1811
    info_command = "info migrate"
1812
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
1813
      result = self._CallMonitorCommand(instance.name, info_command)
1814
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
1815
      if not match:
1816
        if not result.stdout:
1817
          logging.info("KVM: empty 'info migrate' result")
1818
        else:
1819
          logging.warning("KVM: unknown 'info migrate' result: %s",
1820
                          result.stdout)
1821
      else:
1822
        status = match.group(1)
1823
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
1824
          migration_status = objects.MigrationStatus(status=status)
1825
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
1826
          if match:
1827
            migration_status.transferred_ram = match.group("transferred")
1828
            migration_status.total_ram = match.group("total")
1829

    
1830
          return migration_status
1831

    
1832
        logging.warning("KVM: unknown migration status '%s'", status)
1833

    
1834
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1835

    
1836
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
1837

    
1838
  def BalloonInstanceMemory(self, instance, mem):
1839
    """Balloon an instance memory to a certain value.
1840

1841
    @type instance: L{objects.Instance}
1842
    @param instance: instance to be accepted
1843
    @type mem: int
1844
    @param mem: actual memory size to use for instance runtime
1845

1846
    """
1847
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
1848

    
1849
  def GetNodeInfo(self):
1850
    """Return information about the node.
1851

1852
    @return: a dict with the following keys (values in MiB):
1853
          - memory_total: the total memory size on the node
1854
          - memory_free: the available memory on the node for instances
1855
          - memory_dom0: the memory used by the node itself, if available
1856
          - hv_version: the hypervisor version in the form (major, minor,
1857
                        revision)
1858

1859
    """
1860
    result = self.GetLinuxNodeInfo()
1861
    _, v_major, v_min, v_rev = self._GetKVMVersion()
1862
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
1863
    return result
1864

    
1865
  @classmethod
1866
  def GetInstanceConsole(cls, instance, hvparams, beparams):
1867
    """Return a command for connecting to the console of an instance.
1868

1869
    """
1870
    if hvparams[constants.HV_SERIAL_CONSOLE]:
1871
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
1872
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1873
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1874
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
1875
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1876
      return objects.InstanceConsole(instance=instance.name,
1877
                                     kind=constants.CONS_SSH,
1878
                                     host=instance.primary_node,
1879
                                     user=constants.SSH_CONSOLE_USER,
1880
                                     command=cmd)
1881

    
1882
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1883
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1884
      display = instance.network_port - constants.VNC_BASE_PORT
1885
      return objects.InstanceConsole(instance=instance.name,
1886
                                     kind=constants.CONS_VNC,
1887
                                     host=vnc_bind_address,
1888
                                     port=instance.network_port,
1889
                                     display=display)
1890

    
1891
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1892
    if spice_bind:
1893
      return objects.InstanceConsole(instance=instance.name,
1894
                                     kind=constants.CONS_SPICE,
1895
                                     host=spice_bind,
1896
                                     port=instance.network_port)
1897

    
1898
    return objects.InstanceConsole(instance=instance.name,
1899
                                   kind=constants.CONS_MESSAGE,
1900
                                   message=("No serial shell for instance %s" %
1901
                                            instance.name))
1902

    
1903
  def Verify(self):
1904
    """Verify the hypervisor.
1905

1906
    Check that the binary exists.
1907

1908
    """
1909
    if not os.path.exists(constants.KVM_PATH):
1910
      return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
1911
    if not os.path.exists(constants.SOCAT_PATH):
1912
      return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
1913

    
1914
  @classmethod
1915
  def CheckParameterSyntax(cls, hvparams):
1916
    """Check the given parameters for validity.
1917

1918
    @type hvparams:  dict
1919
    @param hvparams: dictionary with parameter names/value
1920
    @raise errors.HypervisorError: when a parameter is not valid
1921

1922
    """
1923
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
1924

    
1925
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
1926
    if kernel_path:
1927
      if not hvparams[constants.HV_ROOT_PATH]:
1928
        raise errors.HypervisorError("Need a root partition for the instance,"
1929
                                     " if a kernel is defined")
1930

    
1931
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
1932
        not hvparams[constants.HV_VNC_X509]):
1933
      raise errors.HypervisorError("%s must be defined, if %s is" %
1934
                                   (constants.HV_VNC_X509,
1935
                                    constants.HV_VNC_X509_VERIFY))
1936

    
1937
    boot_order = hvparams[constants.HV_BOOT_ORDER]
1938
    if (boot_order == constants.HT_BO_CDROM and
1939
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
1940
      raise errors.HypervisorError("Cannot boot from cdrom without an"
1941
                                   " ISO path")
1942

    
1943
    security_model = hvparams[constants.HV_SECURITY_MODEL]
1944
    if security_model == constants.HT_SM_USER:
1945
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
1946
        raise errors.HypervisorError("A security domain (user to run kvm as)"
1947
                                     " must be specified")
1948
    elif (security_model == constants.HT_SM_NONE or
1949
          security_model == constants.HT_SM_POOL):
1950
      if hvparams[constants.HV_SECURITY_DOMAIN]:
1951
        raise errors.HypervisorError("Cannot have a security domain when the"
1952
                                     " security model is 'none' or 'pool'")
1953

    
1954
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1955
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
1956
    if spice_bind:
1957
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1958
        # if an IP version is specified, the spice_bind parameter must be an
1959
        # IP of that family
1960
        if (netutils.IP4Address.IsValid(spice_bind) and
1961
            spice_ip_version != constants.IP4_VERSION):
1962
          raise errors.HypervisorError("spice: got an IPv4 address (%s), but"
1963
                                       " the specified IP version is %s" %
1964
                                       (spice_bind, spice_ip_version))
1965

    
1966
        if (netutils.IP6Address.IsValid(spice_bind) and
1967
            spice_ip_version != constants.IP6_VERSION):
1968
          raise errors.HypervisorError("spice: got an IPv6 address (%s), but"
1969
                                       " the specified IP version is %s" %
1970
                                       (spice_bind, spice_ip_version))
1971
    else:
1972
      # All the other SPICE parameters depend on spice_bind being set. Raise an
1973
      # error if any of them is set without it.
1974
      for param in _SPICE_ADDITIONAL_PARAMS:
1975
        if hvparams[param]:
1976
          raise errors.HypervisorError("spice: %s requires %s to be set" %
1977
                                       (param, constants.HV_KVM_SPICE_BIND))
1978

    
1979
  @classmethod
1980
  def ValidateParameters(cls, hvparams):
1981
    """Check the given parameters for validity.
1982

1983
    @type hvparams:  dict
1984
    @param hvparams: dictionary with parameter names/value
1985
    @raise errors.HypervisorError: when a parameter is not valid
1986

1987
    """
1988
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
1989

    
1990
    security_model = hvparams[constants.HV_SECURITY_MODEL]
1991
    if security_model == constants.HT_SM_USER:
1992
      username = hvparams[constants.HV_SECURITY_DOMAIN]
1993
      try:
1994
        pwd.getpwnam(username)
1995
      except KeyError:
1996
        raise errors.HypervisorError("Unknown security domain user %s"
1997
                                     % username)
1998

    
1999
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2000
    if spice_bind:
2001
      # only one of VNC and SPICE can be used currently.
2002
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2003
        raise errors.HypervisorError("both SPICE and VNC are configured, but"
2004
                                     " only one of them can be used at a"
2005
                                     " given time.")
2006

    
2007
      # KVM version should be >= 0.14.0
2008
      _, v_major, v_min, _ = cls._GetKVMVersion()
2009
      if (v_major, v_min) < (0, 14):
2010
        raise errors.HypervisorError("spice is configured, but it is not"
2011
                                     " available in versions of KVM < 0.14")
2012

    
2013
      # if spice_bind is not an IP address, it must be a valid interface
2014
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind)
2015
                       or netutils.IP6Address.IsValid(spice_bind))
2016
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2017
        raise errors.HypervisorError("spice: the %s parameter must be either"
2018
                                     " a valid IP address or interface name" %
2019
                                     constants.HV_KVM_SPICE_BIND)
2020

    
2021
  @classmethod
2022
  def PowercycleNode(cls):
2023
    """KVM powercycle, just a wrapper over Linux powercycle.
2024

2025
    """
2026
    cls.LinuxPowercycle()