Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ f5a4b9ce

History | View | Annotate | Download (68.4 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 StringIO
39
try:
40
  import affinity   # pylint: disable=F0401
41
except ImportError:
42
  affinity = None
43

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

    
55

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

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

    
69

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

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

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

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

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

    
101

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

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

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

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

    
119
  flags = IFF_TAP | IFF_NO_PI
120

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

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

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

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

    
136

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

140
  """
141

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

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

    
149
    self.data = data
150

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

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

159
    """
160

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

    
164
    return None
165

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

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

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

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

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

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

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

    
196

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

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

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

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

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

    
229
  def _check_connection(self):
230
    """Make sure that the connection is established.
231

232
    """
233
    if not self._connected:
234
      raise errors.ProgrammerError("To use a QmpConnection you need to first"
235
                                   " invoke connect() on it")
236

    
237
  def connect(self):
238
    """Connects to the QMP monitor.
239

240
    Connects to the UNIX socket and makes sure that we can actually send and
241
    receive data to the kvm instance via QMP.
242

243
    @raise errors.HypervisorError: when there are communication errors
244
    @raise errors.ProgrammerError: when there are data serialization errors
245

246
    """
247
    self.sock.connect(self.monitor_filename)
248
    self._connected = True
249

    
250
    # Check if we receive a correct greeting message from the server
251
    # (As per the QEMU Protocol Specification 0.1 - section 2.2)
252
    greeting = self._Recv()
253
    if not greeting[self._FIRST_MESSAGE_KEY]:
254
      self._connected = False
255
      raise errors.HypervisorError("kvm: qmp communication error (wrong"
256
                                   " server greeting")
257

    
258
    # Let's put the monitor in command mode using the qmp_capabilities
259
    # command, or else no command will be executable.
260
    # (As per the QEMU Protocol Specification 0.1 - section 4)
261
    self.Execute(self._CAPABILITIES_COMMAND)
262

    
263
  def _ParseMessage(self, buf):
264
    """Extract and parse a QMP message from the given buffer.
265

266
    Seeks for a QMP message in the given buf. If found, it parses it and
267
    returns it together with the rest of the characters in the buf.
268
    If no message is found, returns None and the whole buffer.
269

270
    @raise errors.ProgrammerError: when there are data serialization errors
271

272
    """
273
    message = None
274
    # Check if we got the message end token (CRLF, as per the QEMU Protocol
275
    # Specification 0.1 - Section 2.1.1)
276
    pos = buf.find(self._MESSAGE_END_TOKEN)
277
    if pos >= 0:
278
      try:
279
        message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
280
      except Exception, err:
281
        raise errors.ProgrammerError("QMP data serialization error: %s" % err)
282
      buf = buf[pos + 1:]
283

    
284
    return (message, buf)
285

    
286
  def _Recv(self):
287
    """Receives a message from QMP and decodes the received JSON object.
288

289
    @rtype: QmpMessage
290
    @return: the received message
291
    @raise errors.HypervisorError: when there are communication errors
292
    @raise errors.ProgrammerError: when there are data serialization errors
293

294
    """
295
    self._check_connection()
296

    
297
    # Check if there is already a message in the buffer
298
    (message, self._buf) = self._ParseMessage(self._buf)
299
    if message:
300
      return message
301

    
302
    recv_buffer = StringIO.StringIO(self._buf)
303
    recv_buffer.seek(len(self._buf))
304
    try:
305
      while True:
306
        data = self.sock.recv(4096)
307
        if not data:
308
          break
309
        recv_buffer.write(data)
310

    
311
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
312
        if message:
313
          return message
314

    
315
    except socket.timeout, err:
316
      raise errors.HypervisorError("Timeout while receiving a QMP message: "
317
                                   "%s" % (err))
318
    except socket.error, err:
319
      raise errors.HypervisorError("Unable to receive data from KVM using the"
320
                                   " QMP protocol: %s" % err)
321

    
322
  def _Send(self, message):
323
    """Encodes and sends a message to KVM using QMP.
324

325
    @type message: QmpMessage
326
    @param message: message to send to KVM
327
    @raise errors.HypervisorError: when there are communication errors
328
    @raise errors.ProgrammerError: when there are data serialization errors
329

330
    """
331
    self._check_connection()
332
    try:
333
      message_str = str(message)
334
    except Exception, err:
335
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
336

    
337
    try:
338
      self.sock.sendall(message_str)
339
    except socket.timeout, err:
340
      raise errors.HypervisorError("Timeout while sending a QMP message: "
341
                                   "%s (%s)" % (err.string, err.errno))
342
    except socket.error, err:
343
      raise errors.HypervisorError("Unable to send data from KVM using the"
344
                                   " QMP protocol: %s" % err)
345

    
346
  def Execute(self, command, arguments=None):
347
    """Executes a QMP command and returns the response of the server.
348

349
    @type command: str
350
    @param command: the command to execute
351
    @type arguments: dict
352
    @param arguments: dictionary of arguments to be passed to the command
353
    @rtype: dict
354
    @return: dictionary representing the received JSON object
355
    @raise errors.HypervisorError: when there are communication errors
356
    @raise errors.ProgrammerError: when there are data serialization errors
357

358
    """
359
    self._check_connection()
360
    message = QmpMessage({self._EXECUTE_KEY: command})
361
    if arguments:
362
      message[self._ARGUMENTS_KEY] = arguments
363
    self._Send(message)
364

    
365
    # Events can occur between the sending of the command and the reception
366
    # of the response, so we need to filter out messages with the event key.
367
    while True:
368
      response = self._Recv()
369
      err = response[self._ERROR_KEY]
370
      if err:
371
        raise errors.HypervisorError("kvm: error executing the %s"
372
                                     " command: %s (%s, %s):" %
373
                                     (command,
374
                                      err[self._ERROR_DESC_KEY],
375
                                      err[self._ERROR_CLASS_KEY],
376
                                      err[self._ERROR_DATA_KEY]))
377

    
378
      elif not response[self._EVENT_KEY]:
379
        return response
380

    
381

    
382
class KVMHypervisor(hv_base.BaseHypervisor):
383
  """KVM hypervisor interface"""
384
  CAN_MIGRATE = True
385

    
386
  _ROOT_DIR = constants.RUN_GANETI_DIR + "/kvm-hypervisor"
387
  _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
388
  _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
389
  _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
390
  _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
391
  _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
392
  _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
393
  # KVM instances with chroot enabled are started in empty chroot directories.
394
  _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
395
  # After an instance is stopped, its chroot directory is removed.
396
  # If the chroot directory is not empty, it can't be removed.
397
  # A non-empty chroot directory indicates a possible security incident.
398
  # To support forensics, the non-empty chroot directory is quarantined in
399
  # a separate directory, called 'chroot-quarantine'.
400
  _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
401
  _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
402
           _CHROOT_DIR, _CHROOT_QUARANTINE_DIR]
403

    
404
  PARAMETERS = {
405
    constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
406
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
407
    constants.HV_ROOT_PATH: hv_base.NO_CHECK,
408
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
409
    constants.HV_ACPI: hv_base.NO_CHECK,
410
    constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
411
    constants.HV_VNC_BIND_ADDRESS:
412
      (False, lambda x: (netutils.IP4Address.IsValid(x) or
413
                         utils.IsNormAbsPath(x)),
414
       "the VNC bind address must be either a valid IP address or an absolute"
415
       " pathname", None, None),
416
    constants.HV_VNC_TLS: hv_base.NO_CHECK,
417
    constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
418
    constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
419
    constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
420
    constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
421
    constants.HV_KVM_SPICE_IP_VERSION:
422
      (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
423
                         x in constants.VALID_IP_VERSIONS),
424
       "the SPICE IP version should be 4 or 6",
425
       None, None),
426
    constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
427
    constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
428
      hv_base.ParamInSet(False,
429
        constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
430
    constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
431
      hv_base.ParamInSet(False,
432
        constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
433
    constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
434
      hv_base.ParamInSet(False,
435
        constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
436
    constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
437
      hv_base.ParamInSet(False,
438
        constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
439
    constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
440
    constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
441
    constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
442
    constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
443
    constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
444
    constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
445
    constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
446
    constants.HV_BOOT_ORDER:
447
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
448
    constants.HV_NIC_TYPE:
449
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
450
    constants.HV_DISK_TYPE:
451
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
452
    constants.HV_KVM_CDROM_DISK_TYPE:
453
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
454
    constants.HV_USB_MOUSE:
455
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
456
    constants.HV_KEYMAP: hv_base.NO_CHECK,
457
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
458
    constants.HV_MIGRATION_BANDWIDTH: hv_base.NO_CHECK,
459
    constants.HV_MIGRATION_DOWNTIME: hv_base.NO_CHECK,
460
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
461
    constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
462
    constants.HV_DISK_CACHE:
463
      hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
464
    constants.HV_SECURITY_MODEL:
465
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
466
    constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
467
    constants.HV_KVM_FLAG:
468
      hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
469
    constants.HV_VHOST_NET: hv_base.NO_CHECK,
470
    constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
471
    constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
472
    constants.HV_REBOOT_BEHAVIOR:
473
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
474
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
475
    }
476

    
477
  _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
478
                                    re.M | re.I)
479
  _MIGRATION_PROGRESS_RE = re.compile(
480
      "\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
481
      "\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
482
      "\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
483

    
484
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
485
  _MIGRATION_INFO_RETRY_DELAY = 2
486

    
487
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)\.(\d+)\b")
488

    
489
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
490
  _CPU_INFO_CMD = "info cpus"
491
  _CONT_CMD = "cont"
492

    
493
  ANCILLARY_FILES = [
494
    _KVM_NETWORK_SCRIPT,
495
    ]
496
  ANCILLARY_FILES_OPT = [
497
    _KVM_NETWORK_SCRIPT,
498
    ]
499

    
500
  def __init__(self):
501
    hv_base.BaseHypervisor.__init__(self)
502
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
503
    # in a tmpfs filesystem or has been otherwise wiped out.
504
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
505
    utils.EnsureDirs(dirs)
506

    
507
  @classmethod
508
  def _InstancePidFile(cls, instance_name):
509
    """Returns the instance pidfile.
510

511
    """
512
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
513

    
514
  @classmethod
515
  def _InstanceUidFile(cls, instance_name):
516
    """Returns the instance uidfile.
517

518
    """
519
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
520

    
521
  @classmethod
522
  def _InstancePidInfo(cls, pid):
523
    """Check pid file for instance information.
524

525
    Check that a pid file is associated with an instance, and retrieve
526
    information from its command line.
527

528
    @type pid: string or int
529
    @param pid: process id of the instance to check
530
    @rtype: tuple
531
    @return: (instance_name, memory, vcpus)
532
    @raise errors.HypervisorError: when an instance cannot be found
533

534
    """
535
    alive = utils.IsProcessAlive(pid)
536
    if not alive:
537
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
538

    
539
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
540
    try:
541
      cmdline = utils.ReadFile(cmdline_file)
542
    except EnvironmentError, err:
543
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
544
                                   (pid, err))
545

    
546
    instance = None
547
    memory = 0
548
    vcpus = 0
549

    
550
    arg_list = cmdline.split("\x00")
551
    while arg_list:
552
      arg = arg_list.pop(0)
553
      if arg == "-name":
554
        instance = arg_list.pop(0)
555
      elif arg == "-m":
556
        memory = int(arg_list.pop(0))
557
      elif arg == "-smp":
558
        vcpus = int(arg_list.pop(0))
559

    
560
    if instance is None:
561
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
562
                                   " instance" % pid)
563

    
564
    return (instance, memory, vcpus)
565

    
566
  def _InstancePidAlive(self, instance_name):
567
    """Returns the instance pidfile, pid, and liveness.
568

569
    @type instance_name: string
570
    @param instance_name: instance name
571
    @rtype: tuple
572
    @return: (pid file name, pid, liveness)
573

574
    """
575
    pidfile = self._InstancePidFile(instance_name)
576
    pid = utils.ReadPidFile(pidfile)
577

    
578
    alive = False
579
    try:
580
      cmd_instance = self._InstancePidInfo(pid)[0]
581
      alive = (cmd_instance == instance_name)
582
    except errors.HypervisorError:
583
      pass
584

    
585
    return (pidfile, pid, alive)
586

    
587
  def _CheckDown(self, instance_name):
588
    """Raises an error unless the given instance is down.
589

590
    """
591
    alive = self._InstancePidAlive(instance_name)[2]
592
    if alive:
593
      raise errors.HypervisorError("Failed to start instance %s: %s" %
594
                                   (instance_name, "already running"))
595

    
596
  @classmethod
597
  def _InstanceMonitor(cls, instance_name):
598
    """Returns the instance monitor socket name
599

600
    """
601
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
602

    
603
  @classmethod
604
  def _InstanceSerial(cls, instance_name):
605
    """Returns the instance serial socket name
606

607
    """
608
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
609

    
610
  @classmethod
611
  def _InstanceQmpMonitor(cls, instance_name):
612
    """Returns the instance serial QMP socket name
613

614
    """
615
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
616

    
617
  @staticmethod
618
  def _SocatUnixConsoleParams():
619
    """Returns the correct parameters for socat
620

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

623
    """
624
    if constants.SOCAT_USE_ESCAPE:
625
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
626
    else:
627
      return "echo=0,icanon=0"
628

    
629
  @classmethod
630
  def _InstanceKVMRuntime(cls, instance_name):
631
    """Returns the instance KVM runtime filename
632

633
    """
634
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
635

    
636
  @classmethod
637
  def _InstanceChrootDir(cls, instance_name):
638
    """Returns the name of the KVM chroot dir of the instance
639

640
    """
641
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
642

    
643
  @classmethod
644
  def _InstanceNICDir(cls, instance_name):
645
    """Returns the name of the directory holding the tap device files for a
646
    given instance.
647

648
    """
649
    return utils.PathJoin(cls._NICS_DIR, instance_name)
650

    
651
  @classmethod
652
  def _InstanceNICFile(cls, instance_name, seq):
653
    """Returns the name of the file containing the tap device for a given NIC
654

655
    """
656
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
657

    
658
  @classmethod
659
  def _InstanceKeymapFile(cls, instance_name):
660
    """Returns the name of the file containing the keymap for a given instance
661

662
    """
663
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
664

    
665
  @classmethod
666
  def _TryReadUidFile(cls, uid_file):
667
    """Try to read a uid file
668

669
    """
670
    if os.path.exists(uid_file):
671
      try:
672
        uid = int(utils.ReadOneLineFile(uid_file))
673
        return uid
674
      except EnvironmentError:
675
        logging.warning("Can't read uid file", exc_info=True)
676
      except (TypeError, ValueError):
677
        logging.warning("Can't parse uid file contents", exc_info=True)
678
    return None
679

    
680
  @classmethod
681
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
682
    """Removes an instance's rutime sockets/files/dirs.
683

684
    """
685
    utils.RemoveFile(pidfile)
686
    utils.RemoveFile(cls._InstanceMonitor(instance_name))
687
    utils.RemoveFile(cls._InstanceSerial(instance_name))
688
    utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
689
    utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
690
    utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
691
    uid_file = cls._InstanceUidFile(instance_name)
692
    uid = cls._TryReadUidFile(uid_file)
693
    utils.RemoveFile(uid_file)
694
    if uid is not None:
695
      uidpool.ReleaseUid(uid)
696
    try:
697
      shutil.rmtree(cls._InstanceNICDir(instance_name))
698
    except OSError, err:
699
      if err.errno != errno.ENOENT:
700
        raise
701
    try:
702
      chroot_dir = cls._InstanceChrootDir(instance_name)
703
      utils.RemoveDir(chroot_dir)
704
    except OSError, err:
705
      if err.errno == errno.ENOTEMPTY:
706
        # The chroot directory is expected to be empty, but it isn't.
707
        new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
708
                                          prefix="%s-%s-" %
709
                                          (instance_name,
710
                                           utils.TimestampForFilename()))
711
        logging.warning("The chroot directory of instance %s can not be"
712
                        " removed as it is not empty. Moving it to the"
713
                        " quarantine instead. Please investigate the"
714
                        " contents (%s) and clean up manually",
715
                        instance_name, new_chroot_dir)
716
        utils.RenameFile(chroot_dir, new_chroot_dir)
717
      else:
718
        raise
719

    
720
  @staticmethod
721
  def _ConfigureNIC(instance, seq, nic, tap):
722
    """Run the network configuration script for a specified NIC
723

724
    @param instance: instance we're acting on
725
    @type instance: instance object
726
    @param seq: nic sequence number
727
    @type seq: int
728
    @param nic: nic we're acting on
729
    @type nic: nic object
730
    @param tap: the host's tap interface this NIC corresponds to
731
    @type tap: str
732

733
    """
734

    
735
    if instance.tags:
736
      tags = " ".join(instance.tags)
737
    else:
738
      tags = ""
739

    
740
    env = {
741
      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
742
      "INSTANCE": instance.name,
743
      "MAC": nic.mac,
744
      "MODE": nic.nicparams[constants.NIC_MODE],
745
      "INTERFACE": tap,
746
      "INTERFACE_INDEX": str(seq),
747
      "TAGS": tags,
748
    }
749

    
750
    if nic.ip:
751
      env["IP"] = nic.ip
752

    
753
    if nic.nicparams[constants.NIC_LINK]:
754
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
755

    
756
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
757
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
758

    
759
    result = utils.RunCmd([constants.KVM_IFUP, tap], env=env)
760
    if result.failed:
761
      raise errors.HypervisorError("Failed to configure interface %s: %s."
762
                                   " Network configuration script output: %s" %
763
                                   (tap, result.fail_reason, result.output))
764

    
765
  @staticmethod
766
  def _VerifyAffinityPackage():
767
    if affinity is None:
768
      raise errors.HypervisorError("affinity Python package not"
769
        " found; cannot use CPU pinning under KVM")
770

    
771
  @staticmethod
772
  def _BuildAffinityCpuMask(cpu_list):
773
    """Create a CPU mask suitable for sched_setaffinity from a list of
774
    CPUs.
775

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

779
    @type cpu_list: list of int
780
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
781
    @rtype: int
782
    @return: a bit mask of CPU affinities
783

784
    """
785
    if cpu_list == constants.CPU_PINNING_OFF:
786
      return constants.CPU_PINNING_ALL_KVM
787
    else:
788
      return sum(2 ** cpu for cpu in cpu_list)
789

    
790
  @classmethod
791
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
792
    """Change CPU affinity for running VM according to given CPU mask.
793

794
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
795
    @type cpu_mask: string
796
    @param process_id: process ID of KVM process. Used to pin entire VM
797
                       to physical CPUs.
798
    @type process_id: int
799
    @param thread_dict: map of virtual CPUs to KVM thread IDs
800
    @type thread_dict: dict int:int
801

802
    """
803

    
804
    # Convert the string CPU mask to a list of list of int's
805
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
806

    
807
    if len(cpu_list) == 1:
808
      all_cpu_mapping = cpu_list[0]
809
      if all_cpu_mapping == constants.CPU_PINNING_OFF:
810
        # If CPU pinning has 1 entry that's "all", then do nothing
811
        pass
812
      else:
813
        # If CPU pinning has one non-all entry, map the entire VM to
814
        # one set of physical CPUs
815
        cls._VerifyAffinityPackage()
816
        affinity.set_process_affinity_mask(process_id,
817
          cls._BuildAffinityCpuMask(all_cpu_mapping))
818
    else:
819
      # The number of vCPUs mapped should match the number of vCPUs
820
      # reported by KVM. This was already verified earlier, so
821
      # here only as a sanity check.
822
      assert len(thread_dict) == len(cpu_list)
823
      cls._VerifyAffinityPackage()
824

    
825
      # For each vCPU, map it to the proper list of physical CPUs
826
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
827
        affinity.set_process_affinity_mask(thread_dict[i],
828
          cls._BuildAffinityCpuMask(vcpu))
829

    
830
  def _GetVcpuThreadIds(self, instance_name):
831
    """Get a mapping of vCPU no. to thread IDs for the instance
832

833
    @type instance_name: string
834
    @param instance_name: instance in question
835
    @rtype: dictionary of int:int
836
    @return: a dictionary mapping vCPU numbers to thread IDs
837

838
    """
839
    result = {}
840
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
841
    for line in output.stdout.splitlines():
842
      match = self._CPU_INFO_RE.search(line)
843
      if not match:
844
        continue
845
      grp = map(int, match.groups())
846
      result[grp[0]] = grp[1]
847

    
848
    return result
849

    
850
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
851
    """Complete CPU pinning.
852

853
    @type instance_name: string
854
    @param instance_name: name of instance
855
    @type cpu_mask: string
856
    @param cpu_mask: CPU pinning mask as entered by user
857

858
    """
859
    # Get KVM process ID, to be used if need to pin entire VM
860
    _, pid, _ = self._InstancePidAlive(instance_name)
861
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
862
    thread_dict = self._GetVcpuThreadIds(instance_name)
863
    # Run CPU pinning, based on configured mask
864
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
865

    
866
  def ListInstances(self):
867
    """Get the list of running instances.
868

869
    We can do this by listing our live instances directory and
870
    checking whether the associated kvm process is still alive.
871

872
    """
873
    result = []
874
    for name in os.listdir(self._PIDS_DIR):
875
      if self._InstancePidAlive(name)[2]:
876
        result.append(name)
877
    return result
878

    
879
  def GetInstanceInfo(self, instance_name):
880
    """Get instance properties.
881

882
    @type instance_name: string
883
    @param instance_name: the instance name
884
    @rtype: tuple of strings
885
    @return: (name, id, memory, vcpus, stat, times)
886

887
    """
888
    _, pid, alive = self._InstancePidAlive(instance_name)
889
    if not alive:
890
      return None
891

    
892
    _, memory, vcpus = self._InstancePidInfo(pid)
893
    stat = "---b-"
894
    times = "0"
895

    
896
    return (instance_name, pid, memory, vcpus, stat, times)
897

    
898
  def GetAllInstancesInfo(self):
899
    """Get properties of all instances.
900

901
    @return: list of tuples (name, id, memory, vcpus, stat, times)
902

903
    """
904
    data = []
905
    for name in os.listdir(self._PIDS_DIR):
906
      try:
907
        info = self.GetInstanceInfo(name)
908
      except errors.HypervisorError:
909
        continue
910
      if info:
911
        data.append(info)
912
    return data
913

    
914
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused):
915
    """Generate KVM information to start an instance.
916

917
    """
918
    # pylint: disable=R0914,R0915
919
    _, v_major, v_min, _ = self._GetKVMVersion()
920

    
921
    pidfile = self._InstancePidFile(instance.name)
922
    kvm = constants.KVM_PATH
923
    kvm_cmd = [kvm]
924
    # used just by the vnc server, if enabled
925
    kvm_cmd.extend(["-name", instance.name])
926
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
927
    kvm_cmd.extend(["-smp", instance.beparams[constants.BE_VCPUS]])
928
    kvm_cmd.extend(["-pidfile", pidfile])
929
    kvm_cmd.extend(["-daemonize"])
930
    if not instance.hvparams[constants.HV_ACPI]:
931
      kvm_cmd.extend(["-no-acpi"])
932
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
933
        constants.INSTANCE_REBOOT_EXIT:
934
      kvm_cmd.extend(["-no-reboot"])
935

    
936
    hvp = instance.hvparams
937
    boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
938
    boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
939
    boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
940
    boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
941

    
942
    self.ValidateParameters(hvp)
943

    
944
    if startup_paused:
945
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
946

    
947
    if hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED:
948
      kvm_cmd.extend(["-enable-kvm"])
949
    elif hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED:
950
      kvm_cmd.extend(["-disable-kvm"])
951

    
952
    if boot_network:
953
      kvm_cmd.extend(["-boot", "n"])
954

    
955
    disk_type = hvp[constants.HV_DISK_TYPE]
956
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
957
      if_val = ",if=virtio"
958
    else:
959
      if_val = ",if=%s" % disk_type
960
    # Cache mode
961
    disk_cache = hvp[constants.HV_DISK_CACHE]
962
    if instance.disk_template in constants.DTS_EXT_MIRROR:
963
      if disk_cache != "none":
964
        # TODO: make this a hard error, instead of a silent overwrite
965
        logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
966
                        " to prevent shared storage corruption on migration",
967
                        disk_cache)
968
      cache_val = ",cache=none"
969
    elif disk_cache != constants.HT_CACHE_DEFAULT:
970
      cache_val = ",cache=%s" % disk_cache
971
    else:
972
      cache_val = ""
973
    for cfdev, dev_path in block_devices:
974
      if cfdev.mode != constants.DISK_RDWR:
975
        raise errors.HypervisorError("Instance has read-only disks which"
976
                                     " are not supported by KVM")
977
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
978
      boot_val = ""
979
      if boot_disk:
980
        kvm_cmd.extend(["-boot", "c"])
981
        boot_disk = False
982
        if (v_major, v_min) < (0, 14) and disk_type != constants.HT_DISK_IDE:
983
          boot_val = ",boot=on"
984

    
985
      drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
986
                                                cache_val)
987
      kvm_cmd.extend(["-drive", drive_val])
988

    
989
    #Now we can specify a different device type for CDROM devices.
990
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
991
    if not cdrom_disk_type:
992
      cdrom_disk_type = disk_type
993

    
994
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
995
    if iso_image:
996
      options = ",format=raw,media=cdrom"
997
      if boot_cdrom:
998
        kvm_cmd.extend(["-boot", "d"])
999
        if cdrom_disk_type != constants.HT_DISK_IDE:
1000
          options = "%s,boot=on,if=%s" % (options, constants.HT_DISK_IDE)
1001
        else:
1002
          options = "%s,boot=on" % options
1003
      else:
1004
        if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1005
          if_val = ",if=virtio"
1006
        else:
1007
          if_val = ",if=%s" % cdrom_disk_type
1008
        options = "%s%s" % (options, if_val)
1009
      drive_val = "file=%s%s" % (iso_image, options)
1010
      kvm_cmd.extend(["-drive", drive_val])
1011

    
1012
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1013
    if iso_image2:
1014
      options = ",format=raw,media=cdrom"
1015
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1016
        if_val = ",if=virtio"
1017
      else:
1018
        if_val = ",if=%s" % cdrom_disk_type
1019
      options = "%s%s" % (options, if_val)
1020
      drive_val = "file=%s%s" % (iso_image2, options)
1021
      kvm_cmd.extend(["-drive", drive_val])
1022

    
1023
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1024
    if floppy_image:
1025
      options = ",format=raw,media=disk"
1026
      if boot_floppy:
1027
        kvm_cmd.extend(["-boot", "a"])
1028
        options = "%s,boot=on" % options
1029
      if_val = ",if=floppy"
1030
      options = "%s%s" % (options, if_val)
1031
      drive_val = "file=%s%s" % (floppy_image, options)
1032
      kvm_cmd.extend(["-drive", drive_val])
1033

    
1034
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1035
    if kernel_path:
1036
      kvm_cmd.extend(["-kernel", kernel_path])
1037
      initrd_path = hvp[constants.HV_INITRD_PATH]
1038
      if initrd_path:
1039
        kvm_cmd.extend(["-initrd", initrd_path])
1040
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1041
                     hvp[constants.HV_KERNEL_ARGS]]
1042
      if hvp[constants.HV_SERIAL_CONSOLE]:
1043
        root_append.append("console=ttyS0,38400")
1044
      kvm_cmd.extend(["-append", " ".join(root_append)])
1045

    
1046
    mem_path = hvp[constants.HV_MEM_PATH]
1047
    if mem_path:
1048
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1049

    
1050
    mouse_type = hvp[constants.HV_USB_MOUSE]
1051
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1052

    
1053
    if mouse_type:
1054
      kvm_cmd.extend(["-usb"])
1055
      kvm_cmd.extend(["-usbdevice", mouse_type])
1056
    elif vnc_bind_address:
1057
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1058

    
1059
    keymap = hvp[constants.HV_KEYMAP]
1060
    if keymap:
1061
      keymap_path = self._InstanceKeymapFile(instance.name)
1062
      # If a keymap file is specified, KVM won't use its internal defaults. By
1063
      # first including the "en-us" layout, an error on loading the actual
1064
      # layout (e.g. because it can't be found) won't lead to a non-functional
1065
      # keyboard. A keyboard with incorrect keys is still better than none.
1066
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1067
      kvm_cmd.extend(["-k", keymap_path])
1068

    
1069
    if vnc_bind_address:
1070
      if netutils.IP4Address.IsValid(vnc_bind_address):
1071
        if instance.network_port > constants.VNC_BASE_PORT:
1072
          display = instance.network_port - constants.VNC_BASE_PORT
1073
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1074
            vnc_arg = ":%d" % (display)
1075
          else:
1076
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1077
        else:
1078
          logging.error("Network port is not a valid VNC display (%d < %d)."
1079
                        " Not starting VNC", instance.network_port,
1080
                        constants.VNC_BASE_PORT)
1081
          vnc_arg = "none"
1082

    
1083
        # Only allow tls and other option when not binding to a file, for now.
1084
        # kvm/qemu gets confused otherwise about the filename to use.
1085
        vnc_append = ""
1086
        if hvp[constants.HV_VNC_TLS]:
1087
          vnc_append = "%s,tls" % vnc_append
1088
          if hvp[constants.HV_VNC_X509_VERIFY]:
1089
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1090
                                               hvp[constants.HV_VNC_X509])
1091
          elif hvp[constants.HV_VNC_X509]:
1092
            vnc_append = "%s,x509=%s" % (vnc_append,
1093
                                         hvp[constants.HV_VNC_X509])
1094
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1095
          vnc_append = "%s,password" % vnc_append
1096

    
1097
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1098

    
1099
      else:
1100
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1101

    
1102
      kvm_cmd.extend(["-vnc", vnc_arg])
1103
    else:
1104
      kvm_cmd.extend(["-nographic"])
1105

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

    
1116
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1117
    spice_ip_version = None
1118
    if spice_bind:
1119
      if netutils.IsValidInterface(spice_bind):
1120
        # The user specified a network interface, we have to figure out the IP
1121
        # address.
1122
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1123
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1124

    
1125
        # if the user specified an IP version and the interface does not
1126
        # have that kind of IP addresses, throw an exception
1127
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1128
          if not addresses[spice_ip_version]:
1129
            raise errors.HypervisorError("spice: unable to get an IPv%s address"
1130
                                         " for %s" % (spice_ip_version,
1131
                                                      spice_bind))
1132

    
1133
        # the user did not specify an IP version, we have to figure it out
1134
        elif (addresses[constants.IP4_VERSION] and
1135
              addresses[constants.IP6_VERSION]):
1136
          # we have both ipv4 and ipv6, let's use the cluster default IP
1137
          # version
1138
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1139
          spice_ip_version = netutils.IPAddress.GetVersionFromAddressFamily(
1140
              cluster_family)
1141
        elif addresses[constants.IP4_VERSION]:
1142
          spice_ip_version = constants.IP4_VERSION
1143
        elif addresses[constants.IP6_VERSION]:
1144
          spice_ip_version = constants.IP6_VERSION
1145
        else:
1146
          raise errors.HypervisorError("spice: unable to get an IP address"
1147
                                       " for %s" % (spice_bind))
1148

    
1149
        spice_address = addresses[spice_ip_version][0]
1150

    
1151
      else:
1152
        # spice_bind is known to be a valid IP address, because
1153
        # ValidateParameters checked it.
1154
        spice_address = spice_bind
1155

    
1156
      spice_arg = "addr=%s" % spice_address
1157
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1158
        spice_arg = "%s,tls-port=%s,x509-cacert-file=%s" % (spice_arg,
1159
            instance.network_port, constants.SPICE_CACERT_FILE)
1160
        spice_arg = "%s,x509-key-file=%s,x509-cert-file=%s" % (spice_arg,
1161
            constants.SPICE_CERT_FILE, constants.SPICE_CERT_FILE)
1162
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1163
        if tls_ciphers:
1164
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1165
      else:
1166
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1167

    
1168
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1169
        spice_arg = "%s,disable-ticketing" % spice_arg
1170

    
1171
      if spice_ip_version:
1172
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1173

    
1174
      # Image compression options
1175
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1176
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1177
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1178
      if img_lossless:
1179
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1180
      if img_jpeg:
1181
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1182
      if img_zlib_glz:
1183
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1184

    
1185
      # Video stream detection
1186
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1187
      if video_streaming:
1188
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1189

    
1190
      # Audio compression, by default in qemu-kvm it is on
1191
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1192
        spice_arg = "%s,playback-compression=off" % spice_arg
1193
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1194
        spice_arg = "%s,agent-mouse=off" % spice_arg
1195

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

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

    
1202
    if hvp[constants.HV_USE_LOCALTIME]:
1203
      kvm_cmd.extend(["-localtime"])
1204

    
1205
    if hvp[constants.HV_KVM_USE_CHROOT]:
1206
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1207

    
1208
    # Save the current instance nics, but defer their expansion as parameters,
1209
    # as we'll need to generate executable temp files for them.
1210
    kvm_nics = instance.nics
1211
    hvparams = hvp
1212

    
1213
    return (kvm_cmd, kvm_nics, hvparams)
1214

    
1215
  def _WriteKVMRuntime(self, instance_name, data):
1216
    """Write an instance's KVM runtime
1217

1218
    """
1219
    try:
1220
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1221
                      data=data)
1222
    except EnvironmentError, err:
1223
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1224

    
1225
  def _ReadKVMRuntime(self, instance_name):
1226
    """Read an instance's KVM runtime
1227

1228
    """
1229
    try:
1230
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1231
    except EnvironmentError, err:
1232
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1233
    return file_content
1234

    
1235
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1236
    """Save an instance's KVM runtime
1237

1238
    """
1239
    kvm_cmd, kvm_nics, hvparams = kvm_runtime
1240
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1241
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1242
    self._WriteKVMRuntime(instance.name, serialized_form)
1243

    
1244
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1245
    """Load an instance's KVM runtime
1246

1247
    """
1248
    if not serialized_runtime:
1249
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1250
    loaded_runtime = serializer.Load(serialized_runtime)
1251
    kvm_cmd, serialized_nics, hvparams = loaded_runtime
1252
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1253
    return (kvm_cmd, kvm_nics, hvparams)
1254

    
1255
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1256
    """Run the KVM cmd and check for errors
1257

1258
    @type name: string
1259
    @param name: instance name
1260
    @type kvm_cmd: list of strings
1261
    @param kvm_cmd: runcmd input for kvm
1262
    @type tap_fds: list of int
1263
    @param tap_fds: fds of tap devices opened by Ganeti
1264

1265
    """
1266
    try:
1267
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1268
    finally:
1269
      for fd in tap_fds:
1270
        utils_wrapper.CloseFdNoError(fd)
1271

    
1272
    if result.failed:
1273
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1274
                                   (name, result.fail_reason, result.output))
1275
    if not self._InstancePidAlive(name)[2]:
1276
      raise errors.HypervisorError("Failed to start instance %s" % name)
1277

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

1281
    @type incoming: tuple of strings
1282
    @param incoming: (target_host_ip, port)
1283

1284
    """
1285
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1286
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1287
    #    have changed since the instance started; only use them if the change
1288
    #    won't affect the inside of the instance (which hasn't been rebooted).
1289
    #  - up_hvp contains the parameters as they were when the instance was
1290
    #    started, plus any new parameter which has been added between ganeti
1291
    #    versions: it is paramount that those default to a value which won't
1292
    #    affect the inside of the instance as well.
1293
    conf_hvp = instance.hvparams
1294
    name = instance.name
1295
    self._CheckDown(name)
1296

    
1297
    temp_files = []
1298

    
1299
    kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1300
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1301

    
1302
    _, v_major, v_min, _ = self._GetKVMVersion()
1303

    
1304
    # We know it's safe to run as a different user upon migration, so we'll use
1305
    # the latest conf, from conf_hvp.
1306
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1307
    if security_model == constants.HT_SM_USER:
1308
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1309

    
1310
    # We have reasons to believe changing something like the nic driver/type
1311
    # upon migration won't exactly fly with the instance kernel, so for nic
1312
    # related parameters we'll use up_hvp
1313
    tapfds = []
1314
    taps = []
1315
    if not kvm_nics:
1316
      kvm_cmd.extend(["-net", "none"])
1317
    else:
1318
      vnet_hdr = False
1319
      tap_extra = ""
1320
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1321
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1322
        # From version 0.12.0, kvm uses a new sintax for network configuration.
1323
        if (v_major, v_min) >= (0, 12):
1324
          nic_model = "virtio-net-pci"
1325
          vnet_hdr = True
1326
        else:
1327
          nic_model = "virtio"
1328

    
1329
        if up_hvp[constants.HV_VHOST_NET]:
1330
          # vhost_net is only available from version 0.13.0 or newer
1331
          if (v_major, v_min) >= (0, 13):
1332
            tap_extra = ",vhost=on"
1333
          else:
1334
            raise errors.HypervisorError("vhost_net is configured"
1335
                                        " but it is not available")
1336
      else:
1337
        nic_model = nic_type
1338

    
1339
      for nic_seq, nic in enumerate(kvm_nics):
1340
        tapname, tapfd = _OpenTap(vnet_hdr)
1341
        tapfds.append(tapfd)
1342
        taps.append(tapname)
1343
        if (v_major, v_min) >= (0, 12):
1344
          nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1345
          tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1346
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1347
        else:
1348
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1349
                                                         nic.mac, nic_model)
1350
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1351
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1352

    
1353
    if incoming:
1354
      target, port = incoming
1355
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1356

    
1357
    # Changing the vnc password doesn't bother the guest that much. At most it
1358
    # will surprise people who connect to it. Whether positively or negatively
1359
    # it's debatable.
1360
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1361
    vnc_pwd = None
1362
    if vnc_pwd_file:
1363
      try:
1364
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1365
      except EnvironmentError, err:
1366
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1367
                                     % (vnc_pwd_file, err))
1368

    
1369
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1370
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1371
                         constants.SECURE_DIR_MODE)])
1372

    
1373
    # Automatically enable QMP if version is >= 0.14
1374
    if (v_major, v_min) >= (0, 14):
1375
      logging.debug("Enabling QMP")
1376
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1377
                    self._InstanceQmpMonitor(instance.name)])
1378

    
1379
    # Configure the network now for starting instances and bridged interfaces,
1380
    # during FinalizeMigration for incoming instances' routed interfaces
1381
    for nic_seq, nic in enumerate(kvm_nics):
1382
      if (incoming and
1383
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1384
        continue
1385
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1386

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

    
1392
    # Note: CPU pinning is using up_hvp since changes take effect
1393
    # during instance startup anyway, and to avoid problems when soft
1394
    # rebooting the instance.
1395
    cpu_pinning = False
1396
    if up_hvp.get(constants.HV_CPU_MASK, None):
1397
      cpu_pinning = True
1398
      if start_kvm_paused:
1399
        kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1400

    
1401
    if security_model == constants.HT_SM_POOL:
1402
      ss = ssconf.SimpleStore()
1403
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1404
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1405
      uid = uidpool.RequestUnusedUid(all_uids)
1406
      try:
1407
        username = pwd.getpwuid(uid.GetUid()).pw_name
1408
        kvm_cmd.extend(["-runas", username])
1409
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1410
      except:
1411
        uidpool.ReleaseUid(uid)
1412
        raise
1413
      else:
1414
        uid.Unlock()
1415
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1416
    else:
1417
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1418

    
1419
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1420
                     constants.RUN_DIRS_MODE)])
1421
    for nic_seq, tap in enumerate(taps):
1422
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1423
                      data=tap)
1424

    
1425
    if vnc_pwd:
1426
      change_cmd = "change vnc password %s" % vnc_pwd
1427
      self._CallMonitorCommand(instance.name, change_cmd)
1428

    
1429
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1430
    # connection attempts because SPICE by default does not allow connections
1431
    # if neither a password nor the "disable_ticketing" options are specified.
1432
    # As soon as we send the password via QMP, that password is a valid ticket
1433
    # for connection.
1434
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1435
    if spice_password_file:
1436
      try:
1437
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1438
        qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1439
        qmp.connect()
1440
        arguments = {
1441
            "protocol": "spice",
1442
            "password": spice_pwd,
1443
        }
1444
        qmp.Execute("set_password", arguments)
1445
      except EnvironmentError, err:
1446
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1447
                                     % (spice_password_file, err))
1448

    
1449
    for filename in temp_files:
1450
      utils.RemoveFile(filename)
1451

    
1452
    # If requested, set CPU affinity and resume instance execution
1453
    if cpu_pinning:
1454
      try:
1455
        self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1456
      finally:
1457
        if start_kvm_paused:
1458
          # To control CPU pinning, the VM was started frozen, so we need
1459
          # to resume its execution, but only if freezing was not
1460
          # explicitly requested.
1461
          # Note: this is done even when an exception occurred so the VM
1462
          # is not unintentionally frozen.
1463
          self._CallMonitorCommand(instance.name, self._CONT_CMD)
1464

    
1465
  def StartInstance(self, instance, block_devices, startup_paused):
1466
    """Start an instance.
1467

1468
    """
1469
    self._CheckDown(instance.name)
1470
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1471
                                           startup_paused)
1472
    self._SaveKVMRuntime(instance, kvm_runtime)
1473
    self._ExecuteKVMRuntime(instance, kvm_runtime)
1474

    
1475
  def _CallMonitorCommand(self, instance_name, command):
1476
    """Invoke a command on the instance monitor.
1477

1478
    """
1479
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1480
             (utils.ShellQuote(command),
1481
              constants.SOCAT_PATH,
1482
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1483
    result = utils.RunCmd(socat)
1484
    if result.failed:
1485
      msg = ("Failed to send command '%s' to instance %s."
1486
             " output: %s, error: %s, fail_reason: %s" %
1487
             (command, instance_name,
1488
              result.stdout, result.stderr, result.fail_reason))
1489
      raise errors.HypervisorError(msg)
1490

    
1491
    return result
1492

    
1493
  @classmethod
1494
  def _GetKVMVersion(cls):
1495
    """Return the installed KVM version.
1496

1497
    @return: (version, v_maj, v_min, v_rev)
1498
    @raise L{errors.HypervisorError}: when the KVM version cannot be retrieved
1499

1500
    """
1501
    result = utils.RunCmd([constants.KVM_PATH, "--help"])
1502
    if result.failed:
1503
      raise errors.HypervisorError("Unable to get KVM version")
1504
    match = cls._VERSION_RE.search(result.output.splitlines()[0])
1505
    if not match:
1506
      raise errors.HypervisorError("Unable to get KVM version")
1507

    
1508
    return (match.group(0), int(match.group(1)), int(match.group(2)),
1509
            int(match.group(3)))
1510

    
1511
  def StopInstance(self, instance, force=False, retry=False, name=None):
1512
    """Stop an instance.
1513

1514
    """
1515
    if name is not None and not force:
1516
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1517
    if name is None:
1518
      name = instance.name
1519
      acpi = instance.hvparams[constants.HV_ACPI]
1520
    else:
1521
      acpi = False
1522
    _, pid, alive = self._InstancePidAlive(name)
1523
    if pid > 0 and alive:
1524
      if force or not acpi:
1525
        utils.KillProcess(pid)
1526
      else:
1527
        self._CallMonitorCommand(name, "system_powerdown")
1528

    
1529
  def CleanupInstance(self, instance_name):
1530
    """Cleanup after a stopped instance
1531

1532
    """
1533
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
1534
    if pid > 0 and alive:
1535
      raise errors.HypervisorError("Cannot cleanup a live instance")
1536
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1537

    
1538
  def RebootInstance(self, instance):
1539
    """Reboot an instance.
1540

1541
    """
1542
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1543
    # socket the instance will stop, but now power up again. So we'll resort
1544
    # to shutdown and restart.
1545
    _, _, alive = self._InstancePidAlive(instance.name)
1546
    if not alive:
1547
      raise errors.HypervisorError("Failed to reboot instance %s:"
1548
                                   " not running" % instance.name)
1549
    # StopInstance will delete the saved KVM runtime so:
1550
    # ...first load it...
1551
    kvm_runtime = self._LoadKVMRuntime(instance)
1552
    # ...now we can safely call StopInstance...
1553
    if not self.StopInstance(instance):
1554
      self.StopInstance(instance, force=True)
1555
    # ...and finally we can save it again, and execute it...
1556
    self._SaveKVMRuntime(instance, kvm_runtime)
1557
    self._ExecuteKVMRuntime(instance, kvm_runtime)
1558

    
1559
  def MigrationInfo(self, instance):
1560
    """Get instance information to perform a migration.
1561

1562
    @type instance: L{objects.Instance}
1563
    @param instance: instance to be migrated
1564
    @rtype: string
1565
    @return: content of the KVM runtime file
1566

1567
    """
1568
    return self._ReadKVMRuntime(instance.name)
1569

    
1570
  def AcceptInstance(self, instance, info, target):
1571
    """Prepare to accept an instance.
1572

1573
    @type instance: L{objects.Instance}
1574
    @param instance: instance to be accepted
1575
    @type info: string
1576
    @param info: content of the KVM runtime file on the source node
1577
    @type target: string
1578
    @param target: target host (usually ip), on this node
1579

1580
    """
1581
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1582
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1583
    self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
1584

    
1585
  def FinalizeMigrationDst(self, instance, info, success):
1586
    """Finalize the instance migration on the target node.
1587

1588
    Stop the incoming mode KVM.
1589

1590
    @type instance: L{objects.Instance}
1591
    @param instance: instance whose migration is being finalized
1592

1593
    """
1594
    if success:
1595
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1596
      kvm_nics = kvm_runtime[1]
1597

    
1598
      for nic_seq, nic in enumerate(kvm_nics):
1599
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1600
          # Bridged interfaces have already been configured
1601
          continue
1602
        try:
1603
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1604
        except EnvironmentError, err:
1605
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
1606
                          instance.name, nic_seq, str(err))
1607
          continue
1608
        try:
1609
          self._ConfigureNIC(instance, nic_seq, nic, tap)
1610
        except errors.HypervisorError, err:
1611
          logging.warning(str(err))
1612

    
1613
      self._WriteKVMRuntime(instance.name, info)
1614
    else:
1615
      self.StopInstance(instance, force=True)
1616

    
1617
  def MigrateInstance(self, instance, target, live):
1618
    """Migrate an instance to a target node.
1619

1620
    The migration will not be attempted if the instance is not
1621
    currently running.
1622

1623
    @type instance: L{objects.Instance}
1624
    @param instance: the instance to be migrated
1625
    @type target: string
1626
    @param target: ip address of the target node
1627
    @type live: boolean
1628
    @param live: perform a live migration
1629

1630
    """
1631
    instance_name = instance.name
1632
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
1633
    _, _, alive = self._InstancePidAlive(instance_name)
1634
    if not alive:
1635
      raise errors.HypervisorError("Instance not running, cannot migrate")
1636

    
1637
    if not live:
1638
      self._CallMonitorCommand(instance_name, "stop")
1639

    
1640
    migrate_command = ("migrate_set_speed %dm" %
1641
        instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1642
    self._CallMonitorCommand(instance_name, migrate_command)
1643

    
1644
    migrate_command = ("migrate_set_downtime %dms" %
1645
        instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1646
    self._CallMonitorCommand(instance_name, migrate_command)
1647

    
1648
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1649
    self._CallMonitorCommand(instance_name, migrate_command)
1650

    
1651
  def FinalizeMigrationSource(self, instance, success, live):
1652
    """Finalize the instance migration on the source node.
1653

1654
    @type instance: L{objects.Instance}
1655
    @param instance: the instance that was migrated
1656
    @type success: bool
1657
    @param success: whether the migration succeeded or not
1658
    @type live: bool
1659
    @param live: whether the user requested a live migration or not
1660

1661
    """
1662
    if success:
1663
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
1664
      utils.KillProcess(pid)
1665
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1666
    elif live:
1667
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1668

    
1669
  def GetMigrationStatus(self, instance):
1670
    """Get the migration status
1671

1672
    @type instance: L{objects.Instance}
1673
    @param instance: the instance that is being migrated
1674
    @rtype: L{objects.MigrationStatus}
1675
    @return: the status of the current migration (one of
1676
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1677
             progress info that can be retrieved from the hypervisor
1678

1679
    """
1680
    info_command = "info migrate"
1681
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
1682
      result = self._CallMonitorCommand(instance.name, info_command)
1683
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
1684
      if not match:
1685
        if not result.stdout:
1686
          logging.info("KVM: empty 'info migrate' result")
1687
        else:
1688
          logging.warning("KVM: unknown 'info migrate' result: %s",
1689
                          result.stdout)
1690
      else:
1691
        status = match.group(1)
1692
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
1693
          migration_status = objects.MigrationStatus(status=status)
1694
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
1695
          if match:
1696
            migration_status.transferred_ram = match.group("transferred")
1697
            migration_status.total_ram = match.group("total")
1698

    
1699
          return migration_status
1700

    
1701
        logging.warning("KVM: unknown migration status '%s'", status)
1702

    
1703
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1704

    
1705
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED,
1706
                                  info="Too many 'info migrate' broken answers")
1707

    
1708
  def GetNodeInfo(self):
1709
    """Return information about the node.
1710

1711
    @return: a dict with the following keys (values in MiB):
1712
          - memory_total: the total memory size on the node
1713
          - memory_free: the available memory on the node for instances
1714
          - memory_dom0: the memory used by the node itself, if available
1715
          - hv_version: the hypervisor version in the form (major, minor,
1716
                        revision)
1717

1718
    """
1719
    result = self.GetLinuxNodeInfo()
1720
    _, v_major, v_min, v_rev = self._GetKVMVersion()
1721
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
1722
    return result
1723

    
1724
  @classmethod
1725
  def GetInstanceConsole(cls, instance, hvparams, beparams):
1726
    """Return a command for connecting to the console of an instance.
1727

1728
    """
1729
    if hvparams[constants.HV_SERIAL_CONSOLE]:
1730
      cmd = [constants.KVM_CONSOLE_WRAPPER,
1731
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1732
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1733
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
1734
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1735
      return objects.InstanceConsole(instance=instance.name,
1736
                                     kind=constants.CONS_SSH,
1737
                                     host=instance.primary_node,
1738
                                     user=constants.GANETI_RUNAS,
1739
                                     command=cmd)
1740

    
1741
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1742
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1743
      display = instance.network_port - constants.VNC_BASE_PORT
1744
      return objects.InstanceConsole(instance=instance.name,
1745
                                     kind=constants.CONS_VNC,
1746
                                     host=vnc_bind_address,
1747
                                     port=instance.network_port,
1748
                                     display=display)
1749

    
1750
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1751
    if spice_bind:
1752
      return objects.InstanceConsole(instance=instance.name,
1753
                                     kind=constants.CONS_SPICE,
1754
                                     host=spice_bind,
1755
                                     port=instance.network_port)
1756

    
1757
    return objects.InstanceConsole(instance=instance.name,
1758
                                   kind=constants.CONS_MESSAGE,
1759
                                   message=("No serial shell for instance %s" %
1760
                                            instance.name))
1761

    
1762
  def Verify(self):
1763
    """Verify the hypervisor.
1764

1765
    Check that the binary exists.
1766

1767
    """
1768
    if not os.path.exists(constants.KVM_PATH):
1769
      return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
1770
    if not os.path.exists(constants.SOCAT_PATH):
1771
      return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
1772

    
1773
  @classmethod
1774
  def CheckParameterSyntax(cls, hvparams):
1775
    """Check the given parameters for validity.
1776

1777
    @type hvparams:  dict
1778
    @param hvparams: dictionary with parameter names/value
1779
    @raise errors.HypervisorError: when a parameter is not valid
1780

1781
    """
1782
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
1783

    
1784
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
1785
    if kernel_path:
1786
      if not hvparams[constants.HV_ROOT_PATH]:
1787
        raise errors.HypervisorError("Need a root partition for the instance,"
1788
                                     " if a kernel is defined")
1789

    
1790
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
1791
        not hvparams[constants.HV_VNC_X509]):
1792
      raise errors.HypervisorError("%s must be defined, if %s is" %
1793
                                   (constants.HV_VNC_X509,
1794
                                    constants.HV_VNC_X509_VERIFY))
1795

    
1796
    boot_order = hvparams[constants.HV_BOOT_ORDER]
1797
    if (boot_order == constants.HT_BO_CDROM and
1798
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
1799
      raise errors.HypervisorError("Cannot boot from cdrom without an"
1800
                                   " ISO path")
1801

    
1802
    security_model = hvparams[constants.HV_SECURITY_MODEL]
1803
    if security_model == constants.HT_SM_USER:
1804
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
1805
        raise errors.HypervisorError("A security domain (user to run kvm as)"
1806
                                     " must be specified")
1807
    elif (security_model == constants.HT_SM_NONE or
1808
          security_model == constants.HT_SM_POOL):
1809
      if hvparams[constants.HV_SECURITY_DOMAIN]:
1810
        raise errors.HypervisorError("Cannot have a security domain when the"
1811
                                     " security model is 'none' or 'pool'")
1812

    
1813
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1814
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
1815
    if spice_bind:
1816
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1817
        # if an IP version is specified, the spice_bind parameter must be an
1818
        # IP of that family
1819
        if (netutils.IP4Address.IsValid(spice_bind) and
1820
            spice_ip_version != constants.IP4_VERSION):
1821
          raise errors.HypervisorError("spice: got an IPv4 address (%s), but"
1822
                                       " the specified IP version is %s" %
1823
                                       (spice_bind, spice_ip_version))
1824

    
1825
        if (netutils.IP6Address.IsValid(spice_bind) and
1826
            spice_ip_version != constants.IP6_VERSION):
1827
          raise errors.HypervisorError("spice: got an IPv6 address (%s), but"
1828
                                       " the specified IP version is %s" %
1829
                                       (spice_bind, spice_ip_version))
1830
    else:
1831
      # All the other SPICE parameters depend on spice_bind being set. Raise an
1832
      # error if any of them is set without it.
1833
      spice_additional_params = frozenset([
1834
        constants.HV_KVM_SPICE_IP_VERSION,
1835
        constants.HV_KVM_SPICE_PASSWORD_FILE,
1836
        constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR,
1837
        constants.HV_KVM_SPICE_JPEG_IMG_COMPR,
1838
        constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR,
1839
        constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION,
1840
        constants.HV_KVM_SPICE_USE_TLS,
1841
        ])
1842
      for param in spice_additional_params:
1843
        if hvparams[param]:
1844
          raise errors.HypervisorError("spice: %s requires %s to be set" %
1845
                                       (param, constants.HV_KVM_SPICE_BIND))
1846

    
1847
  @classmethod
1848
  def ValidateParameters(cls, hvparams):
1849
    """Check the given parameters for validity.
1850

1851
    @type hvparams:  dict
1852
    @param hvparams: dictionary with parameter names/value
1853
    @raise errors.HypervisorError: when a parameter is not valid
1854

1855
    """
1856
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
1857

    
1858
    security_model = hvparams[constants.HV_SECURITY_MODEL]
1859
    if security_model == constants.HT_SM_USER:
1860
      username = hvparams[constants.HV_SECURITY_DOMAIN]
1861
      try:
1862
        pwd.getpwnam(username)
1863
      except KeyError:
1864
        raise errors.HypervisorError("Unknown security domain user %s"
1865
                                     % username)
1866

    
1867
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1868
    if spice_bind:
1869
      # only one of VNC and SPICE can be used currently.
1870
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
1871
        raise errors.HypervisorError("both SPICE and VNC are configured, but"
1872
                                     " only one of them can be used at a"
1873
                                     " given time.")
1874

    
1875
      # KVM version should be >= 0.14.0
1876
      _, v_major, v_min, _ = cls._GetKVMVersion()
1877
      if (v_major, v_min) < (0, 14):
1878
        raise errors.HypervisorError("spice is configured, but it is not"
1879
                                     " available in versions of KVM < 0.14")
1880

    
1881
      # if spice_bind is not an IP address, it must be a valid interface
1882
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind)
1883
                       or netutils.IP6Address.IsValid(spice_bind))
1884
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
1885
        raise errors.HypervisorError("spice: the %s parameter must be either"
1886
                                     " a valid IP address or interface name" %
1887
                                     constants.HV_KVM_SPICE_BIND)
1888

    
1889
  @classmethod
1890
  def PowercycleNode(cls):
1891
    """KVM powercycle, just a wrapper over Linux powercycle.
1892

1893
    """
1894
    cls.LinuxPowercycle()