Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ d2db2790

History | View | Annotate | Download (87.4 kB)

1
#
2
#
3

    
4
# Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 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
import fdsend
41
import copy
42
from bitarray import bitarray
43
try:
44
  import affinity   # pylint: disable=F0401
45
except ImportError:
46
  affinity = None
47

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

    
60

    
61
_KVM_NETWORK_SCRIPT = pathutils.CONF_DIR + "/kvm-vif-bridge"
62
_KVM_START_PAUSED_FLAG = "-S"
63

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

    
74
#: SPICE parameters which depend on L{constants.HV_KVM_SPICE_BIND}
75
_SPICE_ADDITIONAL_PARAMS = frozenset([
76
  constants.HV_KVM_SPICE_IP_VERSION,
77
  constants.HV_KVM_SPICE_PASSWORD_FILE,
78
  constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR,
79
  constants.HV_KVM_SPICE_JPEG_IMG_COMPR,
80
  constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR,
81
  constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION,
82
  constants.HV_KVM_SPICE_USE_TLS,
83
  ])
84

    
85
FREE = bitarray("0")
86

    
87
def UUIDToKVMId(uuid):
88

    
89
  if uuid:
90
    return "x" + uuid.split("-")[0]
91
  else:
92
    return None
93

    
94
def _ProbeTapVnetHdr(fd):
95
  """Check whether to enable the IFF_VNET_HDR flag.
96

97
  To do this, _all_ of the following conditions must be met:
98
   1. TUNGETFEATURES ioctl() *must* be implemented
99
   2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
100
   3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
101
      drivers/net/tun.c there is no way to test this until after the tap device
102
      has been created using TUNSETIFF, and there is no way to change the
103
      IFF_VNET_HDR flag after creating the interface, catch-22! However both
104
      TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
105
      thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
106

107
   @type fd: int
108
   @param fd: the file descriptor of /dev/net/tun
109

110
  """
111
  req = struct.pack("I", 0)
112
  try:
113
    res = fcntl.ioctl(fd, TUNGETFEATURES, req)
114
  except EnvironmentError:
115
    logging.warning("TUNGETFEATURES ioctl() not implemented")
116
    return False
117

    
118
  tunflags = struct.unpack("I", res)[0]
119
  if tunflags & IFF_VNET_HDR:
120
    return True
121
  else:
122
    logging.warning("Host does not support IFF_VNET_HDR, not enabling")
123
    return False
124

    
125

    
126
def _OpenTap(vnet_hdr=True):
127
  """Open a new tap device and return its file descriptor.
128

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

132
  @type vnet_hdr: boolean
133
  @param vnet_hdr: Enable the VNET Header
134
  @return: (ifname, tapfd)
135
  @rtype: tuple
136

137
  """
138
  try:
139
    tapfd = os.open("/dev/net/tun", os.O_RDWR)
140
  except EnvironmentError:
141
    raise errors.HypervisorError("Failed to open /dev/net/tun")
142

    
143
  flags = IFF_TAP | IFF_NO_PI
144

    
145
  if vnet_hdr and _ProbeTapVnetHdr(tapfd):
146
    flags |= IFF_VNET_HDR
147

    
148
  # The struct ifreq ioctl request (see netdevice(7))
149
  ifr = struct.pack("16sh", "", flags)
150

    
151
  try:
152
    res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
153
  except EnvironmentError, err:
154
    raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
155
                                 err)
156

    
157
  # Get the interface name from the ioctl
158
  ifname = struct.unpack("16sh", res)[0].strip("\x00")
159
  return (ifname, tapfd)
160

    
161

    
162
class QmpMessage:
163
  """QEMU Messaging Protocol (QMP) message.
164

165
  """
166
  def __init__(self, data):
167
    """Creates a new QMP message based on the passed data.
168

169
    """
170
    if not isinstance(data, dict):
171
      raise TypeError("QmpMessage must be initialized with a dict")
172

    
173
    self.data = data
174

    
175
  def __getitem__(self, field_name):
176
    """Get the value of the required field if present, or None.
177

178
    Overrides the [] operator to provide access to the message data,
179
    returning None if the required item is not in the message
180
    @return: the value of the field_name field, or None if field_name
181
             is not contained in the message
182

183
    """
184
    return self.data.get(field_name, None)
185

    
186
  def __setitem__(self, field_name, field_value):
187
    """Set the value of the required field_name to field_value.
188

189
    """
190
    self.data[field_name] = field_value
191

    
192
  @staticmethod
193
  def BuildFromJsonString(json_string):
194
    """Build a QmpMessage from a JSON encoded string.
195

196
    @type json_string: str
197
    @param json_string: JSON string representing the message
198
    @rtype: L{QmpMessage}
199
    @return: a L{QmpMessage} built from json_string
200

201
    """
202
    # Parse the string
203
    data = serializer.LoadJson(json_string)
204
    return QmpMessage(data)
205

    
206
  def __str__(self):
207
    # The protocol expects the JSON object to be sent as a single line.
208
    return serializer.DumpJson(self.data)
209

    
210
  def __eq__(self, other):
211
    # When comparing two QmpMessages, we are interested in comparing
212
    # their internal representation of the message data
213
    return self.data == other.data
214

    
215

    
216
class QmpConnection:
217
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
218

219
  """
220
  _FIRST_MESSAGE_KEY = "QMP"
221
  _EVENT_KEY = "event"
222
  _ERROR_KEY = "error"
223
  _RETURN_KEY = RETURN_KEY = "return"
224
  _ACTUAL_KEY = ACTUAL_KEY = "actual"
225
  _ERROR_CLASS_KEY = "class"
226
  _ERROR_DATA_KEY = "data"
227
  _ERROR_DESC_KEY = "desc"
228
  _EXECUTE_KEY = "execute"
229
  _ARGUMENTS_KEY = "arguments"
230
  _CAPABILITIES_COMMAND = "qmp_capabilities"
231
  _MESSAGE_END_TOKEN = "\r\n"
232
  _SOCKET_TIMEOUT = 5
233

    
234
  def __init__(self, monitor_filename):
235
    """Instantiates the QmpConnection object.
236

237
    @type monitor_filename: string
238
    @param monitor_filename: the filename of the UNIX raw socket on which the
239
                             QMP monitor is listening
240

241
    """
242
    self.monitor_filename = monitor_filename
243
    self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
244
    # We want to fail if the server doesn't send a complete message
245
    # in a reasonable amount of time
246
    self.sock.settimeout(self._SOCKET_TIMEOUT)
247
    self._connected = False
248
    self._buf = ""
249

    
250
  def _check_socket(self):
251
    sock_stat = None
252
    try:
253
      sock_stat = os.stat(self.monitor_filename)
254
    except EnvironmentError, err:
255
      if err.errno == errno.ENOENT:
256
        raise errors.HypervisorError("No qmp socket found")
257
      else:
258
        raise errors.HypervisorError("Error checking qmp socket: %s",
259
                                     utils.ErrnoOrStr(err))
260
    if not stat.S_ISSOCK(sock_stat.st_mode):
261
      raise errors.HypervisorError("Qmp socket is not a socket")
262

    
263
  def _check_connection(self):
264
    """Make sure that the connection is established.
265

266
    """
267
    if not self._connected:
268
      raise errors.ProgrammerError("To use a QmpConnection you need to first"
269
                                   " invoke connect() on it")
270

    
271
  def connect(self):
272
    """Connects to the QMP monitor.
273

274
    Connects to the UNIX socket and makes sure that we can actually send and
275
    receive data to the kvm instance via QMP.
276

277
    @raise errors.HypervisorError: when there are communication errors
278
    @raise errors.ProgrammerError: when there are data serialization errors
279

280
    """
281
    if self._connected:
282
      raise errors.ProgrammerError("Cannot connect twice")
283

    
284
    self._check_socket()
285

    
286
    # Check file existance/stuff
287
    try:
288
      self.sock.connect(self.monitor_filename)
289
    except EnvironmentError:
290
      raise errors.HypervisorError("Can't connect to qmp socket")
291
    self._connected = True
292

    
293
    # Check if we receive a correct greeting message from the server
294
    # (As per the QEMU Protocol Specification 0.1 - section 2.2)
295
    greeting = self._Recv()
296
    if not greeting[self._FIRST_MESSAGE_KEY]:
297
      self._connected = False
298
      raise errors.HypervisorError("kvm: qmp communication error (wrong"
299
                                   " server greeting")
300

    
301
    # Let's put the monitor in command mode using the qmp_capabilities
302
    # command, or else no command will be executable.
303
    # (As per the QEMU Protocol Specification 0.1 - section 4)
304
    self.Execute(self._CAPABILITIES_COMMAND)
305

    
306
  def _ParseMessage(self, buf):
307
    """Extract and parse a QMP message from the given buffer.
308

309
    Seeks for a QMP message in the given buf. If found, it parses it and
310
    returns it together with the rest of the characters in the buf.
311
    If no message is found, returns None and the whole buffer.
312

313
    @raise errors.ProgrammerError: when there are data serialization errors
314

315
    """
316
    message = None
317
    # Check if we got the message end token (CRLF, as per the QEMU Protocol
318
    # Specification 0.1 - Section 2.1.1)
319
    pos = buf.find(self._MESSAGE_END_TOKEN)
320
    if pos >= 0:
321
      try:
322
        message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
323
      except Exception, err:
324
        raise errors.ProgrammerError("QMP data serialization error: %s" % err)
325
      buf = buf[pos + 1:]
326

    
327
    return (message, buf)
328

    
329
  def _Recv(self):
330
    """Receives a message from QMP and decodes the received JSON object.
331

332
    @rtype: QmpMessage
333
    @return: the received message
334
    @raise errors.HypervisorError: when there are communication errors
335
    @raise errors.ProgrammerError: when there are data serialization errors
336

337
    """
338
    self._check_connection()
339

    
340
    # Check if there is already a message in the buffer
341
    (message, self._buf) = self._ParseMessage(self._buf)
342
    if message:
343
      return message
344

    
345
    recv_buffer = StringIO.StringIO(self._buf)
346
    recv_buffer.seek(len(self._buf))
347
    try:
348
      while True:
349
        data = self.sock.recv(4096)
350
        if not data:
351
          break
352
        recv_buffer.write(data)
353

    
354
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
355
        if message:
356
          return message
357

    
358
    except socket.timeout, err:
359
      raise errors.HypervisorError("Timeout while receiving a QMP message: "
360
                                   "%s" % (err))
361
    except socket.error, err:
362
      raise errors.HypervisorError("Unable to receive data from KVM using the"
363
                                   " QMP protocol: %s" % err)
364

    
365
  def _Send(self, message):
366
    """Encodes and sends a message to KVM using QMP.
367

368
    @type message: QmpMessage
369
    @param message: message to send to KVM
370
    @raise errors.HypervisorError: when there are communication errors
371
    @raise errors.ProgrammerError: when there are data serialization errors
372

373
    """
374
    self._check_connection()
375
    try:
376
      message_str = str(message)
377
    except Exception, err:
378
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
379

    
380
    try:
381
      self.sock.sendall(message_str)
382
    except socket.timeout, err:
383
      raise errors.HypervisorError("Timeout while sending a QMP message: "
384
                                   "%s (%s)" % (err.string, err.errno))
385
    except socket.error, err:
386
      raise errors.HypervisorError("Unable to send data from KVM using the"
387
                                   " QMP protocol: %s" % err)
388

    
389
  def Execute(self, command, arguments=None):
390
    """Executes a QMP command and returns the response of the server.
391

392
    @type command: str
393
    @param command: the command to execute
394
    @type arguments: dict
395
    @param arguments: dictionary of arguments to be passed to the command
396
    @rtype: dict
397
    @return: dictionary representing the received JSON object
398
    @raise errors.HypervisorError: when there are communication errors
399
    @raise errors.ProgrammerError: when there are data serialization errors
400

401
    """
402
    self._check_connection()
403
    message = QmpMessage({self._EXECUTE_KEY: command})
404
    if arguments:
405
      message[self._ARGUMENTS_KEY] = arguments
406
    self._Send(message)
407

    
408
    # Events can occur between the sending of the command and the reception
409
    # of the response, so we need to filter out messages with the event key.
410
    while True:
411
      response = self._Recv()
412
      err = response[self._ERROR_KEY]
413
      if err:
414
        raise errors.HypervisorError("kvm: error executing the %s"
415
                                     " command: %s (%s, %s):" %
416
                                     (command,
417
                                      err[self._ERROR_DESC_KEY],
418
                                      err[self._ERROR_CLASS_KEY],
419
                                      err[self._ERROR_DATA_KEY]))
420

    
421
      elif not response[self._EVENT_KEY]:
422
        return response
423

    
424

    
425
class KVMHypervisor(hv_base.BaseHypervisor):
426
  """KVM hypervisor interface
427

428
  """
429
  CAN_MIGRATE = True
430

    
431
  _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
432
  _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
433
  _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
434
  _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
435
  _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
436
  _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
437
  _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
438
  # KVM instances with chroot enabled are started in empty chroot directories.
439
  _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
440
  # After an instance is stopped, its chroot directory is removed.
441
  # If the chroot directory is not empty, it can't be removed.
442
  # A non-empty chroot directory indicates a possible security incident.
443
  # To support forensics, the non-empty chroot directory is quarantined in
444
  # a separate directory, called 'chroot-quarantine'.
445
  _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
446
  _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
447
           _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
448

    
449
  PARAMETERS = {
450
    constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
451
    constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
452
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
453
    constants.HV_ROOT_PATH: hv_base.NO_CHECK,
454
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
455
    constants.HV_ACPI: hv_base.NO_CHECK,
456
    constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
457
    constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
458
    constants.HV_VNC_BIND_ADDRESS:
459
      (False, lambda x: (netutils.IP4Address.IsValid(x) or
460
                         utils.IsNormAbsPath(x)),
461
       "the VNC bind address must be either a valid IP address or an absolute"
462
       " pathname", None, None),
463
    constants.HV_VNC_TLS: hv_base.NO_CHECK,
464
    constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
465
    constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
466
    constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
467
    constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
468
    constants.HV_KVM_SPICE_IP_VERSION:
469
      (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
470
                         x in constants.VALID_IP_VERSIONS),
471
       "the SPICE IP version should be 4 or 6",
472
       None, None),
473
    constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
474
    constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
475
      hv_base.ParamInSet(
476
        False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
477
    constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
478
      hv_base.ParamInSet(
479
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
480
    constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
481
      hv_base.ParamInSet(
482
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
483
    constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
484
      hv_base.ParamInSet(
485
        False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
486
    constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
487
    constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
488
    constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
489
    constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
490
    constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
491
    constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
492
    constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
493
    constants.HV_BOOT_ORDER:
494
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
495
    constants.HV_NIC_TYPE:
496
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
497
    constants.HV_DISK_TYPE:
498
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
499
    constants.HV_KVM_CDROM_DISK_TYPE:
500
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
501
    constants.HV_USB_MOUSE:
502
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
503
    constants.HV_KEYMAP: hv_base.NO_CHECK,
504
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
505
    constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
506
    constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
507
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
508
    constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
509
    constants.HV_DISK_CACHE:
510
      hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
511
    constants.HV_SECURITY_MODEL:
512
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
513
    constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
514
    constants.HV_KVM_FLAG:
515
      hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
516
    constants.HV_VHOST_NET: hv_base.NO_CHECK,
517
    constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
518
    constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
519
    constants.HV_REBOOT_BEHAVIOR:
520
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
521
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
522
    constants.HV_CPU_TYPE: hv_base.NO_CHECK,
523
    constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
524
    constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
525
    constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
526
    constants.HV_SOUNDHW: hv_base.NO_CHECK,
527
    constants.HV_USB_DEVICES: hv_base.NO_CHECK,
528
    constants.HV_VGA: hv_base.NO_CHECK,
529
    constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
530
    constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
531
    }
532

    
533
  _VIRTIO = "virtio"
534
  _VIRTIO_NET_PCI = "virtio-net-pci"
535

    
536
  _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
537
                                    re.M | re.I)
538
  _MIGRATION_PROGRESS_RE = \
539
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
540
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
541
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
542

    
543
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
544
  _MIGRATION_INFO_RETRY_DELAY = 2
545

    
546
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
547

    
548
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
549
  _CPU_INFO_CMD = "info cpus"
550
  _CONT_CMD = "cont"
551

    
552
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
553
  _CHECK_MACHINE_VERSION_RE = \
554
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
555

    
556
  _QMP_RE = re.compile(r"^-qmp\s", re.M)
557
  _SPICE_RE = re.compile(r"^-spice\s", re.M)
558
  _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
559
  _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
560
  _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
561
  _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
562
  _NEW_VIRTIO_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
563
  # match  -drive.*boot=on|off on different lines, but in between accept only
564
  # dashes not preceeded by a new line (which would mean another option
565
  # different than -drive is starting)
566
  _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
567

    
568
  _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
569
  _INFO_PCI_CMD = "info pci"
570
  _INFO_VERSION_RE = re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
571
  _INFO_VERSION_CMD = "info version"
572

    
573
  _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
574

    
575
  ANCILLARY_FILES = [
576
    _KVM_NETWORK_SCRIPT,
577
    ]
578
  ANCILLARY_FILES_OPT = [
579
    _KVM_NETWORK_SCRIPT,
580
    ]
581

    
582
  # Supported kvm options to get output from
583
  _KVMOPT_HELP = "help"
584
  _KVMOPT_MLIST = "mlist"
585
  _KVMOPT_DEVICELIST = "devicelist"
586

    
587
  # Command to execute to get the output from kvm, and whether to
588
  # accept the output even on failure.
589
  _KVMOPTS_CMDS = {
590
    _KVMOPT_HELP: (["--help"], False),
591
    _KVMOPT_MLIST: (["-M", "?"], False),
592
    _KVMOPT_DEVICELIST: (["-device", "?"], True),
593
  }
594

    
595
  def __init__(self):
596
    hv_base.BaseHypervisor.__init__(self)
597
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
598
    # in a tmpfs filesystem or has been otherwise wiped out.
599
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
600
    utils.EnsureDirs(dirs)
601

    
602
  @classmethod
603
  def _InstancePidFile(cls, instance_name):
604
    """Returns the instance pidfile.
605

606
    """
607
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
608

    
609
  @classmethod
610
  def _InstanceUidFile(cls, instance_name):
611
    """Returns the instance uidfile.
612

613
    """
614
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
615

    
616
  @classmethod
617
  def _InstancePidInfo(cls, pid):
618
    """Check pid file for instance information.
619

620
    Check that a pid file is associated with an instance, and retrieve
621
    information from its command line.
622

623
    @type pid: string or int
624
    @param pid: process id of the instance to check
625
    @rtype: tuple
626
    @return: (instance_name, memory, vcpus)
627
    @raise errors.HypervisorError: when an instance cannot be found
628

629
    """
630
    alive = utils.IsProcessAlive(pid)
631
    if not alive:
632
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
633

    
634
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
635
    try:
636
      cmdline = utils.ReadFile(cmdline_file)
637
    except EnvironmentError, err:
638
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
639
                                   (pid, err))
640

    
641
    instance = None
642
    memory = 0
643
    vcpus = 0
644

    
645
    arg_list = cmdline.split("\x00")
646
    while arg_list:
647
      arg = arg_list.pop(0)
648
      if arg == "-name":
649
        instance = arg_list.pop(0)
650
      elif arg == "-m":
651
        memory = int(arg_list.pop(0))
652
      elif arg == "-smp":
653
        vcpus = int(arg_list.pop(0).split(",")[0])
654

    
655
    if instance is None:
656
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
657
                                   " instance" % pid)
658

    
659
    return (instance, memory, vcpus)
660

    
661
  def _InstancePidAlive(self, instance_name):
662
    """Returns the instance pidfile, pid, and liveness.
663

664
    @type instance_name: string
665
    @param instance_name: instance name
666
    @rtype: tuple
667
    @return: (pid file name, pid, liveness)
668

669
    """
670
    pidfile = self._InstancePidFile(instance_name)
671
    pid = utils.ReadPidFile(pidfile)
672

    
673
    alive = False
674
    try:
675
      cmd_instance = self._InstancePidInfo(pid)[0]
676
      alive = (cmd_instance == instance_name)
677
    except errors.HypervisorError:
678
      pass
679

    
680
    return (pidfile, pid, alive)
681

    
682
  def _CheckDown(self, instance_name):
683
    """Raises an error unless the given instance is down.
684

685
    """
686
    alive = self._InstancePidAlive(instance_name)[2]
687
    if alive:
688
      raise errors.HypervisorError("Failed to start instance %s: %s" %
689
                                   (instance_name, "already running"))
690

    
691
  @classmethod
692
  def _InstanceMonitor(cls, instance_name):
693
    """Returns the instance monitor socket name
694

695
    """
696
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
697

    
698
  @classmethod
699
  def _InstanceSerial(cls, instance_name):
700
    """Returns the instance serial socket name
701

702
    """
703
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
704

    
705
  @classmethod
706
  def _InstanceQmpMonitor(cls, instance_name):
707
    """Returns the instance serial QMP socket name
708

709
    """
710
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
711

    
712
  @staticmethod
713
  def _SocatUnixConsoleParams():
714
    """Returns the correct parameters for socat
715

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

718
    """
719
    if constants.SOCAT_USE_ESCAPE:
720
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
721
    else:
722
      return "echo=0,icanon=0"
723

    
724
  @classmethod
725
  def _InstanceKVMRuntime(cls, instance_name):
726
    """Returns the instance KVM runtime filename
727

728
    """
729
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
730

    
731
  @classmethod
732
  def _InstanceChrootDir(cls, instance_name):
733
    """Returns the name of the KVM chroot dir of the instance
734

735
    """
736
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
737

    
738
  @classmethod
739
  def _InstanceNICDir(cls, instance_name):
740
    """Returns the name of the directory holding the tap device files for a
741
    given instance.
742

743
    """
744
    return utils.PathJoin(cls._NICS_DIR, instance_name)
745

    
746
  @classmethod
747
  def _InstanceNICFile(cls, instance_name, seq):
748
    """Returns the name of the file containing the tap device for a given NIC
749

750
    """
751
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
752

    
753
  @classmethod
754
  def _InstanceKeymapFile(cls, instance_name):
755
    """Returns the name of the file containing the keymap for a given instance
756

757
    """
758
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
759

    
760
  @classmethod
761
  def _TryReadUidFile(cls, uid_file):
762
    """Try to read a uid file
763

764
    """
765
    if os.path.exists(uid_file):
766
      try:
767
        uid = int(utils.ReadOneLineFile(uid_file))
768
        return uid
769
      except EnvironmentError:
770
        logging.warning("Can't read uid file", exc_info=True)
771
      except (TypeError, ValueError):
772
        logging.warning("Can't parse uid file contents", exc_info=True)
773
    return None
774

    
775
  @classmethod
776
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
777
    """Removes an instance's rutime sockets/files/dirs.
778

779
    """
780
    utils.RemoveFile(pidfile)
781
    utils.RemoveFile(cls._InstanceMonitor(instance_name))
782
    utils.RemoveFile(cls._InstanceSerial(instance_name))
783
    utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
784
    utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
785
    utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
786
    uid_file = cls._InstanceUidFile(instance_name)
787
    uid = cls._TryReadUidFile(uid_file)
788
    utils.RemoveFile(uid_file)
789
    if uid is not None:
790
      uidpool.ReleaseUid(uid)
791
    try:
792
      shutil.rmtree(cls._InstanceNICDir(instance_name))
793
    except OSError, err:
794
      if err.errno != errno.ENOENT:
795
        raise
796
    try:
797
      chroot_dir = cls._InstanceChrootDir(instance_name)
798
      utils.RemoveDir(chroot_dir)
799
    except OSError, err:
800
      if err.errno == errno.ENOTEMPTY:
801
        # The chroot directory is expected to be empty, but it isn't.
802
        new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
803
                                          prefix="%s-%s-" %
804
                                          (instance_name,
805
                                           utils.TimestampForFilename()))
806
        logging.warning("The chroot directory of instance %s can not be"
807
                        " removed as it is not empty. Moving it to the"
808
                        " quarantine instead. Please investigate the"
809
                        " contents (%s) and clean up manually",
810
                        instance_name, new_chroot_dir)
811
        utils.RenameFile(chroot_dir, new_chroot_dir)
812
      else:
813
        raise
814

    
815
  @staticmethod
816
  def _ConfigureNIC(instance, seq, nic, tap):
817
    """Run the network configuration script for a specified NIC
818

819
    @param instance: instance we're acting on
820
    @type instance: instance object
821
    @param seq: nic sequence number
822
    @type seq: int
823
    @param nic: nic we're acting on
824
    @type nic: nic object
825
    @param tap: the host's tap interface this NIC corresponds to
826
    @type tap: str
827

828
    """
829
    if instance.tags:
830
      tags = " ".join(instance.tags)
831
    else:
832
      tags = ""
833

    
834
    env = {
835
      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
836
      "INSTANCE": instance.name,
837
      "MAC": nic.mac,
838
      "MODE": nic.nicparams[constants.NIC_MODE],
839
      "INTERFACE": tap,
840
      "INTERFACE_INDEX": str(seq),
841
      "TAGS": tags,
842
    }
843

    
844
    if nic.ip:
845
      env["IP"] = nic.ip
846

    
847
    if nic.nicparams[constants.NIC_LINK]:
848
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
849

    
850
    if nic.network:
851
      n = objects.Network.FromDict(nic.netinfo)
852
      env.update(n.HooksDict())
853

    
854
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
855
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
856

    
857
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
858
    if result.failed:
859
      raise errors.HypervisorError("Failed to configure interface %s: %s."
860
                                   " Network configuration script output: %s" %
861
                                   (tap, result.fail_reason, result.output))
862

    
863
  @staticmethod
864
  def _VerifyAffinityPackage():
865
    if affinity is None:
866
      raise errors.HypervisorError("affinity Python package not"
867
                                   " found; cannot use CPU pinning under KVM")
868

    
869
  @staticmethod
870
  def _BuildAffinityCpuMask(cpu_list):
871
    """Create a CPU mask suitable for sched_setaffinity from a list of
872
    CPUs.
873

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

877
    @type cpu_list: list of int
878
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
879
    @rtype: int
880
    @return: a bit mask of CPU affinities
881

882
    """
883
    if cpu_list == constants.CPU_PINNING_OFF:
884
      return constants.CPU_PINNING_ALL_KVM
885
    else:
886
      return sum(2 ** cpu for cpu in cpu_list)
887

    
888
  @classmethod
889
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
890
    """Change CPU affinity for running VM according to given CPU mask.
891

892
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
893
    @type cpu_mask: string
894
    @param process_id: process ID of KVM process. Used to pin entire VM
895
                       to physical CPUs.
896
    @type process_id: int
897
    @param thread_dict: map of virtual CPUs to KVM thread IDs
898
    @type thread_dict: dict int:int
899

900
    """
901
    # Convert the string CPU mask to a list of list of int's
902
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
903

    
904
    if len(cpu_list) == 1:
905
      all_cpu_mapping = cpu_list[0]
906
      if all_cpu_mapping == constants.CPU_PINNING_OFF:
907
        # If CPU pinning has 1 entry that's "all", then do nothing
908
        pass
909
      else:
910
        # If CPU pinning has one non-all entry, map the entire VM to
911
        # one set of physical CPUs
912
        cls._VerifyAffinityPackage()
913
        affinity.set_process_affinity_mask(
914
          process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
915
    else:
916
      # The number of vCPUs mapped should match the number of vCPUs
917
      # reported by KVM. This was already verified earlier, so
918
      # here only as a sanity check.
919
      assert len(thread_dict) == len(cpu_list)
920
      cls._VerifyAffinityPackage()
921

    
922
      # For each vCPU, map it to the proper list of physical CPUs
923
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
924
        affinity.set_process_affinity_mask(thread_dict[i],
925
                                           cls._BuildAffinityCpuMask(vcpu))
926

    
927
  def _GetVcpuThreadIds(self, instance_name):
928
    """Get a mapping of vCPU no. to thread IDs for the instance
929

930
    @type instance_name: string
931
    @param instance_name: instance in question
932
    @rtype: dictionary of int:int
933
    @return: a dictionary mapping vCPU numbers to thread IDs
934

935
    """
936
    result = {}
937
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
938
    for line in output.stdout.splitlines():
939
      match = self._CPU_INFO_RE.search(line)
940
      if not match:
941
        continue
942
      grp = map(int, match.groups())
943
      result[grp[0]] = grp[1]
944

    
945
    return result
946

    
947
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
948
    """Complete CPU pinning.
949

950
    @type instance_name: string
951
    @param instance_name: name of instance
952
    @type cpu_mask: string
953
    @param cpu_mask: CPU pinning mask as entered by user
954

955
    """
956
    # Get KVM process ID, to be used if need to pin entire VM
957
    _, pid, _ = self._InstancePidAlive(instance_name)
958
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
959
    thread_dict = self._GetVcpuThreadIds(instance_name)
960
    # Run CPU pinning, based on configured mask
961
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
962

    
963
  def ListInstances(self):
964
    """Get the list of running instances.
965

966
    We can do this by listing our live instances directory and
967
    checking whether the associated kvm process is still alive.
968

969
    """
970
    result = []
971
    for name in os.listdir(self._PIDS_DIR):
972
      if self._InstancePidAlive(name)[2]:
973
        result.append(name)
974
    return result
975

    
976
  def GetInstanceInfo(self, instance_name):
977
    """Get instance properties.
978

979
    @type instance_name: string
980
    @param instance_name: the instance name
981
    @rtype: tuple of strings
982
    @return: (name, id, memory, vcpus, stat, times)
983

984
    """
985
    _, pid, alive = self._InstancePidAlive(instance_name)
986
    if not alive:
987
      return None
988

    
989
    _, memory, vcpus = self._InstancePidInfo(pid)
990
    istat = "---b-"
991
    times = "0"
992

    
993
    try:
994
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
995
      qmp.connect()
996
      vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
997
      # Will fail if ballooning is not enabled, but we can then just resort to
998
      # the value above.
999
      mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1000
      memory = mem_bytes / 1048576
1001
    except errors.HypervisorError:
1002
      pass
1003

    
1004
    return (instance_name, pid, memory, vcpus, istat, times)
1005

    
1006
  def GetAllInstancesInfo(self):
1007
    """Get properties of all instances.
1008

1009
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1010

1011
    """
1012
    data = []
1013
    for name in os.listdir(self._PIDS_DIR):
1014
      try:
1015
        info = self.GetInstanceInfo(name)
1016
      except errors.HypervisorError:
1017
        # Ignore exceptions due to instances being shut down
1018
        continue
1019
      if info:
1020
        data.append(info)
1021
    return data
1022

    
1023
  def _GenerateKVMBlockDevicesOptions(self, instance, kvm_cmd, block_devices,
1024
                                      pci_reservations, kvmhelp):
1025

    
1026
    hvp = instance.hvparams
1027
    boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1028

    
1029
    # whether this is an older KVM version that uses the boot=on flag
1030
    # on devices
1031
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1032

    
1033
    disk_type = hvp[constants.HV_DISK_TYPE]
1034
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
1035
      if_val = ",if=virtio"
1036
      #TODO: parse kvm -device ? output
1037
      disk_model = "virtio-blk-pci"
1038
    else:
1039
      if_val = ",if=%s" % disk_type
1040
      disk_model = disk_type
1041
    # Cache mode
1042
    disk_cache = hvp[constants.HV_DISK_CACHE]
1043
    if instance.disk_template in constants.DTS_EXT_MIRROR:
1044
      if disk_cache != "none":
1045
        # TODO: make this a hard error, instead of a silent overwrite
1046
        logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1047
                        " to prevent shared storage corruption on migration",
1048
                        disk_cache)
1049
      cache_val = ",cache=none"
1050
    elif disk_cache != constants.HT_CACHE_DEFAULT:
1051
      cache_val = ",cache=%s" % disk_cache
1052
    else:
1053
      cache_val = ""
1054
    for cfdev, dev_path in block_devices:
1055
      uuid = UUIDToKVMId(cfdev.uuid)
1056
      if cfdev.mode != constants.DISK_RDWR:
1057
        raise errors.HypervisorError("Instance has read-only disks which"
1058
                                     " are not supported by KVM")
1059
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
1060
      boot_val = ""
1061
      if boot_disk:
1062
        kvm_cmd.extend(["-boot", "c"])
1063
        boot_disk = False
1064
        if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1065
          boot_val = ",boot=on"
1066
      drive_val = "file=%s,format=raw%s%s" % \
1067
                  (dev_path, boot_val, cache_val)
1068
      if cfdev.uuid is not None:
1069
        #TODO: name id after model
1070
        drive_val += (",if=none,id=%s" % uuid)
1071
        if cfdev.pci is None:
1072
          cfdev.pci = self._GetFreePCISlot(instance, pci_reservations,
1073
                                           live=False)
1074
        drive_val += (",bus=0,unit=%d" % cfdev.pci)
1075
      else:
1076
        drive_val += if_val
1077

    
1078
      kvm_cmd.extend(["-drive", drive_val])
1079

    
1080
      if cfdev.uuid is not None:
1081
        dev_val = ("%s,drive=%s,id=%s" %
1082
                    (disk_model, uuid, uuid))
1083
        if cfdev.pci is None:
1084
          cfdev.pci = self._GetFreePCISlot(instance, pci_reservations,
1085
                                           live=False)
1086
        dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci)
1087
        kvm_cmd.extend(["-device", dev_val])
1088

    
1089
    return kvm_cmd
1090

    
1091
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1092
                          kvmhelp):
1093
    """Generate KVM information to start an instance.
1094

1095
    @type kvmhelp: string
1096
    @param kvmhelp: output of kvm --help
1097
    @attention: this function must not have any side-effects; for
1098
        example, it must not write to the filesystem, or read values
1099
        from the current system the are expected to differ between
1100
        nodes, since it is only run once at instance startup;
1101
        actions/kvm arguments that can vary between systems should be
1102
        done in L{_ExecuteKVMRuntime}
1103

1104
    """
1105
    # pylint: disable=R0912,R0914,R0915
1106
    hvp = instance.hvparams
1107

    
1108
    pidfile = self._InstancePidFile(instance.name)
1109
    kvm = hvp[constants.HV_KVM_PATH]
1110
    kvm_cmd = [kvm]
1111
    # used just by the vnc server, if enabled
1112
    kvm_cmd.extend(["-name", instance.name])
1113
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1114

    
1115
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1116
    if hvp[constants.HV_CPU_CORES]:
1117
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1118
    if hvp[constants.HV_CPU_THREADS]:
1119
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1120
    if hvp[constants.HV_CPU_SOCKETS]:
1121
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1122

    
1123
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1124

    
1125
    kvm_cmd.extend(["-pidfile", pidfile])
1126
    kvm_cmd.extend(["-balloon", "virtio"])
1127
    kvm_cmd.extend(["-daemonize"])
1128
    if not instance.hvparams[constants.HV_ACPI]:
1129
      kvm_cmd.extend(["-no-acpi"])
1130
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1131
        constants.INSTANCE_REBOOT_EXIT:
1132
      kvm_cmd.extend(["-no-reboot"])
1133

    
1134
    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1135
    if not mversion:
1136
      mversion = self._GetDefaultMachineVersion(kvm)
1137
    kvm_cmd.extend(["-M", mversion])
1138

    
1139
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1140
    if kernel_path:
1141
      boot_cdrom = boot_floppy = boot_network = False
1142
    else:
1143
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1144
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1145
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1146

    
1147
    self.ValidateParameters(hvp)
1148

    
1149
    if startup_paused:
1150
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1151

    
1152
    if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1153
        self._ENABLE_KVM_RE.search(kvmhelp)):
1154
      kvm_cmd.extend(["-enable-kvm"])
1155
    elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1156
          self._DISABLE_KVM_RE.search(kvmhelp)):
1157
      kvm_cmd.extend(["-disable-kvm"])
1158

    
1159
    if boot_network:
1160
      kvm_cmd.extend(["-boot", "n"])
1161

    
1162
    # whether this is an older KVM version that uses the boot=on flag
1163
    # on devices
1164
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1165

    
1166
    disk_type = hvp[constants.HV_DISK_TYPE]
1167

    
1168
    #Now we can specify a different device type for CDROM devices.
1169
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1170
    if not cdrom_disk_type:
1171
      cdrom_disk_type = disk_type
1172

    
1173
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1174
    if iso_image:
1175
      options = ",format=raw,media=cdrom"
1176
      # set cdrom 'if' type
1177
      if boot_cdrom:
1178
        actual_cdrom_type = constants.HT_DISK_IDE
1179
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1180
        actual_cdrom_type = "virtio"
1181
      else:
1182
        actual_cdrom_type = cdrom_disk_type
1183
      if_val = ",if=%s" % actual_cdrom_type
1184
      # set boot flag, if needed
1185
      boot_val = ""
1186
      if boot_cdrom:
1187
        kvm_cmd.extend(["-boot", "d"])
1188
        if needs_boot_flag:
1189
          boot_val = ",boot=on"
1190
      # and finally build the entire '-drive' value
1191
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1192
      kvm_cmd.extend(["-drive", drive_val])
1193

    
1194
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1195
    if iso_image2:
1196
      options = ",format=raw,media=cdrom"
1197
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1198
        if_val = ",if=virtio"
1199
      else:
1200
        if_val = ",if=%s" % cdrom_disk_type
1201
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1202
      kvm_cmd.extend(["-drive", drive_val])
1203

    
1204
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1205
    if floppy_image:
1206
      options = ",format=raw,media=disk"
1207
      if boot_floppy:
1208
        kvm_cmd.extend(["-boot", "a"])
1209
        options = "%s,boot=on" % options
1210
      if_val = ",if=floppy"
1211
      options = "%s%s" % (options, if_val)
1212
      drive_val = "file=%s%s" % (floppy_image, options)
1213
      kvm_cmd.extend(["-drive", drive_val])
1214

    
1215
    if kernel_path:
1216
      kvm_cmd.extend(["-kernel", kernel_path])
1217
      initrd_path = hvp[constants.HV_INITRD_PATH]
1218
      if initrd_path:
1219
        kvm_cmd.extend(["-initrd", initrd_path])
1220
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1221
                     hvp[constants.HV_KERNEL_ARGS]]
1222
      if hvp[constants.HV_SERIAL_CONSOLE]:
1223
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1224
        root_append.append("console=ttyS0,%s" % serial_speed)
1225
      kvm_cmd.extend(["-append", " ".join(root_append)])
1226

    
1227
    mem_path = hvp[constants.HV_MEM_PATH]
1228
    if mem_path:
1229
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1230

    
1231
    monitor_dev = ("unix:%s,server,nowait" %
1232
                   self._InstanceMonitor(instance.name))
1233
    kvm_cmd.extend(["-monitor", monitor_dev])
1234
    if hvp[constants.HV_SERIAL_CONSOLE]:
1235
      serial_dev = ("unix:%s,server,nowait" %
1236
                    self._InstanceSerial(instance.name))
1237
      kvm_cmd.extend(["-serial", serial_dev])
1238
    else:
1239
      kvm_cmd.extend(["-serial", "none"])
1240

    
1241
    mouse_type = hvp[constants.HV_USB_MOUSE]
1242
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1243
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1244
    spice_ip_version = None
1245

    
1246
    kvm_cmd.extend(["-usb"])
1247

    
1248
    if mouse_type:
1249
      kvm_cmd.extend(["-usbdevice", mouse_type])
1250
    elif vnc_bind_address:
1251
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1252

    
1253
    if vnc_bind_address:
1254
      if netutils.IP4Address.IsValid(vnc_bind_address):
1255
        if instance.network_port > constants.VNC_BASE_PORT:
1256
          display = instance.network_port - constants.VNC_BASE_PORT
1257
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1258
            vnc_arg = ":%d" % (display)
1259
          else:
1260
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1261
        else:
1262
          logging.error("Network port is not a valid VNC display (%d < %d)."
1263
                        " Not starting VNC", instance.network_port,
1264
                        constants.VNC_BASE_PORT)
1265
          vnc_arg = "none"
1266

    
1267
        # Only allow tls and other option when not binding to a file, for now.
1268
        # kvm/qemu gets confused otherwise about the filename to use.
1269
        vnc_append = ""
1270
        if hvp[constants.HV_VNC_TLS]:
1271
          vnc_append = "%s,tls" % vnc_append
1272
          if hvp[constants.HV_VNC_X509_VERIFY]:
1273
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1274
                                               hvp[constants.HV_VNC_X509])
1275
          elif hvp[constants.HV_VNC_X509]:
1276
            vnc_append = "%s,x509=%s" % (vnc_append,
1277
                                         hvp[constants.HV_VNC_X509])
1278
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1279
          vnc_append = "%s,password" % vnc_append
1280

    
1281
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1282

    
1283
      else:
1284
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1285

    
1286
      kvm_cmd.extend(["-vnc", vnc_arg])
1287
    elif spice_bind:
1288
      # FIXME: this is wrong here; the iface ip address differs
1289
      # between systems, so it should be done in _ExecuteKVMRuntime
1290
      if netutils.IsValidInterface(spice_bind):
1291
        # The user specified a network interface, we have to figure out the IP
1292
        # address.
1293
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1294
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1295

    
1296
        # if the user specified an IP version and the interface does not
1297
        # have that kind of IP addresses, throw an exception
1298
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1299
          if not addresses[spice_ip_version]:
1300
            raise errors.HypervisorError("spice: unable to get an IPv%s address"
1301
                                         " for %s" % (spice_ip_version,
1302
                                                      spice_bind))
1303

    
1304
        # the user did not specify an IP version, we have to figure it out
1305
        elif (addresses[constants.IP4_VERSION] and
1306
              addresses[constants.IP6_VERSION]):
1307
          # we have both ipv4 and ipv6, let's use the cluster default IP
1308
          # version
1309
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1310
          spice_ip_version = \
1311
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1312
        elif addresses[constants.IP4_VERSION]:
1313
          spice_ip_version = constants.IP4_VERSION
1314
        elif addresses[constants.IP6_VERSION]:
1315
          spice_ip_version = constants.IP6_VERSION
1316
        else:
1317
          raise errors.HypervisorError("spice: unable to get an IP address"
1318
                                       " for %s" % (spice_bind))
1319

    
1320
        spice_address = addresses[spice_ip_version][0]
1321

    
1322
      else:
1323
        # spice_bind is known to be a valid IP address, because
1324
        # ValidateParameters checked it.
1325
        spice_address = spice_bind
1326

    
1327
      spice_arg = "addr=%s" % spice_address
1328
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1329
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1330
                     (spice_arg, instance.network_port,
1331
                      pathutils.SPICE_CACERT_FILE))
1332
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1333
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1334
                      pathutils.SPICE_CERT_FILE))
1335
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1336
        if tls_ciphers:
1337
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1338
      else:
1339
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1340

    
1341
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1342
        spice_arg = "%s,disable-ticketing" % spice_arg
1343

    
1344
      if spice_ip_version:
1345
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1346

    
1347
      # Image compression options
1348
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1349
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1350
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1351
      if img_lossless:
1352
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1353
      if img_jpeg:
1354
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1355
      if img_zlib_glz:
1356
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1357

    
1358
      # Video stream detection
1359
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1360
      if video_streaming:
1361
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1362

    
1363
      # Audio compression, by default in qemu-kvm it is on
1364
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1365
        spice_arg = "%s,playback-compression=off" % spice_arg
1366
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1367
        spice_arg = "%s,agent-mouse=off" % spice_arg
1368
      else:
1369
        # Enable the spice agent communication channel between the host and the
1370
        # agent.
1371
        kvm_cmd.extend(["-device", "virtio-serial-pci"])
1372
        kvm_cmd.extend(["-device", "virtserialport,chardev=spicechannel0,"
1373
                                                   "name=com.redhat.spice.0"])
1374
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1375

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

    
1379
    else:
1380
      kvm_cmd.extend(["-nographic"])
1381

    
1382
    if hvp[constants.HV_USE_LOCALTIME]:
1383
      kvm_cmd.extend(["-localtime"])
1384

    
1385
    if hvp[constants.HV_KVM_USE_CHROOT]:
1386
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1387

    
1388
    # Add qemu-KVM -cpu param
1389
    if hvp[constants.HV_CPU_TYPE]:
1390
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1391

    
1392
    # As requested by music lovers
1393
    if hvp[constants.HV_SOUNDHW]:
1394
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1395

    
1396
    # Pass a -vga option if requested, or if spice is used, for backwards
1397
    # compatibility.
1398
    if hvp[constants.HV_VGA]:
1399
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1400
    elif spice_bind:
1401
      kvm_cmd.extend(["-vga", "qxl"])
1402

    
1403
    # Various types of usb devices, comma separated
1404
    if hvp[constants.HV_USB_DEVICES]:
1405
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1406
        kvm_cmd.extend(["-usbdevice", dev])
1407

    
1408
    if hvp[constants.HV_KVM_EXTRA]:
1409
      kvm_cmd.extend([hvp[constants.HV_KVM_EXTRA]])
1410

    
1411
    # Save the current instance nics, but defer their expansion as parameters,
1412
    # as we'll need to generate executable temp files for them.
1413
    kvm_nics = instance.nics
1414
    hvparams = hvp
1415

    
1416
    return (kvm_cmd, kvm_nics, hvparams, block_devices)
1417

    
1418
  def _WriteKVMRuntime(self, instance_name, data):
1419
    """Write an instance's KVM runtime
1420

1421
    """
1422
    try:
1423
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1424
                      data=data)
1425
    except EnvironmentError, err:
1426
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1427

    
1428
  def _ReadKVMRuntime(self, instance_name):
1429
    """Read an instance's KVM runtime
1430

1431
    """
1432
    try:
1433
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1434
    except EnvironmentError, err:
1435
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1436
    return file_content
1437

    
1438
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1439
    """Save an instance's KVM runtime
1440

1441
    """
1442
    kvm_cmd, kvm_nics, hvparams, block_devices = kvm_runtime
1443

    
1444
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1445
    serialized_blockdevs = [(blk.ToDict(), link) for blk, link in block_devices]
1446
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1447
                                      serialized_blockdevs))
1448

    
1449
    self._WriteKVMRuntime(instance.name, serialized_form)
1450

    
1451
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1452
    """Load an instance's KVM runtime
1453

1454
    """
1455
    if not serialized_runtime:
1456
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1457

    
1458
    loaded_runtime = serializer.Load(serialized_runtime)
1459
    kvm_cmd, serialized_nics, hvparams, serialized_blockdevs = loaded_runtime
1460

    
1461
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1462
    block_devices = [(objects.Disk.FromDict(sdisk), link)
1463
                     for sdisk, link in serialized_blockdevs]
1464

    
1465
    return (kvm_cmd, kvm_nics, hvparams, block_devices)
1466

    
1467
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1468
    """Run the KVM cmd and check for errors
1469

1470
    @type name: string
1471
    @param name: instance name
1472
    @type kvm_cmd: list of strings
1473
    @param kvm_cmd: runcmd input for kvm
1474
    @type tap_fds: list of int
1475
    @param tap_fds: fds of tap devices opened by Ganeti
1476

1477
    """
1478
    try:
1479
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1480
    finally:
1481
      for fd in tap_fds:
1482
        utils_wrapper.CloseFdNoError(fd)
1483

    
1484
    if result.failed:
1485
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1486
                                   (name, result.fail_reason, result.output))
1487
    if not self._InstancePidAlive(name)[2]:
1488
      raise errors.HypervisorError("Failed to start instance %s" % name)
1489

    
1490
  # pylint: disable=R0914
1491
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1492
    """Execute a KVM cmd, after completing it with some last minute data.
1493

1494
    @type incoming: tuple of strings
1495
    @param incoming: (target_host_ip, port)
1496
    @type kvmhelp: string
1497
    @param kvmhelp: output of kvm --help
1498

1499
    """
1500
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1501
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1502
    #    have changed since the instance started; only use them if the change
1503
    #    won't affect the inside of the instance (which hasn't been rebooted).
1504
    #  - up_hvp contains the parameters as they were when the instance was
1505
    #    started, plus any new parameter which has been added between ganeti
1506
    #    versions: it is paramount that those default to a value which won't
1507
    #    affect the inside of the instance as well.
1508
    conf_hvp = instance.hvparams
1509
    name = instance.name
1510
    self._CheckDown(name)
1511

    
1512
    temp_files = []
1513

    
1514
    kvm_cmd, kvm_nics, up_hvp, block_devices = kvm_runtime
1515
    # the first element of kvm_cmd is always the path to the kvm binary
1516
    kvm_path = kvm_cmd[0]
1517

    
1518
    kvm_cmd_runtime = copy.deepcopy(kvm_cmd)
1519

    
1520
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1521

    
1522
    # We know it's safe to run as a different user upon migration, so we'll use
1523
    # the latest conf, from conf_hvp.
1524
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1525
    if security_model == constants.HT_SM_USER:
1526
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1527

    
1528
    keymap = conf_hvp[constants.HV_KEYMAP]
1529
    if keymap:
1530
      keymap_path = self._InstanceKeymapFile(name)
1531
      # If a keymap file is specified, KVM won't use its internal defaults. By
1532
      # first including the "en-us" layout, an error on loading the actual
1533
      # layout (e.g. because it can't be found) won't lead to a non-functional
1534
      # keyboard. A keyboard with incorrect keys is still better than none.
1535
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1536
      kvm_cmd.extend(["-k", keymap_path])
1537

    
1538
    pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1539

    
1540
    kvm_cmd = self._GenerateKVMBlockDevicesOptions(instance, kvm_cmd,
1541
                                                   block_devices,
1542
                                                   pci_reservations,
1543
                                                   kvmhelp)
1544

    
1545
    # We have reasons to believe changing something like the nic driver/type
1546
    # upon migration won't exactly fly with the instance kernel, so for nic
1547
    # related parameters we'll use up_hvp
1548
    tapfds = []
1549
    taps = []
1550
    if not kvm_nics:
1551
      kvm_cmd.extend(["-net", "none"])
1552
    else:
1553
      vnet_hdr = False
1554
      tap_extra = ""
1555
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1556
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1557
        nic_model = self._VIRTIO
1558
        try:
1559
          devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1560
          if self._NEW_VIRTIO_RE.search(devlist):
1561
            nic_model = self._VIRTIO_NET_PCI
1562
            vnet_hdr = True
1563
        except errors.HypervisorError, _:
1564
          # Older versions of kvm don't support DEVICE_LIST, but they don't
1565
          # have new virtio syntax either.
1566
          pass
1567

    
1568
        if up_hvp[constants.HV_VHOST_NET]:
1569
          # check for vhost_net support
1570
          if self._VHOST_RE.search(kvmhelp):
1571
            tap_extra = ",vhost=on"
1572
          else:
1573
            raise errors.HypervisorError("vhost_net is configured"
1574
                                         " but it is not available")
1575
      else:
1576
        nic_model = nic_type
1577

    
1578
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1579

    
1580
      for nic_seq, nic in enumerate(kvm_nics):
1581
        uuid = UUIDToKVMId(nic.uuid)
1582
        tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1583
        tapfds.append(tapfd)
1584
        taps.append(tapname)
1585
        if kvm_supports_netdev:
1586
          nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1587
          if nic.uuid is not None:
1588
            nic_val += (",netdev=%s,id=%s" %
1589
                        (uuid, uuid))
1590
            if nic.pci is None:
1591
              nic.pci = self._GetFreePCISlot(instance, pci_reservations,
1592
                                             live=False)
1593
            nic_val += (",bus=pci.0,addr=%s" % hex(nic.pci))
1594
          else:
1595
            nic_val += (",netdev=netdev%d,id=virtio-net-pci.%d" %
1596
                        (nic_seq, nic_seq))
1597
          tap_val = ("type=tap,id=%s,fd=%d%s" %
1598
                     (uuid or nic_seq, tapfd, tap_extra))
1599
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1600
        else:
1601
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1602
                                                         nic.mac, nic_model)
1603
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1604
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1605

    
1606
    if incoming:
1607
      target, port = incoming
1608
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1609

    
1610
    # Changing the vnc password doesn't bother the guest that much. At most it
1611
    # will surprise people who connect to it. Whether positively or negatively
1612
    # it's debatable.
1613
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1614
    vnc_pwd = None
1615
    if vnc_pwd_file:
1616
      try:
1617
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1618
      except EnvironmentError, err:
1619
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1620
                                     % (vnc_pwd_file, err))
1621

    
1622
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1623
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1624
                         constants.SECURE_DIR_MODE)])
1625

    
1626
    # Automatically enable QMP if version is >= 0.14
1627
    if self._QMP_RE.search(kvmhelp):
1628
      logging.debug("Enabling QMP")
1629
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1630
                      self._InstanceQmpMonitor(instance.name)])
1631

    
1632
    # Configure the network now for starting instances and bridged interfaces,
1633
    # during FinalizeMigration for incoming instances' routed interfaces
1634
    for nic_seq, nic in enumerate(kvm_nics):
1635
      if (incoming and
1636
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1637
        continue
1638
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1639

    
1640
    # CPU affinity requires kvm to start paused, so we set this flag if the
1641
    # instance is not already paused and if we are not going to accept a
1642
    # migrating instance. In the latter case, pausing is not needed.
1643
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1644
    if start_kvm_paused:
1645
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1646

    
1647
    # Note: CPU pinning is using up_hvp since changes take effect
1648
    # during instance startup anyway, and to avoid problems when soft
1649
    # rebooting the instance.
1650
    cpu_pinning = False
1651
    if up_hvp.get(constants.HV_CPU_MASK, None):
1652
      cpu_pinning = True
1653

    
1654
    if security_model == constants.HT_SM_POOL:
1655
      ss = ssconf.SimpleStore()
1656
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1657
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1658
      uid = uidpool.RequestUnusedUid(all_uids)
1659
      try:
1660
        username = pwd.getpwuid(uid.GetUid()).pw_name
1661
        kvm_cmd.extend(["-runas", username])
1662
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1663
      except:
1664
        uidpool.ReleaseUid(uid)
1665
        raise
1666
      else:
1667
        uid.Unlock()
1668
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1669
    else:
1670
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1671

    
1672
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1673
                     constants.RUN_DIRS_MODE)])
1674
    for nic_seq, tap in enumerate(taps):
1675
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1676
                      data=tap)
1677

    
1678
    if vnc_pwd:
1679
      change_cmd = "change vnc password %s" % vnc_pwd
1680
      self._CallMonitorCommand(instance.name, change_cmd)
1681

    
1682
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1683
    # connection attempts because SPICE by default does not allow connections
1684
    # if neither a password nor the "disable_ticketing" options are specified.
1685
    # As soon as we send the password via QMP, that password is a valid ticket
1686
    # for connection.
1687
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1688
    if spice_password_file:
1689
      spice_pwd = ""
1690
      try:
1691
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1692
      except EnvironmentError, err:
1693
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1694
                                     % (spice_password_file, err))
1695

    
1696
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1697
      qmp.connect()
1698
      arguments = {
1699
          "protocol": "spice",
1700
          "password": spice_pwd,
1701
      }
1702
      qmp.Execute("set_password", arguments)
1703

    
1704
    for filename in temp_files:
1705
      utils.RemoveFile(filename)
1706

    
1707
    # If requested, set CPU affinity and resume instance execution
1708
    if cpu_pinning:
1709
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1710

    
1711
    start_memory = self._InstanceStartupMemory(instance)
1712
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1713
      self.BalloonInstanceMemory(instance, start_memory)
1714

    
1715
    if start_kvm_paused:
1716
      # To control CPU pinning, ballooning, and vnc/spice passwords
1717
      # the VM was started in a frozen state. If freezing was not
1718
      # explicitly requested resume the vm status.
1719
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1720

    
1721
    kvm_runtime_with_pci_info = (kvm_cmd_runtime, kvm_nics,
1722
                                 up_hvp, block_devices)
1723
    return kvm_runtime_with_pci_info
1724

    
1725
  def StartInstance(self, instance, block_devices, startup_paused):
1726
    """Start an instance.
1727

1728
    """
1729
    self._CheckDown(instance.name)
1730
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1731
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1732
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1733
                                           startup_paused, kvmhelp)
1734
    self._SaveKVMRuntime(instance, kvm_runtime)
1735
    kvm_runtime_with_pci_info = self._ExecuteKVMRuntime(instance, kvm_runtime,
1736
                                                        kvmhelp)
1737
    self._SaveKVMRuntime(instance, kvm_runtime_with_pci_info)
1738

    
1739
  def _CallMonitorCommand(self, instance_name, command):
1740
    """Invoke a command on the instance monitor.
1741

1742
    """
1743
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1744
             (utils.ShellQuote(command),
1745
              constants.SOCAT_PATH,
1746
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1747
    result = utils.RunCmd(socat)
1748
    if result.failed:
1749
      msg = ("Failed to send command '%s' to instance %s."
1750
             " output: %s, error: %s, fail_reason: %s" %
1751
             (command, instance_name,
1752
              result.stdout, result.stderr, result.fail_reason))
1753
      raise errors.HypervisorError(msg)
1754

    
1755
    return result
1756

    
1757
  def _GetFreePCISlot(self, instance, pci_reservations=None, live=False):
1758
    """Get the first available pci slot.
1759

1760
    If the instance is running then use info pci monitor command.
1761
    If not then use pci_reservations passed as argument.
1762
    """
1763
    if live:
1764
      slots = bitarray(32)
1765
      slots.setall(False) # pylint: disable=E1101
1766
      output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
1767
      for line in output.stdout.splitlines():
1768
        match = self._INFO_PCI_RE.search(line)
1769
        if match:
1770
          slot = int(match.group(1))
1771
          slots[slot] = True
1772
    else:
1773
      slots = pci_reservations
1774

    
1775
    [free] = slots.search(FREE, 1) # pylint: disable=E1103
1776
    if not free:
1777
      raise errors.HypervisorError("All PCI slots occupied")
1778

    
1779
    slots[free] = True
1780

    
1781
    return int(free)
1782

    
1783
  def _TryHotplug(self, instance_name):
1784
    """Get QEMU version from the instance's monitor.
1785

1786
    Hotplug is supported for running instances and for versions >= 1.0.
1787
    """
1788
    output = self._CallMonitorCommand(instance_name, self._INFO_VERSION_CMD)
1789
    match = self._INFO_VERSION_RE.search(output.stdout)
1790
    if not match:
1791
      return False
1792
    v_major, v_min, _, _ = match.groups()
1793
    return (v_major, v_min) >= (1, 0)
1794

    
1795
  def HotAddDisk(self, instance, disk, dev_path, _):
1796
    """Hotadd new disk to the VM
1797

1798
    """
1799
    if self._TryHotplug(instance.name):
1800
      uuid = UUIDToKVMId(disk.uuid)
1801

    
1802
      if disk.pci is None:
1803
        disk.pci = self._GetFreePCISlot(instance, live=True)
1804
      command = ("drive_add dummy file=%s,if=none,id=%s,format=raw" %
1805
                 (dev_path, uuid))
1806

    
1807
      logging.info("Run cmd %s", command)
1808
      output = self._CallMonitorCommand(instance.name, command)
1809

    
1810
      command = ("device_add virtio-blk-pci,bus=pci.0,addr=%s,"
1811
                 "drive=%s,id=%s"
1812
                 % (hex(disk.pci), uuid, uuid))
1813
      logging.info("Run cmd %s", command)
1814
      output = self._CallMonitorCommand(instance.name, command)
1815
      for line in output.stdout.splitlines():
1816
        logging.info("%s", line)
1817

    
1818
      (kvm_cmd, kvm_nics,
1819
       hvparams, block_devices) = self._LoadKVMRuntime(instance)
1820
      block_devices.append((disk, dev_path))
1821
      new_kvm_runtime = (kvm_cmd, kvm_nics, hvparams, block_devices)
1822
      self._SaveKVMRuntime(instance, new_kvm_runtime)
1823

    
1824
  def HotDelDisk(self, instance, disk, _):
1825
    """Hotdel disk to the VM
1826

1827
    """
1828
    if self._TryHotplug(instance.name):
1829

    
1830
      uuid = UUIDToKVMId(disk.uuid)
1831

    
1832
      command = "device_del %s" % uuid
1833
      logging.info("Run cmd %s", command)
1834
      output = self._CallMonitorCommand(instance.name, command)
1835
      for line in output.stdout.splitlines():
1836
        logging.info("%s", line)
1837

    
1838
      command = "drive_del %s" % uuid
1839
      logging.info("Run cmd %s", command)
1840
      #output = self._CallMonitorCommand(instance.name, command)
1841
      #for line in output.stdout.splitlines():
1842
      #  logging.info("%s" % line)
1843

    
1844
      (kvm_cmd, kvm_nics,
1845
       hvparams, block_devices) = self._LoadKVMRuntime(instance)
1846
      rem  = [(d, p) for d, p in block_devices
1847
                     if d.uuid == disk.uuid]
1848
      try:
1849
        block_devices.remove(rem[0])
1850
      except (ValueError, IndexError):
1851
        logging.info("Disk with uuid %s disappeared from runtime file", disk.uuid)
1852
      new_kvm_runtime = (kvm_cmd, kvm_nics, hvparams, block_devices)
1853
      self._SaveKVMRuntime(instance, new_kvm_runtime)
1854

    
1855
  def HotAddNic(self, instance, nic, seq):
1856
    """Hotadd new nic to the VM
1857

1858
    """
1859
    if self._TryHotplug(instance.name):
1860
      if nic.pci is None:
1861
        nic.pci = self._GetFreePCISlot(instance, live=True)
1862
      mac = nic.mac
1863

    
1864
      uuid = UUIDToKVMId(nic.uuid)
1865

    
1866
      (tap, fd) = _OpenTap()
1867
      logging.info("%s %d", tap, fd)
1868

    
1869
      self._PassTapFd(instance, fd, nic)
1870

    
1871
      command = ("netdev_add tap,id=%s,fd=%s"
1872
                 % (uuid, uuid))
1873
      logging.info("Run cmd %s", command)
1874
      output = self._CallMonitorCommand(instance.name, command)
1875
      for line in output.stdout.splitlines():
1876
        logging.info("%s", line)
1877

    
1878
      command = ("device_add virtio-net-pci,bus=pci.0,addr=%s,mac=%s,"
1879
                 "netdev=%s,id=%s"
1880
                 % (hex(nic.pci), mac, uuid, uuid))
1881
      logging.info("Run cmd %s", command)
1882
      output = self._CallMonitorCommand(instance.name, command)
1883
      for line in output.stdout.splitlines():
1884
        logging.info("%s", line)
1885

    
1886
      self._ConfigureNIC(instance, seq, nic, tap)
1887

    
1888
      (kvm_cmd, kvm_nics,
1889
       hvparams, block_devices) = self._LoadKVMRuntime(instance)
1890
      kvm_nics.append(nic)
1891
      new_kvm_runtime = (kvm_cmd, kvm_nics, hvparams, block_devices)
1892
      self._SaveKVMRuntime(instance, new_kvm_runtime)
1893

    
1894
  def HotDelNic(self, instance, nic, _):
1895
    """Hotadd new nic to the VM
1896

1897
    """
1898
    if self._TryHotplug(instance.name):
1899

    
1900
      uuid = UUIDToKVMId(nic.uuid)
1901

    
1902
      command = "device_del %s" % uuid
1903
      logging.info("Run cmd %s", command)
1904
      output = self._CallMonitorCommand(instance.name, command)
1905
      for line in output.stdout.splitlines():
1906
        logging.info("%s", line)
1907

    
1908
      command = "netdev_del %s" % uuid
1909
      logging.info("Run cmd %s", command)
1910
      output = self._CallMonitorCommand(instance.name, command)
1911
      for line in output.stdout.splitlines():
1912
        logging.info("%s", line)
1913

    
1914
      (kvm_cmd, kvm_nics,
1915
       hvparams, block_devices) = self._LoadKVMRuntime(instance)
1916
      rem  = [n for n in kvm_nics if n.uuid == nic.uuid]
1917
      try:
1918
        kvm_nics.remove(rem[0])
1919
      except (ValueError, IndexError):
1920
        logging.info("NIC with uuid %s disappeared from runtime file", nic.uuid)
1921
      new_kvm_runtime = (kvm_cmd, kvm_nics, hvparams, block_devices)
1922
      self._SaveKVMRuntime(instance, new_kvm_runtime)
1923

    
1924
  def _PassTapFd(self, instance, fd, nic):
1925
    monsock = utils.ShellQuote(self._InstanceMonitor(instance.name))
1926
    s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
1927
    s.connect(monsock)
1928
    uuid = UUIDToKVMId(nic.uuid)
1929
    command = "getfd %s\n" % uuid
1930
    fds = [fd]
1931
    logging.info("%s", fds)
1932
    fdsend.sendfds(s, command, fds = fds)
1933
    s.close()
1934

    
1935
  @classmethod
1936
  def _ParseKVMVersion(cls, text):
1937
    """Parse the KVM version from the --help output.
1938

1939
    @type text: string
1940
    @param text: output of kvm --help
1941
    @return: (version, v_maj, v_min, v_rev)
1942
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1943

1944
    """
1945
    match = cls._VERSION_RE.search(text.splitlines()[0])
1946
    if not match:
1947
      raise errors.HypervisorError("Unable to get KVM version")
1948

    
1949
    v_all = match.group(0)
1950
    v_maj = int(match.group(1))
1951
    v_min = int(match.group(2))
1952
    if match.group(4):
1953
      v_rev = int(match.group(4))
1954
    else:
1955
      v_rev = 0
1956
    return (v_all, v_maj, v_min, v_rev)
1957

    
1958
  @classmethod
1959
  def _GetKVMOutput(cls, kvm_path, option):
1960
    """Return the output of a kvm invocation
1961

1962
    @type kvm_path: string
1963
    @param kvm_path: path to the kvm executable
1964
    @type option: a key of _KVMOPTS_CMDS
1965
    @param option: kvm option to fetch the output from
1966
    @return: output a supported kvm invocation
1967
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1968

1969
    """
1970
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
1971

    
1972
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
1973

    
1974
    result = utils.RunCmd([kvm_path] + optlist)
1975
    if result.failed and not can_fail:
1976
      raise errors.HypervisorError("Unable to get KVM %s output" %
1977
                                    " ".join(cls._KVMOPTS_CMDS[option]))
1978
    return result.output
1979

    
1980
  @classmethod
1981
  def _GetKVMVersion(cls, kvm_path):
1982
    """Return the installed KVM version.
1983

1984
    @return: (version, v_maj, v_min, v_rev)
1985
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1986

1987
    """
1988
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
1989

    
1990
  @classmethod
1991
  def _GetDefaultMachineVersion(cls, kvm_path):
1992
    """Return the default hardware revision (e.g. pc-1.1)
1993

1994
    """
1995
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
1996
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
1997
    if match:
1998
      return match.group(1)
1999
    else:
2000
      return "pc"
2001

    
2002
  def StopInstance(self, instance, force=False, retry=False, name=None):
2003
    """Stop an instance.
2004

2005
    """
2006
    if name is not None and not force:
2007
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2008
    if name is None:
2009
      name = instance.name
2010
      acpi = instance.hvparams[constants.HV_ACPI]
2011
    else:
2012
      acpi = False
2013
    _, pid, alive = self._InstancePidAlive(name)
2014
    if pid > 0 and alive:
2015
      if force or not acpi:
2016
        utils.KillProcess(pid)
2017
      else:
2018
        self._CallMonitorCommand(name, "system_powerdown")
2019

    
2020
  def CleanupInstance(self, instance_name):
2021
    """Cleanup after a stopped instance
2022

2023
    """
2024
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
2025
    if pid > 0 and alive:
2026
      raise errors.HypervisorError("Cannot cleanup a live instance")
2027
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2028

    
2029
  def RebootInstance(self, instance):
2030
    """Reboot an instance.
2031

2032
    """
2033
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2034
    # socket the instance will stop, but now power up again. So we'll resort
2035
    # to shutdown and restart.
2036
    _, _, alive = self._InstancePidAlive(instance.name)
2037
    if not alive:
2038
      raise errors.HypervisorError("Failed to reboot instance %s:"
2039
                                   " not running" % instance.name)
2040
    # StopInstance will delete the saved KVM runtime so:
2041
    # ...first load it...
2042
    kvm_runtime = self._LoadKVMRuntime(instance)
2043
    # ...now we can safely call StopInstance...
2044
    if not self.StopInstance(instance):
2045
      self.StopInstance(instance, force=True)
2046
    # ...and finally we can save it again, and execute it...
2047
    self._SaveKVMRuntime(instance, kvm_runtime)
2048
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2049
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2050
    kvm_runtime_with_pci_info = \
2051
      self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2052
    self._SaveKVMRuntime(instance, kvm_runtime_with_pci_info)
2053

    
2054
  def MigrationInfo(self, instance):
2055
    """Get instance information to perform a migration.
2056

2057
    @type instance: L{objects.Instance}
2058
    @param instance: instance to be migrated
2059
    @rtype: string
2060
    @return: content of the KVM runtime file
2061

2062
    """
2063
    return self._ReadKVMRuntime(instance.name)
2064

    
2065
  def AcceptInstance(self, instance, info, target):
2066
    """Prepare to accept an instance.
2067

2068
    @type instance: L{objects.Instance}
2069
    @param instance: instance to be accepted
2070
    @type info: string
2071
    @param info: content of the KVM runtime file on the source node
2072
    @type target: string
2073
    @param target: target host (usually ip), on this node
2074

2075
    """
2076
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2077
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2078
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2079
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2080
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2081
                            incoming=incoming_address)
2082

    
2083
  def FinalizeMigrationDst(self, instance, info, success):
2084
    """Finalize the instance migration on the target node.
2085

2086
    Stop the incoming mode KVM.
2087

2088
    @type instance: L{objects.Instance}
2089
    @param instance: instance whose migration is being finalized
2090

2091
    """
2092
    if success:
2093
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2094
      kvm_nics = kvm_runtime[1]
2095

    
2096
      for nic_seq, nic in enumerate(kvm_nics):
2097
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2098
          # Bridged interfaces have already been configured
2099
          continue
2100
        try:
2101
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2102
        except EnvironmentError, err:
2103
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
2104
                          instance.name, nic_seq, str(err))
2105
          continue
2106
        try:
2107
          self._ConfigureNIC(instance, nic_seq, nic, tap)
2108
        except errors.HypervisorError, err:
2109
          logging.warning(str(err))
2110

    
2111
      self._WriteKVMRuntime(instance.name, info)
2112
    else:
2113
      self.StopInstance(instance, force=True)
2114

    
2115
  def MigrateInstance(self, instance, target, live):
2116
    """Migrate an instance to a target node.
2117

2118
    The migration will not be attempted if the instance is not
2119
    currently running.
2120

2121
    @type instance: L{objects.Instance}
2122
    @param instance: the instance to be migrated
2123
    @type target: string
2124
    @param target: ip address of the target node
2125
    @type live: boolean
2126
    @param live: perform a live migration
2127

2128
    """
2129
    instance_name = instance.name
2130
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
2131
    _, _, alive = self._InstancePidAlive(instance_name)
2132
    if not alive:
2133
      raise errors.HypervisorError("Instance not running, cannot migrate")
2134

    
2135
    if not live:
2136
      self._CallMonitorCommand(instance_name, "stop")
2137

    
2138
    migrate_command = ("migrate_set_speed %dm" %
2139
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2140
    self._CallMonitorCommand(instance_name, migrate_command)
2141

    
2142
    migrate_command = ("migrate_set_downtime %dms" %
2143
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2144
    self._CallMonitorCommand(instance_name, migrate_command)
2145

    
2146
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2147
    self._CallMonitorCommand(instance_name, migrate_command)
2148

    
2149
  def FinalizeMigrationSource(self, instance, success, live):
2150
    """Finalize the instance migration on the source node.
2151

2152
    @type instance: L{objects.Instance}
2153
    @param instance: the instance that was migrated
2154
    @type success: bool
2155
    @param success: whether the migration succeeded or not
2156
    @type live: bool
2157
    @param live: whether the user requested a live migration or not
2158

2159
    """
2160
    if success:
2161
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2162
      utils.KillProcess(pid)
2163
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2164
    elif live:
2165
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2166

    
2167
  def GetMigrationStatus(self, instance):
2168
    """Get the migration status
2169

2170
    @type instance: L{objects.Instance}
2171
    @param instance: the instance that is being migrated
2172
    @rtype: L{objects.MigrationStatus}
2173
    @return: the status of the current migration (one of
2174
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2175
             progress info that can be retrieved from the hypervisor
2176

2177
    """
2178
    info_command = "info migrate"
2179
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2180
      result = self._CallMonitorCommand(instance.name, info_command)
2181
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
2182
      if not match:
2183
        if not result.stdout:
2184
          logging.info("KVM: empty 'info migrate' result")
2185
        else:
2186
          logging.warning("KVM: unknown 'info migrate' result: %s",
2187
                          result.stdout)
2188
      else:
2189
        status = match.group(1)
2190
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2191
          migration_status = objects.MigrationStatus(status=status)
2192
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2193
          if match:
2194
            migration_status.transferred_ram = match.group("transferred")
2195
            migration_status.total_ram = match.group("total")
2196

    
2197
          return migration_status
2198

    
2199
        logging.warning("KVM: unknown migration status '%s'", status)
2200

    
2201
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2202

    
2203
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2204

    
2205
  def BalloonInstanceMemory(self, instance, mem):
2206
    """Balloon an instance memory to a certain value.
2207

2208
    @type instance: L{objects.Instance}
2209
    @param instance: instance to be accepted
2210
    @type mem: int
2211
    @param mem: actual memory size to use for instance runtime
2212

2213
    """
2214
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2215

    
2216
  def GetNodeInfo(self):
2217
    """Return information about the node.
2218

2219
    @return: a dict with the following keys (values in MiB):
2220
          - memory_total: the total memory size on the node
2221
          - memory_free: the available memory on the node for instances
2222
          - memory_dom0: the memory used by the node itself, if available
2223
          - hv_version: the hypervisor version in the form (major, minor,
2224
                        revision)
2225

2226
    """
2227
    result = self.GetLinuxNodeInfo()
2228
    # FIXME: this is the global kvm version, but the actual version can be
2229
    # customized as an hv parameter. we should use the nodegroup's default kvm
2230
    # path parameter here.
2231
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2232
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2233
    return result
2234

    
2235
  @classmethod
2236
  def GetInstanceConsole(cls, instance, hvparams, beparams):
2237
    """Return a command for connecting to the console of an instance.
2238

2239
    """
2240
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2241
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2242
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2243
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2244
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2245
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2246
      return objects.InstanceConsole(instance=instance.name,
2247
                                     kind=constants.CONS_SSH,
2248
                                     host=instance.primary_node,
2249
                                     user=constants.SSH_CONSOLE_USER,
2250
                                     command=cmd)
2251

    
2252
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2253
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2254
      display = instance.network_port - constants.VNC_BASE_PORT
2255
      return objects.InstanceConsole(instance=instance.name,
2256
                                     kind=constants.CONS_VNC,
2257
                                     host=vnc_bind_address,
2258
                                     port=instance.network_port,
2259
                                     display=display)
2260

    
2261
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2262
    if spice_bind:
2263
      return objects.InstanceConsole(instance=instance.name,
2264
                                     kind=constants.CONS_SPICE,
2265
                                     host=spice_bind,
2266
                                     port=instance.network_port)
2267

    
2268
    return objects.InstanceConsole(instance=instance.name,
2269
                                   kind=constants.CONS_MESSAGE,
2270
                                   message=("No serial shell for instance %s" %
2271
                                            instance.name))
2272

    
2273
  def Verify(self):
2274
    """Verify the hypervisor.
2275

2276
    Check that the required binaries exist.
2277

2278
    @return: Problem description if something is wrong, C{None} otherwise
2279

2280
    """
2281
    msgs = []
2282
    # FIXME: this is the global kvm binary, but the actual path can be
2283
    # customized as an hv parameter; we should use the nodegroup's
2284
    # default kvm path parameter here.
2285
    if not os.path.exists(constants.KVM_PATH):
2286
      msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2287
    if not os.path.exists(constants.SOCAT_PATH):
2288
      msgs.append("The socat binary ('%s') does not exist" %
2289
                  constants.SOCAT_PATH)
2290

    
2291
    return self._FormatVerifyResults(msgs)
2292

    
2293
  @classmethod
2294
  def CheckParameterSyntax(cls, hvparams):
2295
    """Check the given parameters for validity.
2296

2297
    @type hvparams:  dict
2298
    @param hvparams: dictionary with parameter names/value
2299
    @raise errors.HypervisorError: when a parameter is not valid
2300

2301
    """
2302
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2303

    
2304
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2305
    if kernel_path:
2306
      if not hvparams[constants.HV_ROOT_PATH]:
2307
        raise errors.HypervisorError("Need a root partition for the instance,"
2308
                                     " if a kernel is defined")
2309

    
2310
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2311
        not hvparams[constants.HV_VNC_X509]):
2312
      raise errors.HypervisorError("%s must be defined, if %s is" %
2313
                                   (constants.HV_VNC_X509,
2314
                                    constants.HV_VNC_X509_VERIFY))
2315

    
2316
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2317
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2318
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2319
      if not serial_speed or serial_speed not in valid_speeds:
2320
        raise errors.HypervisorError("Invalid serial console speed, must be"
2321
                                     " one of: %s" %
2322
                                     utils.CommaJoin(valid_speeds))
2323

    
2324
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2325
    if (boot_order == constants.HT_BO_CDROM and
2326
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2327
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2328
                                   " ISO path")
2329

    
2330
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2331
    if security_model == constants.HT_SM_USER:
2332
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2333
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2334
                                     " must be specified")
2335
    elif (security_model == constants.HT_SM_NONE or
2336
          security_model == constants.HT_SM_POOL):
2337
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2338
        raise errors.HypervisorError("Cannot have a security domain when the"
2339
                                     " security model is 'none' or 'pool'")
2340

    
2341
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2342
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2343
    if spice_bind:
2344
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2345
        # if an IP version is specified, the spice_bind parameter must be an
2346
        # IP of that family
2347
        if (netutils.IP4Address.IsValid(spice_bind) and
2348
            spice_ip_version != constants.IP4_VERSION):
2349
          raise errors.HypervisorError("spice: got an IPv4 address (%s), but"
2350
                                       " the specified IP version is %s" %
2351
                                       (spice_bind, spice_ip_version))
2352

    
2353
        if (netutils.IP6Address.IsValid(spice_bind) and
2354
            spice_ip_version != constants.IP6_VERSION):
2355
          raise errors.HypervisorError("spice: got an IPv6 address (%s), but"
2356
                                       " the specified IP version is %s" %
2357
                                       (spice_bind, spice_ip_version))
2358
    else:
2359
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2360
      # error if any of them is set without it.
2361
      for param in _SPICE_ADDITIONAL_PARAMS:
2362
        if hvparams[param]:
2363
          raise errors.HypervisorError("spice: %s requires %s to be set" %
2364
                                       (param, constants.HV_KVM_SPICE_BIND))
2365

    
2366
  @classmethod
2367
  def ValidateParameters(cls, hvparams):
2368
    """Check the given parameters for validity.
2369

2370
    @type hvparams:  dict
2371
    @param hvparams: dictionary with parameter names/value
2372
    @raise errors.HypervisorError: when a parameter is not valid
2373

2374
    """
2375
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2376

    
2377
    kvm_path = hvparams[constants.HV_KVM_PATH]
2378

    
2379
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2380
    if security_model == constants.HT_SM_USER:
2381
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2382
      try:
2383
        pwd.getpwnam(username)
2384
      except KeyError:
2385
        raise errors.HypervisorError("Unknown security domain user %s"
2386
                                     % username)
2387

    
2388
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2389
    if spice_bind:
2390
      # only one of VNC and SPICE can be used currently.
2391
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2392
        raise errors.HypervisorError("both SPICE and VNC are configured, but"
2393
                                     " only one of them can be used at a"
2394
                                     " given time.")
2395

    
2396
      # check that KVM supports SPICE
2397
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2398
      if not cls._SPICE_RE.search(kvmhelp):
2399
        raise errors.HypervisorError("spice is configured, but it is not"
2400
                                     " supported according to kvm --help")
2401

    
2402
      # if spice_bind is not an IP address, it must be a valid interface
2403
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind)
2404
                       or netutils.IP6Address.IsValid(spice_bind))
2405
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2406
        raise errors.HypervisorError("spice: the %s parameter must be either"
2407
                                     " a valid IP address or interface name" %
2408
                                     constants.HV_KVM_SPICE_BIND)
2409

    
2410
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2411
    if machine_version:
2412
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2413
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2414
        raise errors.HypervisorError("Unsupported machine version: %s" %
2415
                                     machine_version)
2416

    
2417
  @classmethod
2418
  def PowercycleNode(cls):
2419
    """KVM powercycle, just a wrapper over Linux powercycle.
2420

2421
    """
2422
    cls.LinuxPowercycle()