Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 172a75dc

History | View | Annotate | Download (89.7 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
from bitarray import bitarray
41
try:
42
  import affinity   # pylint: disable=F0401
43
except ImportError:
44
  affinity = None
45
try:
46
  import fdsend   # pylint: disable=F0401
47
except ImportError:
48
  fdsend = None
49

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

    
62

    
63
_KVM_NETWORK_SCRIPT = pathutils.CONF_DIR + "/kvm-vif-bridge"
64
_KVM_START_PAUSED_FLAG = "-S"
65

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

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

    
87
# Constant bitarray that reflects to a free pci slot
88
# Use it with bitarray.search()
89
_AVAILABLE_PCI_SLOT = bitarray("0")
90

    
91
# below constants show the format of runtime file
92
# the nics are in second possition, while the disks in 4th (last)
93
# moreover disk entries are stored in tupples of L{objects.Disk}, dev_path
94
_KVM_NICS_RUNTIME_INDEX = 1
95
_KVM_DISKS_RUNTIME_INDEX = 3
96
_DEVICE_RUNTIME_INDEX = {
97
  constants.HOTPLUG_TARGET_DISK: _KVM_DISKS_RUNTIME_INDEX,
98
  constants.HOTPLUG_TARGET_NIC: _KVM_NICS_RUNTIME_INDEX
99
  }
100
_FIND_RUNTIME_ENTRY = {
101
  constants.HOTPLUG_TARGET_NIC:
102
    lambda nic, kvm_nics: [n for n in kvm_nics if n.uuid == nic.uuid],
103
  constants.HOTPLUG_TARGET_DISK:
104
    lambda disk, kvm_disks: [(d, l) for (d, l) in kvm_disks
105
                             if d.uuid == disk.uuid]
106
  }
107
_RUNTIME_DEVICE = {
108
  constants.HOTPLUG_TARGET_NIC: lambda d: d,
109
  constants.HOTPLUG_TARGET_DISK: lambda (d, e): d
110
  }
111
_RUNTIME_ENTRY = {
112
  constants.HOTPLUG_TARGET_NIC: lambda d, e: d,
113
  constants.HOTPLUG_TARGET_DISK: lambda d, e: (d, e)
114
  }
115

    
116

    
117
def _GenerateDeviceKVMId(dev_type, dev):
118
  """Helper function to generate a unique device name used by KVM
119

120
  QEMU monitor commands use names to identify devices. Here we use their pci
121
  slot and a part of their UUID to name them. dev.pci might be None for old
122
  devices in the cluster.
123

124
  @type dev_type: sting
125
  @param dev_type: device type of param dev
126
  @type dev: L{objects.Disk} or L{objects.NIC}
127
  @param dev: the device object for which we generate a kvm name
128
  @raise errors.HotplugError: in case a device has no pci slot (old devices)
129

130
  """
131

    
132
  if not dev.pci:
133
    raise errors.HotplugError("Hotplug is not supported for %s with UUID %s" %
134
                              (dev_type, dev.uuid))
135

    
136
  return "%s-%s-pci-%d" % (dev_type.lower(), dev.uuid.split("-")[0], dev.pci)
137

    
138

    
139
def _UpdatePCISlots(dev, pci_reservations):
140
  """Update pci configuration for a stopped instance
141

142
  If dev has a pci slot then reserve it, else find first available
143
  in pci_reservations bitarray. It acts on the same objects passed
144
  as params so there is no need to return anything.
145

146
  @type dev: L{objects.Disk} or L{objects.NIC}
147
  @param dev: the device object for which we update its pci slot
148
  @type pci_reservations: bitarray
149
  @param pci_reservations: existing pci reservations for an instance
150
  @raise errors.HotplugError: in case an instance has all its slot occupied
151

152
  """
153
  if dev.pci:
154
    free = dev.pci
155
  else: # pylint: disable=E1103
156
    [free] = pci_reservations.search(_AVAILABLE_PCI_SLOT, 1)
157
    if not free:
158
      raise errors.HypervisorError("All PCI slots occupied")
159
    dev.pci = int(free)
160

    
161
  pci_reservations[free] = True
162

    
163

    
164
def _GetExistingDeviceInfo(dev_type, device, runtime):
165
  """Helper function to get an existing device inside the runtime file
166

167
  Used when an instance is running. Load kvm runtime file and search
168
  for a device based on its type and uuid.
169

170
  @type dev_type: sting
171
  @param dev_type: device type of param dev
172
  @type device: L{objects.Disk} or L{objects.NIC}
173
  @param device: the device object for which we generate a kvm name
174
  @type runtime: tuple (cmd, nics, hvparams, disks)
175
  @param runtime: the runtime data to search for the device
176
  @raise errors.HotplugError: in case the requested device does not
177
    exist (e.g. device has been added without --hotplug option) or
178
    device info has not pci slot (e.g. old devices in the cluster)
179

180
  """
181
  index = _DEVICE_RUNTIME_INDEX[dev_type]
182
  found = _FIND_RUNTIME_ENTRY[dev_type](device, runtime[index])
183
  if not found:
184
    raise errors.HotplugError("Cannot find runtime info for %s with UUID %s" %
185
                              (dev_type, device.uuid))
186

    
187
  return found[0]
188

    
189

    
190
def _AnalyzeSerializedRuntime(serialized_runtime):
191
  """Return runtime entries for a serialized runtime file
192

193
  @type serialized_runtime: string
194
  @param serialized_runtime: raw text data read from actual runtime file
195
  @return: (cmd, nics, hvparams, bdevs)
196
  @rtype: list
197

198
  """
199
  loaded_runtime = serializer.Load(serialized_runtime)
200
  if len(loaded_runtime) == 3:
201
    serialized_blockdevs = []
202
    kvm_cmd, serialized_nics, hvparams = loaded_runtime
203
  else:
204
    kvm_cmd, serialized_nics, hvparams, serialized_blockdevs = loaded_runtime
205

    
206
  kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
207
  block_devices = [(objects.Disk.FromDict(sdisk), link)
208
                   for sdisk, link in serialized_blockdevs]
209

    
210
  return (kvm_cmd, kvm_nics, hvparams, block_devices)
211

    
212

    
213
def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
214
  """Retrieves supported TUN features from file descriptor.
215

216
  @see: L{_ProbeTapVnetHdr}
217

218
  """
219
  req = struct.pack("I", 0)
220
  try:
221
    buf = _ioctl(fd, TUNGETFEATURES, req)
222
  except EnvironmentError, err:
223
    logging.warning("ioctl(TUNGETFEATURES) failed: %s", err)
224
    return None
225
  else:
226
    (flags, ) = struct.unpack("I", buf)
227
    return flags
228

    
229

    
230
def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
231
  """Check whether to enable the IFF_VNET_HDR flag.
232

233
  To do this, _all_ of the following conditions must be met:
234
   1. TUNGETFEATURES ioctl() *must* be implemented
235
   2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
236
   3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
237
      drivers/net/tun.c there is no way to test this until after the tap device
238
      has been created using TUNSETIFF, and there is no way to change the
239
      IFF_VNET_HDR flag after creating the interface, catch-22! However both
240
      TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
241
      thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
242

243
   @type fd: int
244
   @param fd: the file descriptor of /dev/net/tun
245

246
  """
247
  flags = _features_fn(fd)
248

    
249
  if flags is None:
250
    # Not supported
251
    return False
252

    
253
  result = bool(flags & IFF_VNET_HDR)
254

    
255
  if not result:
256
    logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
257

    
258
  return result
259

    
260

    
261
def _OpenTap(vnet_hdr=True):
262
  """Open a new tap device and return its file descriptor.
263

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

267
  @type vnet_hdr: boolean
268
  @param vnet_hdr: Enable the VNET Header
269
  @return: (ifname, tapfd)
270
  @rtype: tuple
271

272
  """
273
  try:
274
    tapfd = os.open("/dev/net/tun", os.O_RDWR)
275
  except EnvironmentError:
276
    raise errors.HypervisorError("Failed to open /dev/net/tun")
277

    
278
  flags = IFF_TAP | IFF_NO_PI
279

    
280
  if vnet_hdr and _ProbeTapVnetHdr(tapfd):
281
    flags |= IFF_VNET_HDR
282

    
283
  # The struct ifreq ioctl request (see netdevice(7))
284
  ifr = struct.pack("16sh", "", flags)
285

    
286
  try:
287
    res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
288
  except EnvironmentError, err:
289
    raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
290
                                 err)
291

    
292
  # Get the interface name from the ioctl
293
  ifname = struct.unpack("16sh", res)[0].strip("\x00")
294
  return (ifname, tapfd)
295

    
296

    
297
class QmpMessage:
298
  """QEMU Messaging Protocol (QMP) message.
299

300
  """
301
  def __init__(self, data):
302
    """Creates a new QMP message based on the passed data.
303

304
    """
305
    if not isinstance(data, dict):
306
      raise TypeError("QmpMessage must be initialized with a dict")
307

    
308
    self.data = data
309

    
310
  def __getitem__(self, field_name):
311
    """Get the value of the required field if present, or None.
312

313
    Overrides the [] operator to provide access to the message data,
314
    returning None if the required item is not in the message
315
    @return: the value of the field_name field, or None if field_name
316
             is not contained in the message
317

318
    """
319
    return self.data.get(field_name, None)
320

    
321
  def __setitem__(self, field_name, field_value):
322
    """Set the value of the required field_name to field_value.
323

324
    """
325
    self.data[field_name] = field_value
326

    
327
  @staticmethod
328
  def BuildFromJsonString(json_string):
329
    """Build a QmpMessage from a JSON encoded string.
330

331
    @type json_string: str
332
    @param json_string: JSON string representing the message
333
    @rtype: L{QmpMessage}
334
    @return: a L{QmpMessage} built from json_string
335

336
    """
337
    # Parse the string
338
    data = serializer.LoadJson(json_string)
339
    return QmpMessage(data)
340

    
341
  def __str__(self):
342
    # The protocol expects the JSON object to be sent as a single line.
343
    return serializer.DumpJson(self.data)
344

    
345
  def __eq__(self, other):
346
    # When comparing two QmpMessages, we are interested in comparing
347
    # their internal representation of the message data
348
    return self.data == other.data
349

    
350

    
351
class MonitorSocket(object):
352
  _SOCKET_TIMEOUT = 5
353

    
354
  def __init__(self, monitor_filename):
355
    """Instantiates the MonitorSocket object.
356

357
    @type monitor_filename: string
358
    @param monitor_filename: the filename of the UNIX raw socket on which the
359
                             monitor (QMP or simple one) is listening
360

361
    """
362
    self.monitor_filename = monitor_filename
363
    self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
364
    # We want to fail if the server doesn't send a complete message
365
    # in a reasonable amount of time
366
    self.sock.settimeout(self._SOCKET_TIMEOUT)
367
    self._connected = False
368

    
369
  def _check_socket(self):
370
    sock_stat = None
371
    try:
372
      sock_stat = os.stat(self.monitor_filename)
373
    except EnvironmentError, err:
374
      if err.errno == errno.ENOENT:
375
        raise errors.HypervisorError("No monitor socket found")
376
      else:
377
        raise errors.HypervisorError("Error checking monitor socket: %s",
378
                                     utils.ErrnoOrStr(err))
379
    if not stat.S_ISSOCK(sock_stat.st_mode):
380
      raise errors.HypervisorError("Monitor socket is not a socket")
381

    
382
  def _check_connection(self):
383
    """Make sure that the connection is established.
384

385
    """
386
    if not self._connected:
387
      raise errors.ProgrammerError("To use a MonitorSocket you need to first"
388
                                   " invoke connect() on it")
389

    
390
  def connect(self):
391
    """Connects to the monitor.
392

393
    Connects to the UNIX socket
394

395
    @raise errors.HypervisorError: when there are communication errors
396

397
    """
398
    if self._connected:
399
      raise errors.ProgrammerError("Cannot connect twice")
400

    
401
    self._check_socket()
402

    
403
    # Check file existance/stuff
404
    try:
405
      self.sock.connect(self.monitor_filename)
406
    except EnvironmentError:
407
      raise errors.HypervisorError("Can't connect to qmp socket")
408
    self._connected = True
409

    
410
  def close(self):
411
    """Closes the socket
412

413
    It cannot be used after this call.
414

415
    """
416
    self.sock.close()
417

    
418

    
419
class QmpConnection(MonitorSocket):
420
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
421

422
  """
423
  _FIRST_MESSAGE_KEY = "QMP"
424
  _EVENT_KEY = "event"
425
  _ERROR_KEY = "error"
426
  _RETURN_KEY = RETURN_KEY = "return"
427
  _ACTUAL_KEY = ACTUAL_KEY = "actual"
428
  _ERROR_CLASS_KEY = "class"
429
  _ERROR_DATA_KEY = "data"
430
  _ERROR_DESC_KEY = "desc"
431
  _EXECUTE_KEY = "execute"
432
  _ARGUMENTS_KEY = "arguments"
433
  _CAPABILITIES_COMMAND = "qmp_capabilities"
434
  _MESSAGE_END_TOKEN = "\r\n"
435

    
436
  def __init__(self, monitor_filename):
437
    super(QmpConnection, self).__init__(monitor_filename)
438
    self._buf = ""
439

    
440
  def connect(self):
441
    """Connects to the QMP monitor.
442

443
    Connects to the UNIX socket and makes sure that we can actually send and
444
    receive data to the kvm instance via QMP.
445

446
    @raise errors.HypervisorError: when there are communication errors
447
    @raise errors.ProgrammerError: when there are data serialization errors
448

449
    """
450
    super(QmpConnection, self).connect()
451
    # Check if we receive a correct greeting message from the server
452
    # (As per the QEMU Protocol Specification 0.1 - section 2.2)
453
    greeting = self._Recv()
454
    if not greeting[self._FIRST_MESSAGE_KEY]:
455
      self._connected = False
456
      raise errors.HypervisorError("kvm: QMP communication error (wrong"
457
                                   " server greeting")
458

    
459
    # Let's put the monitor in command mode using the qmp_capabilities
460
    # command, or else no command will be executable.
461
    # (As per the QEMU Protocol Specification 0.1 - section 4)
462
    self.Execute(self._CAPABILITIES_COMMAND)
463

    
464
  def _ParseMessage(self, buf):
465
    """Extract and parse a QMP message from the given buffer.
466

467
    Seeks for a QMP message in the given buf. If found, it parses it and
468
    returns it together with the rest of the characters in the buf.
469
    If no message is found, returns None and the whole buffer.
470

471
    @raise errors.ProgrammerError: when there are data serialization errors
472

473
    """
474
    message = None
475
    # Check if we got the message end token (CRLF, as per the QEMU Protocol
476
    # Specification 0.1 - Section 2.1.1)
477
    pos = buf.find(self._MESSAGE_END_TOKEN)
478
    if pos >= 0:
479
      try:
480
        message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
481
      except Exception, err:
482
        raise errors.ProgrammerError("QMP data serialization error: %s" % err)
483
      buf = buf[pos + 1:]
484

    
485
    return (message, buf)
486

    
487
  def _Recv(self):
488
    """Receives a message from QMP and decodes the received JSON object.
489

490
    @rtype: QmpMessage
491
    @return: the received message
492
    @raise errors.HypervisorError: when there are communication errors
493
    @raise errors.ProgrammerError: when there are data serialization errors
494

495
    """
496
    self._check_connection()
497

    
498
    # Check if there is already a message in the buffer
499
    (message, self._buf) = self._ParseMessage(self._buf)
500
    if message:
501
      return message
502

    
503
    recv_buffer = StringIO.StringIO(self._buf)
504
    recv_buffer.seek(len(self._buf))
505
    try:
506
      while True:
507
        data = self.sock.recv(4096)
508
        if not data:
509
          break
510
        recv_buffer.write(data)
511

    
512
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
513
        if message:
514
          return message
515

    
516
    except socket.timeout, err:
517
      raise errors.HypervisorError("Timeout while receiving a QMP message: "
518
                                   "%s" % (err))
519
    except socket.error, err:
520
      raise errors.HypervisorError("Unable to receive data from KVM using the"
521
                                   " QMP protocol: %s" % err)
522

    
523
  def _Send(self, message):
524
    """Encodes and sends a message to KVM using QMP.
525

526
    @type message: QmpMessage
527
    @param message: message to send to KVM
528
    @raise errors.HypervisorError: when there are communication errors
529
    @raise errors.ProgrammerError: when there are data serialization errors
530

531
    """
532
    self._check_connection()
533
    try:
534
      message_str = str(message)
535
    except Exception, err:
536
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
537

    
538
    try:
539
      self.sock.sendall(message_str)
540
    except socket.timeout, err:
541
      raise errors.HypervisorError("Timeout while sending a QMP message: "
542
                                   "%s (%s)" % (err.string, err.errno))
543
    except socket.error, err:
544
      raise errors.HypervisorError("Unable to send data from KVM using the"
545
                                   " QMP protocol: %s" % err)
546

    
547
  def Execute(self, command, arguments=None):
548
    """Executes a QMP command and returns the response of the server.
549

550
    @type command: str
551
    @param command: the command to execute
552
    @type arguments: dict
553
    @param arguments: dictionary of arguments to be passed to the command
554
    @rtype: dict
555
    @return: dictionary representing the received JSON object
556
    @raise errors.HypervisorError: when there are communication errors
557
    @raise errors.ProgrammerError: when there are data serialization errors
558

559
    """
560
    self._check_connection()
561
    message = QmpMessage({self._EXECUTE_KEY: command})
562
    if arguments:
563
      message[self._ARGUMENTS_KEY] = arguments
564
    self._Send(message)
565

    
566
    # Events can occur between the sending of the command and the reception
567
    # of the response, so we need to filter out messages with the event key.
568
    while True:
569
      response = self._Recv()
570
      err = response[self._ERROR_KEY]
571
      if err:
572
        raise errors.HypervisorError("kvm: error executing the %s"
573
                                     " command: %s (%s, %s):" %
574
                                     (command,
575
                                      err[self._ERROR_DESC_KEY],
576
                                      err[self._ERROR_CLASS_KEY],
577
                                      err[self._ERROR_DATA_KEY]))
578

    
579
      elif not response[self._EVENT_KEY]:
580
        return response
581

    
582

    
583
class KVMHypervisor(hv_base.BaseHypervisor):
584
  """KVM hypervisor interface
585

586
  """
587
  CAN_MIGRATE = True
588

    
589
  _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
590
  _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
591
  _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
592
  _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
593
  _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
594
  _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
595
  _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
596
  # KVM instances with chroot enabled are started in empty chroot directories.
597
  _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
598
  # After an instance is stopped, its chroot directory is removed.
599
  # If the chroot directory is not empty, it can't be removed.
600
  # A non-empty chroot directory indicates a possible security incident.
601
  # To support forensics, the non-empty chroot directory is quarantined in
602
  # a separate directory, called 'chroot-quarantine'.
603
  _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
604
  _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
605
           _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
606

    
607
  PARAMETERS = {
608
    constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
609
    constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
610
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
611
    constants.HV_ROOT_PATH: hv_base.NO_CHECK,
612
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
613
    constants.HV_ACPI: hv_base.NO_CHECK,
614
    constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
615
    constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
616
    constants.HV_VNC_BIND_ADDRESS:
617
      (False, lambda x: (netutils.IP4Address.IsValid(x) or
618
                         utils.IsNormAbsPath(x)),
619
       "The VNC bind address must be either a valid IP address or an absolute"
620
       " pathname", None, None),
621
    constants.HV_VNC_TLS: hv_base.NO_CHECK,
622
    constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
623
    constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
624
    constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
625
    constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
626
    constants.HV_KVM_SPICE_IP_VERSION:
627
      (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
628
                         x in constants.VALID_IP_VERSIONS),
629
       "The SPICE IP version should be 4 or 6",
630
       None, None),
631
    constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
632
    constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
633
      hv_base.ParamInSet(
634
        False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
635
    constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
636
      hv_base.ParamInSet(
637
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
638
    constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
639
      hv_base.ParamInSet(
640
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
641
    constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
642
      hv_base.ParamInSet(
643
        False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
644
    constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
645
    constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
646
    constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
647
    constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
648
    constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
649
    constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
650
    constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
651
    constants.HV_BOOT_ORDER:
652
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
653
    constants.HV_NIC_TYPE:
654
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
655
    constants.HV_DISK_TYPE:
656
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
657
    constants.HV_KVM_CDROM_DISK_TYPE:
658
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
659
    constants.HV_USB_MOUSE:
660
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
661
    constants.HV_KEYMAP: hv_base.NO_CHECK,
662
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
663
    constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
664
    constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
665
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
666
    constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
667
    constants.HV_DISK_CACHE:
668
      hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
669
    constants.HV_SECURITY_MODEL:
670
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
671
    constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
672
    constants.HV_KVM_FLAG:
673
      hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
674
    constants.HV_VHOST_NET: hv_base.NO_CHECK,
675
    constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
676
    constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
677
    constants.HV_REBOOT_BEHAVIOR:
678
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
679
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
680
    constants.HV_CPU_TYPE: hv_base.NO_CHECK,
681
    constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
682
    constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
683
    constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
684
    constants.HV_SOUNDHW: hv_base.NO_CHECK,
685
    constants.HV_USB_DEVICES: hv_base.NO_CHECK,
686
    constants.HV_VGA: hv_base.NO_CHECK,
687
    constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
688
    constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
689
    constants.HV_VNET_HDR: hv_base.NO_CHECK,
690
    }
691

    
692
  _VIRTIO = "virtio"
693
  _VIRTIO_NET_PCI = "virtio-net-pci"
694
  _VIRTIO_BLK_PCI = "virtio-blk-pci"
695

    
696
  _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
697
                                    re.M | re.I)
698
  _MIGRATION_PROGRESS_RE = \
699
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
700
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
701
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
702

    
703
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
704
  _MIGRATION_INFO_RETRY_DELAY = 2
705

    
706
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
707

    
708
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
709
  _CPU_INFO_CMD = "info cpus"
710
  _CONT_CMD = "cont"
711

    
712
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
713
  _CHECK_MACHINE_VERSION_RE = \
714
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
715

    
716
  _QMP_RE = re.compile(r"^-qmp\s", re.M)
717
  _SPICE_RE = re.compile(r"^-spice\s", re.M)
718
  _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
719
  _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
720
  _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
721
  _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
722
  _DISPLAY_RE = re.compile(r"^-display\s", re.M)
723
  _MACHINE_RE = re.compile(r"^-machine\s", re.M)
724
  _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
725
  _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M)
726
  # match  -drive.*boot=on|off on different lines, but in between accept only
727
  # dashes not preceeded by a new line (which would mean another option
728
  # different than -drive is starting)
729
  _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
730

    
731
  _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
732
  _INFO_PCI_CMD = "info pci"
733
  _INFO_VERSION_RE = \
734
    re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
735
  _INFO_VERSION_CMD = "info version"
736

    
737
  _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
738

    
739
  ANCILLARY_FILES = [
740
    _KVM_NETWORK_SCRIPT,
741
    ]
742
  ANCILLARY_FILES_OPT = [
743
    _KVM_NETWORK_SCRIPT,
744
    ]
745

    
746
  # Supported kvm options to get output from
747
  _KVMOPT_HELP = "help"
748
  _KVMOPT_MLIST = "mlist"
749
  _KVMOPT_DEVICELIST = "devicelist"
750

    
751
  # Command to execute to get the output from kvm, and whether to
752
  # accept the output even on failure.
753
  _KVMOPTS_CMDS = {
754
    _KVMOPT_HELP: (["--help"], False),
755
    _KVMOPT_MLIST: (["-M", "?"], False),
756
    _KVMOPT_DEVICELIST: (["-device", "?"], True),
757
  }
758

    
759
  def __init__(self):
760
    hv_base.BaseHypervisor.__init__(self)
761
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
762
    # in a tmpfs filesystem or has been otherwise wiped out.
763
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
764
    utils.EnsureDirs(dirs)
765

    
766
  @classmethod
767
  def _InstancePidFile(cls, instance_name):
768
    """Returns the instance pidfile.
769

770
    """
771
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
772

    
773
  @classmethod
774
  def _InstanceUidFile(cls, instance_name):
775
    """Returns the instance uidfile.
776

777
    """
778
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
779

    
780
  @classmethod
781
  def _InstancePidInfo(cls, pid):
782
    """Check pid file for instance information.
783

784
    Check that a pid file is associated with an instance, and retrieve
785
    information from its command line.
786

787
    @type pid: string or int
788
    @param pid: process id of the instance to check
789
    @rtype: tuple
790
    @return: (instance_name, memory, vcpus)
791
    @raise errors.HypervisorError: when an instance cannot be found
792

793
    """
794
    alive = utils.IsProcessAlive(pid)
795
    if not alive:
796
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
797

    
798
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
799
    try:
800
      cmdline = utils.ReadFile(cmdline_file)
801
    except EnvironmentError, err:
802
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
803
                                   (pid, err))
804

    
805
    instance = None
806
    memory = 0
807
    vcpus = 0
808

    
809
    arg_list = cmdline.split("\x00")
810
    while arg_list:
811
      arg = arg_list.pop(0)
812
      if arg == "-name":
813
        instance = arg_list.pop(0)
814
      elif arg == "-m":
815
        memory = int(arg_list.pop(0))
816
      elif arg == "-smp":
817
        vcpus = int(arg_list.pop(0).split(",")[0])
818

    
819
    if instance is None:
820
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
821
                                   " instance" % pid)
822

    
823
    return (instance, memory, vcpus)
824

    
825
  def _InstancePidAlive(self, instance_name):
826
    """Returns the instance pidfile, pid, and liveness.
827

828
    @type instance_name: string
829
    @param instance_name: instance name
830
    @rtype: tuple
831
    @return: (pid file name, pid, liveness)
832

833
    """
834
    pidfile = self._InstancePidFile(instance_name)
835
    pid = utils.ReadPidFile(pidfile)
836

    
837
    alive = False
838
    try:
839
      cmd_instance = self._InstancePidInfo(pid)[0]
840
      alive = (cmd_instance == instance_name)
841
    except errors.HypervisorError:
842
      pass
843

    
844
    return (pidfile, pid, alive)
845

    
846
  def _CheckDown(self, instance_name):
847
    """Raises an error unless the given instance is down.
848

849
    """
850
    alive = self._InstancePidAlive(instance_name)[2]
851
    if alive:
852
      raise errors.HypervisorError("Failed to start instance %s: %s" %
853
                                   (instance_name, "already running"))
854

    
855
  @classmethod
856
  def _InstanceMonitor(cls, instance_name):
857
    """Returns the instance monitor socket name
858

859
    """
860
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
861

    
862
  @classmethod
863
  def _InstanceSerial(cls, instance_name):
864
    """Returns the instance serial socket name
865

866
    """
867
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
868

    
869
  @classmethod
870
  def _InstanceQmpMonitor(cls, instance_name):
871
    """Returns the instance serial QMP socket name
872

873
    """
874
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
875

    
876
  @staticmethod
877
  def _SocatUnixConsoleParams():
878
    """Returns the correct parameters for socat
879

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

882
    """
883
    if constants.SOCAT_USE_ESCAPE:
884
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
885
    else:
886
      return "echo=0,icanon=0"
887

    
888
  @classmethod
889
  def _InstanceKVMRuntime(cls, instance_name):
890
    """Returns the instance KVM runtime filename
891

892
    """
893
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
894

    
895
  @classmethod
896
  def _InstanceChrootDir(cls, instance_name):
897
    """Returns the name of the KVM chroot dir of the instance
898

899
    """
900
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
901

    
902
  @classmethod
903
  def _InstanceNICDir(cls, instance_name):
904
    """Returns the name of the directory holding the tap device files for a
905
    given instance.
906

907
    """
908
    return utils.PathJoin(cls._NICS_DIR, instance_name)
909

    
910
  @classmethod
911
  def _InstanceNICFile(cls, instance_name, seq):
912
    """Returns the name of the file containing the tap device for a given NIC
913

914
    """
915
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
916

    
917
  @classmethod
918
  def _InstanceKeymapFile(cls, instance_name):
919
    """Returns the name of the file containing the keymap for a given instance
920

921
    """
922
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
923

    
924
  @classmethod
925
  def _TryReadUidFile(cls, uid_file):
926
    """Try to read a uid file
927

928
    """
929
    if os.path.exists(uid_file):
930
      try:
931
        uid = int(utils.ReadOneLineFile(uid_file))
932
        return uid
933
      except EnvironmentError:
934
        logging.warning("Can't read uid file", exc_info=True)
935
      except (TypeError, ValueError):
936
        logging.warning("Can't parse uid file contents", exc_info=True)
937
    return None
938

    
939
  @classmethod
940
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
941
    """Removes an instance's rutime sockets/files/dirs.
942

943
    """
944
    utils.RemoveFile(pidfile)
945
    utils.RemoveFile(cls._InstanceMonitor(instance_name))
946
    utils.RemoveFile(cls._InstanceSerial(instance_name))
947
    utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
948
    utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
949
    utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
950
    uid_file = cls._InstanceUidFile(instance_name)
951
    uid = cls._TryReadUidFile(uid_file)
952
    utils.RemoveFile(uid_file)
953
    if uid is not None:
954
      uidpool.ReleaseUid(uid)
955
    try:
956
      shutil.rmtree(cls._InstanceNICDir(instance_name))
957
    except OSError, err:
958
      if err.errno != errno.ENOENT:
959
        raise
960
    try:
961
      chroot_dir = cls._InstanceChrootDir(instance_name)
962
      utils.RemoveDir(chroot_dir)
963
    except OSError, err:
964
      if err.errno == errno.ENOTEMPTY:
965
        # The chroot directory is expected to be empty, but it isn't.
966
        new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
967
                                          prefix="%s-%s-" %
968
                                          (instance_name,
969
                                           utils.TimestampForFilename()))
970
        logging.warning("The chroot directory of instance %s can not be"
971
                        " removed as it is not empty. Moving it to the"
972
                        " quarantine instead. Please investigate the"
973
                        " contents (%s) and clean up manually",
974
                        instance_name, new_chroot_dir)
975
        utils.RenameFile(chroot_dir, new_chroot_dir)
976
      else:
977
        raise
978

    
979
  @staticmethod
980
  def _ConfigureNIC(instance, seq, nic, tap):
981
    """Run the network configuration script for a specified NIC
982

983
    @param instance: instance we're acting on
984
    @type instance: instance object
985
    @param seq: nic sequence number
986
    @type seq: int
987
    @param nic: nic we're acting on
988
    @type nic: nic object
989
    @param tap: the host's tap interface this NIC corresponds to
990
    @type tap: str
991

992
    """
993
    if instance.tags:
994
      tags = " ".join(instance.tags)
995
    else:
996
      tags = ""
997

    
998
    env = {
999
      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
1000
      "INSTANCE": instance.name,
1001
      "MAC": nic.mac,
1002
      "MODE": nic.nicparams[constants.NIC_MODE],
1003
      "INTERFACE": tap,
1004
      "INTERFACE_INDEX": str(seq),
1005
      "TAGS": tags,
1006
    }
1007

    
1008
    if nic.ip:
1009
      env["IP"] = nic.ip
1010

    
1011
    if nic.nicparams[constants.NIC_LINK]:
1012
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
1013

    
1014
    if nic.network:
1015
      n = objects.Network.FromDict(nic.netinfo)
1016
      env.update(n.HooksDict())
1017

    
1018
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1019
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
1020

    
1021
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
1022
    if result.failed:
1023
      raise errors.HypervisorError("Failed to configure interface %s: %s;"
1024
                                   " network configuration script output: %s" %
1025
                                   (tap, result.fail_reason, result.output))
1026

    
1027
  @staticmethod
1028
  def _VerifyAffinityPackage():
1029
    if affinity is None:
1030
      raise errors.HypervisorError("affinity Python package not"
1031
                                   " found; cannot use CPU pinning under KVM")
1032

    
1033
  @staticmethod
1034
  def _BuildAffinityCpuMask(cpu_list):
1035
    """Create a CPU mask suitable for sched_setaffinity from a list of
1036
    CPUs.
1037

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

1041
    @type cpu_list: list of int
1042
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
1043
    @rtype: int
1044
    @return: a bit mask of CPU affinities
1045

1046
    """
1047
    if cpu_list == constants.CPU_PINNING_OFF:
1048
      return constants.CPU_PINNING_ALL_KVM
1049
    else:
1050
      return sum(2 ** cpu for cpu in cpu_list)
1051

    
1052
  @classmethod
1053
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
1054
    """Change CPU affinity for running VM according to given CPU mask.
1055

1056
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
1057
    @type cpu_mask: string
1058
    @param process_id: process ID of KVM process. Used to pin entire VM
1059
                       to physical CPUs.
1060
    @type process_id: int
1061
    @param thread_dict: map of virtual CPUs to KVM thread IDs
1062
    @type thread_dict: dict int:int
1063

1064
    """
1065
    # Convert the string CPU mask to a list of list of int's
1066
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
1067

    
1068
    if len(cpu_list) == 1:
1069
      all_cpu_mapping = cpu_list[0]
1070
      if all_cpu_mapping == constants.CPU_PINNING_OFF:
1071
        # If CPU pinning has 1 entry that's "all", then do nothing
1072
        pass
1073
      else:
1074
        # If CPU pinning has one non-all entry, map the entire VM to
1075
        # one set of physical CPUs
1076
        cls._VerifyAffinityPackage()
1077
        affinity.set_process_affinity_mask(
1078
          process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
1079
    else:
1080
      # The number of vCPUs mapped should match the number of vCPUs
1081
      # reported by KVM. This was already verified earlier, so
1082
      # here only as a sanity check.
1083
      assert len(thread_dict) == len(cpu_list)
1084
      cls._VerifyAffinityPackage()
1085

    
1086
      # For each vCPU, map it to the proper list of physical CPUs
1087
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1088
        affinity.set_process_affinity_mask(thread_dict[i],
1089
                                           cls._BuildAffinityCpuMask(vcpu))
1090

    
1091
  def _GetVcpuThreadIds(self, instance_name):
1092
    """Get a mapping of vCPU no. to thread IDs for the instance
1093

1094
    @type instance_name: string
1095
    @param instance_name: instance in question
1096
    @rtype: dictionary of int:int
1097
    @return: a dictionary mapping vCPU numbers to thread IDs
1098

1099
    """
1100
    result = {}
1101
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1102
    for line in output.stdout.splitlines():
1103
      match = self._CPU_INFO_RE.search(line)
1104
      if not match:
1105
        continue
1106
      grp = map(int, match.groups())
1107
      result[grp[0]] = grp[1]
1108

    
1109
    return result
1110

    
1111
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1112
    """Complete CPU pinning.
1113

1114
    @type instance_name: string
1115
    @param instance_name: name of instance
1116
    @type cpu_mask: string
1117
    @param cpu_mask: CPU pinning mask as entered by user
1118

1119
    """
1120
    # Get KVM process ID, to be used if need to pin entire VM
1121
    _, pid, _ = self._InstancePidAlive(instance_name)
1122
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1123
    thread_dict = self._GetVcpuThreadIds(instance_name)
1124
    # Run CPU pinning, based on configured mask
1125
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1126

    
1127
  def ListInstances(self):
1128
    """Get the list of running instances.
1129

1130
    We can do this by listing our live instances directory and
1131
    checking whether the associated kvm process is still alive.
1132

1133
    """
1134
    result = []
1135
    for name in os.listdir(self._PIDS_DIR):
1136
      if self._InstancePidAlive(name)[2]:
1137
        result.append(name)
1138
    return result
1139

    
1140
  def GetInstanceInfo(self, instance_name):
1141
    """Get instance properties.
1142

1143
    @type instance_name: string
1144
    @param instance_name: the instance name
1145
    @rtype: tuple of strings
1146
    @return: (name, id, memory, vcpus, stat, times)
1147

1148
    """
1149
    _, pid, alive = self._InstancePidAlive(instance_name)
1150
    if not alive:
1151
      return None
1152

    
1153
    _, memory, vcpus = self._InstancePidInfo(pid)
1154
    istat = "---b-"
1155
    times = "0"
1156

    
1157
    try:
1158
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1159
      qmp.connect()
1160
      vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1161
      # Will fail if ballooning is not enabled, but we can then just resort to
1162
      # the value above.
1163
      mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1164
      memory = mem_bytes / 1048576
1165
    except errors.HypervisorError:
1166
      pass
1167

    
1168
    return (instance_name, pid, memory, vcpus, istat, times)
1169

    
1170
  def GetAllInstancesInfo(self):
1171
    """Get properties of all instances.
1172

1173
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1174

1175
    """
1176
    data = []
1177
    for name in os.listdir(self._PIDS_DIR):
1178
      try:
1179
        info = self.GetInstanceInfo(name)
1180
      except errors.HypervisorError:
1181
        # Ignore exceptions due to instances being shut down
1182
        continue
1183
      if info:
1184
        data.append(info)
1185
    return data
1186

    
1187
  def _GenerateKVMBlockDevicesOptions(self, instance, block_devices, kvmhelp):
1188

    
1189
    hvp = instance.hvparams
1190
    boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1191
    kvm_path = hvp[constants.HV_KVM_PATH]
1192

    
1193
    # whether this is an older KVM version that uses the boot=on flag
1194
    # on devices
1195
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1196

    
1197
    dev_opts = []
1198
    device_driver = None
1199
    disk_type = hvp[constants.HV_DISK_TYPE]
1200
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
1201
      if_val = ",if=%s" % self._VIRTIO
1202
      try:
1203
        devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1204
        if self._VIRTIO_BLK_RE.search(devlist):
1205
          if_val = ",if=none"
1206
          # will be passed in -device option as driver
1207
          device_driver = self._VIRTIO_BLK_PCI
1208
      except errors.HypervisorError, _:
1209
        pass
1210
    else:
1211
      if_val = ",if=%s" % disk_type
1212
    # Cache mode
1213
    disk_cache = hvp[constants.HV_DISK_CACHE]
1214
    if instance.disk_template in constants.DTS_EXT_MIRROR:
1215
      if disk_cache != "none":
1216
        # TODO: make this a hard error, instead of a silent overwrite
1217
        logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1218
                        " to prevent shared storage corruption on migration",
1219
                        disk_cache)
1220
      cache_val = ",cache=none"
1221
    elif disk_cache != constants.HT_CACHE_DEFAULT:
1222
      cache_val = ",cache=%s" % disk_cache
1223
    else:
1224
      cache_val = ""
1225
    for cfdev, dev_path in block_devices:
1226
      if cfdev.mode != constants.DISK_RDWR:
1227
        raise errors.HypervisorError("Instance has read-only disks which"
1228
                                     " are not supported by KVM")
1229
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
1230
      boot_val = ""
1231
      if boot_disk:
1232
        dev_opts.extend(["-boot", "c"])
1233
        boot_disk = False
1234
        if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1235
          boot_val = ",boot=on"
1236
      drive_val = "file=%s,format=raw%s%s%s" % \
1237
                  (dev_path, if_val, boot_val, cache_val)
1238

    
1239
      if device_driver:
1240
        # block_devices are the 4th entry of runtime file that did not exist in
1241
        # the past. That means that cfdev should always have pci slot and
1242
        # _GenerateDeviceKVMId() will not raise a exception.
1243
        kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_DISK, cfdev)
1244
        drive_val += (",id=%s" % kvm_devid)
1245
        drive_val += (",bus=0,unit=%d" % cfdev.pci)
1246
        dev_val = ("%s,drive=%s,id=%s" %
1247
                   (device_driver, kvm_devid, kvm_devid))
1248
        dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci)
1249
        dev_opts.extend(["-device", dev_val])
1250

    
1251
      dev_opts.extend(["-drive", drive_val])
1252

    
1253
    return dev_opts
1254

    
1255
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1256
                          kvmhelp):
1257
    """Generate KVM information to start an instance.
1258

1259
    @type kvmhelp: string
1260
    @param kvmhelp: output of kvm --help
1261
    @attention: this function must not have any side-effects; for
1262
        example, it must not write to the filesystem, or read values
1263
        from the current system the are expected to differ between
1264
        nodes, since it is only run once at instance startup;
1265
        actions/kvm arguments that can vary between systems should be
1266
        done in L{_ExecuteKVMRuntime}
1267

1268
    """
1269
    # pylint: disable=R0912,R0914,R0915
1270
    hvp = instance.hvparams
1271
    self.ValidateParameters(hvp)
1272

    
1273
    pidfile = self._InstancePidFile(instance.name)
1274
    kvm = hvp[constants.HV_KVM_PATH]
1275
    kvm_cmd = [kvm]
1276
    # used just by the vnc server, if enabled
1277
    kvm_cmd.extend(["-name", instance.name])
1278
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1279

    
1280
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1281
    if hvp[constants.HV_CPU_CORES]:
1282
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1283
    if hvp[constants.HV_CPU_THREADS]:
1284
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1285
    if hvp[constants.HV_CPU_SOCKETS]:
1286
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1287

    
1288
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1289

    
1290
    kvm_cmd.extend(["-pidfile", pidfile])
1291
    kvm_cmd.extend(["-balloon", "virtio"])
1292
    kvm_cmd.extend(["-daemonize"])
1293
    if not instance.hvparams[constants.HV_ACPI]:
1294
      kvm_cmd.extend(["-no-acpi"])
1295
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1296
        constants.INSTANCE_REBOOT_EXIT:
1297
      kvm_cmd.extend(["-no-reboot"])
1298

    
1299
    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1300
    if not mversion:
1301
      mversion = self._GetDefaultMachineVersion(kvm)
1302
    if self._MACHINE_RE.search(kvmhelp):
1303
      # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1304
      # extra hypervisor parameters. We should also investigate whether and how
1305
      # shadow_mem should be considered for the resource model.
1306
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1307
        specprop = ",accel=kvm"
1308
      else:
1309
        specprop = ""
1310
      machinespec = "%s%s" % (mversion, specprop)
1311
      kvm_cmd.extend(["-machine", machinespec])
1312
    else:
1313
      kvm_cmd.extend(["-M", mversion])
1314
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1315
          self._ENABLE_KVM_RE.search(kvmhelp)):
1316
        kvm_cmd.extend(["-enable-kvm"])
1317
      elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1318
            self._DISABLE_KVM_RE.search(kvmhelp)):
1319
        kvm_cmd.extend(["-disable-kvm"])
1320

    
1321
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1322
    if kernel_path:
1323
      boot_cdrom = boot_floppy = boot_network = False
1324
    else:
1325
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1326
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1327
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1328

    
1329
    if startup_paused:
1330
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1331

    
1332
    if boot_network:
1333
      kvm_cmd.extend(["-boot", "n"])
1334

    
1335
    # whether this is an older KVM version that uses the boot=on flag
1336
    # on devices
1337
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1338

    
1339
    disk_type = hvp[constants.HV_DISK_TYPE]
1340

    
1341
    #Now we can specify a different device type for CDROM devices.
1342
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1343
    if not cdrom_disk_type:
1344
      cdrom_disk_type = disk_type
1345

    
1346
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1347
    if iso_image:
1348
      options = ",format=raw,media=cdrom"
1349
      # set cdrom 'if' type
1350
      if boot_cdrom:
1351
        actual_cdrom_type = constants.HT_DISK_IDE
1352
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1353
        actual_cdrom_type = "virtio"
1354
      else:
1355
        actual_cdrom_type = cdrom_disk_type
1356
      if_val = ",if=%s" % actual_cdrom_type
1357
      # set boot flag, if needed
1358
      boot_val = ""
1359
      if boot_cdrom:
1360
        kvm_cmd.extend(["-boot", "d"])
1361
        if needs_boot_flag:
1362
          boot_val = ",boot=on"
1363
      # and finally build the entire '-drive' value
1364
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1365
      kvm_cmd.extend(["-drive", drive_val])
1366

    
1367
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1368
    if iso_image2:
1369
      options = ",format=raw,media=cdrom"
1370
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1371
        if_val = ",if=virtio"
1372
      else:
1373
        if_val = ",if=%s" % cdrom_disk_type
1374
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1375
      kvm_cmd.extend(["-drive", drive_val])
1376

    
1377
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1378
    if floppy_image:
1379
      options = ",format=raw,media=disk"
1380
      if boot_floppy:
1381
        kvm_cmd.extend(["-boot", "a"])
1382
        options = "%s,boot=on" % options
1383
      if_val = ",if=floppy"
1384
      options = "%s%s" % (options, if_val)
1385
      drive_val = "file=%s%s" % (floppy_image, options)
1386
      kvm_cmd.extend(["-drive", drive_val])
1387

    
1388
    if kernel_path:
1389
      kvm_cmd.extend(["-kernel", kernel_path])
1390
      initrd_path = hvp[constants.HV_INITRD_PATH]
1391
      if initrd_path:
1392
        kvm_cmd.extend(["-initrd", initrd_path])
1393
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1394
                     hvp[constants.HV_KERNEL_ARGS]]
1395
      if hvp[constants.HV_SERIAL_CONSOLE]:
1396
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1397
        root_append.append("console=ttyS0,%s" % serial_speed)
1398
      kvm_cmd.extend(["-append", " ".join(root_append)])
1399

    
1400
    mem_path = hvp[constants.HV_MEM_PATH]
1401
    if mem_path:
1402
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1403

    
1404
    monitor_dev = ("unix:%s,server,nowait" %
1405
                   self._InstanceMonitor(instance.name))
1406
    kvm_cmd.extend(["-monitor", monitor_dev])
1407
    if hvp[constants.HV_SERIAL_CONSOLE]:
1408
      serial_dev = ("unix:%s,server,nowait" %
1409
                    self._InstanceSerial(instance.name))
1410
      kvm_cmd.extend(["-serial", serial_dev])
1411
    else:
1412
      kvm_cmd.extend(["-serial", "none"])
1413

    
1414
    mouse_type = hvp[constants.HV_USB_MOUSE]
1415
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1416
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1417
    spice_ip_version = None
1418

    
1419
    kvm_cmd.extend(["-usb"])
1420

    
1421
    if mouse_type:
1422
      kvm_cmd.extend(["-usbdevice", mouse_type])
1423
    elif vnc_bind_address:
1424
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1425

    
1426
    if vnc_bind_address:
1427
      if netutils.IP4Address.IsValid(vnc_bind_address):
1428
        if instance.network_port > constants.VNC_BASE_PORT:
1429
          display = instance.network_port - constants.VNC_BASE_PORT
1430
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1431
            vnc_arg = ":%d" % (display)
1432
          else:
1433
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1434
        else:
1435
          logging.error("Network port is not a valid VNC display (%d < %d),"
1436
                        " not starting VNC",
1437
                        instance.network_port, constants.VNC_BASE_PORT)
1438
          vnc_arg = "none"
1439

    
1440
        # Only allow tls and other option when not binding to a file, for now.
1441
        # kvm/qemu gets confused otherwise about the filename to use.
1442
        vnc_append = ""
1443
        if hvp[constants.HV_VNC_TLS]:
1444
          vnc_append = "%s,tls" % vnc_append
1445
          if hvp[constants.HV_VNC_X509_VERIFY]:
1446
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1447
                                               hvp[constants.HV_VNC_X509])
1448
          elif hvp[constants.HV_VNC_X509]:
1449
            vnc_append = "%s,x509=%s" % (vnc_append,
1450
                                         hvp[constants.HV_VNC_X509])
1451
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1452
          vnc_append = "%s,password" % vnc_append
1453

    
1454
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1455

    
1456
      else:
1457
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1458

    
1459
      kvm_cmd.extend(["-vnc", vnc_arg])
1460
    elif spice_bind:
1461
      # FIXME: this is wrong here; the iface ip address differs
1462
      # between systems, so it should be done in _ExecuteKVMRuntime
1463
      if netutils.IsValidInterface(spice_bind):
1464
        # The user specified a network interface, we have to figure out the IP
1465
        # address.
1466
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1467
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1468

    
1469
        # if the user specified an IP version and the interface does not
1470
        # have that kind of IP addresses, throw an exception
1471
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1472
          if not addresses[spice_ip_version]:
1473
            raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1474
                                         " for %s" % (spice_ip_version,
1475
                                                      spice_bind))
1476

    
1477
        # the user did not specify an IP version, we have to figure it out
1478
        elif (addresses[constants.IP4_VERSION] and
1479
              addresses[constants.IP6_VERSION]):
1480
          # we have both ipv4 and ipv6, let's use the cluster default IP
1481
          # version
1482
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1483
          spice_ip_version = \
1484
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1485
        elif addresses[constants.IP4_VERSION]:
1486
          spice_ip_version = constants.IP4_VERSION
1487
        elif addresses[constants.IP6_VERSION]:
1488
          spice_ip_version = constants.IP6_VERSION
1489
        else:
1490
          raise errors.HypervisorError("SPICE: Unable to get an IP address"
1491
                                       " for %s" % (spice_bind))
1492

    
1493
        spice_address = addresses[spice_ip_version][0]
1494

    
1495
      else:
1496
        # spice_bind is known to be a valid IP address, because
1497
        # ValidateParameters checked it.
1498
        spice_address = spice_bind
1499

    
1500
      spice_arg = "addr=%s" % spice_address
1501
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1502
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1503
                     (spice_arg, instance.network_port,
1504
                      pathutils.SPICE_CACERT_FILE))
1505
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1506
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1507
                      pathutils.SPICE_CERT_FILE))
1508
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1509
        if tls_ciphers:
1510
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1511
      else:
1512
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1513

    
1514
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1515
        spice_arg = "%s,disable-ticketing" % spice_arg
1516

    
1517
      if spice_ip_version:
1518
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1519

    
1520
      # Image compression options
1521
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1522
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1523
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1524
      if img_lossless:
1525
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1526
      if img_jpeg:
1527
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1528
      if img_zlib_glz:
1529
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1530

    
1531
      # Video stream detection
1532
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1533
      if video_streaming:
1534
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1535

    
1536
      # Audio compression, by default in qemu-kvm it is on
1537
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1538
        spice_arg = "%s,playback-compression=off" % spice_arg
1539
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1540
        spice_arg = "%s,agent-mouse=off" % spice_arg
1541
      else:
1542
        # Enable the spice agent communication channel between the host and the
1543
        # agent.
1544
        kvm_cmd.extend(["-device", "virtio-serial-pci"])
1545
        kvm_cmd.extend([
1546
          "-device",
1547
          "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1548
          ])
1549
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1550

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

    
1554
    else:
1555
      # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1556
      # also works in earlier versions though (tested with 1.1 and 1.3)
1557
      if self._DISPLAY_RE.search(kvmhelp):
1558
        kvm_cmd.extend(["-display", "none"])
1559
      else:
1560
        kvm_cmd.extend(["-nographic"])
1561

    
1562
    if hvp[constants.HV_USE_LOCALTIME]:
1563
      kvm_cmd.extend(["-localtime"])
1564

    
1565
    if hvp[constants.HV_KVM_USE_CHROOT]:
1566
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1567

    
1568
    # Add qemu-KVM -cpu param
1569
    if hvp[constants.HV_CPU_TYPE]:
1570
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1571

    
1572
    # As requested by music lovers
1573
    if hvp[constants.HV_SOUNDHW]:
1574
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1575

    
1576
    # Pass a -vga option if requested, or if spice is used, for backwards
1577
    # compatibility.
1578
    if hvp[constants.HV_VGA]:
1579
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1580
    elif spice_bind:
1581
      kvm_cmd.extend(["-vga", "qxl"])
1582

    
1583
    # Various types of usb devices, comma separated
1584
    if hvp[constants.HV_USB_DEVICES]:
1585
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1586
        kvm_cmd.extend(["-usbdevice", dev])
1587

    
1588
    if hvp[constants.HV_KVM_EXTRA]:
1589
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1590

    
1591
    pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1592
    kvm_disks = []
1593
    for disk, link_name in block_devices:
1594
      _UpdatePCISlots(disk, pci_reservations)
1595
      kvm_disks.append((disk, link_name))
1596

    
1597
    kvm_nics = []
1598
    for nic in instance.nics:
1599
      _UpdatePCISlots(nic, pci_reservations)
1600
      kvm_nics.append(nic)
1601

    
1602
    hvparams = hvp
1603

    
1604
    return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1605

    
1606
  def _WriteKVMRuntime(self, instance_name, data):
1607
    """Write an instance's KVM runtime
1608

1609
    """
1610
    try:
1611
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1612
                      data=data)
1613
    except EnvironmentError, err:
1614
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1615

    
1616
  def _ReadKVMRuntime(self, instance_name):
1617
    """Read an instance's KVM runtime
1618

1619
    """
1620
    try:
1621
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1622
    except EnvironmentError, err:
1623
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1624
    return file_content
1625

    
1626
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1627
    """Save an instance's KVM runtime
1628

1629
    """
1630
    kvm_cmd, kvm_nics, hvparams, block_devices = kvm_runtime
1631

    
1632
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1633
    serialized_blockdevs = [(blk.ToDict(), link)
1634
                            for blk, link in block_devices]
1635
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1636
                                      serialized_blockdevs))
1637

    
1638
    self._WriteKVMRuntime(instance.name, serialized_form)
1639

    
1640
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1641
    """Load an instance's KVM runtime
1642

1643
    """
1644
    if not serialized_runtime:
1645
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1646

    
1647
    return _AnalyzeSerializedRuntime(serialized_runtime)
1648

    
1649
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1650
    """Run the KVM cmd and check for errors
1651

1652
    @type name: string
1653
    @param name: instance name
1654
    @type kvm_cmd: list of strings
1655
    @param kvm_cmd: runcmd input for kvm
1656
    @type tap_fds: list of int
1657
    @param tap_fds: fds of tap devices opened by Ganeti
1658

1659
    """
1660
    try:
1661
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1662
    finally:
1663
      for fd in tap_fds:
1664
        utils_wrapper.CloseFdNoError(fd)
1665

    
1666
    if result.failed:
1667
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1668
                                   (name, result.fail_reason, result.output))
1669
    if not self._InstancePidAlive(name)[2]:
1670
      raise errors.HypervisorError("Failed to start instance %s" % name)
1671

    
1672
  # 52/50 local variables
1673
  # pylint: disable=R0914
1674
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1675
    """Execute a KVM cmd, after completing it with some last minute data.
1676

1677
    @type incoming: tuple of strings
1678
    @param incoming: (target_host_ip, port)
1679
    @type kvmhelp: string
1680
    @param kvmhelp: output of kvm --help
1681

1682
    """
1683
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1684
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1685
    #    have changed since the instance started; only use them if the change
1686
    #    won't affect the inside of the instance (which hasn't been rebooted).
1687
    #  - up_hvp contains the parameters as they were when the instance was
1688
    #    started, plus any new parameter which has been added between ganeti
1689
    #    versions: it is paramount that those default to a value which won't
1690
    #    affect the inside of the instance as well.
1691
    conf_hvp = instance.hvparams
1692
    name = instance.name
1693
    self._CheckDown(name)
1694

    
1695
    temp_files = []
1696

    
1697
    kvm_cmd, kvm_nics, up_hvp, block_devices = kvm_runtime
1698
    # the first element of kvm_cmd is always the path to the kvm binary
1699
    kvm_path = kvm_cmd[0]
1700
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1701

    
1702
    # We know it's safe to run as a different user upon migration, so we'll use
1703
    # the latest conf, from conf_hvp.
1704
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1705
    if security_model == constants.HT_SM_USER:
1706
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1707

    
1708
    keymap = conf_hvp[constants.HV_KEYMAP]
1709
    if keymap:
1710
      keymap_path = self._InstanceKeymapFile(name)
1711
      # If a keymap file is specified, KVM won't use its internal defaults. By
1712
      # first including the "en-us" layout, an error on loading the actual
1713
      # layout (e.g. because it can't be found) won't lead to a non-functional
1714
      # keyboard. A keyboard with incorrect keys is still better than none.
1715
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1716
      kvm_cmd.extend(["-k", keymap_path])
1717

    
1718
    # We have reasons to believe changing something like the nic driver/type
1719
    # upon migration won't exactly fly with the instance kernel, so for nic
1720
    # related parameters we'll use up_hvp
1721
    tapfds = []
1722
    taps = []
1723
    if not kvm_nics:
1724
      kvm_cmd.extend(["-net", "none"])
1725
    else:
1726
      vnet_hdr = False
1727
      tap_extra = ""
1728
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1729
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1730
        nic_model = self._VIRTIO
1731
        try:
1732
          devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1733
          if self._VIRTIO_NET_RE.search(devlist):
1734
            nic_model = self._VIRTIO_NET_PCI
1735
            vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1736
        except errors.HypervisorError, _:
1737
          # Older versions of kvm don't support DEVICE_LIST, but they don't
1738
          # have new virtio syntax either.
1739
          pass
1740

    
1741
        if up_hvp[constants.HV_VHOST_NET]:
1742
          # check for vhost_net support
1743
          if self._VHOST_RE.search(kvmhelp):
1744
            tap_extra = ",vhost=on"
1745
          else:
1746
            raise errors.HypervisorError("vhost_net is configured"
1747
                                         " but it is not available")
1748
      else:
1749
        nic_model = nic_type
1750

    
1751
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1752

    
1753
      for nic_seq, nic in enumerate(kvm_nics):
1754
        tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1755
        tapfds.append(tapfd)
1756
        taps.append(tapname)
1757
        if kvm_supports_netdev:
1758
          nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1759
          try:
1760
            # kvm_nics already exist in old runtime files and thus there might
1761
            # be some entries without pci slot (therefore try: except:)
1762
            kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1763
            netdev = kvm_devid
1764
            nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1765
          except errors.HotplugError:
1766
            netdev = "netdev%d" % nic_seq
1767
          nic_val += (",netdev=%s" % netdev)
1768
          tap_val = ("type=tap,id=%s,fd=%d%s" %
1769
                     (netdev, tapfd, tap_extra))
1770
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1771
        else:
1772
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1773
                                                         nic.mac, nic_model)
1774
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1775
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1776

    
1777
    if incoming:
1778
      target, port = incoming
1779
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1780

    
1781
    # Changing the vnc password doesn't bother the guest that much. At most it
1782
    # will surprise people who connect to it. Whether positively or negatively
1783
    # it's debatable.
1784
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1785
    vnc_pwd = None
1786
    if vnc_pwd_file:
1787
      try:
1788
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1789
      except EnvironmentError, err:
1790
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1791
                                     % (vnc_pwd_file, err))
1792

    
1793
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1794
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1795
                         constants.SECURE_DIR_MODE)])
1796

    
1797
    # Automatically enable QMP if version is >= 0.14
1798
    if self._QMP_RE.search(kvmhelp):
1799
      logging.debug("Enabling QMP")
1800
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1801
                      self._InstanceQmpMonitor(instance.name)])
1802

    
1803
    # Configure the network now for starting instances and bridged interfaces,
1804
    # during FinalizeMigration for incoming instances' routed interfaces
1805
    for nic_seq, nic in enumerate(kvm_nics):
1806
      if (incoming and
1807
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1808
        continue
1809
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1810

    
1811
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1812
                                                     block_devices,
1813
                                                     kvmhelp)
1814
    kvm_cmd.extend(bdev_opts)
1815
    # CPU affinity requires kvm to start paused, so we set this flag if the
1816
    # instance is not already paused and if we are not going to accept a
1817
    # migrating instance. In the latter case, pausing is not needed.
1818
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1819
    if start_kvm_paused:
1820
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1821

    
1822
    # Note: CPU pinning is using up_hvp since changes take effect
1823
    # during instance startup anyway, and to avoid problems when soft
1824
    # rebooting the instance.
1825
    cpu_pinning = False
1826
    if up_hvp.get(constants.HV_CPU_MASK, None):
1827
      cpu_pinning = True
1828

    
1829
    if security_model == constants.HT_SM_POOL:
1830
      ss = ssconf.SimpleStore()
1831
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1832
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1833
      uid = uidpool.RequestUnusedUid(all_uids)
1834
      try:
1835
        username = pwd.getpwuid(uid.GetUid()).pw_name
1836
        kvm_cmd.extend(["-runas", username])
1837
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1838
      except:
1839
        uidpool.ReleaseUid(uid)
1840
        raise
1841
      else:
1842
        uid.Unlock()
1843
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1844
    else:
1845
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1846

    
1847
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1848
                     constants.RUN_DIRS_MODE)])
1849
    for nic_seq, tap in enumerate(taps):
1850
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1851
                      data=tap)
1852

    
1853
    if vnc_pwd:
1854
      change_cmd = "change vnc password %s" % vnc_pwd
1855
      self._CallMonitorCommand(instance.name, change_cmd)
1856

    
1857
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1858
    # connection attempts because SPICE by default does not allow connections
1859
    # if neither a password nor the "disable_ticketing" options are specified.
1860
    # As soon as we send the password via QMP, that password is a valid ticket
1861
    # for connection.
1862
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1863
    if spice_password_file:
1864
      spice_pwd = ""
1865
      try:
1866
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1867
      except EnvironmentError, err:
1868
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1869
                                     % (spice_password_file, err))
1870

    
1871
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1872
      qmp.connect()
1873
      arguments = {
1874
          "protocol": "spice",
1875
          "password": spice_pwd,
1876
      }
1877
      qmp.Execute("set_password", arguments)
1878

    
1879
    for filename in temp_files:
1880
      utils.RemoveFile(filename)
1881

    
1882
    # If requested, set CPU affinity and resume instance execution
1883
    if cpu_pinning:
1884
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1885

    
1886
    start_memory = self._InstanceStartupMemory(instance)
1887
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1888
      self.BalloonInstanceMemory(instance, start_memory)
1889

    
1890
    if start_kvm_paused:
1891
      # To control CPU pinning, ballooning, and vnc/spice passwords
1892
      # the VM was started in a frozen state. If freezing was not
1893
      # explicitly requested resume the vm status.
1894
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1895

    
1896
  def StartInstance(self, instance, block_devices, startup_paused):
1897
    """Start an instance.
1898

1899
    """
1900
    self._CheckDown(instance.name)
1901
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1902
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1903
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1904
                                           startup_paused, kvmhelp)
1905
    self._SaveKVMRuntime(instance, kvm_runtime)
1906
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1907

    
1908
  def _CallMonitorCommand(self, instance_name, command):
1909
    """Invoke a command on the instance monitor.
1910

1911
    """
1912
    # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1913
    # version. The monitor protocol is designed for human consumption, whereas
1914
    # QMP is made for programmatic usage. In the worst case QMP can also
1915
    # execute monitor commands. As it is, all calls to socat take at least
1916
    # 500ms and likely more: socat can't detect the end of the reply and waits
1917
    # for 500ms of no data received before exiting (500 ms is the default for
1918
    # the "-t" parameter).
1919
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1920
             (utils.ShellQuote(command),
1921
              constants.SOCAT_PATH,
1922
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1923
    result = utils.RunCmd(socat)
1924
    if result.failed:
1925
      msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1926
             " output: %s" %
1927
             (command, instance_name, result.fail_reason, result.output))
1928
      raise errors.HypervisorError(msg)
1929

    
1930
    return result
1931

    
1932
  def _GetFreePCISlot(self, instance, dev):
1933
    """Get the first available pci slot of a runnung instance.
1934

1935
    """
1936
    slots = bitarray(32)
1937
    slots.setall(False) # pylint: disable=E1101
1938
    output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
1939
    for line in output.stdout.splitlines():
1940
      match = self._INFO_PCI_RE.search(line)
1941
      if match:
1942
        slot = int(match.group(1))
1943
        slots[slot] = True
1944

    
1945
    [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
1946
    if not free:
1947
      raise errors.HypervisorError("All PCI slots occupied")
1948

    
1949
    dev.pci = int(free)
1950

    
1951
  def HotplugSupported(self, instance, action, dev_type):
1952
    """Check if hotplug is supported.
1953

1954
    Hotplug is *not* supported in case of:
1955
     - qemu versions < 1.0
1956
     - security models and chroot (disk hotplug)
1957
     - fdsend module is missing (nic hot-add)
1958

1959
    @raise errors.HypervisorError: in previous cases
1960

1961
    """
1962
    output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
1963
    # TODO: search for netdev_add, drive_add, device_add.....
1964
    match = self._INFO_VERSION_RE.search(output.stdout)
1965
    if not match:
1966
      raise errors.HotplugError("Try hotplug only in running instances.")
1967
    v_major, v_min, _, _ = match.groups()
1968
    if (v_major, v_min) < (1, 0):
1969
      raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
1970

    
1971
    if dev_type == constants.HOTPLUG_TARGET_DISK:
1972
      hvp = instance.hvparams
1973
      security_model = hvp[constants.HV_SECURITY_MODEL]
1974
      use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
1975
      if use_chroot:
1976
        raise errors.HotplugError("Disk hotplug is not supported"
1977
                                  " in case of chroot.")
1978
      if security_model != constants.HT_SM_NONE:
1979
        raise errors.HotplugError("Disk Hotplug is not supported in case"
1980
                                  " security models are used.")
1981

    
1982
    if (dev_type == constants.HOTPLUG_TARGET_NIC and
1983
        action == constants.HOTPLUG_ACTION_ADD and not fdsend):
1984
      raise errors.HotplugError("Cannot hot-add NIC."
1985
                                " fdsend python module is missing.")
1986
    return True
1987

    
1988
  def _CallHotplugCommand(self, name, cmd):
1989
    output = self._CallMonitorCommand(name, cmd)
1990
    # TODO: parse output and check if succeeded
1991
    for line in output.stdout.splitlines():
1992
      logging.info("%s", line)
1993

    
1994
  @classmethod
1995
  def _ParseKVMVersion(cls, text):
1996
    """Parse the KVM version from the --help output.
1997

1998
    @type text: string
1999
    @param text: output of kvm --help
2000
    @return: (version, v_maj, v_min, v_rev)
2001
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2002

2003
    """
2004
    match = cls._VERSION_RE.search(text.splitlines()[0])
2005
    if not match:
2006
      raise errors.HypervisorError("Unable to get KVM version")
2007

    
2008
    v_all = match.group(0)
2009
    v_maj = int(match.group(1))
2010
    v_min = int(match.group(2))
2011
    if match.group(4):
2012
      v_rev = int(match.group(4))
2013
    else:
2014
      v_rev = 0
2015
    return (v_all, v_maj, v_min, v_rev)
2016

    
2017
  @classmethod
2018
  def _GetKVMOutput(cls, kvm_path, option):
2019
    """Return the output of a kvm invocation
2020

2021
    @type kvm_path: string
2022
    @param kvm_path: path to the kvm executable
2023
    @type option: a key of _KVMOPTS_CMDS
2024
    @param option: kvm option to fetch the output from
2025
    @return: output a supported kvm invocation
2026
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2027

2028
    """
2029
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2030

    
2031
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
2032

    
2033
    result = utils.RunCmd([kvm_path] + optlist)
2034
    if result.failed and not can_fail:
2035
      raise errors.HypervisorError("Unable to get KVM %s output" %
2036
                                    " ".join(optlist))
2037
    return result.output
2038

    
2039
  @classmethod
2040
  def _GetKVMVersion(cls, kvm_path):
2041
    """Return the installed KVM version.
2042

2043
    @return: (version, v_maj, v_min, v_rev)
2044
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2045

2046
    """
2047
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2048

    
2049
  @classmethod
2050
  def _GetDefaultMachineVersion(cls, kvm_path):
2051
    """Return the default hardware revision (e.g. pc-1.1)
2052

2053
    """
2054
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2055
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2056
    if match:
2057
      return match.group(1)
2058
    else:
2059
      return "pc"
2060

    
2061
  def StopInstance(self, instance, force=False, retry=False, name=None):
2062
    """Stop an instance.
2063

2064
    """
2065
    if name is not None and not force:
2066
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2067
    if name is None:
2068
      name = instance.name
2069
      acpi = instance.hvparams[constants.HV_ACPI]
2070
    else:
2071
      acpi = False
2072
    _, pid, alive = self._InstancePidAlive(name)
2073
    if pid > 0 and alive:
2074
      if force or not acpi:
2075
        utils.KillProcess(pid)
2076
      else:
2077
        self._CallMonitorCommand(name, "system_powerdown")
2078

    
2079
  def CleanupInstance(self, instance_name):
2080
    """Cleanup after a stopped instance
2081

2082
    """
2083
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
2084
    if pid > 0 and alive:
2085
      raise errors.HypervisorError("Cannot cleanup a live instance")
2086
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2087

    
2088
  def RebootInstance(self, instance):
2089
    """Reboot an instance.
2090

2091
    """
2092
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2093
    # socket the instance will stop, but now power up again. So we'll resort
2094
    # to shutdown and restart.
2095
    _, _, alive = self._InstancePidAlive(instance.name)
2096
    if not alive:
2097
      raise errors.HypervisorError("Failed to reboot instance %s:"
2098
                                   " not running" % instance.name)
2099
    # StopInstance will delete the saved KVM runtime so:
2100
    # ...first load it...
2101
    kvm_runtime = self._LoadKVMRuntime(instance)
2102
    # ...now we can safely call StopInstance...
2103
    if not self.StopInstance(instance):
2104
      self.StopInstance(instance, force=True)
2105
    # ...and finally we can save it again, and execute it...
2106
    self._SaveKVMRuntime(instance, kvm_runtime)
2107
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2108
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2109
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2110

    
2111
  def MigrationInfo(self, instance):
2112
    """Get instance information to perform a migration.
2113

2114
    @type instance: L{objects.Instance}
2115
    @param instance: instance to be migrated
2116
    @rtype: string
2117
    @return: content of the KVM runtime file
2118

2119
    """
2120
    return self._ReadKVMRuntime(instance.name)
2121

    
2122
  def AcceptInstance(self, instance, info, target):
2123
    """Prepare to accept an instance.
2124

2125
    @type instance: L{objects.Instance}
2126
    @param instance: instance to be accepted
2127
    @type info: string
2128
    @param info: content of the KVM runtime file on the source node
2129
    @type target: string
2130
    @param target: target host (usually ip), on this node
2131

2132
    """
2133
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2134
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2135
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2136
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2137
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2138
                            incoming=incoming_address)
2139

    
2140
  def FinalizeMigrationDst(self, instance, info, success):
2141
    """Finalize the instance migration on the target node.
2142

2143
    Stop the incoming mode KVM.
2144

2145
    @type instance: L{objects.Instance}
2146
    @param instance: instance whose migration is being finalized
2147

2148
    """
2149
    if success:
2150
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2151
      kvm_nics = kvm_runtime[1]
2152

    
2153
      for nic_seq, nic in enumerate(kvm_nics):
2154
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2155
          # Bridged interfaces have already been configured
2156
          continue
2157
        try:
2158
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2159
        except EnvironmentError, err:
2160
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
2161
                          instance.name, nic_seq, str(err))
2162
          continue
2163
        try:
2164
          self._ConfigureNIC(instance, nic_seq, nic, tap)
2165
        except errors.HypervisorError, err:
2166
          logging.warning(str(err))
2167

    
2168
      self._WriteKVMRuntime(instance.name, info)
2169
    else:
2170
      self.StopInstance(instance, force=True)
2171

    
2172
  def MigrateInstance(self, instance, target, live):
2173
    """Migrate an instance to a target node.
2174

2175
    The migration will not be attempted if the instance is not
2176
    currently running.
2177

2178
    @type instance: L{objects.Instance}
2179
    @param instance: the instance to be migrated
2180
    @type target: string
2181
    @param target: ip address of the target node
2182
    @type live: boolean
2183
    @param live: perform a live migration
2184

2185
    """
2186
    instance_name = instance.name
2187
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
2188
    _, _, alive = self._InstancePidAlive(instance_name)
2189
    if not alive:
2190
      raise errors.HypervisorError("Instance not running, cannot migrate")
2191

    
2192
    if not live:
2193
      self._CallMonitorCommand(instance_name, "stop")
2194

    
2195
    migrate_command = ("migrate_set_speed %dm" %
2196
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2197
    self._CallMonitorCommand(instance_name, migrate_command)
2198

    
2199
    migrate_command = ("migrate_set_downtime %dms" %
2200
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2201
    self._CallMonitorCommand(instance_name, migrate_command)
2202

    
2203
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2204
    self._CallMonitorCommand(instance_name, migrate_command)
2205

    
2206
  def FinalizeMigrationSource(self, instance, success, live):
2207
    """Finalize the instance migration on the source node.
2208

2209
    @type instance: L{objects.Instance}
2210
    @param instance: the instance that was migrated
2211
    @type success: bool
2212
    @param success: whether the migration succeeded or not
2213
    @type live: bool
2214
    @param live: whether the user requested a live migration or not
2215

2216
    """
2217
    if success:
2218
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2219
      utils.KillProcess(pid)
2220
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2221
    elif live:
2222
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2223

    
2224
  def GetMigrationStatus(self, instance):
2225
    """Get the migration status
2226

2227
    @type instance: L{objects.Instance}
2228
    @param instance: the instance that is being migrated
2229
    @rtype: L{objects.MigrationStatus}
2230
    @return: the status of the current migration (one of
2231
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2232
             progress info that can be retrieved from the hypervisor
2233

2234
    """
2235
    info_command = "info migrate"
2236
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2237
      result = self._CallMonitorCommand(instance.name, info_command)
2238
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
2239
      if not match:
2240
        if not result.stdout:
2241
          logging.info("KVM: empty 'info migrate' result")
2242
        else:
2243
          logging.warning("KVM: unknown 'info migrate' result: %s",
2244
                          result.stdout)
2245
      else:
2246
        status = match.group(1)
2247
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2248
          migration_status = objects.MigrationStatus(status=status)
2249
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2250
          if match:
2251
            migration_status.transferred_ram = match.group("transferred")
2252
            migration_status.total_ram = match.group("total")
2253

    
2254
          return migration_status
2255

    
2256
        logging.warning("KVM: unknown migration status '%s'", status)
2257

    
2258
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2259

    
2260
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2261

    
2262
  def BalloonInstanceMemory(self, instance, mem):
2263
    """Balloon an instance memory to a certain value.
2264

2265
    @type instance: L{objects.Instance}
2266
    @param instance: instance to be accepted
2267
    @type mem: int
2268
    @param mem: actual memory size to use for instance runtime
2269

2270
    """
2271
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2272

    
2273
  def GetNodeInfo(self):
2274
    """Return information about the node.
2275

2276
    @return: a dict with the following keys (values in MiB):
2277
          - memory_total: the total memory size on the node
2278
          - memory_free: the available memory on the node for instances
2279
          - memory_dom0: the memory used by the node itself, if available
2280
          - hv_version: the hypervisor version in the form (major, minor,
2281
                        revision)
2282

2283
    """
2284
    result = self.GetLinuxNodeInfo()
2285
    # FIXME: this is the global kvm version, but the actual version can be
2286
    # customized as an hv parameter. we should use the nodegroup's default kvm
2287
    # path parameter here.
2288
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2289
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2290
    return result
2291

    
2292
  @classmethod
2293
  def GetInstanceConsole(cls, instance, hvparams, beparams):
2294
    """Return a command for connecting to the console of an instance.
2295

2296
    """
2297
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2298
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2299
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2300
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2301
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2302
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2303
      return objects.InstanceConsole(instance=instance.name,
2304
                                     kind=constants.CONS_SSH,
2305
                                     host=instance.primary_node,
2306
                                     user=constants.SSH_CONSOLE_USER,
2307
                                     command=cmd)
2308

    
2309
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2310
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2311
      display = instance.network_port - constants.VNC_BASE_PORT
2312
      return objects.InstanceConsole(instance=instance.name,
2313
                                     kind=constants.CONS_VNC,
2314
                                     host=vnc_bind_address,
2315
                                     port=instance.network_port,
2316
                                     display=display)
2317

    
2318
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2319
    if spice_bind:
2320
      return objects.InstanceConsole(instance=instance.name,
2321
                                     kind=constants.CONS_SPICE,
2322
                                     host=spice_bind,
2323
                                     port=instance.network_port)
2324

    
2325
    return objects.InstanceConsole(instance=instance.name,
2326
                                   kind=constants.CONS_MESSAGE,
2327
                                   message=("No serial shell for instance %s" %
2328
                                            instance.name))
2329

    
2330
  def Verify(self):
2331
    """Verify the hypervisor.
2332

2333
    Check that the required binaries exist.
2334

2335
    @return: Problem description if something is wrong, C{None} otherwise
2336

2337
    """
2338
    msgs = []
2339
    # FIXME: this is the global kvm binary, but the actual path can be
2340
    # customized as an hv parameter; we should use the nodegroup's
2341
    # default kvm path parameter here.
2342
    if not os.path.exists(constants.KVM_PATH):
2343
      msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2344
    if not os.path.exists(constants.SOCAT_PATH):
2345
      msgs.append("The socat binary ('%s') does not exist" %
2346
                  constants.SOCAT_PATH)
2347

    
2348
    return self._FormatVerifyResults(msgs)
2349

    
2350
  @classmethod
2351
  def CheckParameterSyntax(cls, hvparams):
2352
    """Check the given parameters for validity.
2353

2354
    @type hvparams:  dict
2355
    @param hvparams: dictionary with parameter names/value
2356
    @raise errors.HypervisorError: when a parameter is not valid
2357

2358
    """
2359
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2360

    
2361
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2362
    if kernel_path:
2363
      if not hvparams[constants.HV_ROOT_PATH]:
2364
        raise errors.HypervisorError("Need a root partition for the instance,"
2365
                                     " if a kernel is defined")
2366

    
2367
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2368
        not hvparams[constants.HV_VNC_X509]):
2369
      raise errors.HypervisorError("%s must be defined, if %s is" %
2370
                                   (constants.HV_VNC_X509,
2371
                                    constants.HV_VNC_X509_VERIFY))
2372

    
2373
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2374
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2375
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2376
      if not serial_speed or serial_speed not in valid_speeds:
2377
        raise errors.HypervisorError("Invalid serial console speed, must be"
2378
                                     " one of: %s" %
2379
                                     utils.CommaJoin(valid_speeds))
2380

    
2381
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2382
    if (boot_order == constants.HT_BO_CDROM and
2383
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2384
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2385
                                   " ISO path")
2386

    
2387
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2388
    if security_model == constants.HT_SM_USER:
2389
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2390
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2391
                                     " must be specified")
2392
    elif (security_model == constants.HT_SM_NONE or
2393
          security_model == constants.HT_SM_POOL):
2394
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2395
        raise errors.HypervisorError("Cannot have a security domain when the"
2396
                                     " security model is 'none' or 'pool'")
2397

    
2398
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2399
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2400
    if spice_bind:
2401
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2402
        # if an IP version is specified, the spice_bind parameter must be an
2403
        # IP of that family
2404
        if (netutils.IP4Address.IsValid(spice_bind) and
2405
            spice_ip_version != constants.IP4_VERSION):
2406
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2407
                                       " the specified IP version is %s" %
2408
                                       (spice_bind, spice_ip_version))
2409

    
2410
        if (netutils.IP6Address.IsValid(spice_bind) and
2411
            spice_ip_version != constants.IP6_VERSION):
2412
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2413
                                       " the specified IP version is %s" %
2414
                                       (spice_bind, spice_ip_version))
2415
    else:
2416
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2417
      # error if any of them is set without it.
2418
      for param in _SPICE_ADDITIONAL_PARAMS:
2419
        if hvparams[param]:
2420
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2421
                                       (param, constants.HV_KVM_SPICE_BIND))
2422

    
2423
  @classmethod
2424
  def ValidateParameters(cls, hvparams):
2425
    """Check the given parameters for validity.
2426

2427
    @type hvparams:  dict
2428
    @param hvparams: dictionary with parameter names/value
2429
    @raise errors.HypervisorError: when a parameter is not valid
2430

2431
    """
2432
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2433

    
2434
    kvm_path = hvparams[constants.HV_KVM_PATH]
2435

    
2436
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2437
    if security_model == constants.HT_SM_USER:
2438
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2439
      try:
2440
        pwd.getpwnam(username)
2441
      except KeyError:
2442
        raise errors.HypervisorError("Unknown security domain user %s"
2443
                                     % username)
2444

    
2445
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2446
    if spice_bind:
2447
      # only one of VNC and SPICE can be used currently.
2448
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2449
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2450
                                     " only one of them can be used at a"
2451
                                     " given time")
2452

    
2453
      # check that KVM supports SPICE
2454
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2455
      if not cls._SPICE_RE.search(kvmhelp):
2456
        raise errors.HypervisorError("SPICE is configured, but it is not"
2457
                                     " supported according to 'kvm --help'")
2458

    
2459
      # if spice_bind is not an IP address, it must be a valid interface
2460
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2461
                       netutils.IP6Address.IsValid(spice_bind))
2462
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2463
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2464
                                     " a valid IP address or interface name" %
2465
                                     constants.HV_KVM_SPICE_BIND)
2466

    
2467
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2468
    if machine_version:
2469
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2470
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2471
        raise errors.HypervisorError("Unsupported machine version: %s" %
2472
                                     machine_version)
2473

    
2474
  @classmethod
2475
  def PowercycleNode(cls):
2476
    """KVM powercycle, just a wrapper over Linux powercycle.
2477

2478
    """
2479
    cls.LinuxPowercycle()