Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 8df21834

History | View | Annotate | Download (72.8 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

    
72
def _ProbeTapVnetHdr(fd):
73
  """Check whether to enable the IFF_VNET_HDR flag.
74

75
  To do this, _all_ of the following conditions must be met:
76
   1. TUNGETFEATURES ioctl() *must* be implemented
77
   2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
78
   3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
79
      drivers/net/tun.c there is no way to test this until after the tap device
80
      has been created using TUNSETIFF, and there is no way to change the
81
      IFF_VNET_HDR flag after creating the interface, catch-22! However both
82
      TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
83
      thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
84

85
   @type fd: int
86
   @param fd: the file descriptor of /dev/net/tun
87

88
  """
89
  req = struct.pack("I", 0)
90
  try:
91
    res = fcntl.ioctl(fd, TUNGETFEATURES, req)
92
  except EnvironmentError:
93
    logging.warning("TUNGETFEATURES ioctl() not implemented")
94
    return False
95

    
96
  tunflags = struct.unpack("I", res)[0]
97
  if tunflags & IFF_VNET_HDR:
98
    return True
99
  else:
100
    logging.warning("Host does not support IFF_VNET_HDR, not enabling")
101
    return False
102

    
103

    
104
def _OpenTap(vnet_hdr=True):
105
  """Open a new tap device and return its file descriptor.
106

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

110
  @type vnet_hdr: boolean
111
  @param vnet_hdr: Enable the VNET Header
112
  @return: (ifname, tapfd)
113
  @rtype: tuple
114

115
  """
116
  try:
117
    tapfd = os.open("/dev/net/tun", os.O_RDWR)
118
  except EnvironmentError:
119
    raise errors.HypervisorError("Failed to open /dev/net/tun")
120

    
121
  flags = IFF_TAP | IFF_NO_PI
122

    
123
  if vnet_hdr and _ProbeTapVnetHdr(tapfd):
124
    flags |= IFF_VNET_HDR
125

    
126
  # The struct ifreq ioctl request (see netdevice(7))
127
  ifr = struct.pack("16sh", "", flags)
128

    
129
  try:
130
    res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
131
  except EnvironmentError:
132
    raise errors.HypervisorError("Failed to allocate a new TAP device")
133

    
134
  # Get the interface name from the ioctl
135
  ifname = struct.unpack("16sh", res)[0].strip("\x00")
136
  return (ifname, tapfd)
137

    
138

    
139
def _BuildNetworkEnv(name, network, gateway, network6, gateway6,
140
                     network_type, mac_prefix, tags, env):
141
  """Build environment variables concerning a Network.
142

143
  """
144
  if name:
145
    env["NETWORK_NAME"] = name
146
  if network:
147
    env["NETWORK_SUBNET"] = network
148
  if gateway:
149
    env["NETWORK_GATEWAY"] = gateway
150
  if network6:
151
    env["NETWORK_SUBNET6"] = network6
152
  if gateway6:
153
    env["NETWORK_GATEWAY6"] = gateway6
154
  if mac_prefix:
155
    env["NETWORK_MAC_PREFIX"] = mac_prefix
156
  if network_type:
157
    env["NETWORK_TYPE"] = network_type
158
  if tags:
159
    env["NETWORK_TAGS"] = " ".join(tags)
160

    
161
  return env
162

    
163

    
164
class QmpMessage:
165
  """QEMU Messaging Protocol (QMP) message.
166

167
  """
168
  def __init__(self, data):
169
    """Creates a new QMP message based on the passed data.
170

171
    """
172
    if not isinstance(data, dict):
173
      raise TypeError("QmpMessage must be initialized with a dict")
174

    
175
    self.data = data
176

    
177
  def __getitem__(self, field_name):
178
    """Get the value of the required field if present, or None.
179

180
    Overrides the [] operator to provide access to the message data,
181
    returning None if the required item is not in the message
182
    @return: the value of the field_name field, or None if field_name
183
             is not contained in the message
184

185
    """
186
    return self.data.get(field_name, None)
187

    
188
  def __setitem__(self, field_name, field_value):
189
    """Set the value of the required field_name to field_value.
190

191
    """
192
    self.data[field_name] = field_value
193

    
194
  @staticmethod
195
  def BuildFromJsonString(json_string):
196
    """Build a QmpMessage from a JSON encoded string.
197

198
    @type json_string: str
199
    @param json_string: JSON string representing the message
200
    @rtype: L{QmpMessage}
201
    @return: a L{QmpMessage} built from json_string
202

203
    """
204
    # Parse the string
205
    data = serializer.LoadJson(json_string)
206
    return QmpMessage(data)
207

    
208
  def __str__(self):
209
    # The protocol expects the JSON object to be sent as a single line.
210
    return serializer.DumpJson(self.data)
211

    
212
  def __eq__(self, other):
213
    # When comparing two QmpMessages, we are interested in comparing
214
    # their internal representation of the message data
215
    return self.data == other.data
216

    
217

    
218
class QmpConnection:
219
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
220

221
  """
222
  _FIRST_MESSAGE_KEY = "QMP"
223
  _EVENT_KEY = "event"
224
  _ERROR_KEY = "error"
225
  _RETURN_KEY = RETURN_KEY = "return"
226
  _ACTUAL_KEY = ACTUAL_KEY = "actual"
227
  _ERROR_CLASS_KEY = "class"
228
  _ERROR_DATA_KEY = "data"
229
  _ERROR_DESC_KEY = "desc"
230
  _EXECUTE_KEY = "execute"
231
  _ARGUMENTS_KEY = "arguments"
232
  _CAPABILITIES_COMMAND = "qmp_capabilities"
233
  _MESSAGE_END_TOKEN = "\r\n"
234
  _SOCKET_TIMEOUT = 5
235

    
236
  def __init__(self, monitor_filename):
237
    """Instantiates the QmpConnection object.
238

239
    @type monitor_filename: string
240
    @param monitor_filename: the filename of the UNIX raw socket on which the
241
                             QMP monitor is listening
242

243
    """
244
    self.monitor_filename = monitor_filename
245
    self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
246
    # We want to fail if the server doesn't send a complete message
247
    # in a reasonable amount of time
248
    self.sock.settimeout(self._SOCKET_TIMEOUT)
249
    self._connected = False
250
    self._buf = ""
251

    
252
  def _check_socket(self):
253
    sock_stat = None
254
    try:
255
      sock_stat = os.stat(self.monitor_filename)
256
    except EnvironmentError, err:
257
      if err.errno == errno.ENOENT:
258
        raise errors.HypervisorError("No qmp socket found")
259
      else:
260
        raise errors.HypervisorError("Error checking qmp socket: %s",
261
                                     utils.ErrnoOrStr(err))
262
    if not stat.S_ISSOCK(sock_stat.st_mode):
263
      raise errors.HypervisorError("Qmp socket is not a socket")
264

    
265
  def _check_connection(self):
266
    """Make sure that the connection is established.
267

268
    """
269
    if not self._connected:
270
      raise errors.ProgrammerError("To use a QmpConnection you need to first"
271
                                   " invoke connect() on it")
272

    
273
  def connect(self):
274
    """Connects to the QMP monitor.
275

276
    Connects to the UNIX socket and makes sure that we can actually send and
277
    receive data to the kvm instance via QMP.
278

279
    @raise errors.HypervisorError: when there are communication errors
280
    @raise errors.ProgrammerError: when there are data serialization errors
281

282
    """
283
    if self._connected:
284
      raise errors.ProgrammerError("Cannot connect twice")
285

    
286
    self._check_socket()
287

    
288
    # Check file existance/stuff
289
    try:
290
      self.sock.connect(self.monitor_filename)
291
    except EnvironmentError:
292
      raise errors.HypervisorError("Can't connect to qmp socket")
293
    self._connected = True
294

    
295
    # Check if we receive a correct greeting message from the server
296
    # (As per the QEMU Protocol Specification 0.1 - section 2.2)
297
    greeting = self._Recv()
298
    if not greeting[self._FIRST_MESSAGE_KEY]:
299
      self._connected = False
300
      raise errors.HypervisorError("kvm: qmp communication error (wrong"
301
                                   " server greeting")
302

    
303
    # Let's put the monitor in command mode using the qmp_capabilities
304
    # command, or else no command will be executable.
305
    # (As per the QEMU Protocol Specification 0.1 - section 4)
306
    self.Execute(self._CAPABILITIES_COMMAND)
307

    
308
  def _ParseMessage(self, buf):
309
    """Extract and parse a QMP message from the given buffer.
310

311
    Seeks for a QMP message in the given buf. If found, it parses it and
312
    returns it together with the rest of the characters in the buf.
313
    If no message is found, returns None and the whole buffer.
314

315
    @raise errors.ProgrammerError: when there are data serialization errors
316

317
    """
318
    message = None
319
    # Check if we got the message end token (CRLF, as per the QEMU Protocol
320
    # Specification 0.1 - Section 2.1.1)
321
    pos = buf.find(self._MESSAGE_END_TOKEN)
322
    if pos >= 0:
323
      try:
324
        message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
325
      except Exception, err:
326
        raise errors.ProgrammerError("QMP data serialization error: %s" % err)
327
      buf = buf[pos + 1:]
328

    
329
    return (message, buf)
330

    
331
  def _Recv(self):
332
    """Receives a message from QMP and decodes the received JSON object.
333

334
    @rtype: QmpMessage
335
    @return: the received message
336
    @raise errors.HypervisorError: when there are communication errors
337
    @raise errors.ProgrammerError: when there are data serialization errors
338

339
    """
340
    self._check_connection()
341

    
342
    # Check if there is already a message in the buffer
343
    (message, self._buf) = self._ParseMessage(self._buf)
344
    if message:
345
      return message
346

    
347
    recv_buffer = StringIO.StringIO(self._buf)
348
    recv_buffer.seek(len(self._buf))
349
    try:
350
      while True:
351
        data = self.sock.recv(4096)
352
        if not data:
353
          break
354
        recv_buffer.write(data)
355

    
356
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
357
        if message:
358
          return message
359

    
360
    except socket.timeout, err:
361
      raise errors.HypervisorError("Timeout while receiving a QMP message: "
362
                                   "%s" % (err))
363
    except socket.error, err:
364
      raise errors.HypervisorError("Unable to receive data from KVM using the"
365
                                   " QMP protocol: %s" % err)
366

    
367
  def _Send(self, message):
368
    """Encodes and sends a message to KVM using QMP.
369

370
    @type message: QmpMessage
371
    @param message: message to send to KVM
372
    @raise errors.HypervisorError: when there are communication errors
373
    @raise errors.ProgrammerError: when there are data serialization errors
374

375
    """
376
    self._check_connection()
377
    try:
378
      message_str = str(message)
379
    except Exception, err:
380
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
381

    
382
    try:
383
      self.sock.sendall(message_str)
384
    except socket.timeout, err:
385
      raise errors.HypervisorError("Timeout while sending a QMP message: "
386
                                   "%s (%s)" % (err.string, err.errno))
387
    except socket.error, err:
388
      raise errors.HypervisorError("Unable to send data from KVM using the"
389
                                   " QMP protocol: %s" % err)
390

    
391
  def Execute(self, command, arguments=None):
392
    """Executes a QMP command and returns the response of the server.
393

394
    @type command: str
395
    @param command: the command to execute
396
    @type arguments: dict
397
    @param arguments: dictionary of arguments to be passed to the command
398
    @rtype: dict
399
    @return: dictionary representing the received JSON object
400
    @raise errors.HypervisorError: when there are communication errors
401
    @raise errors.ProgrammerError: when there are data serialization errors
402

403
    """
404
    self._check_connection()
405
    message = QmpMessage({self._EXECUTE_KEY: command})
406
    if arguments:
407
      message[self._ARGUMENTS_KEY] = arguments
408
    self._Send(message)
409

    
410
    # Events can occur between the sending of the command and the reception
411
    # of the response, so we need to filter out messages with the event key.
412
    while True:
413
      response = self._Recv()
414
      err = response[self._ERROR_KEY]
415
      if err:
416
        raise errors.HypervisorError("kvm: error executing the %s"
417
                                     " command: %s (%s, %s):" %
418
                                     (command,
419
                                      err[self._ERROR_DESC_KEY],
420
                                      err[self._ERROR_CLASS_KEY],
421
                                      err[self._ERROR_DATA_KEY]))
422

    
423
      elif not response[self._EVENT_KEY]:
424
        return response
425

    
426

    
427
class KVMHypervisor(hv_base.BaseHypervisor):
428
  """KVM hypervisor interface
429

430
  """
431
  CAN_MIGRATE = True
432

    
433
  _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
434
  _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
435
  _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
436
  _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
437
  _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
438
  _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
439
  _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
440
  # KVM instances with chroot enabled are started in empty chroot directories.
441
  _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
442
  # After an instance is stopped, its chroot directory is removed.
443
  # If the chroot directory is not empty, it can't be removed.
444
  # A non-empty chroot directory indicates a possible security incident.
445
  # To support forensics, the non-empty chroot directory is quarantined in
446
  # a separate directory, called 'chroot-quarantine'.
447
  _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
448
  _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
449
           _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
450

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

    
525
  _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
526
                                    re.M | re.I)
527
  _MIGRATION_PROGRESS_RE = \
528
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
529
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
530
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
531

    
532
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
533
  _MIGRATION_INFO_RETRY_DELAY = 2
534

    
535
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
536

    
537
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
538
  _CPU_INFO_CMD = "info cpus"
539
  _CONT_CMD = "cont"
540

    
541
  ANCILLARY_FILES = [
542
    _KVM_NETWORK_SCRIPT,
543
    ]
544
  ANCILLARY_FILES_OPT = [
545
    _KVM_NETWORK_SCRIPT,
546
    ]
547

    
548
  def __init__(self):
549
    hv_base.BaseHypervisor.__init__(self)
550
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
551
    # in a tmpfs filesystem or has been otherwise wiped out.
552
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
553
    utils.EnsureDirs(dirs)
554

    
555
  @classmethod
556
  def _InstancePidFile(cls, instance_name):
557
    """Returns the instance pidfile.
558

559
    """
560
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
561

    
562
  @classmethod
563
  def _InstanceUidFile(cls, instance_name):
564
    """Returns the instance uidfile.
565

566
    """
567
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
568

    
569
  @classmethod
570
  def _InstancePidInfo(cls, pid):
571
    """Check pid file for instance information.
572

573
    Check that a pid file is associated with an instance, and retrieve
574
    information from its command line.
575

576
    @type pid: string or int
577
    @param pid: process id of the instance to check
578
    @rtype: tuple
579
    @return: (instance_name, memory, vcpus)
580
    @raise errors.HypervisorError: when an instance cannot be found
581

582
    """
583
    alive = utils.IsProcessAlive(pid)
584
    if not alive:
585
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
586

    
587
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
588
    try:
589
      cmdline = utils.ReadFile(cmdline_file)
590
    except EnvironmentError, err:
591
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
592
                                   (pid, err))
593

    
594
    instance = None
595
    memory = 0
596
    vcpus = 0
597

    
598
    arg_list = cmdline.split("\x00")
599
    while arg_list:
600
      arg = arg_list.pop(0)
601
      if arg == "-name":
602
        instance = arg_list.pop(0)
603
      elif arg == "-m":
604
        memory = int(arg_list.pop(0))
605
      elif arg == "-smp":
606
        vcpus = int(arg_list.pop(0))
607

    
608
    if instance is None:
609
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
610
                                   " instance" % pid)
611

    
612
    return (instance, memory, vcpus)
613

    
614
  def _InstancePidAlive(self, instance_name):
615
    """Returns the instance pidfile, pid, and liveness.
616

617
    @type instance_name: string
618
    @param instance_name: instance name
619
    @rtype: tuple
620
    @return: (pid file name, pid, liveness)
621

622
    """
623
    pidfile = self._InstancePidFile(instance_name)
624
    pid = utils.ReadPidFile(pidfile)
625

    
626
    alive = False
627
    try:
628
      cmd_instance = self._InstancePidInfo(pid)[0]
629
      alive = (cmd_instance == instance_name)
630
    except errors.HypervisorError:
631
      pass
632

    
633
    return (pidfile, pid, alive)
634

    
635
  def _CheckDown(self, instance_name):
636
    """Raises an error unless the given instance is down.
637

638
    """
639
    alive = self._InstancePidAlive(instance_name)[2]
640
    if alive:
641
      raise errors.HypervisorError("Failed to start instance %s: %s" %
642
                                   (instance_name, "already running"))
643

    
644
  @classmethod
645
  def _InstanceMonitor(cls, instance_name):
646
    """Returns the instance monitor socket name
647

648
    """
649
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
650

    
651
  @classmethod
652
  def _InstanceSerial(cls, instance_name):
653
    """Returns the instance serial socket name
654

655
    """
656
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
657

    
658
  @classmethod
659
  def _InstanceQmpMonitor(cls, instance_name):
660
    """Returns the instance serial QMP socket name
661

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

    
665
  @staticmethod
666
  def _SocatUnixConsoleParams():
667
    """Returns the correct parameters for socat
668

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

671
    """
672
    if constants.SOCAT_USE_ESCAPE:
673
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
674
    else:
675
      return "echo=0,icanon=0"
676

    
677
  @classmethod
678
  def _InstanceKVMRuntime(cls, instance_name):
679
    """Returns the instance KVM runtime filename
680

681
    """
682
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
683

    
684
  @classmethod
685
  def _InstanceChrootDir(cls, instance_name):
686
    """Returns the name of the KVM chroot dir of the instance
687

688
    """
689
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
690

    
691
  @classmethod
692
  def _InstanceNICDir(cls, instance_name):
693
    """Returns the name of the directory holding the tap device files for a
694
    given instance.
695

696
    """
697
    return utils.PathJoin(cls._NICS_DIR, instance_name)
698

    
699
  @classmethod
700
  def _InstanceNICFile(cls, instance_name, seq):
701
    """Returns the name of the file containing the tap device for a given NIC
702

703
    """
704
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
705

    
706
  @classmethod
707
  def _InstanceKeymapFile(cls, instance_name):
708
    """Returns the name of the file containing the keymap for a given instance
709

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

    
713
  @classmethod
714
  def _TryReadUidFile(cls, uid_file):
715
    """Try to read a uid file
716

717
    """
718
    if os.path.exists(uid_file):
719
      try:
720
        uid = int(utils.ReadOneLineFile(uid_file))
721
        return uid
722
      except EnvironmentError:
723
        logging.warning("Can't read uid file", exc_info=True)
724
      except (TypeError, ValueError):
725
        logging.warning("Can't parse uid file contents", exc_info=True)
726
    return None
727

    
728
  @classmethod
729
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
730
    """Removes an instance's rutime sockets/files/dirs.
731

732
    """
733
    utils.RemoveFile(pidfile)
734
    utils.RemoveFile(cls._InstanceMonitor(instance_name))
735
    utils.RemoveFile(cls._InstanceSerial(instance_name))
736
    utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
737
    utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
738
    utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
739
    uid_file = cls._InstanceUidFile(instance_name)
740
    uid = cls._TryReadUidFile(uid_file)
741
    utils.RemoveFile(uid_file)
742
    if uid is not None:
743
      uidpool.ReleaseUid(uid)
744
    try:
745
      shutil.rmtree(cls._InstanceNICDir(instance_name))
746
    except OSError, err:
747
      if err.errno != errno.ENOENT:
748
        raise
749
    try:
750
      chroot_dir = cls._InstanceChrootDir(instance_name)
751
      utils.RemoveDir(chroot_dir)
752
    except OSError, err:
753
      if err.errno == errno.ENOTEMPTY:
754
        # The chroot directory is expected to be empty, but it isn't.
755
        new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
756
                                          prefix="%s-%s-" %
757
                                          (instance_name,
758
                                           utils.TimestampForFilename()))
759
        logging.warning("The chroot directory of instance %s can not be"
760
                        " removed as it is not empty. Moving it to the"
761
                        " quarantine instead. Please investigate the"
762
                        " contents (%s) and clean up manually",
763
                        instance_name, new_chroot_dir)
764
        utils.RenameFile(chroot_dir, new_chroot_dir)
765
      else:
766
        raise
767

    
768
  @staticmethod
769
  def _ConfigureNIC(instance, seq, nic, tap):
770
    """Run the network configuration script for a specified NIC
771

772
    @param instance: instance we're acting on
773
    @type instance: instance object
774
    @param seq: nic sequence number
775
    @type seq: int
776
    @param nic: nic we're acting on
777
    @type nic: nic object
778
    @param tap: the host's tap interface this NIC corresponds to
779
    @type tap: str
780

781
    """
782
    if instance.tags:
783
      tags = " ".join(instance.tags)
784
    else:
785
      tags = ""
786

    
787
    env = {
788
      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
789
      "INSTANCE": instance.name,
790
      "MAC": nic.mac,
791
      "MODE": nic.nicparams[constants.NIC_MODE],
792
      "INTERFACE": tap,
793
      "INTERFACE_INDEX": str(seq),
794
      "TAGS": tags,
795
    }
796

    
797
    if nic.ip:
798
      env["IP"] = nic.ip
799

    
800
    if nic.nicparams[constants.NIC_LINK]:
801
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
802

    
803
    if nic.network:
804
      n = objects.Network.FromDict(nic.netinfo)
805
      _BuildNetworkEnv(nic.network, n.network, n.gateway,
806
                       n.network6, n.gateway6, n.network_type,
807
                       n.mac_prefix, n.tags, env)
808

    
809
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
810
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
811

    
812
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
813
    if result.failed:
814
      raise errors.HypervisorError("Failed to configure interface %s: %s."
815
                                   " Network configuration script output: %s" %
816
                                   (tap, result.fail_reason, result.output))
817

    
818
  @staticmethod
819
  def _VerifyAffinityPackage():
820
    if affinity is None:
821
      raise errors.HypervisorError("affinity Python package not"
822
                                   " found; cannot use CPU pinning under KVM")
823

    
824
  @staticmethod
825
  def _BuildAffinityCpuMask(cpu_list):
826
    """Create a CPU mask suitable for sched_setaffinity from a list of
827
    CPUs.
828

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

832
    @type cpu_list: list of int
833
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
834
    @rtype: int
835
    @return: a bit mask of CPU affinities
836

837
    """
838
    if cpu_list == constants.CPU_PINNING_OFF:
839
      return constants.CPU_PINNING_ALL_KVM
840
    else:
841
      return sum(2 ** cpu for cpu in cpu_list)
842

    
843
  @classmethod
844
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
845
    """Change CPU affinity for running VM according to given CPU mask.
846

847
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
848
    @type cpu_mask: string
849
    @param process_id: process ID of KVM process. Used to pin entire VM
850
                       to physical CPUs.
851
    @type process_id: int
852
    @param thread_dict: map of virtual CPUs to KVM thread IDs
853
    @type thread_dict: dict int:int
854

855
    """
856
    # Convert the string CPU mask to a list of list of int's
857
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
858

    
859
    if len(cpu_list) == 1:
860
      all_cpu_mapping = cpu_list[0]
861
      if all_cpu_mapping == constants.CPU_PINNING_OFF:
862
        # If CPU pinning has 1 entry that's "all", then do nothing
863
        pass
864
      else:
865
        # If CPU pinning has one non-all entry, map the entire VM to
866
        # one set of physical CPUs
867
        cls._VerifyAffinityPackage()
868
        affinity.set_process_affinity_mask(
869
          process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
870
    else:
871
      # The number of vCPUs mapped should match the number of vCPUs
872
      # reported by KVM. This was already verified earlier, so
873
      # here only as a sanity check.
874
      assert len(thread_dict) == len(cpu_list)
875
      cls._VerifyAffinityPackage()
876

    
877
      # For each vCPU, map it to the proper list of physical CPUs
878
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
879
        affinity.set_process_affinity_mask(thread_dict[i],
880
                                           cls._BuildAffinityCpuMask(vcpu))
881

    
882
  def _GetVcpuThreadIds(self, instance_name):
883
    """Get a mapping of vCPU no. to thread IDs for the instance
884

885
    @type instance_name: string
886
    @param instance_name: instance in question
887
    @rtype: dictionary of int:int
888
    @return: a dictionary mapping vCPU numbers to thread IDs
889

890
    """
891
    result = {}
892
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
893
    for line in output.stdout.splitlines():
894
      match = self._CPU_INFO_RE.search(line)
895
      if not match:
896
        continue
897
      grp = map(int, match.groups())
898
      result[grp[0]] = grp[1]
899

    
900
    return result
901

    
902
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
903
    """Complete CPU pinning.
904

905
    @type instance_name: string
906
    @param instance_name: name of instance
907
    @type cpu_mask: string
908
    @param cpu_mask: CPU pinning mask as entered by user
909

910
    """
911
    # Get KVM process ID, to be used if need to pin entire VM
912
    _, pid, _ = self._InstancePidAlive(instance_name)
913
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
914
    thread_dict = self._GetVcpuThreadIds(instance_name)
915
    # Run CPU pinning, based on configured mask
916
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
917

    
918
  def ListInstances(self):
919
    """Get the list of running instances.
920

921
    We can do this by listing our live instances directory and
922
    checking whether the associated kvm process is still alive.
923

924
    """
925
    result = []
926
    for name in os.listdir(self._PIDS_DIR):
927
      if self._InstancePidAlive(name)[2]:
928
        result.append(name)
929
    return result
930

    
931
  def GetInstanceInfo(self, instance_name):
932
    """Get instance properties.
933

934
    @type instance_name: string
935
    @param instance_name: the instance name
936
    @rtype: tuple of strings
937
    @return: (name, id, memory, vcpus, stat, times)
938

939
    """
940
    _, pid, alive = self._InstancePidAlive(instance_name)
941
    if not alive:
942
      return None
943

    
944
    _, memory, vcpus = self._InstancePidInfo(pid)
945
    istat = "---b-"
946
    times = "0"
947

    
948
    try:
949
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
950
      qmp.connect()
951
      vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
952
      # Will fail if ballooning is not enabled, but we can then just resort to
953
      # the value above.
954
      mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
955
      memory = mem_bytes / 1048576
956
    except errors.HypervisorError:
957
      pass
958

    
959
    return (instance_name, pid, memory, vcpus, istat, times)
960

    
961
  def GetAllInstancesInfo(self):
962
    """Get properties of all instances.
963

964
    @return: list of tuples (name, id, memory, vcpus, stat, times)
965

966
    """
967
    data = []
968
    for name in os.listdir(self._PIDS_DIR):
969
      try:
970
        info = self.GetInstanceInfo(name)
971
      except errors.HypervisorError:
972
        # Ignore exceptions due to instances being shut down
973
        continue
974
      if info:
975
        data.append(info)
976
    return data
977

    
978
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused):
979
    """Generate KVM information to start an instance.
980

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

988
    """
989
    # pylint: disable=R0914,R0915
990
    _, v_major, v_min, _ = self._GetKVMVersion()
991

    
992
    pidfile = self._InstancePidFile(instance.name)
993
    kvm = constants.KVM_PATH
994
    kvm_cmd = [kvm]
995
    # used just by the vnc server, if enabled
996
    kvm_cmd.extend(["-name", instance.name])
997
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
998
    kvm_cmd.extend(["-smp", instance.beparams[constants.BE_VCPUS]])
999
    kvm_cmd.extend(["-pidfile", pidfile])
1000
    kvm_cmd.extend(["-balloon", "virtio"])
1001
    kvm_cmd.extend(["-daemonize"])
1002
    if not instance.hvparams[constants.HV_ACPI]:
1003
      kvm_cmd.extend(["-no-acpi"])
1004
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1005
        constants.INSTANCE_REBOOT_EXIT:
1006
      kvm_cmd.extend(["-no-reboot"])
1007

    
1008
    hvp = instance.hvparams
1009
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1010
    if kernel_path:
1011
      boot_disk = boot_cdrom = boot_floppy = boot_network = False
1012
    else:
1013
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1014
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1015
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1016
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1017

    
1018
    self.ValidateParameters(hvp)
1019

    
1020
    if startup_paused:
1021
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1022

    
1023
    if hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED:
1024
      kvm_cmd.extend(["-enable-kvm"])
1025
    elif hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED:
1026
      kvm_cmd.extend(["-disable-kvm"])
1027

    
1028
    if boot_network:
1029
      kvm_cmd.extend(["-boot", "n"])
1030

    
1031
    # whether this is an older KVM version that uses the boot=on flag
1032
    # on devices
1033
    needs_boot_flag = (v_major, v_min) < (0, 14)
1034

    
1035
    disk_type = hvp[constants.HV_DISK_TYPE]
1036
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
1037
      if_val = ",if=virtio"
1038
    else:
1039
      if_val = ",if=%s" % disk_type
1040
    # Cache mode
1041
    disk_cache = hvp[constants.HV_DISK_CACHE]
1042
    if instance.disk_template in constants.DTS_EXT_MIRROR:
1043
      if disk_cache != "none":
1044
        # TODO: make this a hard error, instead of a silent overwrite
1045
        logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1046
                        " to prevent shared storage corruption on migration",
1047
                        disk_cache)
1048
      cache_val = ",cache=none"
1049
    elif disk_cache != constants.HT_CACHE_DEFAULT:
1050
      cache_val = ",cache=%s" % disk_cache
1051
    else:
1052
      cache_val = ""
1053
    for cfdev, dev_path in block_devices:
1054
      if cfdev.mode != constants.DISK_RDWR:
1055
        raise errors.HypervisorError("Instance has read-only disks which"
1056
                                     " are not supported by KVM")
1057
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
1058
      boot_val = ""
1059
      if boot_disk:
1060
        kvm_cmd.extend(["-boot", "c"])
1061
        boot_disk = False
1062
        if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1063
          boot_val = ",boot=on"
1064

    
1065
      drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
1066
                                                cache_val)
1067
      kvm_cmd.extend(["-drive", drive_val])
1068

    
1069
    #Now we can specify a different device type for CDROM devices.
1070
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1071
    if not cdrom_disk_type:
1072
      cdrom_disk_type = disk_type
1073

    
1074
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1075
    if iso_image:
1076
      options = ",format=raw,media=cdrom"
1077
      # set cdrom 'if' type
1078
      if boot_cdrom:
1079
        actual_cdrom_type = constants.HT_DISK_IDE
1080
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1081
        actual_cdrom_type = "virtio"
1082
      else:
1083
        actual_cdrom_type = cdrom_disk_type
1084
      if_val = ",if=%s" % actual_cdrom_type
1085
      # set boot flag, if needed
1086
      boot_val = ""
1087
      if boot_cdrom:
1088
        kvm_cmd.extend(["-boot", "d"])
1089
        if needs_boot_flag:
1090
          boot_val = ",boot=on"
1091
      # and finally build the entire '-drive' value
1092
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1093
      kvm_cmd.extend(["-drive", drive_val])
1094

    
1095
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1096
    if iso_image2:
1097
      options = ",format=raw,media=cdrom"
1098
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1099
        if_val = ",if=virtio"
1100
      else:
1101
        if_val = ",if=%s" % cdrom_disk_type
1102
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1103
      kvm_cmd.extend(["-drive", drive_val])
1104

    
1105
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1106
    if floppy_image:
1107
      options = ",format=raw,media=disk"
1108
      if boot_floppy:
1109
        kvm_cmd.extend(["-boot", "a"])
1110
        options = "%s,boot=on" % options
1111
      if_val = ",if=floppy"
1112
      options = "%s%s" % (options, if_val)
1113
      drive_val = "file=%s%s" % (floppy_image, options)
1114
      kvm_cmd.extend(["-drive", drive_val])
1115

    
1116
    if kernel_path:
1117
      kvm_cmd.extend(["-kernel", kernel_path])
1118
      initrd_path = hvp[constants.HV_INITRD_PATH]
1119
      if initrd_path:
1120
        kvm_cmd.extend(["-initrd", initrd_path])
1121
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1122
                     hvp[constants.HV_KERNEL_ARGS]]
1123
      if hvp[constants.HV_SERIAL_CONSOLE]:
1124
        root_append.append("console=ttyS0,38400")
1125
      kvm_cmd.extend(["-append", " ".join(root_append)])
1126

    
1127
    mem_path = hvp[constants.HV_MEM_PATH]
1128
    if mem_path:
1129
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1130

    
1131
    monitor_dev = ("unix:%s,server,nowait" %
1132
                   self._InstanceMonitor(instance.name))
1133
    kvm_cmd.extend(["-monitor", monitor_dev])
1134
    if hvp[constants.HV_SERIAL_CONSOLE]:
1135
      serial_dev = ("unix:%s,server,nowait" %
1136
                    self._InstanceSerial(instance.name))
1137
      kvm_cmd.extend(["-serial", serial_dev])
1138
    else:
1139
      kvm_cmd.extend(["-serial", "none"])
1140

    
1141
    mouse_type = hvp[constants.HV_USB_MOUSE]
1142
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1143
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1144
    spice_ip_version = None
1145

    
1146
    if mouse_type:
1147
      kvm_cmd.extend(["-usb"])
1148
      kvm_cmd.extend(["-usbdevice", mouse_type])
1149
    elif vnc_bind_address:
1150
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1151

    
1152
    if vnc_bind_address:
1153
      if netutils.IP4Address.IsValid(vnc_bind_address):
1154
        if instance.network_port > constants.VNC_BASE_PORT:
1155
          display = instance.network_port - constants.VNC_BASE_PORT
1156
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1157
            vnc_arg = ":%d" % (display)
1158
          else:
1159
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1160
        else:
1161
          logging.error("Network port is not a valid VNC display (%d < %d)."
1162
                        " Not starting VNC", instance.network_port,
1163
                        constants.VNC_BASE_PORT)
1164
          vnc_arg = "none"
1165

    
1166
        # Only allow tls and other option when not binding to a file, for now.
1167
        # kvm/qemu gets confused otherwise about the filename to use.
1168
        vnc_append = ""
1169
        if hvp[constants.HV_VNC_TLS]:
1170
          vnc_append = "%s,tls" % vnc_append
1171
          if hvp[constants.HV_VNC_X509_VERIFY]:
1172
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1173
                                               hvp[constants.HV_VNC_X509])
1174
          elif hvp[constants.HV_VNC_X509]:
1175
            vnc_append = "%s,x509=%s" % (vnc_append,
1176
                                         hvp[constants.HV_VNC_X509])
1177
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1178
          vnc_append = "%s,password" % vnc_append
1179

    
1180
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1181

    
1182
      else:
1183
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1184

    
1185
      kvm_cmd.extend(["-vnc", vnc_arg])
1186
    elif spice_bind:
1187
      # FIXME: this is wrong here; the iface ip address differs
1188
      # between systems, so it should be done in _ExecuteKVMRuntime
1189
      if netutils.IsValidInterface(spice_bind):
1190
        # The user specified a network interface, we have to figure out the IP
1191
        # address.
1192
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1193
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1194

    
1195
        # if the user specified an IP version and the interface does not
1196
        # have that kind of IP addresses, throw an exception
1197
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1198
          if not addresses[spice_ip_version]:
1199
            raise errors.HypervisorError("spice: unable to get an IPv%s address"
1200
                                         " for %s" % (spice_ip_version,
1201
                                                      spice_bind))
1202

    
1203
        # the user did not specify an IP version, we have to figure it out
1204
        elif (addresses[constants.IP4_VERSION] and
1205
              addresses[constants.IP6_VERSION]):
1206
          # we have both ipv4 and ipv6, let's use the cluster default IP
1207
          # version
1208
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1209
          spice_ip_version = \
1210
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1211
        elif addresses[constants.IP4_VERSION]:
1212
          spice_ip_version = constants.IP4_VERSION
1213
        elif addresses[constants.IP6_VERSION]:
1214
          spice_ip_version = constants.IP6_VERSION
1215
        else:
1216
          raise errors.HypervisorError("spice: unable to get an IP address"
1217
                                       " for %s" % (spice_bind))
1218

    
1219
        spice_address = addresses[spice_ip_version][0]
1220

    
1221
      else:
1222
        # spice_bind is known to be a valid IP address, because
1223
        # ValidateParameters checked it.
1224
        spice_address = spice_bind
1225

    
1226
      spice_arg = "addr=%s" % spice_address
1227
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1228
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1229
                     (spice_arg, instance.network_port,
1230
                      pathutils.SPICE_CACERT_FILE))
1231
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1232
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1233
                      pathutils.SPICE_CERT_FILE))
1234
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1235
        if tls_ciphers:
1236
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1237
      else:
1238
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1239

    
1240
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1241
        spice_arg = "%s,disable-ticketing" % spice_arg
1242

    
1243
      if spice_ip_version:
1244
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1245

    
1246
      # Image compression options
1247
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1248
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1249
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1250
      if img_lossless:
1251
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1252
      if img_jpeg:
1253
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1254
      if img_zlib_glz:
1255
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1256

    
1257
      # Video stream detection
1258
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1259
      if video_streaming:
1260
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1261

    
1262
      # Audio compression, by default in qemu-kvm it is on
1263
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1264
        spice_arg = "%s,playback-compression=off" % spice_arg
1265
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1266
        spice_arg = "%s,agent-mouse=off" % spice_arg
1267
      else:
1268
        # Enable the spice agent communication channel between the host and the
1269
        # agent.
1270
        kvm_cmd.extend(["-device", "virtio-serial-pci"])
1271
        kvm_cmd.extend(["-device", "virtserialport,chardev=spicechannel0,"
1272
                                                   "name=com.redhat.spice.0"])
1273
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1274

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

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

    
1281
    else:
1282
      kvm_cmd.extend(["-nographic"])
1283

    
1284
    if hvp[constants.HV_USE_LOCALTIME]:
1285
      kvm_cmd.extend(["-localtime"])
1286

    
1287
    if hvp[constants.HV_KVM_USE_CHROOT]:
1288
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1289

    
1290
    # Add qemu-KVM -cpu param
1291
    if hvp[constants.HV_CPU_TYPE]:
1292
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1293

    
1294
    # Save the current instance nics, but defer their expansion as parameters,
1295
    # as we'll need to generate executable temp files for them.
1296
    kvm_nics = instance.nics
1297
    hvparams = hvp
1298

    
1299
    return (kvm_cmd, kvm_nics, hvparams)
1300

    
1301
  def _WriteKVMRuntime(self, instance_name, data):
1302
    """Write an instance's KVM runtime
1303

1304
    """
1305
    try:
1306
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1307
                      data=data)
1308
    except EnvironmentError, err:
1309
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1310

    
1311
  def _ReadKVMRuntime(self, instance_name):
1312
    """Read an instance's KVM runtime
1313

1314
    """
1315
    try:
1316
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1317
    except EnvironmentError, err:
1318
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1319
    return file_content
1320

    
1321
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1322
    """Save an instance's KVM runtime
1323

1324
    """
1325
    kvm_cmd, kvm_nics, hvparams = kvm_runtime
1326
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1327
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1328
    self._WriteKVMRuntime(instance.name, serialized_form)
1329

    
1330
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1331
    """Load an instance's KVM runtime
1332

1333
    """
1334
    if not serialized_runtime:
1335
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1336
    loaded_runtime = serializer.Load(serialized_runtime)
1337
    kvm_cmd, serialized_nics, hvparams = loaded_runtime
1338
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1339
    return (kvm_cmd, kvm_nics, hvparams)
1340

    
1341
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1342
    """Run the KVM cmd and check for errors
1343

1344
    @type name: string
1345
    @param name: instance name
1346
    @type kvm_cmd: list of strings
1347
    @param kvm_cmd: runcmd input for kvm
1348
    @type tap_fds: list of int
1349
    @param tap_fds: fds of tap devices opened by Ganeti
1350

1351
    """
1352
    try:
1353
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1354
    finally:
1355
      for fd in tap_fds:
1356
        utils_wrapper.CloseFdNoError(fd)
1357

    
1358
    if result.failed:
1359
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1360
                                   (name, result.fail_reason, result.output))
1361
    if not self._InstancePidAlive(name)[2]:
1362
      raise errors.HypervisorError("Failed to start instance %s" % name)
1363

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

1367
    @type incoming: tuple of strings
1368
    @param incoming: (target_host_ip, port)
1369

1370
    """
1371
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1372
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1373
    #    have changed since the instance started; only use them if the change
1374
    #    won't affect the inside of the instance (which hasn't been rebooted).
1375
    #  - up_hvp contains the parameters as they were when the instance was
1376
    #    started, plus any new parameter which has been added between ganeti
1377
    #    versions: it is paramount that those default to a value which won't
1378
    #    affect the inside of the instance as well.
1379
    conf_hvp = instance.hvparams
1380
    name = instance.name
1381
    self._CheckDown(name)
1382

    
1383
    temp_files = []
1384

    
1385
    kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1386
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1387

    
1388
    _, v_major, v_min, _ = self._GetKVMVersion()
1389

    
1390
    # We know it's safe to run as a different user upon migration, so we'll use
1391
    # the latest conf, from conf_hvp.
1392
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1393
    if security_model == constants.HT_SM_USER:
1394
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1395

    
1396
    keymap = conf_hvp[constants.HV_KEYMAP]
1397
    if keymap:
1398
      keymap_path = self._InstanceKeymapFile(name)
1399
      # If a keymap file is specified, KVM won't use its internal defaults. By
1400
      # first including the "en-us" layout, an error on loading the actual
1401
      # layout (e.g. because it can't be found) won't lead to a non-functional
1402
      # keyboard. A keyboard with incorrect keys is still better than none.
1403
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1404
      kvm_cmd.extend(["-k", keymap_path])
1405

    
1406
    # We have reasons to believe changing something like the nic driver/type
1407
    # upon migration won't exactly fly with the instance kernel, so for nic
1408
    # related parameters we'll use up_hvp
1409
    tapfds = []
1410
    taps = []
1411
    if not kvm_nics:
1412
      kvm_cmd.extend(["-net", "none"])
1413
    else:
1414
      vnet_hdr = False
1415
      tap_extra = ""
1416
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1417
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1418
        # From version 0.12.0, kvm uses a new sintax for network configuration.
1419
        if (v_major, v_min) >= (0, 12):
1420
          nic_model = "virtio-net-pci"
1421
          vnet_hdr = True
1422
        else:
1423
          nic_model = "virtio"
1424

    
1425
        if up_hvp[constants.HV_VHOST_NET]:
1426
          # vhost_net is only available from version 0.13.0 or newer
1427
          if (v_major, v_min) >= (0, 13):
1428
            tap_extra = ",vhost=on"
1429
          else:
1430
            raise errors.HypervisorError("vhost_net is configured"
1431
                                         " but it is not available")
1432
      else:
1433
        nic_model = nic_type
1434

    
1435
      for nic_seq, nic in enumerate(kvm_nics):
1436
        tapname, tapfd = _OpenTap(vnet_hdr)
1437
        tapfds.append(tapfd)
1438
        taps.append(tapname)
1439
        if (v_major, v_min) >= (0, 12):
1440
          nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1441
          tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1442
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1443
        else:
1444
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1445
                                                         nic.mac, nic_model)
1446
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1447
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1448

    
1449
    if incoming:
1450
      target, port = incoming
1451
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1452

    
1453
    # Changing the vnc password doesn't bother the guest that much. At most it
1454
    # will surprise people who connect to it. Whether positively or negatively
1455
    # it's debatable.
1456
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1457
    vnc_pwd = None
1458
    if vnc_pwd_file:
1459
      try:
1460
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1461
      except EnvironmentError, err:
1462
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1463
                                     % (vnc_pwd_file, err))
1464

    
1465
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1466
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1467
                         constants.SECURE_DIR_MODE)])
1468

    
1469
    # Automatically enable QMP if version is >= 0.14
1470
    if (v_major, v_min) >= (0, 14):
1471
      logging.debug("Enabling QMP")
1472
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1473
                      self._InstanceQmpMonitor(instance.name)])
1474

    
1475
    # Configure the network now for starting instances and bridged interfaces,
1476
    # during FinalizeMigration for incoming instances' routed interfaces
1477
    for nic_seq, nic in enumerate(kvm_nics):
1478
      if (incoming and
1479
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1480
        continue
1481
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1482

    
1483
    # CPU affinity requires kvm to start paused, so we set this flag if the
1484
    # instance is not already paused and if we are not going to accept a
1485
    # migrating instance. In the latter case, pausing is not needed.
1486
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1487
    if start_kvm_paused:
1488
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1489

    
1490
    # Note: CPU pinning is using up_hvp since changes take effect
1491
    # during instance startup anyway, and to avoid problems when soft
1492
    # rebooting the instance.
1493
    cpu_pinning = False
1494
    if up_hvp.get(constants.HV_CPU_MASK, None):
1495
      cpu_pinning = True
1496

    
1497
    if security_model == constants.HT_SM_POOL:
1498
      ss = ssconf.SimpleStore()
1499
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1500
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1501
      uid = uidpool.RequestUnusedUid(all_uids)
1502
      try:
1503
        username = pwd.getpwuid(uid.GetUid()).pw_name
1504
        kvm_cmd.extend(["-runas", username])
1505
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1506
      except:
1507
        uidpool.ReleaseUid(uid)
1508
        raise
1509
      else:
1510
        uid.Unlock()
1511
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1512
    else:
1513
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1514

    
1515
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1516
                     constants.RUN_DIRS_MODE)])
1517
    for nic_seq, tap in enumerate(taps):
1518
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1519
                      data=tap)
1520

    
1521
    if vnc_pwd:
1522
      change_cmd = "change vnc password %s" % vnc_pwd
1523
      self._CallMonitorCommand(instance.name, change_cmd)
1524

    
1525
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1526
    # connection attempts because SPICE by default does not allow connections
1527
    # if neither a password nor the "disable_ticketing" options are specified.
1528
    # As soon as we send the password via QMP, that password is a valid ticket
1529
    # for connection.
1530
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1531
    if spice_password_file:
1532
      spice_pwd = ""
1533
      try:
1534
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1535
      except EnvironmentError, err:
1536
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1537
                                     % (spice_password_file, err))
1538

    
1539
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1540
      qmp.connect()
1541
      arguments = {
1542
          "protocol": "spice",
1543
          "password": spice_pwd,
1544
      }
1545
      qmp.Execute("set_password", arguments)
1546

    
1547
    for filename in temp_files:
1548
      utils.RemoveFile(filename)
1549

    
1550
    # If requested, set CPU affinity and resume instance execution
1551
    if cpu_pinning:
1552
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1553

    
1554
    start_memory = self._InstanceStartupMemory(instance)
1555
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1556
      self.BalloonInstanceMemory(instance, start_memory)
1557

    
1558
    if start_kvm_paused:
1559
      # To control CPU pinning, ballooning, and vnc/spice passwords
1560
      # the VM was started in a frozen state. If freezing was not
1561
      # explicitly requested resume the vm status.
1562
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1563

    
1564
  def StartInstance(self, instance, block_devices, startup_paused):
1565
    """Start an instance.
1566

1567
    """
1568
    self._CheckDown(instance.name)
1569
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1570
                                           startup_paused)
1571
    self._SaveKVMRuntime(instance, kvm_runtime)
1572
    self._ExecuteKVMRuntime(instance, kvm_runtime)
1573

    
1574
  def _CallMonitorCommand(self, instance_name, command):
1575
    """Invoke a command on the instance monitor.
1576

1577
    """
1578
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1579
             (utils.ShellQuote(command),
1580
              constants.SOCAT_PATH,
1581
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1582
    result = utils.RunCmd(socat)
1583
    if result.failed:
1584
      msg = ("Failed to send command '%s' to instance %s."
1585
             " output: %s, error: %s, fail_reason: %s" %
1586
             (command, instance_name,
1587
              result.stdout, result.stderr, result.fail_reason))
1588
      raise errors.HypervisorError(msg)
1589

    
1590
    return result
1591

    
1592
  @classmethod
1593
  def _ParseKVMVersion(cls, text):
1594
    """Parse the KVM version from the --help output.
1595

1596
    @type text: string
1597
    @param text: output of kvm --help
1598
    @return: (version, v_maj, v_min, v_rev)
1599
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1600

1601
    """
1602
    match = cls._VERSION_RE.search(text.splitlines()[0])
1603
    if not match:
1604
      raise errors.HypervisorError("Unable to get KVM version")
1605

    
1606
    v_all = match.group(0)
1607
    v_maj = int(match.group(1))
1608
    v_min = int(match.group(2))
1609
    if match.group(4):
1610
      v_rev = int(match.group(4))
1611
    else:
1612
      v_rev = 0
1613
    return (v_all, v_maj, v_min, v_rev)
1614

    
1615
  @classmethod
1616
  def _GetKVMVersion(cls):
1617
    """Return the installed KVM version.
1618

1619
    @return: (version, v_maj, v_min, v_rev)
1620
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1621

1622
    """
1623
    result = utils.RunCmd([constants.KVM_PATH, "--help"])
1624
    if result.failed:
1625
      raise errors.HypervisorError("Unable to get KVM version")
1626
    return cls._ParseKVMVersion(result.output)
1627

    
1628
  def StopInstance(self, instance, force=False, retry=False, name=None):
1629
    """Stop an instance.
1630

1631
    """
1632
    if name is not None and not force:
1633
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1634
    if name is None:
1635
      name = instance.name
1636
      acpi = instance.hvparams[constants.HV_ACPI]
1637
    else:
1638
      acpi = False
1639
    _, pid, alive = self._InstancePidAlive(name)
1640
    if pid > 0 and alive:
1641
      if force or not acpi:
1642
        utils.KillProcess(pid)
1643
      else:
1644
        self._CallMonitorCommand(name, "system_powerdown")
1645

    
1646
  def CleanupInstance(self, instance_name):
1647
    """Cleanup after a stopped instance
1648

1649
    """
1650
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
1651
    if pid > 0 and alive:
1652
      raise errors.HypervisorError("Cannot cleanup a live instance")
1653
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1654

    
1655
  def RebootInstance(self, instance):
1656
    """Reboot an instance.
1657

1658
    """
1659
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1660
    # socket the instance will stop, but now power up again. So we'll resort
1661
    # to shutdown and restart.
1662
    _, _, alive = self._InstancePidAlive(instance.name)
1663
    if not alive:
1664
      raise errors.HypervisorError("Failed to reboot instance %s:"
1665
                                   " not running" % instance.name)
1666
    # StopInstance will delete the saved KVM runtime so:
1667
    # ...first load it...
1668
    kvm_runtime = self._LoadKVMRuntime(instance)
1669
    # ...now we can safely call StopInstance...
1670
    if not self.StopInstance(instance):
1671
      self.StopInstance(instance, force=True)
1672
    # ...and finally we can save it again, and execute it...
1673
    self._SaveKVMRuntime(instance, kvm_runtime)
1674
    self._ExecuteKVMRuntime(instance, kvm_runtime)
1675

    
1676
  def MigrationInfo(self, instance):
1677
    """Get instance information to perform a migration.
1678

1679
    @type instance: L{objects.Instance}
1680
    @param instance: instance to be migrated
1681
    @rtype: string
1682
    @return: content of the KVM runtime file
1683

1684
    """
1685
    return self._ReadKVMRuntime(instance.name)
1686

    
1687
  def AcceptInstance(self, instance, info, target):
1688
    """Prepare to accept an instance.
1689

1690
    @type instance: L{objects.Instance}
1691
    @param instance: instance to be accepted
1692
    @type info: string
1693
    @param info: content of the KVM runtime file on the source node
1694
    @type target: string
1695
    @param target: target host (usually ip), on this node
1696

1697
    """
1698
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1699
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1700
    self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
1701

    
1702
  def FinalizeMigrationDst(self, instance, info, success):
1703
    """Finalize the instance migration on the target node.
1704

1705
    Stop the incoming mode KVM.
1706

1707
    @type instance: L{objects.Instance}
1708
    @param instance: instance whose migration is being finalized
1709

1710
    """
1711
    if success:
1712
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1713
      kvm_nics = kvm_runtime[1]
1714

    
1715
      for nic_seq, nic in enumerate(kvm_nics):
1716
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1717
          # Bridged interfaces have already been configured
1718
          continue
1719
        try:
1720
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1721
        except EnvironmentError, err:
1722
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
1723
                          instance.name, nic_seq, str(err))
1724
          continue
1725
        try:
1726
          self._ConfigureNIC(instance, nic_seq, nic, tap)
1727
        except errors.HypervisorError, err:
1728
          logging.warning(str(err))
1729

    
1730
      self._WriteKVMRuntime(instance.name, info)
1731
    else:
1732
      self.StopInstance(instance, force=True)
1733

    
1734
  def MigrateInstance(self, instance, target, live):
1735
    """Migrate an instance to a target node.
1736

1737
    The migration will not be attempted if the instance is not
1738
    currently running.
1739

1740
    @type instance: L{objects.Instance}
1741
    @param instance: the instance to be migrated
1742
    @type target: string
1743
    @param target: ip address of the target node
1744
    @type live: boolean
1745
    @param live: perform a live migration
1746

1747
    """
1748
    instance_name = instance.name
1749
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
1750
    _, _, alive = self._InstancePidAlive(instance_name)
1751
    if not alive:
1752
      raise errors.HypervisorError("Instance not running, cannot migrate")
1753

    
1754
    if not live:
1755
      self._CallMonitorCommand(instance_name, "stop")
1756

    
1757
    migrate_command = ("migrate_set_speed %dm" %
1758
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1759
    self._CallMonitorCommand(instance_name, migrate_command)
1760

    
1761
    migrate_command = ("migrate_set_downtime %dms" %
1762
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1763
    self._CallMonitorCommand(instance_name, migrate_command)
1764

    
1765
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1766
    self._CallMonitorCommand(instance_name, migrate_command)
1767

    
1768
  def FinalizeMigrationSource(self, instance, success, live):
1769
    """Finalize the instance migration on the source node.
1770

1771
    @type instance: L{objects.Instance}
1772
    @param instance: the instance that was migrated
1773
    @type success: bool
1774
    @param success: whether the migration succeeded or not
1775
    @type live: bool
1776
    @param live: whether the user requested a live migration or not
1777

1778
    """
1779
    if success:
1780
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
1781
      utils.KillProcess(pid)
1782
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1783
    elif live:
1784
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1785

    
1786
  def GetMigrationStatus(self, instance):
1787
    """Get the migration status
1788

1789
    @type instance: L{objects.Instance}
1790
    @param instance: the instance that is being migrated
1791
    @rtype: L{objects.MigrationStatus}
1792
    @return: the status of the current migration (one of
1793
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1794
             progress info that can be retrieved from the hypervisor
1795

1796
    """
1797
    info_command = "info migrate"
1798
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
1799
      result = self._CallMonitorCommand(instance.name, info_command)
1800
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
1801
      if not match:
1802
        if not result.stdout:
1803
          logging.info("KVM: empty 'info migrate' result")
1804
        else:
1805
          logging.warning("KVM: unknown 'info migrate' result: %s",
1806
                          result.stdout)
1807
      else:
1808
        status = match.group(1)
1809
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
1810
          migration_status = objects.MigrationStatus(status=status)
1811
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
1812
          if match:
1813
            migration_status.transferred_ram = match.group("transferred")
1814
            migration_status.total_ram = match.group("total")
1815

    
1816
          return migration_status
1817

    
1818
        logging.warning("KVM: unknown migration status '%s'", status)
1819

    
1820
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1821

    
1822
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
1823

    
1824
  def BalloonInstanceMemory(self, instance, mem):
1825
    """Balloon an instance memory to a certain value.
1826

1827
    @type instance: L{objects.Instance}
1828
    @param instance: instance to be accepted
1829
    @type mem: int
1830
    @param mem: actual memory size to use for instance runtime
1831

1832
    """
1833
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
1834

    
1835
  def GetNodeInfo(self):
1836
    """Return information about the node.
1837

1838
    @return: a dict with the following keys (values in MiB):
1839
          - memory_total: the total memory size on the node
1840
          - memory_free: the available memory on the node for instances
1841
          - memory_dom0: the memory used by the node itself, if available
1842
          - hv_version: the hypervisor version in the form (major, minor,
1843
                        revision)
1844

1845
    """
1846
    result = self.GetLinuxNodeInfo()
1847
    _, v_major, v_min, v_rev = self._GetKVMVersion()
1848
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
1849
    return result
1850

    
1851
  @classmethod
1852
  def GetInstanceConsole(cls, instance, hvparams, beparams):
1853
    """Return a command for connecting to the console of an instance.
1854

1855
    """
1856
    if hvparams[constants.HV_SERIAL_CONSOLE]:
1857
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
1858
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1859
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1860
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
1861
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1862
      return objects.InstanceConsole(instance=instance.name,
1863
                                     kind=constants.CONS_SSH,
1864
                                     host=instance.primary_node,
1865
                                     user=constants.SSH_CONSOLE_USER,
1866
                                     command=cmd)
1867

    
1868
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1869
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1870
      display = instance.network_port - constants.VNC_BASE_PORT
1871
      return objects.InstanceConsole(instance=instance.name,
1872
                                     kind=constants.CONS_VNC,
1873
                                     host=vnc_bind_address,
1874
                                     port=instance.network_port,
1875
                                     display=display)
1876

    
1877
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1878
    if spice_bind:
1879
      return objects.InstanceConsole(instance=instance.name,
1880
                                     kind=constants.CONS_SPICE,
1881
                                     host=spice_bind,
1882
                                     port=instance.network_port)
1883

    
1884
    return objects.InstanceConsole(instance=instance.name,
1885
                                   kind=constants.CONS_MESSAGE,
1886
                                   message=("No serial shell for instance %s" %
1887
                                            instance.name))
1888

    
1889
  def Verify(self):
1890
    """Verify the hypervisor.
1891

1892
    Check that the binary exists.
1893

1894
    """
1895
    if not os.path.exists(constants.KVM_PATH):
1896
      return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
1897
    if not os.path.exists(constants.SOCAT_PATH):
1898
      return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
1899

    
1900
  @classmethod
1901
  def CheckParameterSyntax(cls, hvparams):
1902
    """Check the given parameters for validity.
1903

1904
    @type hvparams:  dict
1905
    @param hvparams: dictionary with parameter names/value
1906
    @raise errors.HypervisorError: when a parameter is not valid
1907

1908
    """
1909
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
1910

    
1911
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
1912
    if kernel_path:
1913
      if not hvparams[constants.HV_ROOT_PATH]:
1914
        raise errors.HypervisorError("Need a root partition for the instance,"
1915
                                     " if a kernel is defined")
1916

    
1917
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
1918
        not hvparams[constants.HV_VNC_X509]):
1919
      raise errors.HypervisorError("%s must be defined, if %s is" %
1920
                                   (constants.HV_VNC_X509,
1921
                                    constants.HV_VNC_X509_VERIFY))
1922

    
1923
    boot_order = hvparams[constants.HV_BOOT_ORDER]
1924
    if (boot_order == constants.HT_BO_CDROM and
1925
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
1926
      raise errors.HypervisorError("Cannot boot from cdrom without an"
1927
                                   " ISO path")
1928

    
1929
    security_model = hvparams[constants.HV_SECURITY_MODEL]
1930
    if security_model == constants.HT_SM_USER:
1931
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
1932
        raise errors.HypervisorError("A security domain (user to run kvm as)"
1933
                                     " must be specified")
1934
    elif (security_model == constants.HT_SM_NONE or
1935
          security_model == constants.HT_SM_POOL):
1936
      if hvparams[constants.HV_SECURITY_DOMAIN]:
1937
        raise errors.HypervisorError("Cannot have a security domain when the"
1938
                                     " security model is 'none' or 'pool'")
1939

    
1940
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1941
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
1942
    if spice_bind:
1943
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1944
        # if an IP version is specified, the spice_bind parameter must be an
1945
        # IP of that family
1946
        if (netutils.IP4Address.IsValid(spice_bind) and
1947
            spice_ip_version != constants.IP4_VERSION):
1948
          raise errors.HypervisorError("spice: got an IPv4 address (%s), but"
1949
                                       " the specified IP version is %s" %
1950
                                       (spice_bind, spice_ip_version))
1951

    
1952
        if (netutils.IP6Address.IsValid(spice_bind) and
1953
            spice_ip_version != constants.IP6_VERSION):
1954
          raise errors.HypervisorError("spice: got an IPv6 address (%s), but"
1955
                                       " the specified IP version is %s" %
1956
                                       (spice_bind, spice_ip_version))
1957
    else:
1958
      # All the other SPICE parameters depend on spice_bind being set. Raise an
1959
      # error if any of them is set without it.
1960
      spice_additional_params = frozenset([
1961
        constants.HV_KVM_SPICE_IP_VERSION,
1962
        constants.HV_KVM_SPICE_PASSWORD_FILE,
1963
        constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR,
1964
        constants.HV_KVM_SPICE_JPEG_IMG_COMPR,
1965
        constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR,
1966
        constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION,
1967
        constants.HV_KVM_SPICE_USE_TLS,
1968
        ])
1969
      for param in spice_additional_params:
1970
        if hvparams[param]:
1971
          raise errors.HypervisorError("spice: %s requires %s to be set" %
1972
                                       (param, constants.HV_KVM_SPICE_BIND))
1973

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

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

1982
    """
1983
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
1984

    
1985
    security_model = hvparams[constants.HV_SECURITY_MODEL]
1986
    if security_model == constants.HT_SM_USER:
1987
      username = hvparams[constants.HV_SECURITY_DOMAIN]
1988
      try:
1989
        pwd.getpwnam(username)
1990
      except KeyError:
1991
        raise errors.HypervisorError("Unknown security domain user %s"
1992
                                     % username)
1993

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

    
2002
      # KVM version should be >= 0.14.0
2003
      _, v_major, v_min, _ = cls._GetKVMVersion()
2004
      if (v_major, v_min) < (0, 14):
2005
        raise errors.HypervisorError("spice is configured, but it is not"
2006
                                     " available in versions of KVM < 0.14")
2007

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

    
2016
  @classmethod
2017
  def PowercycleNode(cls):
2018
    """KVM powercycle, just a wrapper over Linux powercycle.
2019

2020
    """
2021
    cls.LinuxPowercycle()