Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ fc84cd5d

History | View | Annotate | Download (69.2 kB)

1
#
2
#
3

    
4
# Copyright (C) 2008, 2009, 2010, 2011 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.hypervisor import hv_base
53
from ganeti import netutils
54
from ganeti.utils import wrapper as utils_wrapper
55

    
56

    
57
_KVM_NETWORK_SCRIPT = constants.SYSCONFDIR + "/ganeti/kvm-vif-bridge"
58
_KVM_START_PAUSED_FLAG = "-S"
59

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

    
70

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

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

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

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

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

    
102

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

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

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

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

    
120
  flags = IFF_TAP | IFF_NO_PI
121

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

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

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

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

    
137

    
138
class QmpMessage:
139
  """QEMU Messaging Protocol (QMP) message.
140

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

    
162
    if field_name in self.data:
163
      return self.data[field_name]
164

    
165
    return None
166

    
167
  def __setitem__(self, field_name, field_value):
168
    """Set the value of the required field_name to field_value.
169

170
    """
171
    self.data[field_name] = field_value
172

    
173
  @staticmethod
174
  def BuildFromJsonString(json_string):
175
    """Build a QmpMessage from a JSON encoded string.
176

177
    @type json_string: str
178
    @param json_string: JSON string representing the message
179
    @rtype: L{QmpMessage}
180
    @return: a L{QmpMessage} built from json_string
181

182
    """
183
    # Parse the string
184
    data = serializer.LoadJson(json_string)
185
    return QmpMessage(data)
186

    
187
  def __str__(self):
188
    # The protocol expects the JSON object to be sent as a single
189
    # line, hence the need for indent=False.
190
    return serializer.DumpJson(self.data, indent=False)
191

    
192
  def __eq__(self, other):
193
    # When comparing two QmpMessages, we are interested in comparing
194
    # their internal representation of the message data
195
    return self.data == other.data
196

    
197

    
198
class QmpConnection:
199
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
200

201
  """
202
  _FIRST_MESSAGE_KEY = "QMP"
203
  _EVENT_KEY = "event"
204
  _ERROR_KEY = "error"
205
  _ERROR_CLASS_KEY = "class"
206
  _ERROR_DATA_KEY = "data"
207
  _ERROR_DESC_KEY = "desc"
208
  _EXECUTE_KEY = "execute"
209
  _ARGUMENTS_KEY = "arguments"
210
  _CAPABILITIES_COMMAND = "qmp_capabilities"
211
  _MESSAGE_END_TOKEN = "\r\n"
212
  _SOCKET_TIMEOUT = 5
213

    
214
  def __init__(self, monitor_filename):
215
    """Instantiates the QmpConnection object.
216

217
    @type monitor_filename: string
218
    @param monitor_filename: the filename of the UNIX raw socket on which the
219
                             QMP monitor is listening
220

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

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

    
243
  def _check_connection(self):
244
    """Make sure that the connection is established.
245

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

    
251
  def connect(self):
252
    """Connects to the QMP monitor.
253

254
    Connects to the UNIX socket and makes sure that we can actually send and
255
    receive data to the kvm instance via QMP.
256

257
    @raise errors.HypervisorError: when there are communication errors
258
    @raise errors.ProgrammerError: when there are data serialization errors
259

260
    """
261
    if self._connected:
262
      raise errors.ProgrammerError("Cannot connect twice")
263

    
264
    self._check_socket()
265

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

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

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

    
286
  def _ParseMessage(self, buf):
287
    """Extract and parse a QMP message from the given buffer.
288

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

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

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

    
307
    return (message, buf)
308

    
309
  def _Recv(self):
310
    """Receives a message from QMP and decodes the received JSON object.
311

312
    @rtype: QmpMessage
313
    @return: the received message
314
    @raise errors.HypervisorError: when there are communication errors
315
    @raise errors.ProgrammerError: when there are data serialization errors
316

317
    """
318
    self._check_connection()
319

    
320
    # Check if there is already a message in the buffer
321
    (message, self._buf) = self._ParseMessage(self._buf)
322
    if message:
323
      return message
324

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

    
334
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
335
        if message:
336
          return message
337

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

    
345
  def _Send(self, message):
346
    """Encodes and sends a message to KVM using QMP.
347

348
    @type message: QmpMessage
349
    @param message: message to send to KVM
350
    @raise errors.HypervisorError: when there are communication errors
351
    @raise errors.ProgrammerError: when there are data serialization errors
352

353
    """
354
    self._check_connection()
355
    try:
356
      message_str = str(message)
357
    except Exception, err:
358
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
359

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

    
369
  def Execute(self, command, arguments=None):
370
    """Executes a QMP command and returns the response of the server.
371

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

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

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

    
401
      elif not response[self._EVENT_KEY]:
402
        return response
403

    
404

    
405
class KVMHypervisor(hv_base.BaseHypervisor):
406
  """KVM hypervisor interface"""
407
  CAN_MIGRATE = True
408

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

825
    """
826

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

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

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

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

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

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

    
871
    return result
872

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

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

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

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

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

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

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

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

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

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

    
919
    return (instance_name, pid, memory, vcpus, istat, times)
920

    
921
  def GetAllInstancesInfo(self):
922
    """Get properties of all instances.
923

924
    @return: list of tuples (name, id, memory, vcpus, stat, times)
925

926
    """
927
    data = []
928
    for name in os.listdir(self._PIDS_DIR):
929
      try:
930
        info = self.GetInstanceInfo(name)
931
      except errors.HypervisorError:
932
        continue
933
      if info:
934
        data.append(info)
935
    return data
936

    
937
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused):
938
    """Generate KVM information to start an instance.
939

940
    """
941
    # pylint: disable=R0914,R0915
942
    _, v_major, v_min, _ = self._GetKVMVersion()
943

    
944
    pidfile = self._InstancePidFile(instance.name)
945
    kvm = constants.KVM_PATH
946
    kvm_cmd = [kvm]
947
    # used just by the vnc server, if enabled
948
    kvm_cmd.extend(["-name", instance.name])
949
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
950
    kvm_cmd.extend(["-smp", instance.beparams[constants.BE_VCPUS]])
951
    kvm_cmd.extend(["-pidfile", pidfile])
952
    kvm_cmd.extend(["-daemonize"])
953
    if not instance.hvparams[constants.HV_ACPI]:
954
      kvm_cmd.extend(["-no-acpi"])
955
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
956
        constants.INSTANCE_REBOOT_EXIT:
957
      kvm_cmd.extend(["-no-reboot"])
958

    
959
    hvp = instance.hvparams
960
    boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
961
    boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
962
    boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
963
    boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
964

    
965
    self.ValidateParameters(hvp)
966

    
967
    if startup_paused:
968
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
969

    
970
    if hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED:
971
      kvm_cmd.extend(["-enable-kvm"])
972
    elif hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED:
973
      kvm_cmd.extend(["-disable-kvm"])
974

    
975
    if boot_network:
976
      kvm_cmd.extend(["-boot", "n"])
977

    
978
    disk_type = hvp[constants.HV_DISK_TYPE]
979
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
980
      if_val = ",if=virtio"
981
    else:
982
      if_val = ",if=%s" % disk_type
983
    # Cache mode
984
    disk_cache = hvp[constants.HV_DISK_CACHE]
985
    if instance.disk_template in constants.DTS_EXT_MIRROR:
986
      if disk_cache != "none":
987
        # TODO: make this a hard error, instead of a silent overwrite
988
        logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
989
                        " to prevent shared storage corruption on migration",
990
                        disk_cache)
991
      cache_val = ",cache=none"
992
    elif disk_cache != constants.HT_CACHE_DEFAULT:
993
      cache_val = ",cache=%s" % disk_cache
994
    else:
995
      cache_val = ""
996
    for cfdev, dev_path in block_devices:
997
      if cfdev.mode != constants.DISK_RDWR:
998
        raise errors.HypervisorError("Instance has read-only disks which"
999
                                     " are not supported by KVM")
1000
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
1001
      boot_val = ""
1002
      if boot_disk:
1003
        kvm_cmd.extend(["-boot", "c"])
1004
        boot_disk = False
1005
        if (v_major, v_min) < (0, 14) and disk_type != constants.HT_DISK_IDE:
1006
          boot_val = ",boot=on"
1007

    
1008
      drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
1009
                                                cache_val)
1010
      kvm_cmd.extend(["-drive", drive_val])
1011

    
1012
    #Now we can specify a different device type for CDROM devices.
1013
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1014
    if not cdrom_disk_type:
1015
      cdrom_disk_type = disk_type
1016

    
1017
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1018
    if iso_image:
1019
      options = ",format=raw,media=cdrom"
1020
      if boot_cdrom:
1021
        kvm_cmd.extend(["-boot", "d"])
1022
        if cdrom_disk_type != constants.HT_DISK_IDE:
1023
          options = "%s,boot=on,if=%s" % (options, constants.HT_DISK_IDE)
1024
        else:
1025
          options = "%s,boot=on" % options
1026
      else:
1027
        if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1028
          if_val = ",if=virtio"
1029
        else:
1030
          if_val = ",if=%s" % cdrom_disk_type
1031
        options = "%s%s" % (options, if_val)
1032
      drive_val = "file=%s%s" % (iso_image, options)
1033
      kvm_cmd.extend(["-drive", drive_val])
1034

    
1035
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1036
    if iso_image2:
1037
      options = ",format=raw,media=cdrom"
1038
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1039
        if_val = ",if=virtio"
1040
      else:
1041
        if_val = ",if=%s" % cdrom_disk_type
1042
      options = "%s%s" % (options, if_val)
1043
      drive_val = "file=%s%s" % (iso_image2, options)
1044
      kvm_cmd.extend(["-drive", drive_val])
1045

    
1046
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1047
    if floppy_image:
1048
      options = ",format=raw,media=disk"
1049
      if boot_floppy:
1050
        kvm_cmd.extend(["-boot", "a"])
1051
        options = "%s,boot=on" % options
1052
      if_val = ",if=floppy"
1053
      options = "%s%s" % (options, if_val)
1054
      drive_val = "file=%s%s" % (floppy_image, options)
1055
      kvm_cmd.extend(["-drive", drive_val])
1056

    
1057
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1058
    if kernel_path:
1059
      kvm_cmd.extend(["-kernel", kernel_path])
1060
      initrd_path = hvp[constants.HV_INITRD_PATH]
1061
      if initrd_path:
1062
        kvm_cmd.extend(["-initrd", initrd_path])
1063
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1064
                     hvp[constants.HV_KERNEL_ARGS]]
1065
      if hvp[constants.HV_SERIAL_CONSOLE]:
1066
        root_append.append("console=ttyS0,38400")
1067
      kvm_cmd.extend(["-append", " ".join(root_append)])
1068

    
1069
    mem_path = hvp[constants.HV_MEM_PATH]
1070
    if mem_path:
1071
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1072

    
1073
    mouse_type = hvp[constants.HV_USB_MOUSE]
1074
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1075

    
1076
    if mouse_type:
1077
      kvm_cmd.extend(["-usb"])
1078
      kvm_cmd.extend(["-usbdevice", mouse_type])
1079
    elif vnc_bind_address:
1080
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1081

    
1082
    keymap = hvp[constants.HV_KEYMAP]
1083
    if keymap:
1084
      keymap_path = self._InstanceKeymapFile(instance.name)
1085
      # If a keymap file is specified, KVM won't use its internal defaults. By
1086
      # first including the "en-us" layout, an error on loading the actual
1087
      # layout (e.g. because it can't be found) won't lead to a non-functional
1088
      # keyboard. A keyboard with incorrect keys is still better than none.
1089
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1090
      kvm_cmd.extend(["-k", keymap_path])
1091

    
1092
    if vnc_bind_address:
1093
      if netutils.IP4Address.IsValid(vnc_bind_address):
1094
        if instance.network_port > constants.VNC_BASE_PORT:
1095
          display = instance.network_port - constants.VNC_BASE_PORT
1096
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1097
            vnc_arg = ":%d" % (display)
1098
          else:
1099
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1100
        else:
1101
          logging.error("Network port is not a valid VNC display (%d < %d)."
1102
                        " Not starting VNC", instance.network_port,
1103
                        constants.VNC_BASE_PORT)
1104
          vnc_arg = "none"
1105

    
1106
        # Only allow tls and other option when not binding to a file, for now.
1107
        # kvm/qemu gets confused otherwise about the filename to use.
1108
        vnc_append = ""
1109
        if hvp[constants.HV_VNC_TLS]:
1110
          vnc_append = "%s,tls" % vnc_append
1111
          if hvp[constants.HV_VNC_X509_VERIFY]:
1112
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1113
                                               hvp[constants.HV_VNC_X509])
1114
          elif hvp[constants.HV_VNC_X509]:
1115
            vnc_append = "%s,x509=%s" % (vnc_append,
1116
                                         hvp[constants.HV_VNC_X509])
1117
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1118
          vnc_append = "%s,password" % vnc_append
1119

    
1120
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1121

    
1122
      else:
1123
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1124

    
1125
      kvm_cmd.extend(["-vnc", vnc_arg])
1126
    else:
1127
      kvm_cmd.extend(["-nographic"])
1128

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

    
1139
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1140
    spice_ip_version = None
1141
    if spice_bind:
1142
      if netutils.IsValidInterface(spice_bind):
1143
        # The user specified a network interface, we have to figure out the IP
1144
        # address.
1145
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1146
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1147

    
1148
        # if the user specified an IP version and the interface does not
1149
        # have that kind of IP addresses, throw an exception
1150
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1151
          if not addresses[spice_ip_version]:
1152
            raise errors.HypervisorError("spice: unable to get an IPv%s address"
1153
                                         " for %s" % (spice_ip_version,
1154
                                                      spice_bind))
1155

    
1156
        # the user did not specify an IP version, we have to figure it out
1157
        elif (addresses[constants.IP4_VERSION] and
1158
              addresses[constants.IP6_VERSION]):
1159
          # we have both ipv4 and ipv6, let's use the cluster default IP
1160
          # version
1161
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1162
          spice_ip_version = netutils.IPAddress.GetVersionFromAddressFamily(
1163
              cluster_family)
1164
        elif addresses[constants.IP4_VERSION]:
1165
          spice_ip_version = constants.IP4_VERSION
1166
        elif addresses[constants.IP6_VERSION]:
1167
          spice_ip_version = constants.IP6_VERSION
1168
        else:
1169
          raise errors.HypervisorError("spice: unable to get an IP address"
1170
                                       " for %s" % (spice_bind))
1171

    
1172
        spice_address = addresses[spice_ip_version][0]
1173

    
1174
      else:
1175
        # spice_bind is known to be a valid IP address, because
1176
        # ValidateParameters checked it.
1177
        spice_address = spice_bind
1178

    
1179
      spice_arg = "addr=%s" % spice_address
1180
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1181
        spice_arg = "%s,tls-port=%s,x509-cacert-file=%s" % (spice_arg,
1182
            instance.network_port, constants.SPICE_CACERT_FILE)
1183
        spice_arg = "%s,x509-key-file=%s,x509-cert-file=%s" % (spice_arg,
1184
            constants.SPICE_CERT_FILE, constants.SPICE_CERT_FILE)
1185
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1186
        if tls_ciphers:
1187
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1188
      else:
1189
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1190

    
1191
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1192
        spice_arg = "%s,disable-ticketing" % spice_arg
1193

    
1194
      if spice_ip_version:
1195
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1196

    
1197
      # Image compression options
1198
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1199
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1200
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1201
      if img_lossless:
1202
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1203
      if img_jpeg:
1204
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1205
      if img_zlib_glz:
1206
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1207

    
1208
      # Video stream detection
1209
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1210
      if video_streaming:
1211
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1212

    
1213
      # Audio compression, by default in qemu-kvm it is on
1214
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1215
        spice_arg = "%s,playback-compression=off" % spice_arg
1216
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1217
        spice_arg = "%s,agent-mouse=off" % spice_arg
1218

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

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

    
1225
    if hvp[constants.HV_USE_LOCALTIME]:
1226
      kvm_cmd.extend(["-localtime"])
1227

    
1228
    if hvp[constants.HV_KVM_USE_CHROOT]:
1229
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1230

    
1231
    # Save the current instance nics, but defer their expansion as parameters,
1232
    # as we'll need to generate executable temp files for them.
1233
    kvm_nics = instance.nics
1234
    hvparams = hvp
1235

    
1236
    return (kvm_cmd, kvm_nics, hvparams)
1237

    
1238
  def _WriteKVMRuntime(self, instance_name, data):
1239
    """Write an instance's KVM runtime
1240

1241
    """
1242
    try:
1243
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1244
                      data=data)
1245
    except EnvironmentError, err:
1246
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1247

    
1248
  def _ReadKVMRuntime(self, instance_name):
1249
    """Read an instance's KVM runtime
1250

1251
    """
1252
    try:
1253
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1254
    except EnvironmentError, err:
1255
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1256
    return file_content
1257

    
1258
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1259
    """Save an instance's KVM runtime
1260

1261
    """
1262
    kvm_cmd, kvm_nics, hvparams = kvm_runtime
1263
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1264
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1265
    self._WriteKVMRuntime(instance.name, serialized_form)
1266

    
1267
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1268
    """Load an instance's KVM runtime
1269

1270
    """
1271
    if not serialized_runtime:
1272
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1273
    loaded_runtime = serializer.Load(serialized_runtime)
1274
    kvm_cmd, serialized_nics, hvparams = loaded_runtime
1275
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1276
    return (kvm_cmd, kvm_nics, hvparams)
1277

    
1278
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1279
    """Run the KVM cmd and check for errors
1280

1281
    @type name: string
1282
    @param name: instance name
1283
    @type kvm_cmd: list of strings
1284
    @param kvm_cmd: runcmd input for kvm
1285
    @type tap_fds: list of int
1286
    @param tap_fds: fds of tap devices opened by Ganeti
1287

1288
    """
1289
    try:
1290
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1291
    finally:
1292
      for fd in tap_fds:
1293
        utils_wrapper.CloseFdNoError(fd)
1294

    
1295
    if result.failed:
1296
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1297
                                   (name, result.fail_reason, result.output))
1298
    if not self._InstancePidAlive(name)[2]:
1299
      raise errors.HypervisorError("Failed to start instance %s" % name)
1300

    
1301
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
1302
    """Execute a KVM cmd, after completing it with some last minute data
1303

1304
    @type incoming: tuple of strings
1305
    @param incoming: (target_host_ip, port)
1306

1307
    """
1308
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1309
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1310
    #    have changed since the instance started; only use them if the change
1311
    #    won't affect the inside of the instance (which hasn't been rebooted).
1312
    #  - up_hvp contains the parameters as they were when the instance was
1313
    #    started, plus any new parameter which has been added between ganeti
1314
    #    versions: it is paramount that those default to a value which won't
1315
    #    affect the inside of the instance as well.
1316
    conf_hvp = instance.hvparams
1317
    name = instance.name
1318
    self._CheckDown(name)
1319

    
1320
    temp_files = []
1321

    
1322
    kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1323
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1324

    
1325
    _, v_major, v_min, _ = self._GetKVMVersion()
1326

    
1327
    # We know it's safe to run as a different user upon migration, so we'll use
1328
    # the latest conf, from conf_hvp.
1329
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1330
    if security_model == constants.HT_SM_USER:
1331
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1332

    
1333
    # We have reasons to believe changing something like the nic driver/type
1334
    # upon migration won't exactly fly with the instance kernel, so for nic
1335
    # related parameters we'll use up_hvp
1336
    tapfds = []
1337
    taps = []
1338
    if not kvm_nics:
1339
      kvm_cmd.extend(["-net", "none"])
1340
    else:
1341
      vnet_hdr = False
1342
      tap_extra = ""
1343
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1344
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1345
        # From version 0.12.0, kvm uses a new sintax for network configuration.
1346
        if (v_major, v_min) >= (0, 12):
1347
          nic_model = "virtio-net-pci"
1348
          vnet_hdr = True
1349
        else:
1350
          nic_model = "virtio"
1351

    
1352
        if up_hvp[constants.HV_VHOST_NET]:
1353
          # vhost_net is only available from version 0.13.0 or newer
1354
          if (v_major, v_min) >= (0, 13):
1355
            tap_extra = ",vhost=on"
1356
          else:
1357
            raise errors.HypervisorError("vhost_net is configured"
1358
                                        " but it is not available")
1359
      else:
1360
        nic_model = nic_type
1361

    
1362
      for nic_seq, nic in enumerate(kvm_nics):
1363
        tapname, tapfd = _OpenTap(vnet_hdr)
1364
        tapfds.append(tapfd)
1365
        taps.append(tapname)
1366
        if (v_major, v_min) >= (0, 12):
1367
          nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1368
          tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1369
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1370
        else:
1371
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1372
                                                         nic.mac, nic_model)
1373
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1374
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1375

    
1376
    if incoming:
1377
      target, port = incoming
1378
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1379

    
1380
    # Changing the vnc password doesn't bother the guest that much. At most it
1381
    # will surprise people who connect to it. Whether positively or negatively
1382
    # it's debatable.
1383
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1384
    vnc_pwd = None
1385
    if vnc_pwd_file:
1386
      try:
1387
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1388
      except EnvironmentError, err:
1389
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1390
                                     % (vnc_pwd_file, err))
1391

    
1392
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1393
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1394
                         constants.SECURE_DIR_MODE)])
1395

    
1396
    # Automatically enable QMP if version is >= 0.14
1397
    if (v_major, v_min) >= (0, 14):
1398
      logging.debug("Enabling QMP")
1399
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1400
                    self._InstanceQmpMonitor(instance.name)])
1401

    
1402
    # Configure the network now for starting instances and bridged interfaces,
1403
    # during FinalizeMigration for incoming instances' routed interfaces
1404
    for nic_seq, nic in enumerate(kvm_nics):
1405
      if (incoming and
1406
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1407
        continue
1408
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1409

    
1410
    # CPU affinity requires kvm to start paused, so we set this flag if the
1411
    # instance is not already paused and if we are not going to accept a
1412
    # migrating instance. In the latter case, pausing is not needed.
1413
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1414

    
1415
    # Note: CPU pinning is using up_hvp since changes take effect
1416
    # during instance startup anyway, and to avoid problems when soft
1417
    # rebooting the instance.
1418
    cpu_pinning = False
1419
    if up_hvp.get(constants.HV_CPU_MASK, None):
1420
      cpu_pinning = True
1421
      if start_kvm_paused:
1422
        kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1423

    
1424
    if security_model == constants.HT_SM_POOL:
1425
      ss = ssconf.SimpleStore()
1426
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1427
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1428
      uid = uidpool.RequestUnusedUid(all_uids)
1429
      try:
1430
        username = pwd.getpwuid(uid.GetUid()).pw_name
1431
        kvm_cmd.extend(["-runas", username])
1432
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1433
      except:
1434
        uidpool.ReleaseUid(uid)
1435
        raise
1436
      else:
1437
        uid.Unlock()
1438
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1439
    else:
1440
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1441

    
1442
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1443
                     constants.RUN_DIRS_MODE)])
1444
    for nic_seq, tap in enumerate(taps):
1445
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1446
                      data=tap)
1447

    
1448
    if vnc_pwd:
1449
      change_cmd = "change vnc password %s" % vnc_pwd
1450
      self._CallMonitorCommand(instance.name, change_cmd)
1451

    
1452
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1453
    # connection attempts because SPICE by default does not allow connections
1454
    # if neither a password nor the "disable_ticketing" options are specified.
1455
    # As soon as we send the password via QMP, that password is a valid ticket
1456
    # for connection.
1457
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1458
    if spice_password_file:
1459
      spice_pwd = ""
1460
      try:
1461
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1462
      except EnvironmentError, err:
1463
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1464
                                     % (spice_password_file, err))
1465

    
1466
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1467
      qmp.connect()
1468
      arguments = {
1469
          "protocol": "spice",
1470
          "password": spice_pwd,
1471
      }
1472
      qmp.Execute("set_password", arguments)
1473

    
1474
    for filename in temp_files:
1475
      utils.RemoveFile(filename)
1476

    
1477
    # If requested, set CPU affinity and resume instance execution
1478
    if cpu_pinning:
1479
      try:
1480
        self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1481
      finally:
1482
        if start_kvm_paused:
1483
          # To control CPU pinning, the VM was started frozen, so we need
1484
          # to resume its execution, but only if freezing was not
1485
          # explicitly requested.
1486
          # Note: this is done even when an exception occurred so the VM
1487
          # is not unintentionally frozen.
1488
          self._CallMonitorCommand(instance.name, self._CONT_CMD)
1489

    
1490
  def StartInstance(self, instance, block_devices, startup_paused):
1491
    """Start an instance.
1492

1493
    """
1494
    self._CheckDown(instance.name)
1495
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1496
                                           startup_paused)
1497
    self._SaveKVMRuntime(instance, kvm_runtime)
1498
    self._ExecuteKVMRuntime(instance, kvm_runtime)
1499

    
1500
  def _CallMonitorCommand(self, instance_name, command):
1501
    """Invoke a command on the instance monitor.
1502

1503
    """
1504
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1505
             (utils.ShellQuote(command),
1506
              constants.SOCAT_PATH,
1507
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1508
    result = utils.RunCmd(socat)
1509
    if result.failed:
1510
      msg = ("Failed to send command '%s' to instance %s."
1511
             " output: %s, error: %s, fail_reason: %s" %
1512
             (command, instance_name,
1513
              result.stdout, result.stderr, result.fail_reason))
1514
      raise errors.HypervisorError(msg)
1515

    
1516
    return result
1517

    
1518
  @classmethod
1519
  def _GetKVMVersion(cls):
1520
    """Return the installed KVM version.
1521

1522
    @return: (version, v_maj, v_min, v_rev)
1523
    @raise L{errors.HypervisorError}: when the KVM version cannot be retrieved
1524

1525
    """
1526
    result = utils.RunCmd([constants.KVM_PATH, "--help"])
1527
    if result.failed:
1528
      raise errors.HypervisorError("Unable to get KVM version")
1529
    match = cls._VERSION_RE.search(result.output.splitlines()[0])
1530
    if not match:
1531
      raise errors.HypervisorError("Unable to get KVM version")
1532

    
1533
    return (match.group(0), int(match.group(1)), int(match.group(2)),
1534
            int(match.group(3)))
1535

    
1536
  def StopInstance(self, instance, force=False, retry=False, name=None):
1537
    """Stop an instance.
1538

1539
    """
1540
    if name is not None and not force:
1541
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1542
    if name is None:
1543
      name = instance.name
1544
      acpi = instance.hvparams[constants.HV_ACPI]
1545
    else:
1546
      acpi = False
1547
    _, pid, alive = self._InstancePidAlive(name)
1548
    if pid > 0 and alive:
1549
      if force or not acpi:
1550
        utils.KillProcess(pid)
1551
      else:
1552
        self._CallMonitorCommand(name, "system_powerdown")
1553

    
1554
  def CleanupInstance(self, instance_name):
1555
    """Cleanup after a stopped instance
1556

1557
    """
1558
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
1559
    if pid > 0 and alive:
1560
      raise errors.HypervisorError("Cannot cleanup a live instance")
1561
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1562

    
1563
  def RebootInstance(self, instance):
1564
    """Reboot an instance.
1565

1566
    """
1567
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1568
    # socket the instance will stop, but now power up again. So we'll resort
1569
    # to shutdown and restart.
1570
    _, _, alive = self._InstancePidAlive(instance.name)
1571
    if not alive:
1572
      raise errors.HypervisorError("Failed to reboot instance %s:"
1573
                                   " not running" % instance.name)
1574
    # StopInstance will delete the saved KVM runtime so:
1575
    # ...first load it...
1576
    kvm_runtime = self._LoadKVMRuntime(instance)
1577
    # ...now we can safely call StopInstance...
1578
    if not self.StopInstance(instance):
1579
      self.StopInstance(instance, force=True)
1580
    # ...and finally we can save it again, and execute it...
1581
    self._SaveKVMRuntime(instance, kvm_runtime)
1582
    self._ExecuteKVMRuntime(instance, kvm_runtime)
1583

    
1584
  def MigrationInfo(self, instance):
1585
    """Get instance information to perform a migration.
1586

1587
    @type instance: L{objects.Instance}
1588
    @param instance: instance to be migrated
1589
    @rtype: string
1590
    @return: content of the KVM runtime file
1591

1592
    """
1593
    return self._ReadKVMRuntime(instance.name)
1594

    
1595
  def AcceptInstance(self, instance, info, target):
1596
    """Prepare to accept an instance.
1597

1598
    @type instance: L{objects.Instance}
1599
    @param instance: instance to be accepted
1600
    @type info: string
1601
    @param info: content of the KVM runtime file on the source node
1602
    @type target: string
1603
    @param target: target host (usually ip), on this node
1604

1605
    """
1606
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1607
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1608
    self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
1609

    
1610
  def FinalizeMigrationDst(self, instance, info, success):
1611
    """Finalize the instance migration on the target node.
1612

1613
    Stop the incoming mode KVM.
1614

1615
    @type instance: L{objects.Instance}
1616
    @param instance: instance whose migration is being finalized
1617

1618
    """
1619
    if success:
1620
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1621
      kvm_nics = kvm_runtime[1]
1622

    
1623
      for nic_seq, nic in enumerate(kvm_nics):
1624
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1625
          # Bridged interfaces have already been configured
1626
          continue
1627
        try:
1628
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1629
        except EnvironmentError, err:
1630
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
1631
                          instance.name, nic_seq, str(err))
1632
          continue
1633
        try:
1634
          self._ConfigureNIC(instance, nic_seq, nic, tap)
1635
        except errors.HypervisorError, err:
1636
          logging.warning(str(err))
1637

    
1638
      self._WriteKVMRuntime(instance.name, info)
1639
    else:
1640
      self.StopInstance(instance, force=True)
1641

    
1642
  def MigrateInstance(self, instance, target, live):
1643
    """Migrate an instance to a target node.
1644

1645
    The migration will not be attempted if the instance is not
1646
    currently running.
1647

1648
    @type instance: L{objects.Instance}
1649
    @param instance: the instance to be migrated
1650
    @type target: string
1651
    @param target: ip address of the target node
1652
    @type live: boolean
1653
    @param live: perform a live migration
1654

1655
    """
1656
    instance_name = instance.name
1657
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
1658
    _, _, alive = self._InstancePidAlive(instance_name)
1659
    if not alive:
1660
      raise errors.HypervisorError("Instance not running, cannot migrate")
1661

    
1662
    if not live:
1663
      self._CallMonitorCommand(instance_name, "stop")
1664

    
1665
    migrate_command = ("migrate_set_speed %dm" %
1666
        instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1667
    self._CallMonitorCommand(instance_name, migrate_command)
1668

    
1669
    migrate_command = ("migrate_set_downtime %dms" %
1670
        instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1671
    self._CallMonitorCommand(instance_name, migrate_command)
1672

    
1673
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1674
    self._CallMonitorCommand(instance_name, migrate_command)
1675

    
1676
  def FinalizeMigrationSource(self, instance, success, live):
1677
    """Finalize the instance migration on the source node.
1678

1679
    @type instance: L{objects.Instance}
1680
    @param instance: the instance that was migrated
1681
    @type success: bool
1682
    @param success: whether the migration succeeded or not
1683
    @type live: bool
1684
    @param live: whether the user requested a live migration or not
1685

1686
    """
1687
    if success:
1688
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
1689
      utils.KillProcess(pid)
1690
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1691
    elif live:
1692
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1693

    
1694
  def GetMigrationStatus(self, instance):
1695
    """Get the migration status
1696

1697
    @type instance: L{objects.Instance}
1698
    @param instance: the instance that is being migrated
1699
    @rtype: L{objects.MigrationStatus}
1700
    @return: the status of the current migration (one of
1701
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1702
             progress info that can be retrieved from the hypervisor
1703

1704
    """
1705
    info_command = "info migrate"
1706
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
1707
      result = self._CallMonitorCommand(instance.name, info_command)
1708
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
1709
      if not match:
1710
        if not result.stdout:
1711
          logging.info("KVM: empty 'info migrate' result")
1712
        else:
1713
          logging.warning("KVM: unknown 'info migrate' result: %s",
1714
                          result.stdout)
1715
      else:
1716
        status = match.group(1)
1717
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
1718
          migration_status = objects.MigrationStatus(status=status)
1719
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
1720
          if match:
1721
            migration_status.transferred_ram = match.group("transferred")
1722
            migration_status.total_ram = match.group("total")
1723

    
1724
          return migration_status
1725

    
1726
        logging.warning("KVM: unknown migration status '%s'", status)
1727

    
1728
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1729

    
1730
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED,
1731
                                  info="Too many 'info migrate' broken answers")
1732

    
1733
  def GetNodeInfo(self):
1734
    """Return information about the node.
1735

1736
    @return: a dict with the following keys (values in MiB):
1737
          - memory_total: the total memory size on the node
1738
          - memory_free: the available memory on the node for instances
1739
          - memory_dom0: the memory used by the node itself, if available
1740
          - hv_version: the hypervisor version in the form (major, minor,
1741
                        revision)
1742

1743
    """
1744
    result = self.GetLinuxNodeInfo()
1745
    _, v_major, v_min, v_rev = self._GetKVMVersion()
1746
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
1747
    return result
1748

    
1749
  @classmethod
1750
  def GetInstanceConsole(cls, instance, hvparams, beparams):
1751
    """Return a command for connecting to the console of an instance.
1752

1753
    """
1754
    if hvparams[constants.HV_SERIAL_CONSOLE]:
1755
      cmd = [constants.KVM_CONSOLE_WRAPPER,
1756
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1757
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1758
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
1759
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1760
      return objects.InstanceConsole(instance=instance.name,
1761
                                     kind=constants.CONS_SSH,
1762
                                     host=instance.primary_node,
1763
                                     user=constants.GANETI_RUNAS,
1764
                                     command=cmd)
1765

    
1766
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1767
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1768
      display = instance.network_port - constants.VNC_BASE_PORT
1769
      return objects.InstanceConsole(instance=instance.name,
1770
                                     kind=constants.CONS_VNC,
1771
                                     host=vnc_bind_address,
1772
                                     port=instance.network_port,
1773
                                     display=display)
1774

    
1775
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1776
    if spice_bind:
1777
      return objects.InstanceConsole(instance=instance.name,
1778
                                     kind=constants.CONS_SPICE,
1779
                                     host=spice_bind,
1780
                                     port=instance.network_port)
1781

    
1782
    return objects.InstanceConsole(instance=instance.name,
1783
                                   kind=constants.CONS_MESSAGE,
1784
                                   message=("No serial shell for instance %s" %
1785
                                            instance.name))
1786

    
1787
  def Verify(self):
1788
    """Verify the hypervisor.
1789

1790
    Check that the binary exists.
1791

1792
    """
1793
    if not os.path.exists(constants.KVM_PATH):
1794
      return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
1795
    if not os.path.exists(constants.SOCAT_PATH):
1796
      return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
1797

    
1798
  @classmethod
1799
  def CheckParameterSyntax(cls, hvparams):
1800
    """Check the given parameters for validity.
1801

1802
    @type hvparams:  dict
1803
    @param hvparams: dictionary with parameter names/value
1804
    @raise errors.HypervisorError: when a parameter is not valid
1805

1806
    """
1807
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
1808

    
1809
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
1810
    if kernel_path:
1811
      if not hvparams[constants.HV_ROOT_PATH]:
1812
        raise errors.HypervisorError("Need a root partition for the instance,"
1813
                                     " if a kernel is defined")
1814

    
1815
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
1816
        not hvparams[constants.HV_VNC_X509]):
1817
      raise errors.HypervisorError("%s must be defined, if %s is" %
1818
                                   (constants.HV_VNC_X509,
1819
                                    constants.HV_VNC_X509_VERIFY))
1820

    
1821
    boot_order = hvparams[constants.HV_BOOT_ORDER]
1822
    if (boot_order == constants.HT_BO_CDROM and
1823
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
1824
      raise errors.HypervisorError("Cannot boot from cdrom without an"
1825
                                   " ISO path")
1826

    
1827
    security_model = hvparams[constants.HV_SECURITY_MODEL]
1828
    if security_model == constants.HT_SM_USER:
1829
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
1830
        raise errors.HypervisorError("A security domain (user to run kvm as)"
1831
                                     " must be specified")
1832
    elif (security_model == constants.HT_SM_NONE or
1833
          security_model == constants.HT_SM_POOL):
1834
      if hvparams[constants.HV_SECURITY_DOMAIN]:
1835
        raise errors.HypervisorError("Cannot have a security domain when the"
1836
                                     " security model is 'none' or 'pool'")
1837

    
1838
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1839
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
1840
    if spice_bind:
1841
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1842
        # if an IP version is specified, the spice_bind parameter must be an
1843
        # IP of that family
1844
        if (netutils.IP4Address.IsValid(spice_bind) and
1845
            spice_ip_version != constants.IP4_VERSION):
1846
          raise errors.HypervisorError("spice: got an IPv4 address (%s), but"
1847
                                       " the specified IP version is %s" %
1848
                                       (spice_bind, spice_ip_version))
1849

    
1850
        if (netutils.IP6Address.IsValid(spice_bind) and
1851
            spice_ip_version != constants.IP6_VERSION):
1852
          raise errors.HypervisorError("spice: got an IPv6 address (%s), but"
1853
                                       " the specified IP version is %s" %
1854
                                       (spice_bind, spice_ip_version))
1855
    else:
1856
      # All the other SPICE parameters depend on spice_bind being set. Raise an
1857
      # error if any of them is set without it.
1858
      spice_additional_params = frozenset([
1859
        constants.HV_KVM_SPICE_IP_VERSION,
1860
        constants.HV_KVM_SPICE_PASSWORD_FILE,
1861
        constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR,
1862
        constants.HV_KVM_SPICE_JPEG_IMG_COMPR,
1863
        constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR,
1864
        constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION,
1865
        constants.HV_KVM_SPICE_USE_TLS,
1866
        ])
1867
      for param in spice_additional_params:
1868
        if hvparams[param]:
1869
          raise errors.HypervisorError("spice: %s requires %s to be set" %
1870
                                       (param, constants.HV_KVM_SPICE_BIND))
1871

    
1872
  @classmethod
1873
  def ValidateParameters(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).ValidateParameters(hvparams)
1882

    
1883
    security_model = hvparams[constants.HV_SECURITY_MODEL]
1884
    if security_model == constants.HT_SM_USER:
1885
      username = hvparams[constants.HV_SECURITY_DOMAIN]
1886
      try:
1887
        pwd.getpwnam(username)
1888
      except KeyError:
1889
        raise errors.HypervisorError("Unknown security domain user %s"
1890
                                     % username)
1891

    
1892
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1893
    if spice_bind:
1894
      # only one of VNC and SPICE can be used currently.
1895
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
1896
        raise errors.HypervisorError("both SPICE and VNC are configured, but"
1897
                                     " only one of them can be used at a"
1898
                                     " given time.")
1899

    
1900
      # KVM version should be >= 0.14.0
1901
      _, v_major, v_min, _ = cls._GetKVMVersion()
1902
      if (v_major, v_min) < (0, 14):
1903
        raise errors.HypervisorError("spice is configured, but it is not"
1904
                                     " available in versions of KVM < 0.14")
1905

    
1906
      # if spice_bind is not an IP address, it must be a valid interface
1907
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind)
1908
                       or netutils.IP6Address.IsValid(spice_bind))
1909
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
1910
        raise errors.HypervisorError("spice: the %s parameter must be either"
1911
                                     " a valid IP address or interface name" %
1912
                                     constants.HV_KVM_SPICE_BIND)
1913

    
1914
  @classmethod
1915
  def PowercycleNode(cls):
1916
    """KVM powercycle, just a wrapper over Linux powercycle.
1917

1918
    """
1919
    cls.LinuxPowercycle()