Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ cbe4a0a5

History | View | Annotate | Download (72.8 kB)

1
#
2
#
3

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

    
21

    
22
"""KVM hypervisor
23

24
"""
25

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

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

    
57

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

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

    
71

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

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

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

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

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

    
103

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

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

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

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

    
121
  flags = IFF_TAP | IFF_NO_PI
122

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

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

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

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

    
138

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

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

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

    
150
    self.data = data
151

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

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

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

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

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

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

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

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

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

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

    
192

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

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

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

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

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

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

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

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

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

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

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

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

    
261
    self._check_socket()
262

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

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

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

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

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

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

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

    
304
    return (message, buf)
305

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

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

314
    """
315
    self._check_connection()
316

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

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

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

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

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

345
    @type message: QmpMessage
346
    @param message: message to send to KVM
347
    @raise errors.HypervisorError: when there are communication errors
348
    @raise errors.ProgrammerError: when there are data serialization errors
349

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

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

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

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

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

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

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

    
401

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

405
  """
406
  CAN_MIGRATE = True
407

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

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

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

    
507
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
508
  _MIGRATION_INFO_RETRY_DELAY = 2
509

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
587
    return (instance, memory, vcpus)
588

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

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

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

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

    
608
    return (pidfile, pid, alive)
609

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
778
    def _BuildNetworkEnv(name, network, gateway, network6, gateway6,
779
                         network_type, mac_prefix, tags, env):
780
      if name:
781
        env["NETWORK_NAME"] = name
782
      if network:
783
        env["NETWORK_SUBNET"] = network
784
      if gateway:
785
        env["NETWORK_GATEWAY"] = gateway
786
      if network6:
787
        env["NETWORK_SUBNET6"] = network6
788
      if gateway6:
789
        env["NETWORK_GATEWAY6"] = gateway6
790
      if mac_prefix:
791
        env["NETWORK_MAC_PREFIX"] = mac_prefix
792
      if network_type:
793
        env["NETWORK_TYPE"] = network_type
794
      if tags:
795
        env["NETWORK_TAGS"] = " ".join(tags)
796

    
797
      return env
798

    
799

    
800
    if nic.network:
801
      n = objects.Network.FromDict(nic.netinfo)
802
      _BuildNetworkEnv(nic.network, n.network, n.gateway,
803
                       n.network6, n.gateway6, n.network_type,
804
                       n.mac_prefix, n.tags, env)
805

    
806
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
807
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
808

    
809
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
810
    if result.failed:
811
      raise errors.HypervisorError("Failed to configure interface %s: %s."
812
                                   " Network configuration script output: %s" %
813
                                   (tap, result.fail_reason, result.output))
814

    
815
  @staticmethod
816
  def _VerifyAffinityPackage():
817
    if affinity is None:
818
      raise errors.HypervisorError("affinity Python package not"
819
                                   " found; cannot use CPU pinning under KVM")
820

    
821
  @staticmethod
822
  def _BuildAffinityCpuMask(cpu_list):
823
    """Create a CPU mask suitable for sched_setaffinity from a list of
824
    CPUs.
825

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

829
    @type cpu_list: list of int
830
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
831
    @rtype: int
832
    @return: a bit mask of CPU affinities
833

834
    """
835
    if cpu_list == constants.CPU_PINNING_OFF:
836
      return constants.CPU_PINNING_ALL_KVM
837
    else:
838
      return sum(2 ** cpu for cpu in cpu_list)
839

    
840
  @classmethod
841
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
842
    """Change CPU affinity for running VM according to given CPU mask.
843

844
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
845
    @type cpu_mask: string
846
    @param process_id: process ID of KVM process. Used to pin entire VM
847
                       to physical CPUs.
848
    @type process_id: int
849
    @param thread_dict: map of virtual CPUs to KVM thread IDs
850
    @type thread_dict: dict int:int
851

852
    """
853
    # Convert the string CPU mask to a list of list of int's
854
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
855

    
856
    if len(cpu_list) == 1:
857
      all_cpu_mapping = cpu_list[0]
858
      if all_cpu_mapping == constants.CPU_PINNING_OFF:
859
        # If CPU pinning has 1 entry that's "all", then do nothing
860
        pass
861
      else:
862
        # If CPU pinning has one non-all entry, map the entire VM to
863
        # one set of physical CPUs
864
        cls._VerifyAffinityPackage()
865
        affinity.set_process_affinity_mask(
866
          process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
867
    else:
868
      # The number of vCPUs mapped should match the number of vCPUs
869
      # reported by KVM. This was already verified earlier, so
870
      # here only as a sanity check.
871
      assert len(thread_dict) == len(cpu_list)
872
      cls._VerifyAffinityPackage()
873

    
874
      # For each vCPU, map it to the proper list of physical CPUs
875
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
876
        affinity.set_process_affinity_mask(thread_dict[i],
877
                                           cls._BuildAffinityCpuMask(vcpu))
878

    
879
  def _GetVcpuThreadIds(self, instance_name):
880
    """Get a mapping of vCPU no. to thread IDs for the instance
881

882
    @type instance_name: string
883
    @param instance_name: instance in question
884
    @rtype: dictionary of int:int
885
    @return: a dictionary mapping vCPU numbers to thread IDs
886

887
    """
888
    result = {}
889
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
890
    for line in output.stdout.splitlines():
891
      match = self._CPU_INFO_RE.search(line)
892
      if not match:
893
        continue
894
      grp = map(int, match.groups())
895
      result[grp[0]] = grp[1]
896

    
897
    return result
898

    
899
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
900
    """Complete CPU pinning.
901

902
    @type instance_name: string
903
    @param instance_name: name of instance
904
    @type cpu_mask: string
905
    @param cpu_mask: CPU pinning mask as entered by user
906

907
    """
908
    # Get KVM process ID, to be used if need to pin entire VM
909
    _, pid, _ = self._InstancePidAlive(instance_name)
910
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
911
    thread_dict = self._GetVcpuThreadIds(instance_name)
912
    # Run CPU pinning, based on configured mask
913
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
914

    
915
  def ListInstances(self):
916
    """Get the list of running instances.
917

918
    We can do this by listing our live instances directory and
919
    checking whether the associated kvm process is still alive.
920

921
    """
922
    result = []
923
    for name in os.listdir(self._PIDS_DIR):
924
      if self._InstancePidAlive(name)[2]:
925
        result.append(name)
926
    return result
927

    
928
  def GetInstanceInfo(self, instance_name):
929
    """Get instance properties.
930

931
    @type instance_name: string
932
    @param instance_name: the instance name
933
    @rtype: tuple of strings
934
    @return: (name, id, memory, vcpus, stat, times)
935

936
    """
937
    _, pid, alive = self._InstancePidAlive(instance_name)
938
    if not alive:
939
      return None
940

    
941
    _, memory, vcpus = self._InstancePidInfo(pid)
942
    istat = "---b-"
943
    times = "0"
944

    
945
    try:
946
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
947
      qmp.connect()
948
      vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
949
      # Will fail if ballooning is not enabled, but we can then just resort to
950
      # the value above.
951
      mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
952
      memory = mem_bytes / 1048576
953
    except errors.HypervisorError:
954
      pass
955

    
956
    return (instance_name, pid, memory, vcpus, istat, times)
957

    
958
  def GetAllInstancesInfo(self):
959
    """Get properties of all instances.
960

961
    @return: list of tuples (name, id, memory, vcpus, stat, times)
962

963
    """
964
    data = []
965
    for name in os.listdir(self._PIDS_DIR):
966
      try:
967
        info = self.GetInstanceInfo(name)
968
      except errors.HypervisorError:
969
        # Ignore exceptions due to instances being shut down
970
        continue
971
      if info:
972
        data.append(info)
973
    return data
974

    
975
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused):
976
    """Generate KVM information to start an instance.
977

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

985
    """
986
    # pylint: disable=R0914,R0915
987
    _, v_major, v_min, _ = self._GetKVMVersion()
988

    
989
    pidfile = self._InstancePidFile(instance.name)
990
    kvm = constants.KVM_PATH
991
    kvm_cmd = [kvm]
992
    # used just by the vnc server, if enabled
993
    kvm_cmd.extend(["-name", instance.name])
994
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
995
    kvm_cmd.extend(["-smp", instance.beparams[constants.BE_VCPUS]])
996
    kvm_cmd.extend(["-pidfile", pidfile])
997
    kvm_cmd.extend(["-balloon", "virtio"])
998
    kvm_cmd.extend(["-daemonize"])
999
    if not instance.hvparams[constants.HV_ACPI]:
1000
      kvm_cmd.extend(["-no-acpi"])
1001
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1002
        constants.INSTANCE_REBOOT_EXIT:
1003
      kvm_cmd.extend(["-no-reboot"])
1004

    
1005
    hvp = instance.hvparams
1006
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1007
    if kernel_path:
1008
      boot_disk = boot_cdrom = boot_floppy = boot_network = False
1009
    else:
1010
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1011
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1012
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1013
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1014

    
1015
    self.ValidateParameters(hvp)
1016

    
1017
    if startup_paused:
1018
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1019

    
1020
    if hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED:
1021
      kvm_cmd.extend(["-enable-kvm"])
1022
    elif hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED:
1023
      kvm_cmd.extend(["-disable-kvm"])
1024

    
1025
    if boot_network:
1026
      kvm_cmd.extend(["-boot", "n"])
1027

    
1028
    # whether this is an older KVM version that uses the boot=on flag
1029
    # on devices
1030
    needs_boot_flag = (v_major, v_min) < (0, 14)
1031

    
1032
    disk_type = hvp[constants.HV_DISK_TYPE]
1033
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
1034
      if_val = ",if=virtio"
1035
    else:
1036
      if_val = ",if=%s" % disk_type
1037
    # Cache mode
1038
    disk_cache = hvp[constants.HV_DISK_CACHE]
1039
    if instance.disk_template in constants.DTS_EXT_MIRROR:
1040
      if disk_cache != "none":
1041
        # TODO: make this a hard error, instead of a silent overwrite
1042
        logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1043
                        " to prevent shared storage corruption on migration",
1044
                        disk_cache)
1045
      cache_val = ",cache=none"
1046
    elif disk_cache != constants.HT_CACHE_DEFAULT:
1047
      cache_val = ",cache=%s" % disk_cache
1048
    else:
1049
      cache_val = ""
1050
    for cfdev, dev_path in block_devices:
1051
      if cfdev.mode != constants.DISK_RDWR:
1052
        raise errors.HypervisorError("Instance has read-only disks which"
1053
                                     " are not supported by KVM")
1054
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
1055
      boot_val = ""
1056
      if boot_disk:
1057
        kvm_cmd.extend(["-boot", "c"])
1058
        boot_disk = False
1059
        if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1060
          boot_val = ",boot=on"
1061

    
1062
      drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
1063
                                                cache_val)
1064
      kvm_cmd.extend(["-drive", drive_val])
1065

    
1066
    #Now we can specify a different device type for CDROM devices.
1067
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1068
    if not cdrom_disk_type:
1069
      cdrom_disk_type = disk_type
1070

    
1071
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1072
    if iso_image:
1073
      options = ",format=raw,media=cdrom"
1074
      # set cdrom 'if' type
1075
      if boot_cdrom:
1076
        actual_cdrom_type = constants.HT_DISK_IDE
1077
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1078
        actual_cdrom_type = "virtio"
1079
      else:
1080
        actual_cdrom_type = cdrom_disk_type
1081
      if_val = ",if=%s" % actual_cdrom_type
1082
      # set boot flag, if needed
1083
      boot_val = ""
1084
      if boot_cdrom:
1085
        kvm_cmd.extend(["-boot", "d"])
1086
        if needs_boot_flag:
1087
          boot_val = ",boot=on"
1088
      # and finally build the entire '-drive' value
1089
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1090
      kvm_cmd.extend(["-drive", drive_val])
1091

    
1092
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1093
    if iso_image2:
1094
      options = ",format=raw,media=cdrom"
1095
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1096
        if_val = ",if=virtio"
1097
      else:
1098
        if_val = ",if=%s" % cdrom_disk_type
1099
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1100
      kvm_cmd.extend(["-drive", drive_val])
1101

    
1102
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1103
    if floppy_image:
1104
      options = ",format=raw,media=disk"
1105
      if boot_floppy:
1106
        kvm_cmd.extend(["-boot", "a"])
1107
        options = "%s,boot=on" % options
1108
      if_val = ",if=floppy"
1109
      options = "%s%s" % (options, if_val)
1110
      drive_val = "file=%s%s" % (floppy_image, options)
1111
      kvm_cmd.extend(["-drive", drive_val])
1112

    
1113
    if kernel_path:
1114
      kvm_cmd.extend(["-kernel", kernel_path])
1115
      initrd_path = hvp[constants.HV_INITRD_PATH]
1116
      if initrd_path:
1117
        kvm_cmd.extend(["-initrd", initrd_path])
1118
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1119
                     hvp[constants.HV_KERNEL_ARGS]]
1120
      if hvp[constants.HV_SERIAL_CONSOLE]:
1121
        root_append.append("console=ttyS0,38400")
1122
      kvm_cmd.extend(["-append", " ".join(root_append)])
1123

    
1124
    mem_path = hvp[constants.HV_MEM_PATH]
1125
    if mem_path:
1126
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1127

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

    
1138
    mouse_type = hvp[constants.HV_USB_MOUSE]
1139
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1140
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1141
    spice_ip_version = None
1142

    
1143
    if mouse_type:
1144
      kvm_cmd.extend(["-usb"])
1145
      kvm_cmd.extend(["-usbdevice", mouse_type])
1146
    elif vnc_bind_address:
1147
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1148

    
1149
    if vnc_bind_address:
1150
      if netutils.IP4Address.IsValid(vnc_bind_address):
1151
        if instance.network_port > constants.VNC_BASE_PORT:
1152
          display = instance.network_port - constants.VNC_BASE_PORT
1153
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1154
            vnc_arg = ":%d" % (display)
1155
          else:
1156
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1157
        else:
1158
          logging.error("Network port is not a valid VNC display (%d < %d)."
1159
                        " Not starting VNC", instance.network_port,
1160
                        constants.VNC_BASE_PORT)
1161
          vnc_arg = "none"
1162

    
1163
        # Only allow tls and other option when not binding to a file, for now.
1164
        # kvm/qemu gets confused otherwise about the filename to use.
1165
        vnc_append = ""
1166
        if hvp[constants.HV_VNC_TLS]:
1167
          vnc_append = "%s,tls" % vnc_append
1168
          if hvp[constants.HV_VNC_X509_VERIFY]:
1169
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1170
                                               hvp[constants.HV_VNC_X509])
1171
          elif hvp[constants.HV_VNC_X509]:
1172
            vnc_append = "%s,x509=%s" % (vnc_append,
1173
                                         hvp[constants.HV_VNC_X509])
1174
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1175
          vnc_append = "%s,password" % vnc_append
1176

    
1177
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1178

    
1179
      else:
1180
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1181

    
1182
      kvm_cmd.extend(["-vnc", vnc_arg])
1183
    elif spice_bind:
1184
      # FIXME: this is wrong here; the iface ip address differs
1185
      # between systems, so it should be done in _ExecuteKVMRuntime
1186
      if netutils.IsValidInterface(spice_bind):
1187
        # The user specified a network interface, we have to figure out the IP
1188
        # address.
1189
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1190
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1191

    
1192
        # if the user specified an IP version and the interface does not
1193
        # have that kind of IP addresses, throw an exception
1194
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1195
          if not addresses[spice_ip_version]:
1196
            raise errors.HypervisorError("spice: unable to get an IPv%s address"
1197
                                         " for %s" % (spice_ip_version,
1198
                                                      spice_bind))
1199

    
1200
        # the user did not specify an IP version, we have to figure it out
1201
        elif (addresses[constants.IP4_VERSION] and
1202
              addresses[constants.IP6_VERSION]):
1203
          # we have both ipv4 and ipv6, let's use the cluster default IP
1204
          # version
1205
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1206
          spice_ip_version = \
1207
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1208
        elif addresses[constants.IP4_VERSION]:
1209
          spice_ip_version = constants.IP4_VERSION
1210
        elif addresses[constants.IP6_VERSION]:
1211
          spice_ip_version = constants.IP6_VERSION
1212
        else:
1213
          raise errors.HypervisorError("spice: unable to get an IP address"
1214
                                       " for %s" % (spice_bind))
1215

    
1216
        spice_address = addresses[spice_ip_version][0]
1217

    
1218
      else:
1219
        # spice_bind is known to be a valid IP address, because
1220
        # ValidateParameters checked it.
1221
        spice_address = spice_bind
1222

    
1223
      spice_arg = "addr=%s" % spice_address
1224
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1225
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1226
                     (spice_arg, instance.network_port,
1227
                      pathutils.SPICE_CACERT_FILE))
1228
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1229
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1230
                      pathutils.SPICE_CERT_FILE))
1231
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1232
        if tls_ciphers:
1233
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1234
      else:
1235
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1236

    
1237
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1238
        spice_arg = "%s,disable-ticketing" % spice_arg
1239

    
1240
      if spice_ip_version:
1241
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1242

    
1243
      # Image compression options
1244
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1245
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1246
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1247
      if img_lossless:
1248
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1249
      if img_jpeg:
1250
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1251
      if img_zlib_glz:
1252
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1253

    
1254
      # Video stream detection
1255
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1256
      if video_streaming:
1257
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1258

    
1259
      # Audio compression, by default in qemu-kvm it is on
1260
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1261
        spice_arg = "%s,playback-compression=off" % spice_arg
1262
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1263
        spice_arg = "%s,agent-mouse=off" % spice_arg
1264
      else:
1265
        # Enable the spice agent communication channel between the host and the
1266
        # agent.
1267
        kvm_cmd.extend(["-device", "virtio-serial-pci"])
1268
        kvm_cmd.extend(["-device", "virtserialport,chardev=spicechannel0,"
1269
                                                   "name=com.redhat.spice.0"])
1270
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1271

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

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

    
1278
    else:
1279
      kvm_cmd.extend(["-nographic"])
1280

    
1281
    if hvp[constants.HV_USE_LOCALTIME]:
1282
      kvm_cmd.extend(["-localtime"])
1283

    
1284
    if hvp[constants.HV_KVM_USE_CHROOT]:
1285
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1286

    
1287
    # Add qemu-KVM -cpu param
1288
    if hvp[constants.HV_CPU_TYPE]:
1289
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1290

    
1291
    # Save the current instance nics, but defer their expansion as parameters,
1292
    # as we'll need to generate executable temp files for them.
1293
    kvm_nics = instance.nics
1294
    hvparams = hvp
1295

    
1296
    return (kvm_cmd, kvm_nics, hvparams)
1297

    
1298
  def _WriteKVMRuntime(self, instance_name, data):
1299
    """Write an instance's KVM runtime
1300

1301
    """
1302
    try:
1303
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1304
                      data=data)
1305
    except EnvironmentError, err:
1306
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1307

    
1308
  def _ReadKVMRuntime(self, instance_name):
1309
    """Read an instance's KVM runtime
1310

1311
    """
1312
    try:
1313
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1314
    except EnvironmentError, err:
1315
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1316
    return file_content
1317

    
1318
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1319
    """Save an instance's KVM runtime
1320

1321
    """
1322
    kvm_cmd, kvm_nics, hvparams = kvm_runtime
1323
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1324
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1325
    self._WriteKVMRuntime(instance.name, serialized_form)
1326

    
1327
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1328
    """Load an instance's KVM runtime
1329

1330
    """
1331
    if not serialized_runtime:
1332
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1333
    loaded_runtime = serializer.Load(serialized_runtime)
1334
    kvm_cmd, serialized_nics, hvparams = loaded_runtime
1335
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1336
    return (kvm_cmd, kvm_nics, hvparams)
1337

    
1338
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1339
    """Run the KVM cmd and check for errors
1340

1341
    @type name: string
1342
    @param name: instance name
1343
    @type kvm_cmd: list of strings
1344
    @param kvm_cmd: runcmd input for kvm
1345
    @type tap_fds: list of int
1346
    @param tap_fds: fds of tap devices opened by Ganeti
1347

1348
    """
1349
    try:
1350
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1351
    finally:
1352
      for fd in tap_fds:
1353
        utils_wrapper.CloseFdNoError(fd)
1354

    
1355
    if result.failed:
1356
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1357
                                   (name, result.fail_reason, result.output))
1358
    if not self._InstancePidAlive(name)[2]:
1359
      raise errors.HypervisorError("Failed to start instance %s" % name)
1360

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

1364
    @type incoming: tuple of strings
1365
    @param incoming: (target_host_ip, port)
1366

1367
    """
1368
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1369
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1370
    #    have changed since the instance started; only use them if the change
1371
    #    won't affect the inside of the instance (which hasn't been rebooted).
1372
    #  - up_hvp contains the parameters as they were when the instance was
1373
    #    started, plus any new parameter which has been added between ganeti
1374
    #    versions: it is paramount that those default to a value which won't
1375
    #    affect the inside of the instance as well.
1376
    conf_hvp = instance.hvparams
1377
    name = instance.name
1378
    self._CheckDown(name)
1379

    
1380
    temp_files = []
1381

    
1382
    kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1383
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1384

    
1385
    _, v_major, v_min, _ = self._GetKVMVersion()
1386

    
1387
    # We know it's safe to run as a different user upon migration, so we'll use
1388
    # the latest conf, from conf_hvp.
1389
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1390
    if security_model == constants.HT_SM_USER:
1391
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1392

    
1393
    keymap = conf_hvp[constants.HV_KEYMAP]
1394
    if keymap:
1395
      keymap_path = self._InstanceKeymapFile(name)
1396
      # If a keymap file is specified, KVM won't use its internal defaults. By
1397
      # first including the "en-us" layout, an error on loading the actual
1398
      # layout (e.g. because it can't be found) won't lead to a non-functional
1399
      # keyboard. A keyboard with incorrect keys is still better than none.
1400
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1401
      kvm_cmd.extend(["-k", keymap_path])
1402

    
1403
    # We have reasons to believe changing something like the nic driver/type
1404
    # upon migration won't exactly fly with the instance kernel, so for nic
1405
    # related parameters we'll use up_hvp
1406
    tapfds = []
1407
    taps = []
1408
    if not kvm_nics:
1409
      kvm_cmd.extend(["-net", "none"])
1410
    else:
1411
      vnet_hdr = False
1412
      tap_extra = ""
1413
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1414
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1415
        # From version 0.12.0, kvm uses a new sintax for network configuration.
1416
        if (v_major, v_min) >= (0, 12):
1417
          nic_model = "virtio-net-pci"
1418
          vnet_hdr = True
1419
        else:
1420
          nic_model = "virtio"
1421

    
1422
        if up_hvp[constants.HV_VHOST_NET]:
1423
          # vhost_net is only available from version 0.13.0 or newer
1424
          if (v_major, v_min) >= (0, 13):
1425
            tap_extra = ",vhost=on"
1426
          else:
1427
            raise errors.HypervisorError("vhost_net is configured"
1428
                                         " but it is not available")
1429
      else:
1430
        nic_model = nic_type
1431

    
1432
      for nic_seq, nic in enumerate(kvm_nics):
1433
        tapname, tapfd = _OpenTap(vnet_hdr)
1434
        tapfds.append(tapfd)
1435
        taps.append(tapname)
1436
        if (v_major, v_min) >= (0, 12):
1437
          nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1438
          tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1439
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1440
        else:
1441
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1442
                                                         nic.mac, nic_model)
1443
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1444
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1445

    
1446
    if incoming:
1447
      target, port = incoming
1448
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1449

    
1450
    # Changing the vnc password doesn't bother the guest that much. At most it
1451
    # will surprise people who connect to it. Whether positively or negatively
1452
    # it's debatable.
1453
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1454
    vnc_pwd = None
1455
    if vnc_pwd_file:
1456
      try:
1457
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1458
      except EnvironmentError, err:
1459
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1460
                                     % (vnc_pwd_file, err))
1461

    
1462
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1463
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1464
                         constants.SECURE_DIR_MODE)])
1465

    
1466
    # Automatically enable QMP if version is >= 0.14
1467
    if (v_major, v_min) >= (0, 14):
1468
      logging.debug("Enabling QMP")
1469
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1470
                      self._InstanceQmpMonitor(instance.name)])
1471

    
1472
    # Configure the network now for starting instances and bridged interfaces,
1473
    # during FinalizeMigration for incoming instances' routed interfaces
1474
    for nic_seq, nic in enumerate(kvm_nics):
1475
      if (incoming and
1476
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1477
        continue
1478
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1479

    
1480
    # CPU affinity requires kvm to start paused, so we set this flag if the
1481
    # instance is not already paused and if we are not going to accept a
1482
    # migrating instance. In the latter case, pausing is not needed.
1483
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1484
    if start_kvm_paused:
1485
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1486

    
1487
    # Note: CPU pinning is using up_hvp since changes take effect
1488
    # during instance startup anyway, and to avoid problems when soft
1489
    # rebooting the instance.
1490
    cpu_pinning = False
1491
    if up_hvp.get(constants.HV_CPU_MASK, None):
1492
      cpu_pinning = True
1493

    
1494
    if security_model == constants.HT_SM_POOL:
1495
      ss = ssconf.SimpleStore()
1496
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1497
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1498
      uid = uidpool.RequestUnusedUid(all_uids)
1499
      try:
1500
        username = pwd.getpwuid(uid.GetUid()).pw_name
1501
        kvm_cmd.extend(["-runas", username])
1502
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1503
      except:
1504
        uidpool.ReleaseUid(uid)
1505
        raise
1506
      else:
1507
        uid.Unlock()
1508
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1509
    else:
1510
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1511

    
1512
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1513
                     constants.RUN_DIRS_MODE)])
1514
    for nic_seq, tap in enumerate(taps):
1515
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1516
                      data=tap)
1517

    
1518
    if vnc_pwd:
1519
      change_cmd = "change vnc password %s" % vnc_pwd
1520
      self._CallMonitorCommand(instance.name, change_cmd)
1521

    
1522
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1523
    # connection attempts because SPICE by default does not allow connections
1524
    # if neither a password nor the "disable_ticketing" options are specified.
1525
    # As soon as we send the password via QMP, that password is a valid ticket
1526
    # for connection.
1527
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1528
    if spice_password_file:
1529
      spice_pwd = ""
1530
      try:
1531
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1532
      except EnvironmentError, err:
1533
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1534
                                     % (spice_password_file, err))
1535

    
1536
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1537
      qmp.connect()
1538
      arguments = {
1539
          "protocol": "spice",
1540
          "password": spice_pwd,
1541
      }
1542
      qmp.Execute("set_password", arguments)
1543

    
1544
    for filename in temp_files:
1545
      utils.RemoveFile(filename)
1546

    
1547
    # If requested, set CPU affinity and resume instance execution
1548
    if cpu_pinning:
1549
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1550

    
1551
    start_memory = self._InstanceStartupMemory(instance)
1552
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1553
      self.BalloonInstanceMemory(instance, start_memory)
1554

    
1555
    if start_kvm_paused:
1556
      # To control CPU pinning, ballooning, and vnc/spice passwords
1557
      # the VM was started in a frozen state. If freezing was not
1558
      # explicitly requested resume the vm status.
1559
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1560

    
1561
  def StartInstance(self, instance, block_devices, startup_paused):
1562
    """Start an instance.
1563

1564
    """
1565
    self._CheckDown(instance.name)
1566
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1567
                                           startup_paused)
1568
    self._SaveKVMRuntime(instance, kvm_runtime)
1569
    self._ExecuteKVMRuntime(instance, kvm_runtime)
1570

    
1571
  def _CallMonitorCommand(self, instance_name, command):
1572
    """Invoke a command on the instance monitor.
1573

1574
    """
1575
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1576
             (utils.ShellQuote(command),
1577
              constants.SOCAT_PATH,
1578
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1579
    result = utils.RunCmd(socat)
1580
    if result.failed:
1581
      msg = ("Failed to send command '%s' to instance %s."
1582
             " output: %s, error: %s, fail_reason: %s" %
1583
             (command, instance_name,
1584
              result.stdout, result.stderr, result.fail_reason))
1585
      raise errors.HypervisorError(msg)
1586

    
1587
    return result
1588

    
1589
  @classmethod
1590
  def _ParseKVMVersion(cls, text):
1591
    """Parse the KVM version from the --help output.
1592

1593
    @type text: string
1594
    @param text: output of kvm --help
1595
    @return: (version, v_maj, v_min, v_rev)
1596
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1597

1598
    """
1599
    match = cls._VERSION_RE.search(text.splitlines()[0])
1600
    if not match:
1601
      raise errors.HypervisorError("Unable to get KVM version")
1602

    
1603
    v_all = match.group(0)
1604
    v_maj = int(match.group(1))
1605
    v_min = int(match.group(2))
1606
    if match.group(4):
1607
      v_rev = int(match.group(4))
1608
    else:
1609
      v_rev = 0
1610
    return (v_all, v_maj, v_min, v_rev)
1611

    
1612
  @classmethod
1613
  def _GetKVMVersion(cls):
1614
    """Return the installed KVM version.
1615

1616
    @return: (version, v_maj, v_min, v_rev)
1617
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1618

1619
    """
1620
    result = utils.RunCmd([constants.KVM_PATH, "--help"])
1621
    if result.failed:
1622
      raise errors.HypervisorError("Unable to get KVM version")
1623
    return cls._ParseKVMVersion(result.output)
1624

    
1625
  def StopInstance(self, instance, force=False, retry=False, name=None):
1626
    """Stop an instance.
1627

1628
    """
1629
    if name is not None and not force:
1630
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1631
    if name is None:
1632
      name = instance.name
1633
      acpi = instance.hvparams[constants.HV_ACPI]
1634
    else:
1635
      acpi = False
1636
    _, pid, alive = self._InstancePidAlive(name)
1637
    if pid > 0 and alive:
1638
      if force or not acpi:
1639
        utils.KillProcess(pid)
1640
      else:
1641
        self._CallMonitorCommand(name, "system_powerdown")
1642

    
1643
  def CleanupInstance(self, instance_name):
1644
    """Cleanup after a stopped instance
1645

1646
    """
1647
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
1648
    if pid > 0 and alive:
1649
      raise errors.HypervisorError("Cannot cleanup a live instance")
1650
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1651

    
1652
  def RebootInstance(self, instance):
1653
    """Reboot an instance.
1654

1655
    """
1656
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1657
    # socket the instance will stop, but now power up again. So we'll resort
1658
    # to shutdown and restart.
1659
    _, _, alive = self._InstancePidAlive(instance.name)
1660
    if not alive:
1661
      raise errors.HypervisorError("Failed to reboot instance %s:"
1662
                                   " not running" % instance.name)
1663
    # StopInstance will delete the saved KVM runtime so:
1664
    # ...first load it...
1665
    kvm_runtime = self._LoadKVMRuntime(instance)
1666
    # ...now we can safely call StopInstance...
1667
    if not self.StopInstance(instance):
1668
      self.StopInstance(instance, force=True)
1669
    # ...and finally we can save it again, and execute it...
1670
    self._SaveKVMRuntime(instance, kvm_runtime)
1671
    self._ExecuteKVMRuntime(instance, kvm_runtime)
1672

    
1673
  def MigrationInfo(self, instance):
1674
    """Get instance information to perform a migration.
1675

1676
    @type instance: L{objects.Instance}
1677
    @param instance: instance to be migrated
1678
    @rtype: string
1679
    @return: content of the KVM runtime file
1680

1681
    """
1682
    return self._ReadKVMRuntime(instance.name)
1683

    
1684
  def AcceptInstance(self, instance, info, target):
1685
    """Prepare to accept an instance.
1686

1687
    @type instance: L{objects.Instance}
1688
    @param instance: instance to be accepted
1689
    @type info: string
1690
    @param info: content of the KVM runtime file on the source node
1691
    @type target: string
1692
    @param target: target host (usually ip), on this node
1693

1694
    """
1695
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1696
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1697
    self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
1698

    
1699
  def FinalizeMigrationDst(self, instance, info, success):
1700
    """Finalize the instance migration on the target node.
1701

1702
    Stop the incoming mode KVM.
1703

1704
    @type instance: L{objects.Instance}
1705
    @param instance: instance whose migration is being finalized
1706

1707
    """
1708
    if success:
1709
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1710
      kvm_nics = kvm_runtime[1]
1711

    
1712
      for nic_seq, nic in enumerate(kvm_nics):
1713
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1714
          # Bridged interfaces have already been configured
1715
          continue
1716
        try:
1717
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1718
        except EnvironmentError, err:
1719
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
1720
                          instance.name, nic_seq, str(err))
1721
          continue
1722
        try:
1723
          self._ConfigureNIC(instance, nic_seq, nic, tap)
1724
        except errors.HypervisorError, err:
1725
          logging.warning(str(err))
1726

    
1727
      self._WriteKVMRuntime(instance.name, info)
1728
    else:
1729
      self.StopInstance(instance, force=True)
1730

    
1731
  def MigrateInstance(self, instance, target, live):
1732
    """Migrate an instance to a target node.
1733

1734
    The migration will not be attempted if the instance is not
1735
    currently running.
1736

1737
    @type instance: L{objects.Instance}
1738
    @param instance: the instance to be migrated
1739
    @type target: string
1740
    @param target: ip address of the target node
1741
    @type live: boolean
1742
    @param live: perform a live migration
1743

1744
    """
1745
    instance_name = instance.name
1746
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
1747
    _, _, alive = self._InstancePidAlive(instance_name)
1748
    if not alive:
1749
      raise errors.HypervisorError("Instance not running, cannot migrate")
1750

    
1751
    if not live:
1752
      self._CallMonitorCommand(instance_name, "stop")
1753

    
1754
    migrate_command = ("migrate_set_speed %dm" %
1755
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1756
    self._CallMonitorCommand(instance_name, migrate_command)
1757

    
1758
    migrate_command = ("migrate_set_downtime %dms" %
1759
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1760
    self._CallMonitorCommand(instance_name, migrate_command)
1761

    
1762
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1763
    self._CallMonitorCommand(instance_name, migrate_command)
1764

    
1765
  def FinalizeMigrationSource(self, instance, success, live):
1766
    """Finalize the instance migration on the source node.
1767

1768
    @type instance: L{objects.Instance}
1769
    @param instance: the instance that was migrated
1770
    @type success: bool
1771
    @param success: whether the migration succeeded or not
1772
    @type live: bool
1773
    @param live: whether the user requested a live migration or not
1774

1775
    """
1776
    if success:
1777
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
1778
      utils.KillProcess(pid)
1779
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1780
    elif live:
1781
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1782

    
1783
  def GetMigrationStatus(self, instance):
1784
    """Get the migration status
1785

1786
    @type instance: L{objects.Instance}
1787
    @param instance: the instance that is being migrated
1788
    @rtype: L{objects.MigrationStatus}
1789
    @return: the status of the current migration (one of
1790
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1791
             progress info that can be retrieved from the hypervisor
1792

1793
    """
1794
    info_command = "info migrate"
1795
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
1796
      result = self._CallMonitorCommand(instance.name, info_command)
1797
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
1798
      if not match:
1799
        if not result.stdout:
1800
          logging.info("KVM: empty 'info migrate' result")
1801
        else:
1802
          logging.warning("KVM: unknown 'info migrate' result: %s",
1803
                          result.stdout)
1804
      else:
1805
        status = match.group(1)
1806
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
1807
          migration_status = objects.MigrationStatus(status=status)
1808
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
1809
          if match:
1810
            migration_status.transferred_ram = match.group("transferred")
1811
            migration_status.total_ram = match.group("total")
1812

    
1813
          return migration_status
1814

    
1815
        logging.warning("KVM: unknown migration status '%s'", status)
1816

    
1817
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1818

    
1819
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
1820

    
1821
  def BalloonInstanceMemory(self, instance, mem):
1822
    """Balloon an instance memory to a certain value.
1823

1824
    @type instance: L{objects.Instance}
1825
    @param instance: instance to be accepted
1826
    @type mem: int
1827
    @param mem: actual memory size to use for instance runtime
1828

1829
    """
1830
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
1831

    
1832
  def GetNodeInfo(self):
1833
    """Return information about the node.
1834

1835
    @return: a dict with the following keys (values in MiB):
1836
          - memory_total: the total memory size on the node
1837
          - memory_free: the available memory on the node for instances
1838
          - memory_dom0: the memory used by the node itself, if available
1839
          - hv_version: the hypervisor version in the form (major, minor,
1840
                        revision)
1841

1842
    """
1843
    result = self.GetLinuxNodeInfo()
1844
    _, v_major, v_min, v_rev = self._GetKVMVersion()
1845
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
1846
    return result
1847

    
1848
  @classmethod
1849
  def GetInstanceConsole(cls, instance, hvparams, beparams):
1850
    """Return a command for connecting to the console of an instance.
1851

1852
    """
1853
    if hvparams[constants.HV_SERIAL_CONSOLE]:
1854
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
1855
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1856
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1857
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
1858
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1859
      return objects.InstanceConsole(instance=instance.name,
1860
                                     kind=constants.CONS_SSH,
1861
                                     host=instance.primary_node,
1862
                                     user=constants.SSH_CONSOLE_USER,
1863
                                     command=cmd)
1864

    
1865
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1866
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1867
      display = instance.network_port - constants.VNC_BASE_PORT
1868
      return objects.InstanceConsole(instance=instance.name,
1869
                                     kind=constants.CONS_VNC,
1870
                                     host=vnc_bind_address,
1871
                                     port=instance.network_port,
1872
                                     display=display)
1873

    
1874
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1875
    if spice_bind:
1876
      return objects.InstanceConsole(instance=instance.name,
1877
                                     kind=constants.CONS_SPICE,
1878
                                     host=spice_bind,
1879
                                     port=instance.network_port)
1880

    
1881
    return objects.InstanceConsole(instance=instance.name,
1882
                                   kind=constants.CONS_MESSAGE,
1883
                                   message=("No serial shell for instance %s" %
1884
                                            instance.name))
1885

    
1886
  def Verify(self):
1887
    """Verify the hypervisor.
1888

1889
    Check that the binary exists.
1890

1891
    """
1892
    if not os.path.exists(constants.KVM_PATH):
1893
      return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
1894
    if not os.path.exists(constants.SOCAT_PATH):
1895
      return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
1896

    
1897
  @classmethod
1898
  def CheckParameterSyntax(cls, hvparams):
1899
    """Check the given parameters for validity.
1900

1901
    @type hvparams:  dict
1902
    @param hvparams: dictionary with parameter names/value
1903
    @raise errors.HypervisorError: when a parameter is not valid
1904

1905
    """
1906
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
1907

    
1908
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
1909
    if kernel_path:
1910
      if not hvparams[constants.HV_ROOT_PATH]:
1911
        raise errors.HypervisorError("Need a root partition for the instance,"
1912
                                     " if a kernel is defined")
1913

    
1914
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
1915
        not hvparams[constants.HV_VNC_X509]):
1916
      raise errors.HypervisorError("%s must be defined, if %s is" %
1917
                                   (constants.HV_VNC_X509,
1918
                                    constants.HV_VNC_X509_VERIFY))
1919

    
1920
    boot_order = hvparams[constants.HV_BOOT_ORDER]
1921
    if (boot_order == constants.HT_BO_CDROM and
1922
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
1923
      raise errors.HypervisorError("Cannot boot from cdrom without an"
1924
                                   " ISO path")
1925

    
1926
    security_model = hvparams[constants.HV_SECURITY_MODEL]
1927
    if security_model == constants.HT_SM_USER:
1928
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
1929
        raise errors.HypervisorError("A security domain (user to run kvm as)"
1930
                                     " must be specified")
1931
    elif (security_model == constants.HT_SM_NONE or
1932
          security_model == constants.HT_SM_POOL):
1933
      if hvparams[constants.HV_SECURITY_DOMAIN]:
1934
        raise errors.HypervisorError("Cannot have a security domain when the"
1935
                                     " security model is 'none' or 'pool'")
1936

    
1937
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1938
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
1939
    if spice_bind:
1940
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1941
        # if an IP version is specified, the spice_bind parameter must be an
1942
        # IP of that family
1943
        if (netutils.IP4Address.IsValid(spice_bind) and
1944
            spice_ip_version != constants.IP4_VERSION):
1945
          raise errors.HypervisorError("spice: got an IPv4 address (%s), but"
1946
                                       " the specified IP version is %s" %
1947
                                       (spice_bind, spice_ip_version))
1948

    
1949
        if (netutils.IP6Address.IsValid(spice_bind) and
1950
            spice_ip_version != constants.IP6_VERSION):
1951
          raise errors.HypervisorError("spice: got an IPv6 address (%s), but"
1952
                                       " the specified IP version is %s" %
1953
                                       (spice_bind, spice_ip_version))
1954
    else:
1955
      # All the other SPICE parameters depend on spice_bind being set. Raise an
1956
      # error if any of them is set without it.
1957
      spice_additional_params = frozenset([
1958
        constants.HV_KVM_SPICE_IP_VERSION,
1959
        constants.HV_KVM_SPICE_PASSWORD_FILE,
1960
        constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR,
1961
        constants.HV_KVM_SPICE_JPEG_IMG_COMPR,
1962
        constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR,
1963
        constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION,
1964
        constants.HV_KVM_SPICE_USE_TLS,
1965
        ])
1966
      for param in spice_additional_params:
1967
        if hvparams[param]:
1968
          raise errors.HypervisorError("spice: %s requires %s to be set" %
1969
                                       (param, constants.HV_KVM_SPICE_BIND))
1970

    
1971
  @classmethod
1972
  def ValidateParameters(cls, hvparams):
1973
    """Check the given parameters for validity.
1974

1975
    @type hvparams:  dict
1976
    @param hvparams: dictionary with parameter names/value
1977
    @raise errors.HypervisorError: when a parameter is not valid
1978

1979
    """
1980
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
1981

    
1982
    security_model = hvparams[constants.HV_SECURITY_MODEL]
1983
    if security_model == constants.HT_SM_USER:
1984
      username = hvparams[constants.HV_SECURITY_DOMAIN]
1985
      try:
1986
        pwd.getpwnam(username)
1987
      except KeyError:
1988
        raise errors.HypervisorError("Unknown security domain user %s"
1989
                                     % username)
1990

    
1991
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1992
    if spice_bind:
1993
      # only one of VNC and SPICE can be used currently.
1994
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
1995
        raise errors.HypervisorError("both SPICE and VNC are configured, but"
1996
                                     " only one of them can be used at a"
1997
                                     " given time.")
1998

    
1999
      # KVM version should be >= 0.14.0
2000
      _, v_major, v_min, _ = cls._GetKVMVersion()
2001
      if (v_major, v_min) < (0, 14):
2002
        raise errors.HypervisorError("spice is configured, but it is not"
2003
                                     " available in versions of KVM < 0.14")
2004

    
2005
      # if spice_bind is not an IP address, it must be a valid interface
2006
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind)
2007
                       or netutils.IP6Address.IsValid(spice_bind))
2008
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2009
        raise errors.HypervisorError("spice: the %s parameter must be either"
2010
                                     " a valid IP address or interface name" %
2011
                                     constants.HV_KVM_SPICE_BIND)
2012

    
2013
  @classmethod
2014
  def PowercycleNode(cls):
2015
    """KVM powercycle, just a wrapper over Linux powercycle.
2016

2017
    """
2018
    cls.LinuxPowercycle()