Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ a5ad5e58

History | View | Annotate | Download (72 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
class QmpMessage:
140
  """QEMU Messaging Protocol (QMP) message.
141

142
  """
143
  def __init__(self, data):
144
    """Creates a new QMP message based on the passed data.
145

146
    """
147
    if not isinstance(data, dict):
148
      raise TypeError("QmpMessage must be initialized with a dict")
149

    
150
    self.data = data
151

    
152
  def __getitem__(self, field_name):
153
    """Get the value of the required field if present, or None.
154

155
    Overrides the [] operator to provide access to the message data,
156
    returning None if the required item is not in the message
157
    @return: the value of the field_name field, or None if field_name
158
             is not contained in the message
159

160
    """
161
    return self.data.get(field_name, None)
162

    
163
  def __setitem__(self, field_name, field_value):
164
    """Set the value of the required field_name to field_value.
165

166
    """
167
    self.data[field_name] = field_value
168

    
169
  @staticmethod
170
  def BuildFromJsonString(json_string):
171
    """Build a QmpMessage from a JSON encoded string.
172

173
    @type json_string: str
174
    @param json_string: JSON string representing the message
175
    @rtype: L{QmpMessage}
176
    @return: a L{QmpMessage} built from json_string
177

178
    """
179
    # Parse the string
180
    data = serializer.LoadJson(json_string)
181
    return QmpMessage(data)
182

    
183
  def __str__(self):
184
    # The protocol expects the JSON object to be sent as a single line.
185
    return serializer.DumpJson(self.data)
186

    
187
  def __eq__(self, other):
188
    # When comparing two QmpMessages, we are interested in comparing
189
    # their internal representation of the message data
190
    return self.data == other.data
191

    
192

    
193
class QmpConnection:
194
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
195

196
  """
197
  _FIRST_MESSAGE_KEY = "QMP"
198
  _EVENT_KEY = "event"
199
  _ERROR_KEY = "error"
200
  _RETURN_KEY = RETURN_KEY = "return"
201
  _ACTUAL_KEY = ACTUAL_KEY = "actual"
202
  _ERROR_CLASS_KEY = "class"
203
  _ERROR_DATA_KEY = "data"
204
  _ERROR_DESC_KEY = "desc"
205
  _EXECUTE_KEY = "execute"
206
  _ARGUMENTS_KEY = "arguments"
207
  _CAPABILITIES_COMMAND = "qmp_capabilities"
208
  _MESSAGE_END_TOKEN = "\r\n"
209
  _SOCKET_TIMEOUT = 5
210

    
211
  def __init__(self, monitor_filename):
212
    """Instantiates the QmpConnection object.
213

214
    @type monitor_filename: string
215
    @param monitor_filename: the filename of the UNIX raw socket on which the
216
                             QMP monitor is listening
217

218
    """
219
    self.monitor_filename = monitor_filename
220
    self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
221
    # We want to fail if the server doesn't send a complete message
222
    # in a reasonable amount of time
223
    self.sock.settimeout(self._SOCKET_TIMEOUT)
224
    self._connected = False
225
    self._buf = ""
226

    
227
  def _check_socket(self):
228
    sock_stat = None
229
    try:
230
      sock_stat = os.stat(self.monitor_filename)
231
    except EnvironmentError, err:
232
      if err.errno == errno.ENOENT:
233
        raise errors.HypervisorError("No qmp socket found")
234
      else:
235
        raise errors.HypervisorError("Error checking qmp socket: %s",
236
                                     utils.ErrnoOrStr(err))
237
    if not stat.S_ISSOCK(sock_stat.st_mode):
238
      raise errors.HypervisorError("Qmp socket is not a socket")
239

    
240
  def _check_connection(self):
241
    """Make sure that the connection is established.
242

243
    """
244
    if not self._connected:
245
      raise errors.ProgrammerError("To use a QmpConnection you need to first"
246
                                   " invoke connect() on it")
247

    
248
  def connect(self):
249
    """Connects to the QMP monitor.
250

251
    Connects to the UNIX socket and makes sure that we can actually send and
252
    receive data to the kvm instance via QMP.
253

254
    @raise errors.HypervisorError: when there are communication errors
255
    @raise errors.ProgrammerError: when there are data serialization errors
256

257
    """
258
    if self._connected:
259
      raise errors.ProgrammerError("Cannot connect twice")
260

    
261
    self._check_socket()
262

    
263
    # Check file existance/stuff
264
    try:
265
      self.sock.connect(self.monitor_filename)
266
    except EnvironmentError:
267
      raise errors.HypervisorError("Can't connect to qmp socket")
268
    self._connected = True
269

    
270
    # Check if we receive a correct greeting message from the server
271
    # (As per the QEMU Protocol Specification 0.1 - section 2.2)
272
    greeting = self._Recv()
273
    if not greeting[self._FIRST_MESSAGE_KEY]:
274
      self._connected = False
275
      raise errors.HypervisorError("kvm: qmp communication error (wrong"
276
                                   " server greeting")
277

    
278
    # Let's put the monitor in command mode using the qmp_capabilities
279
    # command, or else no command will be executable.
280
    # (As per the QEMU Protocol Specification 0.1 - section 4)
281
    self.Execute(self._CAPABILITIES_COMMAND)
282

    
283
  def _ParseMessage(self, buf):
284
    """Extract and parse a QMP message from the given buffer.
285

286
    Seeks for a QMP message in the given buf. If found, it parses it and
287
    returns it together with the rest of the characters in the buf.
288
    If no message is found, returns None and the whole buffer.
289

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

292
    """
293
    message = None
294
    # Check if we got the message end token (CRLF, as per the QEMU Protocol
295
    # Specification 0.1 - Section 2.1.1)
296
    pos = buf.find(self._MESSAGE_END_TOKEN)
297
    if pos >= 0:
298
      try:
299
        message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
300
      except Exception, err:
301
        raise errors.ProgrammerError("QMP data serialization error: %s" % err)
302
      buf = buf[pos + 1:]
303

    
304
    return (message, buf)
305

    
306
  def _Recv(self):
307
    """Receives a message from QMP and decodes the received JSON object.
308

309
    @rtype: QmpMessage
310
    @return: the received message
311
    @raise errors.HypervisorError: when there are communication errors
312
    @raise errors.ProgrammerError: when there are data serialization errors
313

314
    """
315
    self._check_connection()
316

    
317
    # Check if there is already a message in the buffer
318
    (message, self._buf) = self._ParseMessage(self._buf)
319
    if message:
320
      return message
321

    
322
    recv_buffer = StringIO.StringIO(self._buf)
323
    recv_buffer.seek(len(self._buf))
324
    try:
325
      while True:
326
        data = self.sock.recv(4096)
327
        if not data:
328
          break
329
        recv_buffer.write(data)
330

    
331
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
332
        if message:
333
          return message
334

    
335
    except socket.timeout, err:
336
      raise errors.HypervisorError("Timeout while receiving a QMP message: "
337
                                   "%s" % (err))
338
    except socket.error, err:
339
      raise errors.HypervisorError("Unable to receive data from KVM using the"
340
                                   " QMP protocol: %s" % err)
341

    
342
  def _Send(self, message):
343
    """Encodes and sends a message to KVM using QMP.
344

345
    @type message: QmpMessage
346
    @param message: message to send to KVM
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
    try:
353
      message_str = str(message)
354
    except Exception, err:
355
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
356

    
357
    try:
358
      self.sock.sendall(message_str)
359
    except socket.timeout, err:
360
      raise errors.HypervisorError("Timeout while sending a QMP message: "
361
                                   "%s (%s)" % (err.string, err.errno))
362
    except socket.error, err:
363
      raise errors.HypervisorError("Unable to send data from KVM using the"
364
                                   " QMP protocol: %s" % err)
365

    
366
  def Execute(self, command, arguments=None):
367
    """Executes a QMP command and returns the response of the server.
368

369
    @type command: str
370
    @param command: the command to execute
371
    @type arguments: dict
372
    @param arguments: dictionary of arguments to be passed to the command
373
    @rtype: dict
374
    @return: dictionary representing the received JSON object
375
    @raise errors.HypervisorError: when there are communication errors
376
    @raise errors.ProgrammerError: when there are data serialization errors
377

378
    """
379
    self._check_connection()
380
    message = QmpMessage({self._EXECUTE_KEY: command})
381
    if arguments:
382
      message[self._ARGUMENTS_KEY] = arguments
383
    self._Send(message)
384

    
385
    # Events can occur between the sending of the command and the reception
386
    # of the response, so we need to filter out messages with the event key.
387
    while True:
388
      response = self._Recv()
389
      err = response[self._ERROR_KEY]
390
      if err:
391
        raise errors.HypervisorError("kvm: error executing the %s"
392
                                     " command: %s (%s, %s):" %
393
                                     (command,
394
                                      err[self._ERROR_DESC_KEY],
395
                                      err[self._ERROR_CLASS_KEY],
396
                                      err[self._ERROR_DATA_KEY]))
397

    
398
      elif not response[self._EVENT_KEY]:
399
        return response
400

    
401

    
402
class KVMHypervisor(hv_base.BaseHypervisor):
403
  """KVM hypervisor interface
404

405
  """
406
  CAN_MIGRATE = True
407

    
408
  _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
409
  _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
410
  _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
411
  _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
412
  _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
413
  _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
414
  _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
415
  # KVM instances with chroot enabled are started in empty chroot directories.
416
  _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
417
  # After an instance is stopped, its chroot directory is removed.
418
  # If the chroot directory is not empty, it can't be removed.
419
  # A non-empty chroot directory indicates a possible security incident.
420
  # To support forensics, the non-empty chroot directory is quarantined in
421
  # a separate directory, called 'chroot-quarantine'.
422
  _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
423
  _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
424
           _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
425

    
426
  PARAMETERS = {
427
    constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
428
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
429
    constants.HV_ROOT_PATH: hv_base.NO_CHECK,
430
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
431
    constants.HV_ACPI: hv_base.NO_CHECK,
432
    constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
433
    constants.HV_VNC_BIND_ADDRESS:
434
      (False, lambda x: (netutils.IP4Address.IsValid(x) or
435
                         utils.IsNormAbsPath(x)),
436
       "the VNC bind address must be either a valid IP address or an absolute"
437
       " pathname", None, None),
438
    constants.HV_VNC_TLS: hv_base.NO_CHECK,
439
    constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
440
    constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
441
    constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
442
    constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
443
    constants.HV_KVM_SPICE_IP_VERSION:
444
      (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
445
                         x in constants.VALID_IP_VERSIONS),
446
       "the SPICE IP version should be 4 or 6",
447
       None, None),
448
    constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
449
    constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
450
      hv_base.ParamInSet(
451
        False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
452
    constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
453
      hv_base.ParamInSet(
454
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
455
    constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
456
      hv_base.ParamInSet(
457
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
458
    constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
459
      hv_base.ParamInSet(
460
        False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
461
    constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
462
    constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
463
    constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
464
    constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
465
    constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
466
    constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
467
    constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
468
    constants.HV_BOOT_ORDER:
469
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
470
    constants.HV_NIC_TYPE:
471
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
472
    constants.HV_DISK_TYPE:
473
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
474
    constants.HV_KVM_CDROM_DISK_TYPE:
475
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
476
    constants.HV_USB_MOUSE:
477
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
478
    constants.HV_KEYMAP: hv_base.NO_CHECK,
479
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
480
    constants.HV_MIGRATION_BANDWIDTH: hv_base.NO_CHECK,
481
    constants.HV_MIGRATION_DOWNTIME: hv_base.NO_CHECK,
482
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
483
    constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
484
    constants.HV_DISK_CACHE:
485
      hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
486
    constants.HV_SECURITY_MODEL:
487
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
488
    constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
489
    constants.HV_KVM_FLAG:
490
      hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
491
    constants.HV_VHOST_NET: hv_base.NO_CHECK,
492
    constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
493
    constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
494
    constants.HV_REBOOT_BEHAVIOR:
495
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
496
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
497
    constants.HV_CPU_TYPE: hv_base.NO_CHECK
498
    }
499

    
500
  _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
501
                                    re.M | re.I)
502
  _MIGRATION_PROGRESS_RE = \
503
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
504
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
505
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
506

    
507
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
508
  _MIGRATION_INFO_RETRY_DELAY = 2
509

    
510
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
511

    
512
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
513
  _CPU_INFO_CMD = "info cpus"
514
  _CONT_CMD = "cont"
515

    
516
  ANCILLARY_FILES = [
517
    _KVM_NETWORK_SCRIPT,
518
    ]
519
  ANCILLARY_FILES_OPT = [
520
    _KVM_NETWORK_SCRIPT,
521
    ]
522

    
523
  def __init__(self):
524
    hv_base.BaseHypervisor.__init__(self)
525
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
526
    # in a tmpfs filesystem or has been otherwise wiped out.
527
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
528
    utils.EnsureDirs(dirs)
529

    
530
  @classmethod
531
  def _InstancePidFile(cls, instance_name):
532
    """Returns the instance pidfile.
533

534
    """
535
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
536

    
537
  @classmethod
538
  def _InstanceUidFile(cls, instance_name):
539
    """Returns the instance uidfile.
540

541
    """
542
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
543

    
544
  @classmethod
545
  def _InstancePidInfo(cls, pid):
546
    """Check pid file for instance information.
547

548
    Check that a pid file is associated with an instance, and retrieve
549
    information from its command line.
550

551
    @type pid: string or int
552
    @param pid: process id of the instance to check
553
    @rtype: tuple
554
    @return: (instance_name, memory, vcpus)
555
    @raise errors.HypervisorError: when an instance cannot be found
556

557
    """
558
    alive = utils.IsProcessAlive(pid)
559
    if not alive:
560
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
561

    
562
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
563
    try:
564
      cmdline = utils.ReadFile(cmdline_file)
565
    except EnvironmentError, err:
566
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
567
                                   (pid, err))
568

    
569
    instance = None
570
    memory = 0
571
    vcpus = 0
572

    
573
    arg_list = cmdline.split("\x00")
574
    while arg_list:
575
      arg = arg_list.pop(0)
576
      if arg == "-name":
577
        instance = arg_list.pop(0)
578
      elif arg == "-m":
579
        memory = int(arg_list.pop(0))
580
      elif arg == "-smp":
581
        vcpus = int(arg_list.pop(0))
582

    
583
    if instance is None:
584
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
585
                                   " instance" % pid)
586

    
587
    return (instance, memory, vcpus)
588

    
589
  def _InstancePidAlive(self, instance_name):
590
    """Returns the instance pidfile, pid, and liveness.
591

592
    @type instance_name: string
593
    @param instance_name: instance name
594
    @rtype: tuple
595
    @return: (pid file name, pid, liveness)
596

597
    """
598
    pidfile = self._InstancePidFile(instance_name)
599
    pid = utils.ReadPidFile(pidfile)
600

    
601
    alive = False
602
    try:
603
      cmd_instance = self._InstancePidInfo(pid)[0]
604
      alive = (cmd_instance == instance_name)
605
    except errors.HypervisorError:
606
      pass
607

    
608
    return (pidfile, pid, alive)
609

    
610
  def _CheckDown(self, instance_name):
611
    """Raises an error unless the given instance is down.
612

613
    """
614
    alive = self._InstancePidAlive(instance_name)[2]
615
    if alive:
616
      raise errors.HypervisorError("Failed to start instance %s: %s" %
617
                                   (instance_name, "already running"))
618

    
619
  @classmethod
620
  def _InstanceMonitor(cls, instance_name):
621
    """Returns the instance monitor socket name
622

623
    """
624
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
625

    
626
  @classmethod
627
  def _InstanceSerial(cls, instance_name):
628
    """Returns the instance serial socket name
629

630
    """
631
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
632

    
633
  @classmethod
634
  def _InstanceQmpMonitor(cls, instance_name):
635
    """Returns the instance serial QMP socket name
636

637
    """
638
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
639

    
640
  @staticmethod
641
  def _SocatUnixConsoleParams():
642
    """Returns the correct parameters for socat
643

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

646
    """
647
    if constants.SOCAT_USE_ESCAPE:
648
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
649
    else:
650
      return "echo=0,icanon=0"
651

    
652
  @classmethod
653
  def _InstanceKVMRuntime(cls, instance_name):
654
    """Returns the instance KVM runtime filename
655

656
    """
657
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
658

    
659
  @classmethod
660
  def _InstanceChrootDir(cls, instance_name):
661
    """Returns the name of the KVM chroot dir of the instance
662

663
    """
664
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
665

    
666
  @classmethod
667
  def _InstanceNICDir(cls, instance_name):
668
    """Returns the name of the directory holding the tap device files for a
669
    given instance.
670

671
    """
672
    return utils.PathJoin(cls._NICS_DIR, instance_name)
673

    
674
  @classmethod
675
  def _InstanceNICFile(cls, instance_name, seq):
676
    """Returns the name of the file containing the tap device for a given NIC
677

678
    """
679
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
680

    
681
  @classmethod
682
  def _InstanceKeymapFile(cls, instance_name):
683
    """Returns the name of the file containing the keymap for a given instance
684

685
    """
686
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
687

    
688
  @classmethod
689
  def _TryReadUidFile(cls, uid_file):
690
    """Try to read a uid file
691

692
    """
693
    if os.path.exists(uid_file):
694
      try:
695
        uid = int(utils.ReadOneLineFile(uid_file))
696
        return uid
697
      except EnvironmentError:
698
        logging.warning("Can't read uid file", exc_info=True)
699
      except (TypeError, ValueError):
700
        logging.warning("Can't parse uid file contents", exc_info=True)
701
    return None
702

    
703
  @classmethod
704
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
705
    """Removes an instance's rutime sockets/files/dirs.
706

707
    """
708
    utils.RemoveFile(pidfile)
709
    utils.RemoveFile(cls._InstanceMonitor(instance_name))
710
    utils.RemoveFile(cls._InstanceSerial(instance_name))
711
    utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
712
    utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
713
    utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
714
    uid_file = cls._InstanceUidFile(instance_name)
715
    uid = cls._TryReadUidFile(uid_file)
716
    utils.RemoveFile(uid_file)
717
    if uid is not None:
718
      uidpool.ReleaseUid(uid)
719
    try:
720
      shutil.rmtree(cls._InstanceNICDir(instance_name))
721
    except OSError, err:
722
      if err.errno != errno.ENOENT:
723
        raise
724
    try:
725
      chroot_dir = cls._InstanceChrootDir(instance_name)
726
      utils.RemoveDir(chroot_dir)
727
    except OSError, err:
728
      if err.errno == errno.ENOTEMPTY:
729
        # The chroot directory is expected to be empty, but it isn't.
730
        new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
731
                                          prefix="%s-%s-" %
732
                                          (instance_name,
733
                                           utils.TimestampForFilename()))
734
        logging.warning("The chroot directory of instance %s can not be"
735
                        " removed as it is not empty. Moving it to the"
736
                        " quarantine instead. Please investigate the"
737
                        " contents (%s) and clean up manually",
738
                        instance_name, new_chroot_dir)
739
        utils.RenameFile(chroot_dir, new_chroot_dir)
740
      else:
741
        raise
742

    
743
  @staticmethod
744
  def _ConfigureNIC(instance, seq, nic, tap):
745
    """Run the network configuration script for a specified NIC
746

747
    @param instance: instance we're acting on
748
    @type instance: instance object
749
    @param seq: nic sequence number
750
    @type seq: int
751
    @param nic: nic we're acting on
752
    @type nic: nic object
753
    @param tap: the host's tap interface this NIC corresponds to
754
    @type tap: str
755

756
    """
757
    if instance.tags:
758
      tags = " ".join(instance.tags)
759
    else:
760
      tags = ""
761

    
762
    env = {
763
      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
764
      "INSTANCE": instance.name,
765
      "MAC": nic.mac,
766
      "MODE": nic.nicparams[constants.NIC_MODE],
767
      "INTERFACE": tap,
768
      "INTERFACE_INDEX": str(seq),
769
      "TAGS": tags,
770
    }
771

    
772
    if nic.ip:
773
      env["IP"] = nic.ip
774

    
775
    if nic.nicparams[constants.NIC_LINK]:
776
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
777

    
778
    if nic.network:
779
      env["NETWORK"] = nic.network
780

    
781
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
782
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
783

    
784
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
785
    if result.failed:
786
      raise errors.HypervisorError("Failed to configure interface %s: %s."
787
                                   " Network configuration script output: %s" %
788
                                   (tap, result.fail_reason, result.output))
789

    
790
  @staticmethod
791
  def _VerifyAffinityPackage():
792
    if affinity is None:
793
      raise errors.HypervisorError("affinity Python package not"
794
                                   " found; cannot use CPU pinning under KVM")
795

    
796
  @staticmethod
797
  def _BuildAffinityCpuMask(cpu_list):
798
    """Create a CPU mask suitable for sched_setaffinity from a list of
799
    CPUs.
800

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

804
    @type cpu_list: list of int
805
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
806
    @rtype: int
807
    @return: a bit mask of CPU affinities
808

809
    """
810
    if cpu_list == constants.CPU_PINNING_OFF:
811
      return constants.CPU_PINNING_ALL_KVM
812
    else:
813
      return sum(2 ** cpu for cpu in cpu_list)
814

    
815
  @classmethod
816
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
817
    """Change CPU affinity for running VM according to given CPU mask.
818

819
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
820
    @type cpu_mask: string
821
    @param process_id: process ID of KVM process. Used to pin entire VM
822
                       to physical CPUs.
823
    @type process_id: int
824
    @param thread_dict: map of virtual CPUs to KVM thread IDs
825
    @type thread_dict: dict int:int
826

827
    """
828
    # Convert the string CPU mask to a list of list of int's
829
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
830

    
831
    if len(cpu_list) == 1:
832
      all_cpu_mapping = cpu_list[0]
833
      if all_cpu_mapping == constants.CPU_PINNING_OFF:
834
        # If CPU pinning has 1 entry that's "all", then do nothing
835
        pass
836
      else:
837
        # If CPU pinning has one non-all entry, map the entire VM to
838
        # one set of physical CPUs
839
        cls._VerifyAffinityPackage()
840
        affinity.set_process_affinity_mask(
841
          process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
842
    else:
843
      # The number of vCPUs mapped should match the number of vCPUs
844
      # reported by KVM. This was already verified earlier, so
845
      # here only as a sanity check.
846
      assert len(thread_dict) == len(cpu_list)
847
      cls._VerifyAffinityPackage()
848

    
849
      # For each vCPU, map it to the proper list of physical CPUs
850
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
851
        affinity.set_process_affinity_mask(thread_dict[i],
852
                                           cls._BuildAffinityCpuMask(vcpu))
853

    
854
  def _GetVcpuThreadIds(self, instance_name):
855
    """Get a mapping of vCPU no. to thread IDs for the instance
856

857
    @type instance_name: string
858
    @param instance_name: instance in question
859
    @rtype: dictionary of int:int
860
    @return: a dictionary mapping vCPU numbers to thread IDs
861

862
    """
863
    result = {}
864
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
865
    for line in output.stdout.splitlines():
866
      match = self._CPU_INFO_RE.search(line)
867
      if not match:
868
        continue
869
      grp = map(int, match.groups())
870
      result[grp[0]] = grp[1]
871

    
872
    return result
873

    
874
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
875
    """Complete CPU pinning.
876

877
    @type instance_name: string
878
    @param instance_name: name of instance
879
    @type cpu_mask: string
880
    @param cpu_mask: CPU pinning mask as entered by user
881

882
    """
883
    # Get KVM process ID, to be used if need to pin entire VM
884
    _, pid, _ = self._InstancePidAlive(instance_name)
885
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
886
    thread_dict = self._GetVcpuThreadIds(instance_name)
887
    # Run CPU pinning, based on configured mask
888
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
889

    
890
  def ListInstances(self):
891
    """Get the list of running instances.
892

893
    We can do this by listing our live instances directory and
894
    checking whether the associated kvm process is still alive.
895

896
    """
897
    result = []
898
    for name in os.listdir(self._PIDS_DIR):
899
      if self._InstancePidAlive(name)[2]:
900
        result.append(name)
901
    return result
902

    
903
  def GetInstanceInfo(self, instance_name):
904
    """Get instance properties.
905

906
    @type instance_name: string
907
    @param instance_name: the instance name
908
    @rtype: tuple of strings
909
    @return: (name, id, memory, vcpus, stat, times)
910

911
    """
912
    _, pid, alive = self._InstancePidAlive(instance_name)
913
    if not alive:
914
      return None
915

    
916
    _, memory, vcpus = self._InstancePidInfo(pid)
917
    istat = "---b-"
918
    times = "0"
919

    
920
    try:
921
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
922
      qmp.connect()
923
      vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
924
      # Will fail if ballooning is not enabled, but we can then just resort to
925
      # the value above.
926
      mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
927
      memory = mem_bytes / 1048576
928
    except errors.HypervisorError:
929
      pass
930

    
931
    return (instance_name, pid, memory, vcpus, istat, times)
932

    
933
  def GetAllInstancesInfo(self):
934
    """Get properties of all instances.
935

936
    @return: list of tuples (name, id, memory, vcpus, stat, times)
937

938
    """
939
    data = []
940
    for name in os.listdir(self._PIDS_DIR):
941
      try:
942
        info = self.GetInstanceInfo(name)
943
      except errors.HypervisorError:
944
        # Ignore exceptions due to instances being shut down
945
        continue
946
      if info:
947
        data.append(info)
948
    return data
949

    
950
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused):
951
    """Generate KVM information to start an instance.
952

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

960
    """
961
    # pylint: disable=R0914,R0915
962
    _, v_major, v_min, _ = self._GetKVMVersion()
963

    
964
    pidfile = self._InstancePidFile(instance.name)
965
    kvm = constants.KVM_PATH
966
    kvm_cmd = [kvm]
967
    # used just by the vnc server, if enabled
968
    kvm_cmd.extend(["-name", instance.name])
969
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
970
    kvm_cmd.extend(["-smp", instance.beparams[constants.BE_VCPUS]])
971
    kvm_cmd.extend(["-pidfile", pidfile])
972
    kvm_cmd.extend(["-balloon", "virtio"])
973
    kvm_cmd.extend(["-daemonize"])
974
    if not instance.hvparams[constants.HV_ACPI]:
975
      kvm_cmd.extend(["-no-acpi"])
976
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
977
        constants.INSTANCE_REBOOT_EXIT:
978
      kvm_cmd.extend(["-no-reboot"])
979

    
980
    hvp = instance.hvparams
981
    kernel_path = hvp[constants.HV_KERNEL_PATH]
982
    if kernel_path:
983
      boot_disk = boot_cdrom = boot_floppy = boot_network = False
984
    else:
985
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
986
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
987
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
988
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
989

    
990
    self.ValidateParameters(hvp)
991

    
992
    if startup_paused:
993
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
994

    
995
    if hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED:
996
      kvm_cmd.extend(["-enable-kvm"])
997
    elif hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED:
998
      kvm_cmd.extend(["-disable-kvm"])
999

    
1000
    if boot_network:
1001
      kvm_cmd.extend(["-boot", "n"])
1002

    
1003
    # whether this is an older KVM version that uses the boot=on flag
1004
    # on devices
1005
    needs_boot_flag = (v_major, v_min) < (0, 14)
1006

    
1007
    disk_type = hvp[constants.HV_DISK_TYPE]
1008
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
1009
      if_val = ",if=virtio"
1010
    else:
1011
      if_val = ",if=%s" % disk_type
1012
    # Cache mode
1013
    disk_cache = hvp[constants.HV_DISK_CACHE]
1014
    if instance.disk_template in constants.DTS_EXT_MIRROR:
1015
      if disk_cache != "none":
1016
        # TODO: make this a hard error, instead of a silent overwrite
1017
        logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1018
                        " to prevent shared storage corruption on migration",
1019
                        disk_cache)
1020
      cache_val = ",cache=none"
1021
    elif disk_cache != constants.HT_CACHE_DEFAULT:
1022
      cache_val = ",cache=%s" % disk_cache
1023
    else:
1024
      cache_val = ""
1025
    for cfdev, dev_path in block_devices:
1026
      if cfdev.mode != constants.DISK_RDWR:
1027
        raise errors.HypervisorError("Instance has read-only disks which"
1028
                                     " are not supported by KVM")
1029
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
1030
      boot_val = ""
1031
      if boot_disk:
1032
        kvm_cmd.extend(["-boot", "c"])
1033
        boot_disk = False
1034
        if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1035
          boot_val = ",boot=on"
1036

    
1037
      drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
1038
                                                cache_val)
1039
      kvm_cmd.extend(["-drive", drive_val])
1040

    
1041
    #Now we can specify a different device type for CDROM devices.
1042
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1043
    if not cdrom_disk_type:
1044
      cdrom_disk_type = disk_type
1045

    
1046
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1047
    if iso_image:
1048
      options = ",format=raw,media=cdrom"
1049
      # set cdrom 'if' type
1050
      if boot_cdrom:
1051
        actual_cdrom_type = constants.HT_DISK_IDE
1052
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1053
        actual_cdrom_type = "virtio"
1054
      else:
1055
        actual_cdrom_type = cdrom_disk_type
1056
      if_val = ",if=%s" % actual_cdrom_type
1057
      # set boot flag, if needed
1058
      boot_val = ""
1059
      if boot_cdrom:
1060
        kvm_cmd.extend(["-boot", "d"])
1061
        if needs_boot_flag:
1062
          boot_val = ",boot=on"
1063
      # and finally build the entire '-drive' value
1064
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1065
      kvm_cmd.extend(["-drive", drive_val])
1066

    
1067
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1068
    if iso_image2:
1069
      options = ",format=raw,media=cdrom"
1070
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1071
        if_val = ",if=virtio"
1072
      else:
1073
        if_val = ",if=%s" % cdrom_disk_type
1074
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1075
      kvm_cmd.extend(["-drive", drive_val])
1076

    
1077
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1078
    if floppy_image:
1079
      options = ",format=raw,media=disk"
1080
      if boot_floppy:
1081
        kvm_cmd.extend(["-boot", "a"])
1082
        options = "%s,boot=on" % options
1083
      if_val = ",if=floppy"
1084
      options = "%s%s" % (options, if_val)
1085
      drive_val = "file=%s%s" % (floppy_image, options)
1086
      kvm_cmd.extend(["-drive", drive_val])
1087

    
1088
    if kernel_path:
1089
      kvm_cmd.extend(["-kernel", kernel_path])
1090
      initrd_path = hvp[constants.HV_INITRD_PATH]
1091
      if initrd_path:
1092
        kvm_cmd.extend(["-initrd", initrd_path])
1093
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1094
                     hvp[constants.HV_KERNEL_ARGS]]
1095
      if hvp[constants.HV_SERIAL_CONSOLE]:
1096
        root_append.append("console=ttyS0,38400")
1097
      kvm_cmd.extend(["-append", " ".join(root_append)])
1098

    
1099
    mem_path = hvp[constants.HV_MEM_PATH]
1100
    if mem_path:
1101
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1102

    
1103
    monitor_dev = ("unix:%s,server,nowait" %
1104
                   self._InstanceMonitor(instance.name))
1105
    kvm_cmd.extend(["-monitor", monitor_dev])
1106
    if hvp[constants.HV_SERIAL_CONSOLE]:
1107
      serial_dev = ("unix:%s,server,nowait" %
1108
                    self._InstanceSerial(instance.name))
1109
      kvm_cmd.extend(["-serial", serial_dev])
1110
    else:
1111
      kvm_cmd.extend(["-serial", "none"])
1112

    
1113
    mouse_type = hvp[constants.HV_USB_MOUSE]
1114
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1115
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1116
    spice_ip_version = None
1117

    
1118
    if mouse_type:
1119
      kvm_cmd.extend(["-usb"])
1120
      kvm_cmd.extend(["-usbdevice", mouse_type])
1121
    elif vnc_bind_address:
1122
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1123

    
1124
    if vnc_bind_address:
1125
      if netutils.IP4Address.IsValid(vnc_bind_address):
1126
        if instance.network_port > constants.VNC_BASE_PORT:
1127
          display = instance.network_port - constants.VNC_BASE_PORT
1128
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1129
            vnc_arg = ":%d" % (display)
1130
          else:
1131
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1132
        else:
1133
          logging.error("Network port is not a valid VNC display (%d < %d)."
1134
                        " Not starting VNC", instance.network_port,
1135
                        constants.VNC_BASE_PORT)
1136
          vnc_arg = "none"
1137

    
1138
        # Only allow tls and other option when not binding to a file, for now.
1139
        # kvm/qemu gets confused otherwise about the filename to use.
1140
        vnc_append = ""
1141
        if hvp[constants.HV_VNC_TLS]:
1142
          vnc_append = "%s,tls" % vnc_append
1143
          if hvp[constants.HV_VNC_X509_VERIFY]:
1144
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1145
                                               hvp[constants.HV_VNC_X509])
1146
          elif hvp[constants.HV_VNC_X509]:
1147
            vnc_append = "%s,x509=%s" % (vnc_append,
1148
                                         hvp[constants.HV_VNC_X509])
1149
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1150
          vnc_append = "%s,password" % vnc_append
1151

    
1152
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1153

    
1154
      else:
1155
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1156

    
1157
      kvm_cmd.extend(["-vnc", vnc_arg])
1158
    elif spice_bind:
1159
      # FIXME: this is wrong here; the iface ip address differs
1160
      # between systems, so it should be done in _ExecuteKVMRuntime
1161
      if netutils.IsValidInterface(spice_bind):
1162
        # The user specified a network interface, we have to figure out the IP
1163
        # address.
1164
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1165
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1166

    
1167
        # if the user specified an IP version and the interface does not
1168
        # have that kind of IP addresses, throw an exception
1169
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1170
          if not addresses[spice_ip_version]:
1171
            raise errors.HypervisorError("spice: unable to get an IPv%s address"
1172
                                         " for %s" % (spice_ip_version,
1173
                                                      spice_bind))
1174

    
1175
        # the user did not specify an IP version, we have to figure it out
1176
        elif (addresses[constants.IP4_VERSION] and
1177
              addresses[constants.IP6_VERSION]):
1178
          # we have both ipv4 and ipv6, let's use the cluster default IP
1179
          # version
1180
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1181
          spice_ip_version = \
1182
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1183
        elif addresses[constants.IP4_VERSION]:
1184
          spice_ip_version = constants.IP4_VERSION
1185
        elif addresses[constants.IP6_VERSION]:
1186
          spice_ip_version = constants.IP6_VERSION
1187
        else:
1188
          raise errors.HypervisorError("spice: unable to get an IP address"
1189
                                       " for %s" % (spice_bind))
1190

    
1191
        spice_address = addresses[spice_ip_version][0]
1192

    
1193
      else:
1194
        # spice_bind is known to be a valid IP address, because
1195
        # ValidateParameters checked it.
1196
        spice_address = spice_bind
1197

    
1198
      spice_arg = "addr=%s" % spice_address
1199
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1200
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1201
                     (spice_arg, instance.network_port,
1202
                      pathutils.SPICE_CACERT_FILE))
1203
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1204
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1205
                      pathutils.SPICE_CERT_FILE))
1206
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1207
        if tls_ciphers:
1208
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1209
      else:
1210
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1211

    
1212
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1213
        spice_arg = "%s,disable-ticketing" % spice_arg
1214

    
1215
      if spice_ip_version:
1216
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1217

    
1218
      # Image compression options
1219
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1220
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1221
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1222
      if img_lossless:
1223
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1224
      if img_jpeg:
1225
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1226
      if img_zlib_glz:
1227
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1228

    
1229
      # Video stream detection
1230
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1231
      if video_streaming:
1232
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1233

    
1234
      # Audio compression, by default in qemu-kvm it is on
1235
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1236
        spice_arg = "%s,playback-compression=off" % spice_arg
1237
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1238
        spice_arg = "%s,agent-mouse=off" % spice_arg
1239
      else:
1240
        # Enable the spice agent communication channel between the host and the
1241
        # agent.
1242
        kvm_cmd.extend(["-device", "virtio-serial-pci"])
1243
        kvm_cmd.extend(["-device", "virtserialport,chardev=spicechannel0,"
1244
                                                   "name=com.redhat.spice.0"])
1245
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1246

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

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

    
1253
    else:
1254
      kvm_cmd.extend(["-nographic"])
1255

    
1256
    if hvp[constants.HV_USE_LOCALTIME]:
1257
      kvm_cmd.extend(["-localtime"])
1258

    
1259
    if hvp[constants.HV_KVM_USE_CHROOT]:
1260
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1261

    
1262
    # Add qemu-KVM -cpu param
1263
    if hvp[constants.HV_CPU_TYPE]:
1264
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1265

    
1266
    # Save the current instance nics, but defer their expansion as parameters,
1267
    # as we'll need to generate executable temp files for them.
1268
    kvm_nics = instance.nics
1269
    hvparams = hvp
1270

    
1271
    return (kvm_cmd, kvm_nics, hvparams)
1272

    
1273
  def _WriteKVMRuntime(self, instance_name, data):
1274
    """Write an instance's KVM runtime
1275

1276
    """
1277
    try:
1278
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1279
                      data=data)
1280
    except EnvironmentError, err:
1281
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1282

    
1283
  def _ReadKVMRuntime(self, instance_name):
1284
    """Read an instance's KVM runtime
1285

1286
    """
1287
    try:
1288
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1289
    except EnvironmentError, err:
1290
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1291
    return file_content
1292

    
1293
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1294
    """Save an instance's KVM runtime
1295

1296
    """
1297
    kvm_cmd, kvm_nics, hvparams = kvm_runtime
1298
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1299
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1300
    self._WriteKVMRuntime(instance.name, serialized_form)
1301

    
1302
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1303
    """Load an instance's KVM runtime
1304

1305
    """
1306
    if not serialized_runtime:
1307
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1308
    loaded_runtime = serializer.Load(serialized_runtime)
1309
    kvm_cmd, serialized_nics, hvparams = loaded_runtime
1310
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1311
    return (kvm_cmd, kvm_nics, hvparams)
1312

    
1313
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1314
    """Run the KVM cmd and check for errors
1315

1316
    @type name: string
1317
    @param name: instance name
1318
    @type kvm_cmd: list of strings
1319
    @param kvm_cmd: runcmd input for kvm
1320
    @type tap_fds: list of int
1321
    @param tap_fds: fds of tap devices opened by Ganeti
1322

1323
    """
1324
    try:
1325
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1326
    finally:
1327
      for fd in tap_fds:
1328
        utils_wrapper.CloseFdNoError(fd)
1329

    
1330
    if result.failed:
1331
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1332
                                   (name, result.fail_reason, result.output))
1333
    if not self._InstancePidAlive(name)[2]:
1334
      raise errors.HypervisorError("Failed to start instance %s" % name)
1335

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

1339
    @type incoming: tuple of strings
1340
    @param incoming: (target_host_ip, port)
1341

1342
    """
1343
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1344
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1345
    #    have changed since the instance started; only use them if the change
1346
    #    won't affect the inside of the instance (which hasn't been rebooted).
1347
    #  - up_hvp contains the parameters as they were when the instance was
1348
    #    started, plus any new parameter which has been added between ganeti
1349
    #    versions: it is paramount that those default to a value which won't
1350
    #    affect the inside of the instance as well.
1351
    conf_hvp = instance.hvparams
1352
    name = instance.name
1353
    self._CheckDown(name)
1354

    
1355
    temp_files = []
1356

    
1357
    kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1358
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1359

    
1360
    _, v_major, v_min, _ = self._GetKVMVersion()
1361

    
1362
    # We know it's safe to run as a different user upon migration, so we'll use
1363
    # the latest conf, from conf_hvp.
1364
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1365
    if security_model == constants.HT_SM_USER:
1366
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1367

    
1368
    keymap = conf_hvp[constants.HV_KEYMAP]
1369
    if keymap:
1370
      keymap_path = self._InstanceKeymapFile(name)
1371
      # If a keymap file is specified, KVM won't use its internal defaults. By
1372
      # first including the "en-us" layout, an error on loading the actual
1373
      # layout (e.g. because it can't be found) won't lead to a non-functional
1374
      # keyboard. A keyboard with incorrect keys is still better than none.
1375
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1376
      kvm_cmd.extend(["-k", keymap_path])
1377

    
1378
    # We have reasons to believe changing something like the nic driver/type
1379
    # upon migration won't exactly fly with the instance kernel, so for nic
1380
    # related parameters we'll use up_hvp
1381
    tapfds = []
1382
    taps = []
1383
    if not kvm_nics:
1384
      kvm_cmd.extend(["-net", "none"])
1385
    else:
1386
      vnet_hdr = False
1387
      tap_extra = ""
1388
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1389
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1390
        # From version 0.12.0, kvm uses a new sintax for network configuration.
1391
        if (v_major, v_min) >= (0, 12):
1392
          nic_model = "virtio-net-pci"
1393
          vnet_hdr = True
1394
        else:
1395
          nic_model = "virtio"
1396

    
1397
        if up_hvp[constants.HV_VHOST_NET]:
1398
          # vhost_net is only available from version 0.13.0 or newer
1399
          if (v_major, v_min) >= (0, 13):
1400
            tap_extra = ",vhost=on"
1401
          else:
1402
            raise errors.HypervisorError("vhost_net is configured"
1403
                                         " but it is not available")
1404
      else:
1405
        nic_model = nic_type
1406

    
1407
      for nic_seq, nic in enumerate(kvm_nics):
1408
        tapname, tapfd = _OpenTap(vnet_hdr)
1409
        tapfds.append(tapfd)
1410
        taps.append(tapname)
1411
        if (v_major, v_min) >= (0, 12):
1412
          nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1413
          tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1414
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1415
        else:
1416
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1417
                                                         nic.mac, nic_model)
1418
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1419
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1420

    
1421
    if incoming:
1422
      target, port = incoming
1423
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1424

    
1425
    # Changing the vnc password doesn't bother the guest that much. At most it
1426
    # will surprise people who connect to it. Whether positively or negatively
1427
    # it's debatable.
1428
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1429
    vnc_pwd = None
1430
    if vnc_pwd_file:
1431
      try:
1432
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1433
      except EnvironmentError, err:
1434
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1435
                                     % (vnc_pwd_file, err))
1436

    
1437
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1438
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1439
                         constants.SECURE_DIR_MODE)])
1440

    
1441
    # Automatically enable QMP if version is >= 0.14
1442
    if (v_major, v_min) >= (0, 14):
1443
      logging.debug("Enabling QMP")
1444
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1445
                      self._InstanceQmpMonitor(instance.name)])
1446

    
1447
    # Configure the network now for starting instances and bridged interfaces,
1448
    # during FinalizeMigration for incoming instances' routed interfaces
1449
    for nic_seq, nic in enumerate(kvm_nics):
1450
      if (incoming and
1451
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1452
        continue
1453
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1454

    
1455
    # CPU affinity requires kvm to start paused, so we set this flag if the
1456
    # instance is not already paused and if we are not going to accept a
1457
    # migrating instance. In the latter case, pausing is not needed.
1458
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1459
    if start_kvm_paused:
1460
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1461

    
1462
    # Note: CPU pinning is using up_hvp since changes take effect
1463
    # during instance startup anyway, and to avoid problems when soft
1464
    # rebooting the instance.
1465
    cpu_pinning = False
1466
    if up_hvp.get(constants.HV_CPU_MASK, None):
1467
      cpu_pinning = True
1468

    
1469
    if security_model == constants.HT_SM_POOL:
1470
      ss = ssconf.SimpleStore()
1471
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1472
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1473
      uid = uidpool.RequestUnusedUid(all_uids)
1474
      try:
1475
        username = pwd.getpwuid(uid.GetUid()).pw_name
1476
        kvm_cmd.extend(["-runas", username])
1477
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1478
      except:
1479
        uidpool.ReleaseUid(uid)
1480
        raise
1481
      else:
1482
        uid.Unlock()
1483
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1484
    else:
1485
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1486

    
1487
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1488
                     constants.RUN_DIRS_MODE)])
1489
    for nic_seq, tap in enumerate(taps):
1490
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1491
                      data=tap)
1492

    
1493
    if vnc_pwd:
1494
      change_cmd = "change vnc password %s" % vnc_pwd
1495
      self._CallMonitorCommand(instance.name, change_cmd)
1496

    
1497
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1498
    # connection attempts because SPICE by default does not allow connections
1499
    # if neither a password nor the "disable_ticketing" options are specified.
1500
    # As soon as we send the password via QMP, that password is a valid ticket
1501
    # for connection.
1502
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1503
    if spice_password_file:
1504
      spice_pwd = ""
1505
      try:
1506
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1507
      except EnvironmentError, err:
1508
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1509
                                     % (spice_password_file, err))
1510

    
1511
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1512
      qmp.connect()
1513
      arguments = {
1514
          "protocol": "spice",
1515
          "password": spice_pwd,
1516
      }
1517
      qmp.Execute("set_password", arguments)
1518

    
1519
    for filename in temp_files:
1520
      utils.RemoveFile(filename)
1521

    
1522
    # If requested, set CPU affinity and resume instance execution
1523
    if cpu_pinning:
1524
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1525

    
1526
    start_memory = self._InstanceStartupMemory(instance)
1527
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1528
      self.BalloonInstanceMemory(instance, start_memory)
1529

    
1530
    if start_kvm_paused:
1531
      # To control CPU pinning, ballooning, and vnc/spice passwords
1532
      # the VM was started in a frozen state. If freezing was not
1533
      # explicitly requested resume the vm status.
1534
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1535

    
1536
  def StartInstance(self, instance, block_devices, startup_paused):
1537
    """Start an instance.
1538

1539
    """
1540
    self._CheckDown(instance.name)
1541
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1542
                                           startup_paused)
1543
    self._SaveKVMRuntime(instance, kvm_runtime)
1544
    self._ExecuteKVMRuntime(instance, kvm_runtime)
1545

    
1546
  def _CallMonitorCommand(self, instance_name, command):
1547
    """Invoke a command on the instance monitor.
1548

1549
    """
1550
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1551
             (utils.ShellQuote(command),
1552
              constants.SOCAT_PATH,
1553
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1554
    result = utils.RunCmd(socat)
1555
    if result.failed:
1556
      msg = ("Failed to send command '%s' to instance %s."
1557
             " output: %s, error: %s, fail_reason: %s" %
1558
             (command, instance_name,
1559
              result.stdout, result.stderr, result.fail_reason))
1560
      raise errors.HypervisorError(msg)
1561

    
1562
    return result
1563

    
1564
  @classmethod
1565
  def _ParseKVMVersion(cls, text):
1566
    """Parse the KVM version from the --help output.
1567

1568
    @type text: string
1569
    @param text: output of kvm --help
1570
    @return: (version, v_maj, v_min, v_rev)
1571
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1572

1573
    """
1574
    match = cls._VERSION_RE.search(text.splitlines()[0])
1575
    if not match:
1576
      raise errors.HypervisorError("Unable to get KVM version")
1577

    
1578
    v_all = match.group(0)
1579
    v_maj = int(match.group(1))
1580
    v_min = int(match.group(2))
1581
    if match.group(4):
1582
      v_rev = int(match.group(4))
1583
    else:
1584
      v_rev = 0
1585
    return (v_all, v_maj, v_min, v_rev)
1586

    
1587
  @classmethod
1588
  def _GetKVMVersion(cls):
1589
    """Return the installed KVM version.
1590

1591
    @return: (version, v_maj, v_min, v_rev)
1592
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1593

1594
    """
1595
    result = utils.RunCmd([constants.KVM_PATH, "--help"])
1596
    if result.failed:
1597
      raise errors.HypervisorError("Unable to get KVM version")
1598
    return cls._ParseKVMVersion(result.output)
1599

    
1600
  def StopInstance(self, instance, force=False, retry=False, name=None):
1601
    """Stop an instance.
1602

1603
    """
1604
    if name is not None and not force:
1605
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1606
    if name is None:
1607
      name = instance.name
1608
      acpi = instance.hvparams[constants.HV_ACPI]
1609
    else:
1610
      acpi = False
1611
    _, pid, alive = self._InstancePidAlive(name)
1612
    if pid > 0 and alive:
1613
      if force or not acpi:
1614
        utils.KillProcess(pid)
1615
      else:
1616
        self._CallMonitorCommand(name, "system_powerdown")
1617

    
1618
  def CleanupInstance(self, instance_name):
1619
    """Cleanup after a stopped instance
1620

1621
    """
1622
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
1623
    if pid > 0 and alive:
1624
      raise errors.HypervisorError("Cannot cleanup a live instance")
1625
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1626

    
1627
  def RebootInstance(self, instance):
1628
    """Reboot an instance.
1629

1630
    """
1631
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1632
    # socket the instance will stop, but now power up again. So we'll resort
1633
    # to shutdown and restart.
1634
    _, _, alive = self._InstancePidAlive(instance.name)
1635
    if not alive:
1636
      raise errors.HypervisorError("Failed to reboot instance %s:"
1637
                                   " not running" % instance.name)
1638
    # StopInstance will delete the saved KVM runtime so:
1639
    # ...first load it...
1640
    kvm_runtime = self._LoadKVMRuntime(instance)
1641
    # ...now we can safely call StopInstance...
1642
    if not self.StopInstance(instance):
1643
      self.StopInstance(instance, force=True)
1644
    # ...and finally we can save it again, and execute it...
1645
    self._SaveKVMRuntime(instance, kvm_runtime)
1646
    self._ExecuteKVMRuntime(instance, kvm_runtime)
1647

    
1648
  def MigrationInfo(self, instance):
1649
    """Get instance information to perform a migration.
1650

1651
    @type instance: L{objects.Instance}
1652
    @param instance: instance to be migrated
1653
    @rtype: string
1654
    @return: content of the KVM runtime file
1655

1656
    """
1657
    return self._ReadKVMRuntime(instance.name)
1658

    
1659
  def AcceptInstance(self, instance, info, target):
1660
    """Prepare to accept an instance.
1661

1662
    @type instance: L{objects.Instance}
1663
    @param instance: instance to be accepted
1664
    @type info: string
1665
    @param info: content of the KVM runtime file on the source node
1666
    @type target: string
1667
    @param target: target host (usually ip), on this node
1668

1669
    """
1670
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1671
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1672
    self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
1673

    
1674
  def FinalizeMigrationDst(self, instance, info, success):
1675
    """Finalize the instance migration on the target node.
1676

1677
    Stop the incoming mode KVM.
1678

1679
    @type instance: L{objects.Instance}
1680
    @param instance: instance whose migration is being finalized
1681

1682
    """
1683
    if success:
1684
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1685
      kvm_nics = kvm_runtime[1]
1686

    
1687
      for nic_seq, nic in enumerate(kvm_nics):
1688
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1689
          # Bridged interfaces have already been configured
1690
          continue
1691
        try:
1692
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1693
        except EnvironmentError, err:
1694
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
1695
                          instance.name, nic_seq, str(err))
1696
          continue
1697
        try:
1698
          self._ConfigureNIC(instance, nic_seq, nic, tap)
1699
        except errors.HypervisorError, err:
1700
          logging.warning(str(err))
1701

    
1702
      self._WriteKVMRuntime(instance.name, info)
1703
    else:
1704
      self.StopInstance(instance, force=True)
1705

    
1706
  def MigrateInstance(self, instance, target, live):
1707
    """Migrate an instance to a target node.
1708

1709
    The migration will not be attempted if the instance is not
1710
    currently running.
1711

1712
    @type instance: L{objects.Instance}
1713
    @param instance: the instance to be migrated
1714
    @type target: string
1715
    @param target: ip address of the target node
1716
    @type live: boolean
1717
    @param live: perform a live migration
1718

1719
    """
1720
    instance_name = instance.name
1721
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
1722
    _, _, alive = self._InstancePidAlive(instance_name)
1723
    if not alive:
1724
      raise errors.HypervisorError("Instance not running, cannot migrate")
1725

    
1726
    if not live:
1727
      self._CallMonitorCommand(instance_name, "stop")
1728

    
1729
    migrate_command = ("migrate_set_speed %dm" %
1730
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1731
    self._CallMonitorCommand(instance_name, migrate_command)
1732

    
1733
    migrate_command = ("migrate_set_downtime %dms" %
1734
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1735
    self._CallMonitorCommand(instance_name, migrate_command)
1736

    
1737
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1738
    self._CallMonitorCommand(instance_name, migrate_command)
1739

    
1740
  def FinalizeMigrationSource(self, instance, success, live):
1741
    """Finalize the instance migration on the source node.
1742

1743
    @type instance: L{objects.Instance}
1744
    @param instance: the instance that was migrated
1745
    @type success: bool
1746
    @param success: whether the migration succeeded or not
1747
    @type live: bool
1748
    @param live: whether the user requested a live migration or not
1749

1750
    """
1751
    if success:
1752
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
1753
      utils.KillProcess(pid)
1754
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1755
    elif live:
1756
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1757

    
1758
  def GetMigrationStatus(self, instance):
1759
    """Get the migration status
1760

1761
    @type instance: L{objects.Instance}
1762
    @param instance: the instance that is being migrated
1763
    @rtype: L{objects.MigrationStatus}
1764
    @return: the status of the current migration (one of
1765
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1766
             progress info that can be retrieved from the hypervisor
1767

1768
    """
1769
    info_command = "info migrate"
1770
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
1771
      result = self._CallMonitorCommand(instance.name, info_command)
1772
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
1773
      if not match:
1774
        if not result.stdout:
1775
          logging.info("KVM: empty 'info migrate' result")
1776
        else:
1777
          logging.warning("KVM: unknown 'info migrate' result: %s",
1778
                          result.stdout)
1779
      else:
1780
        status = match.group(1)
1781
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
1782
          migration_status = objects.MigrationStatus(status=status)
1783
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
1784
          if match:
1785
            migration_status.transferred_ram = match.group("transferred")
1786
            migration_status.total_ram = match.group("total")
1787

    
1788
          return migration_status
1789

    
1790
        logging.warning("KVM: unknown migration status '%s'", status)
1791

    
1792
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1793

    
1794
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
1795

    
1796
  def BalloonInstanceMemory(self, instance, mem):
1797
    """Balloon an instance memory to a certain value.
1798

1799
    @type instance: L{objects.Instance}
1800
    @param instance: instance to be accepted
1801
    @type mem: int
1802
    @param mem: actual memory size to use for instance runtime
1803

1804
    """
1805
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
1806

    
1807
  def GetNodeInfo(self):
1808
    """Return information about the node.
1809

1810
    @return: a dict with the following keys (values in MiB):
1811
          - memory_total: the total memory size on the node
1812
          - memory_free: the available memory on the node for instances
1813
          - memory_dom0: the memory used by the node itself, if available
1814
          - hv_version: the hypervisor version in the form (major, minor,
1815
                        revision)
1816

1817
    """
1818
    result = self.GetLinuxNodeInfo()
1819
    _, v_major, v_min, v_rev = self._GetKVMVersion()
1820
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
1821
    return result
1822

    
1823
  @classmethod
1824
  def GetInstanceConsole(cls, instance, hvparams, beparams):
1825
    """Return a command for connecting to the console of an instance.
1826

1827
    """
1828
    if hvparams[constants.HV_SERIAL_CONSOLE]:
1829
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
1830
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1831
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1832
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
1833
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1834
      return objects.InstanceConsole(instance=instance.name,
1835
                                     kind=constants.CONS_SSH,
1836
                                     host=instance.primary_node,
1837
                                     user=constants.SSH_CONSOLE_USER,
1838
                                     command=cmd)
1839

    
1840
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1841
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1842
      display = instance.network_port - constants.VNC_BASE_PORT
1843
      return objects.InstanceConsole(instance=instance.name,
1844
                                     kind=constants.CONS_VNC,
1845
                                     host=vnc_bind_address,
1846
                                     port=instance.network_port,
1847
                                     display=display)
1848

    
1849
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1850
    if spice_bind:
1851
      return objects.InstanceConsole(instance=instance.name,
1852
                                     kind=constants.CONS_SPICE,
1853
                                     host=spice_bind,
1854
                                     port=instance.network_port)
1855

    
1856
    return objects.InstanceConsole(instance=instance.name,
1857
                                   kind=constants.CONS_MESSAGE,
1858
                                   message=("No serial shell for instance %s" %
1859
                                            instance.name))
1860

    
1861
  def Verify(self):
1862
    """Verify the hypervisor.
1863

1864
    Check that the binary exists.
1865

1866
    """
1867
    if not os.path.exists(constants.KVM_PATH):
1868
      return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
1869
    if not os.path.exists(constants.SOCAT_PATH):
1870
      return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
1871

    
1872
  @classmethod
1873
  def CheckParameterSyntax(cls, hvparams):
1874
    """Check the given parameters for validity.
1875

1876
    @type hvparams:  dict
1877
    @param hvparams: dictionary with parameter names/value
1878
    @raise errors.HypervisorError: when a parameter is not valid
1879

1880
    """
1881
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
1882

    
1883
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
1884
    if kernel_path:
1885
      if not hvparams[constants.HV_ROOT_PATH]:
1886
        raise errors.HypervisorError("Need a root partition for the instance,"
1887
                                     " if a kernel is defined")
1888

    
1889
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
1890
        not hvparams[constants.HV_VNC_X509]):
1891
      raise errors.HypervisorError("%s must be defined, if %s is" %
1892
                                   (constants.HV_VNC_X509,
1893
                                    constants.HV_VNC_X509_VERIFY))
1894

    
1895
    boot_order = hvparams[constants.HV_BOOT_ORDER]
1896
    if (boot_order == constants.HT_BO_CDROM and
1897
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
1898
      raise errors.HypervisorError("Cannot boot from cdrom without an"
1899
                                   " ISO path")
1900

    
1901
    security_model = hvparams[constants.HV_SECURITY_MODEL]
1902
    if security_model == constants.HT_SM_USER:
1903
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
1904
        raise errors.HypervisorError("A security domain (user to run kvm as)"
1905
                                     " must be specified")
1906
    elif (security_model == constants.HT_SM_NONE or
1907
          security_model == constants.HT_SM_POOL):
1908
      if hvparams[constants.HV_SECURITY_DOMAIN]:
1909
        raise errors.HypervisorError("Cannot have a security domain when the"
1910
                                     " security model is 'none' or 'pool'")
1911

    
1912
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1913
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
1914
    if spice_bind:
1915
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1916
        # if an IP version is specified, the spice_bind parameter must be an
1917
        # IP of that family
1918
        if (netutils.IP4Address.IsValid(spice_bind) and
1919
            spice_ip_version != constants.IP4_VERSION):
1920
          raise errors.HypervisorError("spice: got an IPv4 address (%s), but"
1921
                                       " the specified IP version is %s" %
1922
                                       (spice_bind, spice_ip_version))
1923

    
1924
        if (netutils.IP6Address.IsValid(spice_bind) and
1925
            spice_ip_version != constants.IP6_VERSION):
1926
          raise errors.HypervisorError("spice: got an IPv6 address (%s), but"
1927
                                       " the specified IP version is %s" %
1928
                                       (spice_bind, spice_ip_version))
1929
    else:
1930
      # All the other SPICE parameters depend on spice_bind being set. Raise an
1931
      # error if any of them is set without it.
1932
      spice_additional_params = frozenset([
1933
        constants.HV_KVM_SPICE_IP_VERSION,
1934
        constants.HV_KVM_SPICE_PASSWORD_FILE,
1935
        constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR,
1936
        constants.HV_KVM_SPICE_JPEG_IMG_COMPR,
1937
        constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR,
1938
        constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION,
1939
        constants.HV_KVM_SPICE_USE_TLS,
1940
        ])
1941
      for param in spice_additional_params:
1942
        if hvparams[param]:
1943
          raise errors.HypervisorError("spice: %s requires %s to be set" %
1944
                                       (param, constants.HV_KVM_SPICE_BIND))
1945

    
1946
  @classmethod
1947
  def ValidateParameters(cls, hvparams):
1948
    """Check the given parameters for validity.
1949

1950
    @type hvparams:  dict
1951
    @param hvparams: dictionary with parameter names/value
1952
    @raise errors.HypervisorError: when a parameter is not valid
1953

1954
    """
1955
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
1956

    
1957
    security_model = hvparams[constants.HV_SECURITY_MODEL]
1958
    if security_model == constants.HT_SM_USER:
1959
      username = hvparams[constants.HV_SECURITY_DOMAIN]
1960
      try:
1961
        pwd.getpwnam(username)
1962
      except KeyError:
1963
        raise errors.HypervisorError("Unknown security domain user %s"
1964
                                     % username)
1965

    
1966
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1967
    if spice_bind:
1968
      # only one of VNC and SPICE can be used currently.
1969
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
1970
        raise errors.HypervisorError("both SPICE and VNC are configured, but"
1971
                                     " only one of them can be used at a"
1972
                                     " given time.")
1973

    
1974
      # KVM version should be >= 0.14.0
1975
      _, v_major, v_min, _ = cls._GetKVMVersion()
1976
      if (v_major, v_min) < (0, 14):
1977
        raise errors.HypervisorError("spice is configured, but it is not"
1978
                                     " available in versions of KVM < 0.14")
1979

    
1980
      # if spice_bind is not an IP address, it must be a valid interface
1981
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind)
1982
                       or netutils.IP6Address.IsValid(spice_bind))
1983
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
1984
        raise errors.HypervisorError("spice: the %s parameter must be either"
1985
                                     " a valid IP address or interface name" %
1986
                                     constants.HV_KVM_SPICE_BIND)
1987

    
1988
  @classmethod
1989
  def PowercycleNode(cls):
1990
    """KVM powercycle, just a wrapper over Linux powercycle.
1991

1992
    """
1993
    cls.LinuxPowercycle()