Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ e6ba3320

History | View | Annotate | Download (73.4 kB)

1
#
2
#
3

    
4
# Copyright (C) 2008, 2009, 2010, 2011, 2012 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

    
21

    
22
"""KVM hypervisor
23

24
"""
25

    
26
import errno
27
import os
28
import os.path
29
import re
30
import tempfile
31
import time
32
import logging
33
import pwd
34
import struct
35
import fcntl
36
import shutil
37
import socket
38
import stat
39
import StringIO
40
try:
41
  import affinity   # pylint: disable=F0401
42
except ImportError:
43
  affinity = None
44

    
45
from ganeti import utils
46
from ganeti import constants
47
from ganeti import errors
48
from ganeti import serializer
49
from ganeti import objects
50
from ganeti import uidpool
51
from ganeti import ssconf
52
from ganeti import netutils
53
from ganeti import pathutils
54
from ganeti.hypervisor import hv_base
55
from ganeti.utils import wrapper as utils_wrapper
56

    
57

    
58
_KVM_NETWORK_SCRIPT = pathutils.CONF_DIR + "/kvm-vif-bridge"
59
_KVM_START_PAUSED_FLAG = "-S"
60

    
61
# TUN/TAP driver constants, taken from <linux/if_tun.h>
62
# They are architecture-independent and already hardcoded in qemu-kvm source,
63
# so we can safely include them here.
64
TUNSETIFF = 0x400454ca
65
TUNGETIFF = 0x800454d2
66
TUNGETFEATURES = 0x800454cf
67
IFF_TAP = 0x0002
68
IFF_NO_PI = 0x1000
69
IFF_VNET_HDR = 0x4000
70

    
71
#: SPICE parameters which depend on L{constants.HV_KVM_SPICE_BIND}
72
_SPICE_ADDITIONAL_PARAMS = frozenset([
73
  constants.HV_KVM_SPICE_IP_VERSION,
74
  constants.HV_KVM_SPICE_PASSWORD_FILE,
75
  constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR,
76
  constants.HV_KVM_SPICE_JPEG_IMG_COMPR,
77
  constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR,
78
  constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION,
79
  constants.HV_KVM_SPICE_USE_TLS,
80
  ])
81

    
82

    
83
def _ProbeTapVnetHdr(fd):
84
  """Check whether to enable the IFF_VNET_HDR flag.
85

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

96
   @type fd: int
97
   @param fd: the file descriptor of /dev/net/tun
98

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

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

    
114

    
115
def _OpenTap(vnet_hdr=True):
116
  """Open a new tap device and return its file descriptor.
117

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

121
  @type vnet_hdr: boolean
122
  @param vnet_hdr: Enable the VNET Header
123
  @return: (ifname, tapfd)
124
  @rtype: tuple
125

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

    
132
  flags = IFF_TAP | IFF_NO_PI
133

    
134
  if vnet_hdr and _ProbeTapVnetHdr(tapfd):
135
    flags |= IFF_VNET_HDR
136

    
137
  # The struct ifreq ioctl request (see netdevice(7))
138
  ifr = struct.pack("16sh", "", flags)
139

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

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

    
149

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

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

    
172
  return env
173

    
174

    
175
class QmpMessage:
176
  """QEMU Messaging Protocol (QMP) message.
177

178
  """
179
  def __init__(self, data):
180
    """Creates a new QMP message based on the passed data.
181

182
    """
183
    if not isinstance(data, dict):
184
      raise TypeError("QmpMessage must be initialized with a dict")
185

    
186
    self.data = data
187

    
188
  def __getitem__(self, field_name):
189
    """Get the value of the required field if present, or None.
190

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

196
    """
197
    return self.data.get(field_name, None)
198

    
199
  def __setitem__(self, field_name, field_value):
200
    """Set the value of the required field_name to field_value.
201

202
    """
203
    self.data[field_name] = field_value
204

    
205
  @staticmethod
206
  def BuildFromJsonString(json_string):
207
    """Build a QmpMessage from a JSON encoded string.
208

209
    @type json_string: str
210
    @param json_string: JSON string representing the message
211
    @rtype: L{QmpMessage}
212
    @return: a L{QmpMessage} built from json_string
213

214
    """
215
    # Parse the string
216
    data = serializer.LoadJson(json_string)
217
    return QmpMessage(data)
218

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

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

    
228

    
229
class QmpConnection:
230
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
231

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

    
247
  def __init__(self, monitor_filename):
248
    """Instantiates the QmpConnection object.
249

250
    @type monitor_filename: string
251
    @param monitor_filename: the filename of the UNIX raw socket on which the
252
                             QMP monitor is listening
253

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

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

    
276
  def _check_connection(self):
277
    """Make sure that the connection is established.
278

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

    
284
  def connect(self):
285
    """Connects to the QMP monitor.
286

287
    Connects to the UNIX socket and makes sure that we can actually send and
288
    receive data to the kvm instance via QMP.
289

290
    @raise errors.HypervisorError: when there are communication errors
291
    @raise errors.ProgrammerError: when there are data serialization errors
292

293
    """
294
    if self._connected:
295
      raise errors.ProgrammerError("Cannot connect twice")
296

    
297
    self._check_socket()
298

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

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

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

    
319
  def _ParseMessage(self, buf):
320
    """Extract and parse a QMP message from the given buffer.
321

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

326
    @raise errors.ProgrammerError: when there are data serialization errors
327

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

    
340
    return (message, buf)
341

    
342
  def _Recv(self):
343
    """Receives a message from QMP and decodes the received JSON object.
344

345
    @rtype: QmpMessage
346
    @return: the received message
347
    @raise errors.HypervisorError: when there are communication errors
348
    @raise errors.ProgrammerError: when there are data serialization errors
349

350
    """
351
    self._check_connection()
352

    
353
    # Check if there is already a message in the buffer
354
    (message, self._buf) = self._ParseMessage(self._buf)
355
    if message:
356
      return message
357

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

    
367
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
368
        if message:
369
          return message
370

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

    
378
  def _Send(self, message):
379
    """Encodes and sends a message to KVM using QMP.
380

381
    @type message: QmpMessage
382
    @param message: message to send to KVM
383
    @raise errors.HypervisorError: when there are communication errors
384
    @raise errors.ProgrammerError: when there are data serialization errors
385

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

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

    
402
  def Execute(self, command, arguments=None):
403
    """Executes a QMP command and returns the response of the server.
404

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

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

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

    
434
      elif not response[self._EVENT_KEY]:
435
        return response
436

    
437

    
438
class KVMHypervisor(hv_base.BaseHypervisor):
439
  """KVM hypervisor interface
440

441
  """
442
  CAN_MIGRATE = True
443

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

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

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

    
543
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
544
  _MIGRATION_INFO_RETRY_DELAY = 2
545

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
625
    return (instance, memory, vcpus)
626

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

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

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

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

    
646
    return (pidfile, pid, alive)
647

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
913
    return result
914

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1005
    pidfile = self._InstancePidFile(instance.name)
1006
    kvm = constants.KVM_PATH
1007
    kvm_cmd = [kvm]
1008
    kvm_cmd.extend(["-M", self._GetDefaultMachineVersion()])
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
  @classmethod
1661
  def _GetDefaultMachineVersion(cls):
1662
    """Return the default hardware revision (e.g. pc-1.1)
1663

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

    
1673
    return "pc"
1674

    
1675
  def CleanupInstance(self, instance_name):
1676
    """Cleanup after a stopped instance
1677

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

    
1684
  def RebootInstance(self, instance):
1685
    """Reboot an instance.
1686

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

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

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

1713
    """
1714
    return self._ReadKVMRuntime(instance.name)
1715

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

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

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

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

1734
    Stop the incoming mode KVM.
1735

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

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

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

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

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

1766
    The migration will not be attempted if the instance is not
1767
    currently running.
1768

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

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

    
1783
    if not live:
1784
      self._CallMonitorCommand(instance_name, "stop")
1785

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

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

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

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

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

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

    
1815
  def GetMigrationStatus(self, instance):
1816
    """Get the migration status
1817

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

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

    
1845
          return migration_status
1846

    
1847
        logging.warning("KVM: unknown migration status '%s'", status)
1848

    
1849
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1850

    
1851
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
1852

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

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

1861
    """
1862
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
1863

    
1864
  def GetNodeInfo(self):
1865
    """Return information about the node.
1866

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

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

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

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

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

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

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

    
1918
  def Verify(self):
1919
    """Verify the hypervisor.
1920

1921
    Check that the binary exists.
1922

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

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

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

1937
    """
1938
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
1939

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

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

    
1952
    boot_order = hvparams[constants.HV_BOOT_ORDER]
1953
    if (boot_order == constants.HT_BO_CDROM and
1954
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
1955
      raise errors.HypervisorError("Cannot boot from cdrom without an"
1956
                                   " ISO path")
1957

    
1958
    security_model = hvparams[constants.HV_SECURITY_MODEL]
1959
    if security_model == constants.HT_SM_USER:
1960
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
1961
        raise errors.HypervisorError("A security domain (user to run kvm as)"
1962
                                     " must be specified")
1963
    elif (security_model == constants.HT_SM_NONE or
1964
          security_model == constants.HT_SM_POOL):
1965
      if hvparams[constants.HV_SECURITY_DOMAIN]:
1966
        raise errors.HypervisorError("Cannot have a security domain when the"
1967
                                     " security model is 'none' or 'pool'")
1968

    
1969
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1970
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
1971
    if spice_bind:
1972
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1973
        # if an IP version is specified, the spice_bind parameter must be an
1974
        # IP of that family
1975
        if (netutils.IP4Address.IsValid(spice_bind) and
1976
            spice_ip_version != constants.IP4_VERSION):
1977
          raise errors.HypervisorError("spice: got an IPv4 address (%s), but"
1978
                                       " the specified IP version is %s" %
1979
                                       (spice_bind, spice_ip_version))
1980

    
1981
        if (netutils.IP6Address.IsValid(spice_bind) and
1982
            spice_ip_version != constants.IP6_VERSION):
1983
          raise errors.HypervisorError("spice: got an IPv6 address (%s), but"
1984
                                       " the specified IP version is %s" %
1985
                                       (spice_bind, spice_ip_version))
1986
    else:
1987
      # All the other SPICE parameters depend on spice_bind being set. Raise an
1988
      # error if any of them is set without it.
1989
      for param in _SPICE_ADDITIONAL_PARAMS:
1990
        if hvparams[param]:
1991
          raise errors.HypervisorError("spice: %s requires %s to be set" %
1992
                                       (param, constants.HV_KVM_SPICE_BIND))
1993

    
1994
  @classmethod
1995
  def ValidateParameters(cls, hvparams):
1996
    """Check the given parameters for validity.
1997

1998
    @type hvparams:  dict
1999
    @param hvparams: dictionary with parameter names/value
2000
    @raise errors.HypervisorError: when a parameter is not valid
2001

2002
    """
2003
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2004

    
2005
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2006
    if security_model == constants.HT_SM_USER:
2007
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2008
      try:
2009
        pwd.getpwnam(username)
2010
      except KeyError:
2011
        raise errors.HypervisorError("Unknown security domain user %s"
2012
                                     % username)
2013

    
2014
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2015
    if spice_bind:
2016
      # only one of VNC and SPICE can be used currently.
2017
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2018
        raise errors.HypervisorError("both SPICE and VNC are configured, but"
2019
                                     " only one of them can be used at a"
2020
                                     " given time.")
2021

    
2022
      # KVM version should be >= 0.14.0
2023
      _, v_major, v_min, _ = cls._GetKVMVersion()
2024
      if (v_major, v_min) < (0, 14):
2025
        raise errors.HypervisorError("spice is configured, but it is not"
2026
                                     " available in versions of KVM < 0.14")
2027

    
2028
      # if spice_bind is not an IP address, it must be a valid interface
2029
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind)
2030
                       or netutils.IP6Address.IsValid(spice_bind))
2031
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2032
        raise errors.HypervisorError("spice: the %s parameter must be either"
2033
                                     " a valid IP address or interface name" %
2034
                                     constants.HV_KVM_SPICE_BIND)
2035

    
2036
  @classmethod
2037
  def PowercycleNode(cls):
2038
    """KVM powercycle, just a wrapper over Linux powercycle.
2039

2040
    """
2041
    cls.LinuxPowercycle()