Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 0e1e0b6a

History | View | Annotate | Download (72.1 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.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
779
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
780

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

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

    
793
  @staticmethod
794
  def _BuildAffinityCpuMask(cpu_list):
795
    """Create a CPU mask suitable for sched_setaffinity from a list of
796
    CPUs.
797

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

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

806
    """
807
    if cpu_list == constants.CPU_PINNING_OFF:
808
      return constants.CPU_PINNING_ALL_KVM
809
    else:
810
      return sum(2 ** cpu for cpu in cpu_list)
811

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

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

824
    """
825
    # Convert the string CPU mask to a list of list of int's
826
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
827

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

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

    
851
  def _GetVcpuThreadIds(self, instance_name):
852
    """Get a mapping of vCPU no. to thread IDs for the instance
853

854
    @type instance_name: string
855
    @param instance_name: instance in question
856
    @rtype: dictionary of int:int
857
    @return: a dictionary mapping vCPU numbers to thread IDs
858

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

    
869
    return result
870

    
871
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
872
    """Complete CPU pinning.
873

874
    @type instance_name: string
875
    @param instance_name: name of instance
876
    @type cpu_mask: string
877
    @param cpu_mask: CPU pinning mask as entered by user
878

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

    
887
  def ListInstances(self):
888
    """Get the list of running instances.
889

890
    We can do this by listing our live instances directory and
891
    checking whether the associated kvm process is still alive.
892

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

    
900
  def GetInstanceInfo(self, instance_name):
901
    """Get instance properties.
902

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

908
    """
909
    _, pid, alive = self._InstancePidAlive(instance_name)
910
    if not alive:
911
      return None
912

    
913
    _, memory, vcpus = self._InstancePidInfo(pid)
914
    istat = "---b-"
915
    times = "0"
916

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

    
928
    return (instance_name, pid, memory, vcpus, istat, times)
929

    
930
  def GetAllInstancesInfo(self):
931
    """Get properties of all instances.
932

933
    @return: list of tuples (name, id, memory, vcpus, stat, times)
934

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

    
947
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused):
948
    """Generate KVM information to start an instance.
949

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

957
    """
958
    # pylint: disable=R0914,R0915
959
    _, v_major, v_min, _ = self._GetKVMVersion()
960

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

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

    
987
    self.ValidateParameters(hvp)
988

    
989
    if startup_paused:
990
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
991

    
992
    if hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED:
993
      kvm_cmd.extend(["-enable-kvm"])
994
    elif hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED:
995
      kvm_cmd.extend(["-disable-kvm"])
996

    
997
    if boot_network:
998
      kvm_cmd.extend(["-boot", "n"])
999

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

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

    
1034
      drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
1035
                                                cache_val)
1036
      kvm_cmd.extend(["-drive", drive_val])
1037

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

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

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

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

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

    
1096
    mem_path = hvp[constants.HV_MEM_PATH]
1097
    if mem_path:
1098
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1099

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

    
1110
    mouse_type = hvp[constants.HV_USB_MOUSE]
1111
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1112
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1113
    spice_ip_version = None
1114

    
1115
    if mouse_type:
1116
      kvm_cmd.extend(["-usb"])
1117
      kvm_cmd.extend(["-usbdevice", mouse_type])
1118
    elif vnc_bind_address:
1119
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1120

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

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

    
1149
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1150

    
1151
      else:
1152
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1153

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

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

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

    
1188
        spice_address = addresses[spice_ip_version][0]
1189

    
1190
      else:
1191
        # spice_bind is known to be a valid IP address, because
1192
        # ValidateParameters checked it.
1193
        spice_address = spice_bind
1194

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

    
1209
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1210
        spice_arg = "%s,disable-ticketing" % spice_arg
1211

    
1212
      if spice_ip_version:
1213
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1214

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

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

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

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

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

    
1250
    else:
1251
      kvm_cmd.extend(["-nographic"])
1252

    
1253
    if hvp[constants.HV_USE_LOCALTIME]:
1254
      kvm_cmd.extend(["-localtime"])
1255

    
1256
    if hvp[constants.HV_KVM_USE_CHROOT]:
1257
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1258

    
1259
    # Add qemu-KVM -cpu param
1260
    if hvp[constants.HV_CPU_TYPE]:
1261
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1262

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

    
1268
    return (kvm_cmd, kvm_nics, hvparams)
1269

    
1270
  def _WriteKVMRuntime(self, instance_name, data):
1271
    """Write an instance's KVM runtime
1272

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

    
1280
  def _ReadKVMRuntime(self, instance_name):
1281
    """Read an instance's KVM runtime
1282

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

    
1290
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1291
    """Save an instance's KVM runtime
1292

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

    
1299
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1300
    """Load an instance's KVM runtime
1301

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

    
1310
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1311
    """Run the KVM cmd and check for errors
1312

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

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

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

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

1336
    @type incoming: tuple of strings
1337
    @param incoming: (target_host_ip, port)
1338

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

    
1352
    temp_files = []
1353

    
1354
    kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1355
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1356

    
1357
    _, v_major, v_min, _ = self._GetKVMVersion()
1358

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

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

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

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

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

    
1418
    if incoming:
1419
      target, port = incoming
1420
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1421

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

    
1434
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1435
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1436
                         constants.SECURE_DIR_MODE)])
1437

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

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

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

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

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

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

    
1490
    if vnc_pwd:
1491
      change_cmd = "change vnc password %s" % vnc_pwd
1492
      self._CallMonitorCommand(instance.name, change_cmd)
1493

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

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

    
1516
    for filename in temp_files:
1517
      utils.RemoveFile(filename)
1518

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

    
1523
    start_memory = self._InstanceStartupMemory(instance)
1524
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1525
      self.BalloonInstanceMemory(instance, start_memory)
1526

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

    
1533
  def StartInstance(self, instance, block_devices, startup_paused):
1534
    """Start an instance.
1535

1536
    """
1537
    self._CheckDown(instance.name)
1538
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1539
                                           startup_paused)
1540
    self._SaveKVMRuntime(instance, kvm_runtime)
1541
    self._ExecuteKVMRuntime(instance, kvm_runtime)
1542

    
1543
  def _CallMonitorCommand(self, instance_name, command):
1544
    """Invoke a command on the instance monitor.
1545

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

    
1559
    return result
1560

    
1561
  @classmethod
1562
  def _ParseKVMVersion(cls, text):
1563
    """Parse the KVM version from the --help output.
1564

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

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

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

    
1584
  @classmethod
1585
  def _GetKVMVersion(cls):
1586
    """Return the installed KVM version.
1587

1588
    @return: (version, v_maj, v_min, v_rev)
1589
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1590

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

    
1597
  def StopInstance(self, instance, force=False, retry=False, name=None):
1598
    """Stop an instance.
1599

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

    
1615
  def CleanupInstance(self, instance_name):
1616
    """Cleanup after a stopped instance
1617

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

    
1624
  def RebootInstance(self, instance):
1625
    """Reboot an instance.
1626

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

    
1645
  def MigrationInfo(self, instance):
1646
    """Get instance information to perform a migration.
1647

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

1653
    """
1654
    return self._ReadKVMRuntime(instance.name)
1655

    
1656
  def AcceptInstance(self, instance, info, target):
1657
    """Prepare to accept an instance.
1658

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

1666
    """
1667
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1668
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1669
    self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
1670

    
1671
  def FinalizeMigrationDst(self, instance, info, success):
1672
    """Finalize the instance migration on the target node.
1673

1674
    Stop the incoming mode KVM.
1675

1676
    @type instance: L{objects.Instance}
1677
    @param instance: instance whose migration is being finalized
1678

1679
    """
1680
    if success:
1681
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1682
      kvm_nics = kvm_runtime[1]
1683

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

    
1699
      self._WriteKVMRuntime(instance.name, info)
1700
    else:
1701
      self.StopInstance(instance, force=True)
1702

    
1703
  def MigrateInstance(self, instance, target, live):
1704
    """Migrate an instance to a target node.
1705

1706
    The migration will not be attempted if the instance is not
1707
    currently running.
1708

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

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

    
1723
    if not live:
1724
      self._CallMonitorCommand(instance_name, "stop")
1725

    
1726
    migrate_command = ("migrate_set_speed %dm" %
1727
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1728
    self._CallMonitorCommand(instance_name, migrate_command)
1729

    
1730
    migrate_command = ("migrate_set_downtime %dms" %
1731
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1732
    self._CallMonitorCommand(instance_name, migrate_command)
1733

    
1734
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1735
    self._CallMonitorCommand(instance_name, migrate_command)
1736

    
1737
  def FinalizeMigrationSource(self, instance, success, live):
1738
    """Finalize the instance migration on the source node.
1739

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

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

    
1755
  def GetMigrationStatus(self, instance):
1756
    """Get the migration status
1757

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

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

    
1785
          return migration_status
1786

    
1787
        logging.warning("KVM: unknown migration status '%s'", status)
1788

    
1789
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1790

    
1791
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED,
1792
                                   info="Too many 'info migrate'"
1793
                                   " broken answers")
1794

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

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

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

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

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

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

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

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

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

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

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

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

1863
    Check that the binary exists.
1864

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1991
    """
1992
    cls.LinuxPowercycle()