Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 185192f2

History | View | Annotate | Download (103.8 kB)

1
#
2
#
3

    
4
# Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014 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 urllib2
38
import socket
39
import stat
40
import StringIO
41
from bitarray import bitarray
42
try:
43
  import affinity   # pylint: disable=F0401
44
except ImportError:
45
  affinity = None
46
try:
47
  import fdsend   # pylint: disable=F0401
48
except ImportError:
49
  fdsend = None
50

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

    
63

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

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

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

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

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

    
118
_MIGRATION_CAPS_DELIM = ":"
119

    
120

    
121
def _GenerateDeviceKVMId(dev_type, dev):
122
  """Helper function to generate a unique device name used by KVM
123

124
  QEMU monitor commands use names to identify devices. Here we use their pci
125
  slot and a part of their UUID to name them. dev.pci might be None for old
126
  devices in the cluster.
127

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

134
  """
135

    
136
  if not dev.pci:
137
    raise errors.HotplugError("Hotplug is not supported for %s with UUID %s" %
138
                              (dev_type, dev.uuid))
139

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

    
142

    
143
def _GetFreeSlot(slots, slot=None, reserve=False):
144
  """Helper method to get first available slot in a bitarray
145

146
  @type slots: bitarray
147
  @param slots: the bitarray to operate on
148
  @type slot: integer
149
  @param slot: if given we check whether the slot is free
150
  @type reserve: boolean
151
  @param reserve: whether to reserve the first available slot or not
152
  @return: the idx of the (first) available slot
153
  @raise errors.HotplugError: If all slots in a bitarray are occupied
154
    or the given slot is not free.
155

156
  """
157
  if slot is not None:
158
    assert slot < len(slots)
159
    if slots[slot]:
160
      raise errors.HypervisorError("Slots %d occupied" % slot)
161

    
162
  else:
163
    avail = slots.search(_AVAILABLE_PCI_SLOT, 1)
164
    if not avail:
165
      raise errors.HypervisorError("All slots occupied")
166

    
167
    slot = int(avail[0])
168

    
169
  if reserve:
170
    slots[slot] = True
171

    
172
  return slot
173

    
174

    
175
def _GetExistingDeviceInfo(dev_type, device, runtime):
176
  """Helper function to get an existing device inside the runtime file
177

178
  Used when an instance is running. Load kvm runtime file and search
179
  for a device based on its type and uuid.
180

181
  @type dev_type: sting
182
  @param dev_type: device type of param dev
183
  @type device: L{objects.Disk} or L{objects.NIC}
184
  @param device: the device object for which we generate a kvm name
185
  @type runtime: tuple (cmd, nics, hvparams, disks)
186
  @param runtime: the runtime data to search for the device
187
  @raise errors.HotplugError: in case the requested device does not
188
    exist (e.g. device has been added without --hotplug option) or
189
    device info has not pci slot (e.g. old devices in the cluster)
190

191
  """
192
  index = _DEVICE_RUNTIME_INDEX[dev_type]
193
  found = _FIND_RUNTIME_ENTRY[dev_type](device, runtime[index])
194
  if not found:
195
    raise errors.HotplugError("Cannot find runtime info for %s with UUID %s" %
196
                              (dev_type, device.uuid))
197

    
198
  return found[0]
199

    
200

    
201
def _UpgradeSerializedRuntime(serialized_runtime):
202
  """Upgrade runtime data
203

204
  Remove any deprecated fields or change the format of the data.
205
  The runtime files are not upgraded when Ganeti is upgraded, so the required
206
  modification have to be performed here.
207

208
  @type serialized_runtime: string
209
  @param serialized_runtime: raw text data read from actual runtime file
210
  @return: (cmd, nic dicts, hvparams, bdev dicts)
211
  @rtype: tuple
212

213
  """
214
  loaded_runtime = serializer.Load(serialized_runtime)
215
  kvm_cmd, serialized_nics, hvparams = loaded_runtime[:3]
216
  if len(loaded_runtime) >= 4:
217
    serialized_disks = loaded_runtime[3]
218
  else:
219
    serialized_disks = []
220

    
221
  for nic in serialized_nics:
222
    # Add a dummy uuid slot if an pre-2.8 NIC is found
223
    if "uuid" not in nic:
224
      nic["uuid"] = utils.NewUUID()
225

    
226
  return kvm_cmd, serialized_nics, hvparams, serialized_disks
227

    
228

    
229
def _AnalyzeSerializedRuntime(serialized_runtime):
230
  """Return runtime entries for a serialized runtime file
231

232
  @type serialized_runtime: string
233
  @param serialized_runtime: raw text data read from actual runtime file
234
  @return: (cmd, nics, hvparams, bdevs)
235
  @rtype: tuple
236

237
  """
238
  kvm_cmd, serialized_nics, hvparams, serialized_disks = \
239
    _UpgradeSerializedRuntime(serialized_runtime)
240
  kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
241
  kvm_disks = [(objects.Disk.FromDict(sdisk), link, uri)
242
               for sdisk, link, uri in serialized_disks]
243

    
244
  return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
245

    
246

    
247
def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
248
  """Retrieves supported TUN features from file descriptor.
249

250
  @see: L{_ProbeTapVnetHdr}
251

252
  """
253
  req = struct.pack("I", 0)
254
  try:
255
    buf = _ioctl(fd, TUNGETFEATURES, req)
256
  except EnvironmentError, err:
257
    logging.warning("ioctl(TUNGETFEATURES) failed: %s", err)
258
    return None
259
  else:
260
    (flags, ) = struct.unpack("I", buf)
261
    return flags
262

    
263

    
264
def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
265
  """Check whether to enable the IFF_VNET_HDR flag.
266

267
  To do this, _all_ of the following conditions must be met:
268
   1. TUNGETFEATURES ioctl() *must* be implemented
269
   2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
270
   3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
271
      drivers/net/tun.c there is no way to test this until after the tap device
272
      has been created using TUNSETIFF, and there is no way to change the
273
      IFF_VNET_HDR flag after creating the interface, catch-22! However both
274
      TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
275
      thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
276

277
   @type fd: int
278
   @param fd: the file descriptor of /dev/net/tun
279

280
  """
281
  flags = _features_fn(fd)
282

    
283
  if flags is None:
284
    # Not supported
285
    return False
286

    
287
  result = bool(flags & IFF_VNET_HDR)
288

    
289
  if not result:
290
    logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
291

    
292
  return result
293

    
294

    
295
def _OpenTap(vnet_hdr=True, name=""):
296
  """Open a new tap device and return its file descriptor.
297

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

301
  @type vnet_hdr: boolean
302
  @param vnet_hdr: Enable the VNET Header
303

304
  @type name: string
305
  @param name: name for the TAP interface being created; if an empty
306
               string is passed, the OS will generate a unique name
307

308
  @return: (ifname, tapfd)
309
  @rtype: tuple
310

311
  """
312
  try:
313
    tapfd = os.open("/dev/net/tun", os.O_RDWR)
314
  except EnvironmentError:
315
    raise errors.HypervisorError("Failed to open /dev/net/tun")
316

    
317
  flags = IFF_TAP | IFF_NO_PI
318

    
319
  if vnet_hdr and _ProbeTapVnetHdr(tapfd):
320
    flags |= IFF_VNET_HDR
321

    
322
  # The struct ifreq ioctl request (see netdevice(7))
323
  ifr = struct.pack("16sh", name, flags)
324

    
325
  try:
326
    res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
327
  except EnvironmentError, err:
328
    raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
329
                                 err)
330

    
331
  # Get the interface name from the ioctl
332
  ifname = struct.unpack("16sh", res)[0].strip("\x00")
333
  return (ifname, tapfd)
334

    
335

    
336
class HeadRequest(urllib2.Request):
337
  def get_method(self):
338
    return "HEAD"
339

    
340

    
341
def _CheckUrl(url):
342
  """Check if a given URL exists on the server
343

344
  """
345
  try:
346
    urllib2.urlopen(HeadRequest(url))
347
    return True
348
  except urllib2.URLError:
349
    return False
350

    
351

    
352
class QmpMessage:
353
  """QEMU Messaging Protocol (QMP) message.
354

355
  """
356
  def __init__(self, data):
357
    """Creates a new QMP message based on the passed data.
358

359
    """
360
    if not isinstance(data, dict):
361
      raise TypeError("QmpMessage must be initialized with a dict")
362

    
363
    self.data = data
364

    
365
  def __getitem__(self, field_name):
366
    """Get the value of the required field if present, or None.
367

368
    Overrides the [] operator to provide access to the message data,
369
    returning None if the required item is not in the message
370
    @return: the value of the field_name field, or None if field_name
371
             is not contained in the message
372

373
    """
374
    return self.data.get(field_name, None)
375

    
376
  def __setitem__(self, field_name, field_value):
377
    """Set the value of the required field_name to field_value.
378

379
    """
380
    self.data[field_name] = field_value
381

    
382
  def __len__(self):
383
    """Return the number of fields stored in this QmpMessage.
384

385
    """
386
    return len(self.data)
387

    
388
  def __delitem__(self, key):
389
    """Delete the specified element from the QmpMessage.
390

391
    """
392
    del(self.data[key])
393

    
394
  @staticmethod
395
  def BuildFromJsonString(json_string):
396
    """Build a QmpMessage from a JSON encoded string.
397

398
    @type json_string: str
399
    @param json_string: JSON string representing the message
400
    @rtype: L{QmpMessage}
401
    @return: a L{QmpMessage} built from json_string
402

403
    """
404
    # Parse the string
405
    data = serializer.LoadJson(json_string)
406
    return QmpMessage(data)
407

    
408
  def __str__(self):
409
    # The protocol expects the JSON object to be sent as a single line.
410
    return serializer.DumpJson(self.data)
411

    
412
  def __eq__(self, other):
413
    # When comparing two QmpMessages, we are interested in comparing
414
    # their internal representation of the message data
415
    return self.data == other.data
416

    
417

    
418
class MonitorSocket(object):
419
  _SOCKET_TIMEOUT = 5
420

    
421
  def __init__(self, monitor_filename):
422
    """Instantiates the MonitorSocket object.
423

424
    @type monitor_filename: string
425
    @param monitor_filename: the filename of the UNIX raw socket on which the
426
                             monitor (QMP or simple one) is listening
427

428
    """
429
    self.monitor_filename = monitor_filename
430
    self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
431
    # We want to fail if the server doesn't send a complete message
432
    # in a reasonable amount of time
433
    self.sock.settimeout(self._SOCKET_TIMEOUT)
434
    self._connected = False
435

    
436
  def _check_socket(self):
437
    sock_stat = None
438
    try:
439
      sock_stat = os.stat(self.monitor_filename)
440
    except EnvironmentError, err:
441
      if err.errno == errno.ENOENT:
442
        raise errors.HypervisorError("No monitor socket found")
443
      else:
444
        raise errors.HypervisorError("Error checking monitor socket: %s",
445
                                     utils.ErrnoOrStr(err))
446
    if not stat.S_ISSOCK(sock_stat.st_mode):
447
      raise errors.HypervisorError("Monitor socket is not a socket")
448

    
449
  def _check_connection(self):
450
    """Make sure that the connection is established.
451

452
    """
453
    if not self._connected:
454
      raise errors.ProgrammerError("To use a MonitorSocket you need to first"
455
                                   " invoke connect() on it")
456

    
457
  def connect(self):
458
    """Connects to the monitor.
459

460
    Connects to the UNIX socket
461

462
    @raise errors.HypervisorError: when there are communication errors
463

464
    """
465
    if self._connected:
466
      raise errors.ProgrammerError("Cannot connect twice")
467

    
468
    self._check_socket()
469

    
470
    # Check file existance/stuff
471
    try:
472
      self.sock.connect(self.monitor_filename)
473
    except EnvironmentError:
474
      raise errors.HypervisorError("Can't connect to qmp socket")
475
    self._connected = True
476

    
477
  def close(self):
478
    """Closes the socket
479

480
    It cannot be used after this call.
481

482
    """
483
    self.sock.close()
484

    
485

    
486
class QmpConnection(MonitorSocket):
487
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
488

489
  """
490
  _FIRST_MESSAGE_KEY = "QMP"
491
  _EVENT_KEY = "event"
492
  _ERROR_KEY = "error"
493
  _RETURN_KEY = RETURN_KEY = "return"
494
  _ACTUAL_KEY = ACTUAL_KEY = "actual"
495
  _ERROR_CLASS_KEY = "class"
496
  _ERROR_DESC_KEY = "desc"
497
  _EXECUTE_KEY = "execute"
498
  _ARGUMENTS_KEY = "arguments"
499
  _CAPABILITIES_COMMAND = "qmp_capabilities"
500
  _MESSAGE_END_TOKEN = "\r\n"
501

    
502
  def __init__(self, monitor_filename):
503
    super(QmpConnection, self).__init__(monitor_filename)
504
    self._buf = ""
505

    
506
  def connect(self):
507
    """Connects to the QMP monitor.
508

509
    Connects to the UNIX socket and makes sure that we can actually send and
510
    receive data to the kvm instance via QMP.
511

512
    @raise errors.HypervisorError: when there are communication errors
513
    @raise errors.ProgrammerError: when there are data serialization errors
514

515
    """
516
    super(QmpConnection, self).connect()
517
    # Check if we receive a correct greeting message from the server
518
    # (As per the QEMU Protocol Specification 0.1 - section 2.2)
519
    greeting = self._Recv()
520
    if not greeting[self._FIRST_MESSAGE_KEY]:
521
      self._connected = False
522
      raise errors.HypervisorError("kvm: QMP communication error (wrong"
523
                                   " server greeting")
524

    
525
    # This is needed because QMP can return more than one greetings
526
    # see https://groups.google.com/d/msg/ganeti-devel/gZYcvHKDooU/SnukC8dgS5AJ
527
    self._buf = ""
528

    
529
    # Let's put the monitor in command mode using the qmp_capabilities
530
    # command, or else no command will be executable.
531
    # (As per the QEMU Protocol Specification 0.1 - section 4)
532
    self.Execute(self._CAPABILITIES_COMMAND)
533

    
534
  def _ParseMessage(self, buf):
535
    """Extract and parse a QMP message from the given buffer.
536

537
    Seeks for a QMP message in the given buf. If found, it parses it and
538
    returns it together with the rest of the characters in the buf.
539
    If no message is found, returns None and the whole buffer.
540

541
    @raise errors.ProgrammerError: when there are data serialization errors
542

543
    """
544
    message = None
545
    # Check if we got the message end token (CRLF, as per the QEMU Protocol
546
    # Specification 0.1 - Section 2.1.1)
547
    pos = buf.find(self._MESSAGE_END_TOKEN)
548
    if pos >= 0:
549
      try:
550
        message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
551
      except Exception, err:
552
        raise errors.ProgrammerError("QMP data serialization error: %s" % err)
553
      buf = buf[pos + 1:]
554

    
555
    return (message, buf)
556

    
557
  def _Recv(self):
558
    """Receives a message from QMP and decodes the received JSON object.
559

560
    @rtype: QmpMessage
561
    @return: the received message
562
    @raise errors.HypervisorError: when there are communication errors
563
    @raise errors.ProgrammerError: when there are data serialization errors
564

565
    """
566
    self._check_connection()
567

    
568
    # Check if there is already a message in the buffer
569
    (message, self._buf) = self._ParseMessage(self._buf)
570
    if message:
571
      return message
572

    
573
    recv_buffer = StringIO.StringIO(self._buf)
574
    recv_buffer.seek(len(self._buf))
575
    try:
576
      while True:
577
        data = self.sock.recv(4096)
578
        if not data:
579
          break
580
        recv_buffer.write(data)
581

    
582
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
583
        if message:
584
          return message
585

    
586
    except socket.timeout, err:
587
      raise errors.HypervisorError("Timeout while receiving a QMP message: "
588
                                   "%s" % (err))
589
    except socket.error, err:
590
      raise errors.HypervisorError("Unable to receive data from KVM using the"
591
                                   " QMP protocol: %s" % err)
592

    
593
  def _Send(self, message):
594
    """Encodes and sends a message to KVM using QMP.
595

596
    @type message: QmpMessage
597
    @param message: message to send to KVM
598
    @raise errors.HypervisorError: when there are communication errors
599
    @raise errors.ProgrammerError: when there are data serialization errors
600

601
    """
602
    self._check_connection()
603
    try:
604
      message_str = str(message)
605
    except Exception, err:
606
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
607

    
608
    try:
609
      self.sock.sendall(message_str)
610
    except socket.timeout, err:
611
      raise errors.HypervisorError("Timeout while sending a QMP message: "
612
                                   "%s (%s)" % (err.string, err.errno))
613
    except socket.error, err:
614
      raise errors.HypervisorError("Unable to send data from KVM using the"
615
                                   " QMP protocol: %s" % err)
616

    
617
  def Execute(self, command, arguments=None):
618
    """Executes a QMP command and returns the response of the server.
619

620
    @type command: str
621
    @param command: the command to execute
622
    @type arguments: dict
623
    @param arguments: dictionary of arguments to be passed to the command
624
    @rtype: dict
625
    @return: dictionary representing the received JSON object
626
    @raise errors.HypervisorError: when there are communication errors
627
    @raise errors.ProgrammerError: when there are data serialization errors
628

629
    """
630
    self._check_connection()
631
    message = QmpMessage({self._EXECUTE_KEY: command})
632
    if arguments:
633
      message[self._ARGUMENTS_KEY] = arguments
634
    self._Send(message)
635

    
636
    # Events can occur between the sending of the command and the reception
637
    # of the response, so we need to filter out messages with the event key.
638
    while True:
639
      response = self._Recv()
640
      err = response[self._ERROR_KEY]
641
      if err:
642
        raise errors.HypervisorError("kvm: error executing the %s"
643
                                     " command: %s (%s):" %
644
                                     (command,
645
                                      err[self._ERROR_DESC_KEY],
646
                                      err[self._ERROR_CLASS_KEY]))
647

    
648
      elif not response[self._EVENT_KEY]:
649
        return response
650

    
651

    
652
class KVMHypervisor(hv_base.BaseHypervisor):
653
  """KVM hypervisor interface
654

655
  """
656
  CAN_MIGRATE = True
657

    
658
  _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
659
  _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
660
  _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
661
  _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
662
  _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
663
  _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
664
  _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
665
  # KVM instances with chroot enabled are started in empty chroot directories.
666
  _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
667
  # After an instance is stopped, its chroot directory is removed.
668
  # If the chroot directory is not empty, it can't be removed.
669
  # A non-empty chroot directory indicates a possible security incident.
670
  # To support forensics, the non-empty chroot directory is quarantined in
671
  # a separate directory, called 'chroot-quarantine'.
672
  _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
673
  _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
674
           _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
675

    
676
  PARAMETERS = {
677
    constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
678
    constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
679
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
680
    constants.HV_ROOT_PATH: hv_base.NO_CHECK,
681
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
682
    constants.HV_ACPI: hv_base.NO_CHECK,
683
    constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
684
    constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
685
    constants.HV_VNC_BIND_ADDRESS: hv_base.NO_CHECK, # will be checked later
686
    constants.HV_VNC_TLS: hv_base.NO_CHECK,
687
    constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
688
    constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
689
    constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
690
    constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
691
    constants.HV_KVM_SPICE_IP_VERSION:
692
      (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
693
                         x in constants.VALID_IP_VERSIONS),
694
       "The SPICE IP version should be 4 or 6",
695
       None, None),
696
    constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
697
    constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
698
      hv_base.ParamInSet(
699
        False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
700
    constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
701
      hv_base.ParamInSet(
702
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
703
    constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
704
      hv_base.ParamInSet(
705
        False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
706
    constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
707
      hv_base.ParamInSet(
708
        False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
709
    constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
710
    constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
711
    constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
712
    constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
713
    constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
714
    constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_OR_URL_CHECK,
715
    constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_OR_URL_CHECK,
716
    constants.HV_BOOT_ORDER:
717
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
718
    constants.HV_NIC_TYPE:
719
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
720
    constants.HV_DISK_TYPE:
721
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
722
    constants.HV_KVM_CDROM_DISK_TYPE:
723
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
724
    constants.HV_USB_MOUSE:
725
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
726
    constants.HV_KEYMAP: hv_base.NO_CHECK,
727
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
728
    constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
729
    constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
730
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
731
    constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
732
    constants.HV_DISK_CACHE:
733
      hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
734
    constants.HV_SECURITY_MODEL:
735
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
736
    constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
737
    constants.HV_KVM_FLAG:
738
      hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
739
    constants.HV_VHOST_NET: hv_base.NO_CHECK,
740
    constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
741
    constants.HV_KVM_USER_SHUTDOWN: hv_base.NO_CHECK,
742
    constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
743
    constants.HV_REBOOT_BEHAVIOR:
744
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
745
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
746
    constants.HV_CPU_TYPE: hv_base.NO_CHECK,
747
    constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
748
    constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
749
    constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
750
    constants.HV_SOUNDHW: hv_base.NO_CHECK,
751
    constants.HV_USB_DEVICES: hv_base.NO_CHECK,
752
    constants.HV_VGA: hv_base.NO_CHECK,
753
    constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
754
    constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
755
    constants.HV_KVM_MIGRATION_CAPS: hv_base.NO_CHECK,
756
    constants.HV_VNET_HDR: hv_base.NO_CHECK,
757
    }
758

    
759
  _VIRTIO = "virtio"
760
  _VIRTIO_NET_PCI = "virtio-net-pci"
761
  _VIRTIO_BLK_PCI = "virtio-blk-pci"
762

    
763
  _MIGRATION_STATUS_RE = re.compile(r"Migration\s+status:\s+(\w+)",
764
                                    re.M | re.I)
765
  _MIGRATION_PROGRESS_RE = \
766
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
767
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
768
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
769

    
770
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
771
  _MIGRATION_INFO_RETRY_DELAY = 2
772

    
773
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
774

    
775
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
776
  _CPU_INFO_CMD = "info cpus"
777
  _CONT_CMD = "cont"
778

    
779
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
780
  _CHECK_MACHINE_VERSION_RE = \
781
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
782

    
783
  _QMP_RE = re.compile(r"^-qmp\s", re.M)
784
  _SPICE_RE = re.compile(r"^-spice\s", re.M)
785
  _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
786
  _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
787
  _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
788
  _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
789
  _DISPLAY_RE = re.compile(r"^-display\s", re.M)
790
  _MACHINE_RE = re.compile(r"^-machine\s", re.M)
791
  _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
792
  _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M)
793
  # match  -drive.*boot=on|off on different lines, but in between accept only
794
  # dashes not preceeded by a new line (which would mean another option
795
  # different than -drive is starting)
796
  _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
797
  _UUID_RE = re.compile(r"^-uuid\s", re.M)
798

    
799
  _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
800
  _INFO_PCI_CMD = "info pci"
801
  _FIND_PCI_DEVICE_RE = \
802
    staticmethod(
803
      lambda pci, devid: re.compile(r'Bus.*device[ ]*%d,(.*\n){5,6}.*id "%s"' %
804
                                    (pci, devid), re.M))
805

    
806
  _INFO_VERSION_RE = \
807
    re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
808
  _INFO_VERSION_CMD = "info version"
809

    
810
  # Slot 0 for Host bridge, Slot 1 for ISA bridge, Slot 2 for VGA controller
811
  _DEFAULT_PCI_RESERVATIONS = "11100000000000000000000000000000"
812
  _SOUNDHW_WITH_PCI_SLOT = ["ac97", "es1370", "hda"]
813

    
814
  ANCILLARY_FILES = [
815
    _KVM_NETWORK_SCRIPT,
816
    ]
817
  ANCILLARY_FILES_OPT = [
818
    _KVM_NETWORK_SCRIPT,
819
    ]
820

    
821
  # Supported kvm options to get output from
822
  _KVMOPT_HELP = "help"
823
  _KVMOPT_MLIST = "mlist"
824
  _KVMOPT_DEVICELIST = "devicelist"
825

    
826
  # Command to execute to get the output from kvm, and whether to
827
  # accept the output even on failure.
828
  _KVMOPTS_CMDS = {
829
    _KVMOPT_HELP: (["--help"], False),
830
    _KVMOPT_MLIST: (["-M", "?"], False),
831
    _KVMOPT_DEVICELIST: (["-device", "?"], True),
832
  }
833

    
834
  def __init__(self):
835
    hv_base.BaseHypervisor.__init__(self)
836
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
837
    # in a tmpfs filesystem or has been otherwise wiped out.
838
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
839
    utils.EnsureDirs(dirs)
840

    
841
  @classmethod
842
  def _InstancePidFile(cls, instance_name):
843
    """Returns the instance pidfile.
844

845
    """
846
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
847

    
848
  @classmethod
849
  def _InstanceUidFile(cls, instance_name):
850
    """Returns the instance uidfile.
851

852
    """
853
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
854

    
855
  @classmethod
856
  def _InstancePidInfo(cls, pid):
857
    """Check pid file for instance information.
858

859
    Check that a pid file is associated with an instance, and retrieve
860
    information from its command line.
861

862
    @type pid: string or int
863
    @param pid: process id of the instance to check
864
    @rtype: tuple
865
    @return: (instance_name, memory, vcpus)
866
    @raise errors.HypervisorError: when an instance cannot be found
867

868
    """
869
    alive = utils.IsProcessAlive(pid)
870
    if not alive:
871
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
872

    
873
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
874
    try:
875
      cmdline = utils.ReadFile(cmdline_file)
876
    except EnvironmentError, err:
877
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
878
                                   (pid, err))
879

    
880
    instance = None
881
    memory = 0
882
    vcpus = 0
883

    
884
    arg_list = cmdline.split("\x00")
885
    while arg_list:
886
      arg = arg_list.pop(0)
887
      if arg == "-name":
888
        instance = arg_list.pop(0)
889
      elif arg == "-m":
890
        memory = int(arg_list.pop(0))
891
      elif arg == "-smp":
892
        vcpus = int(arg_list.pop(0).split(",")[0])
893

    
894
    if instance is None:
895
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
896
                                   " instance" % pid)
897

    
898
    return (instance, memory, vcpus)
899

    
900
  @classmethod
901
  def _InstancePidAlive(cls, instance_name):
902
    """Returns the instance pidfile, pid, and liveness.
903

904
    @type instance_name: string
905
    @param instance_name: instance name
906
    @rtype: tuple
907
    @return: (pid file name, pid, liveness)
908

909
    """
910
    pidfile = cls._InstancePidFile(instance_name)
911
    pid = utils.ReadPidFile(pidfile)
912

    
913
    alive = False
914
    try:
915
      cmd_instance = cls._InstancePidInfo(pid)[0]
916
      alive = (cmd_instance == instance_name)
917
    except errors.HypervisorError:
918
      pass
919

    
920
    return (pidfile, pid, alive)
921

    
922
  @classmethod
923
  def _CheckDown(cls, instance_name):
924
    """Raises an error unless the given instance is down.
925

926
    """
927
    alive = cls._InstancePidAlive(instance_name)[2]
928
    if alive:
929
      raise errors.HypervisorError("Failed to start instance %s: %s" %
930
                                   (instance_name, "already running"))
931

    
932
  @classmethod
933
  def _InstanceMonitor(cls, instance_name):
934
    """Returns the instance monitor socket name
935

936
    """
937
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
938

    
939
  @classmethod
940
  def _InstanceSerial(cls, instance_name):
941
    """Returns the instance serial socket name
942

943
    """
944
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
945

    
946
  @classmethod
947
  def _InstanceQmpMonitor(cls, instance_name):
948
    """Returns the instance serial QMP socket name
949

950
    """
951
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
952

    
953
  @classmethod
954
  def _InstanceShutdownMonitor(cls, instance_name):
955
    """Returns the instance QMP output filename
956

957
    """
958
    return utils.PathJoin(cls._CTRL_DIR, "%s.shutdown" % instance_name)
959

    
960
  @staticmethod
961
  def _SocatUnixConsoleParams():
962
    """Returns the correct parameters for socat
963

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

966
    """
967
    if constants.SOCAT_USE_ESCAPE:
968
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
969
    else:
970
      return "echo=0,icanon=0"
971

    
972
  @classmethod
973
  def _InstanceKVMRuntime(cls, instance_name):
974
    """Returns the instance KVM runtime filename
975

976
    """
977
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
978

    
979
  @classmethod
980
  def _InstanceChrootDir(cls, instance_name):
981
    """Returns the name of the KVM chroot dir of the instance
982

983
    """
984
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
985

    
986
  @classmethod
987
  def _InstanceNICDir(cls, instance_name):
988
    """Returns the name of the directory holding the tap device files for a
989
    given instance.
990

991
    """
992
    return utils.PathJoin(cls._NICS_DIR, instance_name)
993

    
994
  @classmethod
995
  def _InstanceNICFile(cls, instance_name, seq):
996
    """Returns the name of the file containing the tap device for a given NIC
997

998
    """
999
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
1000

    
1001
  @classmethod
1002
  def _InstanceKeymapFile(cls, instance_name):
1003
    """Returns the name of the file containing the keymap for a given instance
1004

1005
    """
1006
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
1007

    
1008
  @classmethod
1009
  def _TryReadUidFile(cls, uid_file):
1010
    """Try to read a uid file
1011

1012
    """
1013
    if os.path.exists(uid_file):
1014
      try:
1015
        uid = int(utils.ReadOneLineFile(uid_file))
1016
        return uid
1017
      except EnvironmentError:
1018
        logging.warning("Can't read uid file", exc_info=True)
1019
      except (TypeError, ValueError):
1020
        logging.warning("Can't parse uid file contents", exc_info=True)
1021
    return None
1022

    
1023
  @classmethod
1024
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
1025
    """Removes an instance's rutime sockets/files/dirs.
1026

1027
    """
1028
    utils.RemoveFile(pidfile)
1029
    utils.RemoveFile(cls._InstanceMonitor(instance_name))
1030
    utils.RemoveFile(cls._InstanceSerial(instance_name))
1031
    utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
1032
    utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
1033
    utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
1034
    uid_file = cls._InstanceUidFile(instance_name)
1035
    uid = cls._TryReadUidFile(uid_file)
1036
    utils.RemoveFile(uid_file)
1037
    if uid is not None:
1038
      uidpool.ReleaseUid(uid)
1039
    try:
1040
      shutil.rmtree(cls._InstanceNICDir(instance_name))
1041
    except OSError, err:
1042
      if err.errno != errno.ENOENT:
1043
        raise
1044
    try:
1045
      chroot_dir = cls._InstanceChrootDir(instance_name)
1046
      utils.RemoveDir(chroot_dir)
1047
    except OSError, err:
1048
      if err.errno == errno.ENOTEMPTY:
1049
        # The chroot directory is expected to be empty, but it isn't.
1050
        new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
1051
                                          prefix="%s-%s-" %
1052
                                          (instance_name,
1053
                                           utils.TimestampForFilename()))
1054
        logging.warning("The chroot directory of instance %s can not be"
1055
                        " removed as it is not empty. Moving it to the"
1056
                        " quarantine instead. Please investigate the"
1057
                        " contents (%s) and clean up manually",
1058
                        instance_name, new_chroot_dir)
1059
        utils.RenameFile(chroot_dir, new_chroot_dir)
1060
      else:
1061
        raise
1062

    
1063
  @staticmethod
1064
  def _ConfigureNIC(instance, seq, nic, tap):
1065
    """Run the network configuration script for a specified NIC
1066

1067
    @param instance: instance we're acting on
1068
    @type instance: instance object
1069
    @param seq: nic sequence number
1070
    @type seq: int
1071
    @param nic: nic we're acting on
1072
    @type nic: nic object
1073
    @param tap: the host's tap interface this NIC corresponds to
1074
    @type tap: str
1075

1076
    """
1077
    env = {
1078
      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
1079
      "INSTANCE": instance.name,
1080
      "MAC": nic.mac,
1081
      "MODE": nic.nicparams[constants.NIC_MODE],
1082
      "INTERFACE": tap,
1083
      "INTERFACE_INDEX": str(seq),
1084
      "INTERFACE_UUID": nic.uuid,
1085
      "TAGS": " ".join(instance.GetTags()),
1086
    }
1087

    
1088
    if nic.ip:
1089
      env["IP"] = nic.ip
1090

    
1091
    if nic.name:
1092
      env["INTERFACE_NAME"] = nic.name
1093

    
1094
    if nic.nicparams[constants.NIC_LINK]:
1095
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
1096

    
1097
    if nic.nicparams[constants.NIC_VLAN]:
1098
      env["VLAN"] = nic.nicparams[constants.NIC_VLAN]
1099

    
1100
    if nic.network:
1101
      n = objects.Network.FromDict(nic.netinfo)
1102
      env.update(n.HooksDict())
1103

    
1104
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1105
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
1106

    
1107
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
1108
    if result.failed:
1109
      raise errors.HypervisorError("Failed to configure interface %s: %s;"
1110
                                   " network configuration script output: %s" %
1111
                                   (tap, result.fail_reason, result.output))
1112

    
1113
  @staticmethod
1114
  def _VerifyAffinityPackage():
1115
    if affinity is None:
1116
      raise errors.HypervisorError("affinity Python package not"
1117
                                   " found; cannot use CPU pinning under KVM")
1118

    
1119
  @staticmethod
1120
  def _BuildAffinityCpuMask(cpu_list):
1121
    """Create a CPU mask suitable for sched_setaffinity from a list of
1122
    CPUs.
1123

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

1127
    @type cpu_list: list of int
1128
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
1129
    @rtype: int
1130
    @return: a bit mask of CPU affinities
1131

1132
    """
1133
    if cpu_list == constants.CPU_PINNING_OFF:
1134
      return constants.CPU_PINNING_ALL_KVM
1135
    else:
1136
      return sum(2 ** cpu for cpu in cpu_list)
1137

    
1138
  @classmethod
1139
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
1140
    """Change CPU affinity for running VM according to given CPU mask.
1141

1142
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
1143
    @type cpu_mask: string
1144
    @param process_id: process ID of KVM process. Used to pin entire VM
1145
                       to physical CPUs.
1146
    @type process_id: int
1147
    @param thread_dict: map of virtual CPUs to KVM thread IDs
1148
    @type thread_dict: dict int:int
1149

1150
    """
1151
    # Convert the string CPU mask to a list of list of int's
1152
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
1153

    
1154
    if len(cpu_list) == 1:
1155
      all_cpu_mapping = cpu_list[0]
1156
      if all_cpu_mapping == constants.CPU_PINNING_OFF:
1157
        # If CPU pinning has 1 entry that's "all", then do nothing
1158
        pass
1159
      else:
1160
        # If CPU pinning has one non-all entry, map the entire VM to
1161
        # one set of physical CPUs
1162
        cls._VerifyAffinityPackage()
1163
        affinity.set_process_affinity_mask(
1164
          process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
1165
    else:
1166
      # The number of vCPUs mapped should match the number of vCPUs
1167
      # reported by KVM. This was already verified earlier, so
1168
      # here only as a sanity check.
1169
      assert len(thread_dict) == len(cpu_list)
1170
      cls._VerifyAffinityPackage()
1171

    
1172
      # For each vCPU, map it to the proper list of physical CPUs
1173
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1174
        affinity.set_process_affinity_mask(thread_dict[i],
1175
                                           cls._BuildAffinityCpuMask(vcpu))
1176

    
1177
  def _GetVcpuThreadIds(self, instance_name):
1178
    """Get a mapping of vCPU no. to thread IDs for the instance
1179

1180
    @type instance_name: string
1181
    @param instance_name: instance in question
1182
    @rtype: dictionary of int:int
1183
    @return: a dictionary mapping vCPU numbers to thread IDs
1184

1185
    """
1186
    result = {}
1187
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1188
    for line in output.stdout.splitlines():
1189
      match = self._CPU_INFO_RE.search(line)
1190
      if not match:
1191
        continue
1192
      grp = map(int, match.groups())
1193
      result[grp[0]] = grp[1]
1194

    
1195
    return result
1196

    
1197
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1198
    """Complete CPU pinning.
1199

1200
    @type instance_name: string
1201
    @param instance_name: name of instance
1202
    @type cpu_mask: string
1203
    @param cpu_mask: CPU pinning mask as entered by user
1204

1205
    """
1206
    # Get KVM process ID, to be used if need to pin entire VM
1207
    _, pid, _ = self._InstancePidAlive(instance_name)
1208
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1209
    thread_dict = self._GetVcpuThreadIds(instance_name)
1210
    # Run CPU pinning, based on configured mask
1211
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1212

    
1213
  def ListInstances(self, hvparams=None):
1214
    """Get the list of running instances.
1215

1216
    We can do this by listing our live instances directory and
1217
    checking whether the associated kvm process is still alive.
1218

1219
    """
1220
    result = []
1221
    for name in os.listdir(self._PIDS_DIR):
1222
      if self._InstancePidAlive(name)[2] or self._IsUserShutdown(name):
1223
        result.append(name)
1224
    return result
1225

    
1226
  @classmethod
1227
  def _IsUserShutdown(cls, instance_name):
1228
    return os.path.exists(cls._InstanceShutdownMonitor(instance_name))
1229

    
1230
  @classmethod
1231
  def _ClearUserShutdown(cls, instance_name):
1232
    utils.RemoveFile(cls._InstanceShutdownMonitor(instance_name))
1233

    
1234
  def GetInstanceInfo(self, instance_name, hvparams=None):
1235
    """Get instance properties.
1236

1237
    @type instance_name: string
1238
    @param instance_name: the instance name
1239
    @type hvparams: dict of strings
1240
    @param hvparams: hvparams to be used with this instance
1241
    @rtype: tuple of strings
1242
    @return: (name, id, memory, vcpus, stat, times)
1243

1244
    """
1245
    _, pid, alive = self._InstancePidAlive(instance_name)
1246
    if not alive:
1247
      if self._IsUserShutdown(instance_name):
1248
        return (instance_name, -1, 0, 0, hv_base.HvInstanceState.SHUTDOWN, 0)
1249
      else:
1250
        return None
1251

    
1252
    _, memory, vcpus = self._InstancePidInfo(pid)
1253
    istat = hv_base.HvInstanceState.RUNNING
1254
    times = 0
1255

    
1256
    try:
1257
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1258
      qmp.connect()
1259
      vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1260
      # Will fail if ballooning is not enabled, but we can then just resort to
1261
      # the value above.
1262
      mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1263
      memory = mem_bytes / 1048576
1264
    except errors.HypervisorError:
1265
      pass
1266

    
1267
    return (instance_name, pid, memory, vcpus, istat, times)
1268

    
1269
  def GetAllInstancesInfo(self, hvparams=None):
1270
    """Get properties of all instances.
1271

1272
    @type hvparams: dict of strings
1273
    @param hvparams: hypervisor parameter
1274
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1275

1276
    """
1277
    data = []
1278
    for name in os.listdir(self._PIDS_DIR):
1279
      try:
1280
        info = self.GetInstanceInfo(name)
1281
      except errors.HypervisorError:
1282
        # Ignore exceptions due to instances being shut down
1283
        continue
1284
      if info:
1285
        data.append(info)
1286
    return data
1287

    
1288
  def _GenerateKVMBlockDevicesOptions(self, instance, kvm_disks,
1289
                                      kvmhelp, devlist):
1290
    """Generate KVM options regarding instance's block devices.
1291

1292
    @type instance: L{objects.Instance}
1293
    @param instance: the instance object
1294
    @type kvm_disks: list of tuples
1295
    @param kvm_disks: list of tuples [(disk, link_name, uri)..]
1296
    @type kvmhelp: string
1297
    @param kvmhelp: output of kvm --help
1298
    @type devlist: string
1299
    @param devlist: output of kvm -device ?
1300
    @rtype: list
1301
    @return: list of command line options eventually used by kvm executable
1302

1303
    """
1304
    hvp = instance.hvparams
1305
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1306
    if kernel_path:
1307
      boot_disk = False
1308
    else:
1309
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1310

    
1311
    # whether this is an older KVM version that uses the boot=on flag
1312
    # on devices
1313
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1314

    
1315
    dev_opts = []
1316
    device_driver = None
1317
    disk_type = hvp[constants.HV_DISK_TYPE]
1318
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
1319
      if_val = ",if=%s" % self._VIRTIO
1320
      try:
1321
        if self._VIRTIO_BLK_RE.search(devlist):
1322
          if_val = ",if=none"
1323
          # will be passed in -device option as driver
1324
          device_driver = self._VIRTIO_BLK_PCI
1325
      except errors.HypervisorError, _:
1326
        pass
1327
    else:
1328
      if_val = ",if=%s" % disk_type
1329
    # Cache mode
1330
    disk_cache = hvp[constants.HV_DISK_CACHE]
1331
    if instance.disk_template in constants.DTS_EXT_MIRROR:
1332
      if disk_cache != "none":
1333
        # TODO: make this a hard error, instead of a silent overwrite
1334
        logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1335
                        " to prevent shared storage corruption on migration",
1336
                        disk_cache)
1337
      cache_val = ",cache=none"
1338
    elif disk_cache != constants.HT_CACHE_DEFAULT:
1339
      cache_val = ",cache=%s" % disk_cache
1340
    else:
1341
      cache_val = ""
1342
    for cfdev, link_name, uri in kvm_disks:
1343
      if cfdev.mode != constants.DISK_RDWR:
1344
        raise errors.HypervisorError("Instance has read-only disks which"
1345
                                     " are not supported by KVM")
1346
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
1347
      boot_val = ""
1348
      if boot_disk:
1349
        dev_opts.extend(["-boot", "c"])
1350
        boot_disk = False
1351
        if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1352
          boot_val = ",boot=on"
1353

    
1354
      access_mode = cfdev.params.get(constants.LDP_ACCESS,
1355
                                     constants.DISK_KERNELSPACE)
1356
      if (uri and access_mode == constants.DISK_USERSPACE):
1357
        drive_uri = uri
1358
      else:
1359
        drive_uri = link_name
1360

    
1361
      drive_val = "file=%s,format=raw%s%s%s" % \
1362
                  (drive_uri, if_val, boot_val, cache_val)
1363

    
1364
      if device_driver:
1365
        # kvm_disks are the 4th entry of runtime file that did not exist in
1366
        # the past. That means that cfdev should always have pci slot and
1367
        # _GenerateDeviceKVMId() will not raise a exception.
1368
        kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_DISK, cfdev)
1369
        drive_val += (",id=%s" % kvm_devid)
1370
        drive_val += (",bus=0,unit=%d" % cfdev.pci)
1371
        dev_val = ("%s,drive=%s,id=%s" %
1372
                   (device_driver, kvm_devid, kvm_devid))
1373
        dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci)
1374
        dev_opts.extend(["-device", dev_val])
1375

    
1376
      dev_opts.extend(["-drive", drive_val])
1377

    
1378
    return dev_opts
1379

    
1380
  @staticmethod
1381
  def _CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image, cdrom_boot,
1382
                   needs_boot_flag):
1383
    """Extends L{kvm_cmd} with the '-drive' option for a cdrom, and
1384
    optionally the '-boot' option.
1385

1386
    Example: -drive file=cdrom.iso,media=cdrom,format=raw,if=ide -boot d
1387

1388
    Example: -drive file=cdrom.iso,media=cdrom,format=raw,if=ide,boot=on
1389

1390
    Example: -drive file=http://hostname.com/cdrom.iso,media=cdrom
1391

1392
    @type kvm_cmd: string
1393
    @param kvm_cmd: KVM command line
1394

1395
    @type cdrom_disk_type:
1396
    @param cdrom_disk_type:
1397

1398
    @type cdrom_image:
1399
    @param cdrom_image:
1400

1401
    @type cdrom_boot:
1402
    @param cdrom_boot:
1403

1404
    @type needs_boot_flag:
1405
    @param needs_boot_flag:
1406

1407
    """
1408
    # Check that the ISO image is accessible
1409
    # See https://bugs.launchpad.net/qemu/+bug/597575
1410
    if utils.IsUrl(cdrom_image) and not _CheckUrl(cdrom_image):
1411
      raise errors.HypervisorError("Cdrom ISO image '%s' is not accessible" %
1412
                                   cdrom_image)
1413

    
1414
    # set cdrom 'media' and 'format', if needed
1415
    if utils.IsUrl(cdrom_image):
1416
      options = ",media=cdrom"
1417
    else:
1418
      options = ",media=cdrom,format=raw"
1419

    
1420
    # set cdrom 'if' type
1421
    if cdrom_boot:
1422
      if_val = ",if=" + constants.HT_DISK_IDE
1423
    elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1424
      if_val = ",if=virtio"
1425
    else:
1426
      if_val = ",if=" + cdrom_disk_type
1427

    
1428
    # set boot flag, if needed
1429
    boot_val = ""
1430
    if cdrom_boot:
1431
      kvm_cmd.extend(["-boot", "d"])
1432

    
1433
      # whether this is an older KVM version that requires the 'boot=on' flag
1434
      # on devices
1435
      if needs_boot_flag:
1436
        boot_val = ",boot=on"
1437

    
1438
    # build '-drive' option
1439
    drive_val = "file=%s%s%s%s" % (cdrom_image, options, if_val, boot_val)
1440
    kvm_cmd.extend(["-drive", drive_val])
1441

    
1442
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1443
                          kvmhelp):
1444
    """Generate KVM information to start an instance.
1445

1446
    @type kvmhelp: string
1447
    @param kvmhelp: output of kvm --help
1448
    @attention: this function must not have any side-effects; for
1449
        example, it must not write to the filesystem, or read values
1450
        from the current system the are expected to differ between
1451
        nodes, since it is only run once at instance startup;
1452
        actions/kvm arguments that can vary between systems should be
1453
        done in L{_ExecuteKVMRuntime}
1454

1455
    """
1456
    # pylint: disable=R0912,R0914,R0915
1457
    hvp = instance.hvparams
1458
    self.ValidateParameters(hvp)
1459

    
1460
    pidfile = self._InstancePidFile(instance.name)
1461
    kvm = hvp[constants.HV_KVM_PATH]
1462
    kvm_cmd = [kvm]
1463
    # used just by the vnc server, if enabled
1464
    kvm_cmd.extend(["-name", instance.name])
1465
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1466

    
1467
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1468
    if hvp[constants.HV_CPU_CORES]:
1469
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1470
    if hvp[constants.HV_CPU_THREADS]:
1471
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1472
    if hvp[constants.HV_CPU_SOCKETS]:
1473
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1474

    
1475
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1476

    
1477
    kvm_cmd.extend(["-pidfile", pidfile])
1478

    
1479
    pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1480

    
1481
    # As requested by music lovers
1482
    if hvp[constants.HV_SOUNDHW]:
1483
      soundhw = hvp[constants.HV_SOUNDHW]
1484
      # For some reason only few sound devices require a PCI slot
1485
      # while the Audio controller *must* be in slot 3.
1486
      # That's why we bridge this option early in command line
1487
      if soundhw in self._SOUNDHW_WITH_PCI_SLOT:
1488
        _ = _GetFreeSlot(pci_reservations, reserve=True)
1489
      kvm_cmd.extend(["-soundhw", soundhw])
1490

    
1491
    # Add id to ballon and place to the first available slot (3 or 4)
1492
    addr = _GetFreeSlot(pci_reservations, reserve=True)
1493
    pci_info = ",bus=pci.0,addr=%s" % hex(addr)
1494
    kvm_cmd.extend(["-balloon", "virtio,id=balloon%s" % pci_info])
1495
    kvm_cmd.extend(["-daemonize"])
1496
    if not instance.hvparams[constants.HV_ACPI]:
1497
      kvm_cmd.extend(["-no-acpi"])
1498
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1499
        constants.INSTANCE_REBOOT_EXIT:
1500
      kvm_cmd.extend(["-no-reboot"])
1501

    
1502
    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1503
    if not mversion:
1504
      mversion = self._GetDefaultMachineVersion(kvm)
1505
    if self._MACHINE_RE.search(kvmhelp):
1506
      # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1507
      # extra hypervisor parameters. We should also investigate whether and how
1508
      # shadow_mem should be considered for the resource model.
1509
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1510
        specprop = ",accel=kvm"
1511
      else:
1512
        specprop = ""
1513
      machinespec = "%s%s" % (mversion, specprop)
1514
      kvm_cmd.extend(["-machine", machinespec])
1515
    else:
1516
      kvm_cmd.extend(["-M", mversion])
1517
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1518
          self._ENABLE_KVM_RE.search(kvmhelp)):
1519
        kvm_cmd.extend(["-enable-kvm"])
1520
      elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1521
            self._DISABLE_KVM_RE.search(kvmhelp)):
1522
        kvm_cmd.extend(["-disable-kvm"])
1523

    
1524
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1525
    if kernel_path:
1526
      boot_cdrom = boot_floppy = boot_network = False
1527
    else:
1528
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1529
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1530
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1531

    
1532
    if startup_paused:
1533
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1534

    
1535
    if boot_network:
1536
      kvm_cmd.extend(["-boot", "n"])
1537

    
1538
    disk_type = hvp[constants.HV_DISK_TYPE]
1539

    
1540
    # Now we can specify a different device type for CDROM devices.
1541
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1542
    if not cdrom_disk_type:
1543
      cdrom_disk_type = disk_type
1544

    
1545
    cdrom_image1 = hvp[constants.HV_CDROM_IMAGE_PATH]
1546
    if cdrom_image1:
1547
      needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1548
      self._CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image1, boot_cdrom,
1549
                        needs_boot_flag)
1550

    
1551
    cdrom_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1552
    if cdrom_image2:
1553
      self._CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image2, False, False)
1554

    
1555
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1556
    if floppy_image:
1557
      options = ",format=raw,media=disk"
1558
      if boot_floppy:
1559
        kvm_cmd.extend(["-boot", "a"])
1560
        options = "%s,boot=on" % options
1561
      if_val = ",if=floppy"
1562
      options = "%s%s" % (options, if_val)
1563
      drive_val = "file=%s%s" % (floppy_image, options)
1564
      kvm_cmd.extend(["-drive", drive_val])
1565

    
1566
    if kernel_path:
1567
      kvm_cmd.extend(["-kernel", kernel_path])
1568
      initrd_path = hvp[constants.HV_INITRD_PATH]
1569
      if initrd_path:
1570
        kvm_cmd.extend(["-initrd", initrd_path])
1571
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1572
                     hvp[constants.HV_KERNEL_ARGS]]
1573
      if hvp[constants.HV_SERIAL_CONSOLE]:
1574
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1575
        root_append.append("console=ttyS0,%s" % serial_speed)
1576
      kvm_cmd.extend(["-append", " ".join(root_append)])
1577

    
1578
    mem_path = hvp[constants.HV_MEM_PATH]
1579
    if mem_path:
1580
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1581

    
1582
    monitor_dev = ("unix:%s,server,nowait" %
1583
                   self._InstanceMonitor(instance.name))
1584
    kvm_cmd.extend(["-monitor", monitor_dev])
1585
    if hvp[constants.HV_SERIAL_CONSOLE]:
1586
      serial_dev = ("unix:%s,server,nowait" %
1587
                    self._InstanceSerial(instance.name))
1588
      kvm_cmd.extend(["-serial", serial_dev])
1589
    else:
1590
      kvm_cmd.extend(["-serial", "none"])
1591

    
1592
    mouse_type = hvp[constants.HV_USB_MOUSE]
1593
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1594
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1595
    spice_ip_version = None
1596

    
1597
    kvm_cmd.extend(["-usb"])
1598

    
1599
    if mouse_type:
1600
      kvm_cmd.extend(["-usbdevice", mouse_type])
1601
    elif vnc_bind_address:
1602
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1603

    
1604
    if vnc_bind_address:
1605
      if netutils.IsValidInterface(vnc_bind_address):
1606
        if_addresses = netutils.GetInterfaceIpAddresses(vnc_bind_address)
1607
        if_ip4_addresses = if_addresses[constants.IP4_VERSION]
1608
        if len(if_ip4_addresses) < 1:
1609
          logging.error("Could not determine IPv4 address of interface %s",
1610
                        vnc_bind_address)
1611
        else:
1612
          vnc_bind_address = if_ip4_addresses[0]
1613
      if netutils.IP4Address.IsValid(vnc_bind_address):
1614
        if instance.network_port > constants.VNC_BASE_PORT:
1615
          display = instance.network_port - constants.VNC_BASE_PORT
1616
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1617
            vnc_arg = ":%d" % (display)
1618
          else:
1619
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1620
        else:
1621
          logging.error("Network port is not a valid VNC display (%d < %d),"
1622
                        " not starting VNC",
1623
                        instance.network_port, constants.VNC_BASE_PORT)
1624
          vnc_arg = "none"
1625

    
1626
        # Only allow tls and other option when not binding to a file, for now.
1627
        # kvm/qemu gets confused otherwise about the filename to use.
1628
        vnc_append = ""
1629
        if hvp[constants.HV_VNC_TLS]:
1630
          vnc_append = "%s,tls" % vnc_append
1631
          if hvp[constants.HV_VNC_X509_VERIFY]:
1632
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1633
                                               hvp[constants.HV_VNC_X509])
1634
          elif hvp[constants.HV_VNC_X509]:
1635
            vnc_append = "%s,x509=%s" % (vnc_append,
1636
                                         hvp[constants.HV_VNC_X509])
1637
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1638
          vnc_append = "%s,password" % vnc_append
1639

    
1640
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1641

    
1642
      else:
1643
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1644

    
1645
      kvm_cmd.extend(["-vnc", vnc_arg])
1646
    elif spice_bind:
1647
      # FIXME: this is wrong here; the iface ip address differs
1648
      # between systems, so it should be done in _ExecuteKVMRuntime
1649
      if netutils.IsValidInterface(spice_bind):
1650
        # The user specified a network interface, we have to figure out the IP
1651
        # address.
1652
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1653
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1654

    
1655
        # if the user specified an IP version and the interface does not
1656
        # have that kind of IP addresses, throw an exception
1657
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1658
          if not addresses[spice_ip_version]:
1659
            raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1660
                                         " for %s" % (spice_ip_version,
1661
                                                      spice_bind))
1662

    
1663
        # the user did not specify an IP version, we have to figure it out
1664
        elif (addresses[constants.IP4_VERSION] and
1665
              addresses[constants.IP6_VERSION]):
1666
          # we have both ipv4 and ipv6, let's use the cluster default IP
1667
          # version
1668
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1669
          spice_ip_version = \
1670
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1671
        elif addresses[constants.IP4_VERSION]:
1672
          spice_ip_version = constants.IP4_VERSION
1673
        elif addresses[constants.IP6_VERSION]:
1674
          spice_ip_version = constants.IP6_VERSION
1675
        else:
1676
          raise errors.HypervisorError("SPICE: Unable to get an IP address"
1677
                                       " for %s" % (spice_bind))
1678

    
1679
        spice_address = addresses[spice_ip_version][0]
1680

    
1681
      else:
1682
        # spice_bind is known to be a valid IP address, because
1683
        # ValidateParameters checked it.
1684
        spice_address = spice_bind
1685

    
1686
      spice_arg = "addr=%s" % spice_address
1687
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1688
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1689
                     (spice_arg, instance.network_port,
1690
                      pathutils.SPICE_CACERT_FILE))
1691
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1692
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1693
                      pathutils.SPICE_CERT_FILE))
1694
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1695
        if tls_ciphers:
1696
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1697
      else:
1698
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1699

    
1700
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1701
        spice_arg = "%s,disable-ticketing" % spice_arg
1702

    
1703
      if spice_ip_version:
1704
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1705

    
1706
      # Image compression options
1707
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1708
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1709
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1710
      if img_lossless:
1711
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1712
      if img_jpeg:
1713
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1714
      if img_zlib_glz:
1715
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1716

    
1717
      # Video stream detection
1718
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1719
      if video_streaming:
1720
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1721

    
1722
      # Audio compression, by default in qemu-kvm it is on
1723
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1724
        spice_arg = "%s,playback-compression=off" % spice_arg
1725
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1726
        spice_arg = "%s,agent-mouse=off" % spice_arg
1727
      else:
1728
        # Enable the spice agent communication channel between the host and the
1729
        # agent.
1730
        addr = _GetFreeSlot(pci_reservations, reserve=True)
1731
        pci_info = ",bus=pci.0,addr=%s" % hex(addr)
1732
        kvm_cmd.extend(["-device", "virtio-serial-pci,id=spice%s" % pci_info])
1733
        kvm_cmd.extend([
1734
          "-device",
1735
          "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1736
          ])
1737
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1738

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

    
1742
    else:
1743
      # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1744
      # also works in earlier versions though (tested with 1.1 and 1.3)
1745
      if self._DISPLAY_RE.search(kvmhelp):
1746
        kvm_cmd.extend(["-display", "none"])
1747
      else:
1748
        kvm_cmd.extend(["-nographic"])
1749

    
1750
    if hvp[constants.HV_USE_LOCALTIME]:
1751
      kvm_cmd.extend(["-localtime"])
1752

    
1753
    if hvp[constants.HV_KVM_USE_CHROOT]:
1754
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1755

    
1756
    # Add qemu-KVM -cpu param
1757
    if hvp[constants.HV_CPU_TYPE]:
1758
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1759

    
1760
    # Pass a -vga option if requested, or if spice is used, for backwards
1761
    # compatibility.
1762
    if hvp[constants.HV_VGA]:
1763
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1764
    elif spice_bind:
1765
      kvm_cmd.extend(["-vga", "qxl"])
1766

    
1767
    # Various types of usb devices, comma separated
1768
    if hvp[constants.HV_USB_DEVICES]:
1769
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1770
        kvm_cmd.extend(["-usbdevice", dev])
1771

    
1772
    # Set system UUID to instance UUID
1773
    if self._UUID_RE.search(kvmhelp):
1774
      kvm_cmd.extend(["-uuid", instance.uuid])
1775

    
1776
    if hvp[constants.HV_KVM_EXTRA]:
1777
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1778

    
1779
    kvm_disks = []
1780
    for disk, link_name, uri in block_devices:
1781
      disk.pci = _GetFreeSlot(pci_reservations, disk.pci, True)
1782
      kvm_disks.append((disk, link_name, uri))
1783

    
1784
    kvm_nics = []
1785
    for nic in instance.nics:
1786
      nic.pci = _GetFreeSlot(pci_reservations, nic.pci, True)
1787
      kvm_nics.append(nic)
1788

    
1789
    hvparams = hvp
1790

    
1791
    return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1792

    
1793
  def _WriteKVMRuntime(self, instance_name, data):
1794
    """Write an instance's KVM runtime
1795

1796
    """
1797
    try:
1798
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1799
                      data=data)
1800
    except EnvironmentError, err:
1801
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1802

    
1803
  def _ReadKVMRuntime(self, instance_name):
1804
    """Read an instance's KVM runtime
1805

1806
    """
1807
    try:
1808
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1809
    except EnvironmentError, err:
1810
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1811
    return file_content
1812

    
1813
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1814
    """Save an instance's KVM runtime
1815

1816
    """
1817
    kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1818

    
1819
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1820
    serialized_disks = [(blk.ToDict(), link, uri)
1821
                        for blk, link, uri in kvm_disks]
1822
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1823
                                      serialized_disks))
1824

    
1825
    self._WriteKVMRuntime(instance.name, serialized_form)
1826

    
1827
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1828
    """Load an instance's KVM runtime
1829

1830
    """
1831
    if not serialized_runtime:
1832
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1833

    
1834
    return _AnalyzeSerializedRuntime(serialized_runtime)
1835

    
1836
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1837
    """Run the KVM cmd and check for errors
1838

1839
    @type name: string
1840
    @param name: instance name
1841
    @type kvm_cmd: list of strings
1842
    @param kvm_cmd: runcmd input for kvm
1843
    @type tap_fds: list of int
1844
    @param tap_fds: fds of tap devices opened by Ganeti
1845

1846
    """
1847
    try:
1848
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1849
    finally:
1850
      for fd in tap_fds:
1851
        utils_wrapper.CloseFdNoError(fd)
1852

    
1853
    if result.failed:
1854
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1855
                                   (name, result.fail_reason, result.output))
1856
    if not self._InstancePidAlive(name)[2]:
1857
      raise errors.HypervisorError("Failed to start instance %s" % name)
1858

    
1859
  @staticmethod
1860
  def _GenerateTapName(nic):
1861
    """Generate a TAP network interface name for a NIC.
1862

1863
    This helper function generates a special TAP network interface
1864
    name for NICs that are meant to be used in instance communication.
1865
    This function checks the existing TAP interfaces in order to find
1866
    a unique name for the new TAP network interface.  The TAP network
1867
    interface names are of the form 'gnt.com.%d', where '%d' is a
1868
    unique number within the node.
1869

1870
    @type nic: ganeti.objects.NIC
1871
    @param nic: NIC object for the name should be generated
1872

1873
    @rtype: string
1874
    @return: TAP network interface name, or the empty string if the
1875
             NIC is not used in instance communication
1876

1877
    """
1878
    if nic.name is None or not \
1879
          nic.name.startswith(constants.INSTANCE_COMMUNICATION_NIC_PREFIX):
1880
      return ""
1881

    
1882
    result = utils.RunCmd(["ip", "tuntap", "list"])
1883

    
1884
    if result.failed:
1885
      raise errors.HypervisorError("Failed to list TUN/TAP interfaces")
1886

    
1887
    idxs = set()
1888

    
1889
    for line in result.output.splitlines():
1890
      parts = line.split(": ", 1)
1891

    
1892
      if len(parts) < 2:
1893
        raise errors.HypervisorError("Failed to parse TUN/TAP interfaces")
1894

    
1895
      r = re.match(r"gnt\.com\.([0-9]+)", parts[0])
1896

    
1897
      if r is not None:
1898
        idxs.add(int(r.group(1)))
1899

    
1900
    if idxs:
1901
      idx = max(idxs) + 1
1902
    else:
1903
      idx = 0
1904

    
1905
    return "gnt.com.%d" % idx
1906

    
1907
  # too many local variables
1908
  # pylint: disable=R0914
1909
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1910
    """Execute a KVM cmd, after completing it with some last minute data.
1911

1912
    @type incoming: tuple of strings
1913
    @param incoming: (target_host_ip, port)
1914
    @type kvmhelp: string
1915
    @param kvmhelp: output of kvm --help
1916

1917
    """
1918
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1919
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1920
    #    have changed since the instance started; only use them if the change
1921
    #    won't affect the inside of the instance (which hasn't been rebooted).
1922
    #  - up_hvp contains the parameters as they were when the instance was
1923
    #    started, plus any new parameter which has been added between ganeti
1924
    #    versions: it is paramount that those default to a value which won't
1925
    #    affect the inside of the instance as well.
1926
    conf_hvp = instance.hvparams
1927
    name = instance.name
1928
    self._CheckDown(name)
1929

    
1930
    self._ClearUserShutdown(instance.name)
1931
    self._StartKvmd(instance.hvparams)
1932

    
1933
    temp_files = []
1934

    
1935
    kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1936
    # the first element of kvm_cmd is always the path to the kvm binary
1937
    kvm_path = kvm_cmd[0]
1938
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1939

    
1940
    # We know it's safe to run as a different user upon migration, so we'll use
1941
    # the latest conf, from conf_hvp.
1942
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1943
    if security_model == constants.HT_SM_USER:
1944
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1945

    
1946
    keymap = conf_hvp[constants.HV_KEYMAP]
1947
    if keymap:
1948
      keymap_path = self._InstanceKeymapFile(name)
1949
      # If a keymap file is specified, KVM won't use its internal defaults. By
1950
      # first including the "en-us" layout, an error on loading the actual
1951
      # layout (e.g. because it can't be found) won't lead to a non-functional
1952
      # keyboard. A keyboard with incorrect keys is still better than none.
1953
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1954
      kvm_cmd.extend(["-k", keymap_path])
1955

    
1956
    # We have reasons to believe changing something like the nic driver/type
1957
    # upon migration won't exactly fly with the instance kernel, so for nic
1958
    # related parameters we'll use up_hvp
1959
    tapfds = []
1960
    taps = []
1961
    devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1962
    if not kvm_nics:
1963
      kvm_cmd.extend(["-net", "none"])
1964
    else:
1965
      vnet_hdr = False
1966
      tap_extra = ""
1967
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1968
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1969
        nic_model = self._VIRTIO
1970
        try:
1971
          if self._VIRTIO_NET_RE.search(devlist):
1972
            nic_model = self._VIRTIO_NET_PCI
1973
            vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1974
        except errors.HypervisorError, _:
1975
          # Older versions of kvm don't support DEVICE_LIST, but they don't
1976
          # have new virtio syntax either.
1977
          pass
1978

    
1979
        if up_hvp[constants.HV_VHOST_NET]:
1980
          # check for vhost_net support
1981
          if self._VHOST_RE.search(kvmhelp):
1982
            tap_extra = ",vhost=on"
1983
          else:
1984
            raise errors.HypervisorError("vhost_net is configured"
1985
                                         " but it is not available")
1986
      else:
1987
        nic_model = nic_type
1988

    
1989
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1990

    
1991
      for nic_seq, nic in enumerate(kvm_nics):
1992
        tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr,
1993
                                  name=self._GenerateTapName(nic))
1994
        tapfds.append(tapfd)
1995
        taps.append(tapname)
1996
        if kvm_supports_netdev:
1997
          nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1998
          try:
1999
            # kvm_nics already exist in old runtime files and thus there might
2000
            # be some entries without pci slot (therefore try: except:)
2001
            kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2002
            netdev = kvm_devid
2003
            nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
2004
          except errors.HotplugError:
2005
            netdev = "netdev%d" % nic_seq
2006
          nic_val += (",netdev=%s" % netdev)
2007
          tap_val = ("type=tap,id=%s,fd=%d%s" %
2008
                     (netdev, tapfd, tap_extra))
2009
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
2010
        else:
2011
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
2012
                                                         nic.mac, nic_model)
2013
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
2014
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
2015

    
2016
    if incoming:
2017
      target, port = incoming
2018
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
2019

    
2020
    # Changing the vnc password doesn't bother the guest that much. At most it
2021
    # will surprise people who connect to it. Whether positively or negatively
2022
    # it's debatable.
2023
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
2024
    vnc_pwd = None
2025
    if vnc_pwd_file:
2026
      try:
2027
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
2028
      except EnvironmentError, err:
2029
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
2030
                                     % (vnc_pwd_file, err))
2031

    
2032
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
2033
      utils.EnsureDirs([(self._InstanceChrootDir(name),
2034
                         constants.SECURE_DIR_MODE)])
2035

    
2036
    # Automatically enable QMP if version is >= 0.14
2037
    if self._QMP_RE.search(kvmhelp):
2038
      logging.debug("Enabling QMP")
2039
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
2040
                      self._InstanceQmpMonitor(instance.name)])
2041

    
2042
    # Configure the network now for starting instances and bridged interfaces,
2043
    # during FinalizeMigration for incoming instances' routed interfaces
2044
    for nic_seq, nic in enumerate(kvm_nics):
2045
      if (incoming and
2046
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
2047
        continue
2048
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
2049

    
2050
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
2051
                                                     kvm_disks,
2052
                                                     kvmhelp,
2053
                                                     devlist)
2054
    kvm_cmd.extend(bdev_opts)
2055
    # CPU affinity requires kvm to start paused, so we set this flag if the
2056
    # instance is not already paused and if we are not going to accept a
2057
    # migrating instance. In the latter case, pausing is not needed.
2058
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
2059
    if start_kvm_paused:
2060
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
2061

    
2062
    # Note: CPU pinning is using up_hvp since changes take effect
2063
    # during instance startup anyway, and to avoid problems when soft
2064
    # rebooting the instance.
2065
    cpu_pinning = False
2066
    if up_hvp.get(constants.HV_CPU_MASK, None):
2067
      cpu_pinning = True
2068

    
2069
    if security_model == constants.HT_SM_POOL:
2070
      ss = ssconf.SimpleStore()
2071
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
2072
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
2073
      uid = uidpool.RequestUnusedUid(all_uids)
2074
      try:
2075
        username = pwd.getpwuid(uid.GetUid()).pw_name
2076
        kvm_cmd.extend(["-runas", username])
2077
        self._RunKVMCmd(name, kvm_cmd, tapfds)
2078
      except:
2079
        uidpool.ReleaseUid(uid)
2080
        raise
2081
      else:
2082
        uid.Unlock()
2083
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
2084
    else:
2085
      self._RunKVMCmd(name, kvm_cmd, tapfds)
2086

    
2087
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
2088
                     constants.RUN_DIRS_MODE)])
2089
    for nic_seq, tap in enumerate(taps):
2090
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
2091
                      data=tap)
2092

    
2093
    if vnc_pwd:
2094
      change_cmd = "change vnc password %s" % vnc_pwd
2095
      self._CallMonitorCommand(instance.name, change_cmd)
2096

    
2097
    # Setting SPICE password. We are not vulnerable to malicious passwordless
2098
    # connection attempts because SPICE by default does not allow connections
2099
    # if neither a password nor the "disable_ticketing" options are specified.
2100
    # As soon as we send the password via QMP, that password is a valid ticket
2101
    # for connection.
2102
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
2103
    if spice_password_file:
2104
      spice_pwd = ""
2105
      try:
2106
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
2107
      except EnvironmentError, err:
2108
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
2109
                                     % (spice_password_file, err))
2110

    
2111
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
2112
      qmp.connect()
2113
      arguments = {
2114
          "protocol": "spice",
2115
          "password": spice_pwd,
2116
      }
2117
      qmp.Execute("set_password", arguments)
2118

    
2119
    for filename in temp_files:
2120
      utils.RemoveFile(filename)
2121

    
2122
    # If requested, set CPU affinity and resume instance execution
2123
    if cpu_pinning:
2124
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
2125

    
2126
    start_memory = self._InstanceStartupMemory(instance)
2127
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
2128
      self.BalloonInstanceMemory(instance, start_memory)
2129

    
2130
    if start_kvm_paused:
2131
      # To control CPU pinning, ballooning, and vnc/spice passwords
2132
      # the VM was started in a frozen state. If freezing was not
2133
      # explicitly requested resume the vm status.
2134
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2135

    
2136
  @staticmethod
2137
  def _StartKvmd(hvparams):
2138
    """Ensure that the Kvm daemon is running.
2139

2140
    """
2141
    if hvparams is None \
2142
          or not hvparams[constants.HV_KVM_USER_SHUTDOWN] \
2143
          or utils.IsDaemonAlive(constants.KVMD):
2144
      return
2145

    
2146
    result = utils.RunCmd(constants.KVMD)
2147

    
2148
    if result.failed:
2149
      raise errors.HypervisorError("Failed to start KVM daemon")
2150

    
2151
  def StartInstance(self, instance, block_devices, startup_paused):
2152
    """Start an instance.
2153

2154
    """
2155
    self._CheckDown(instance.name)
2156
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2157
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2158
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
2159
                                           startup_paused, kvmhelp)
2160
    self._SaveKVMRuntime(instance, kvm_runtime)
2161
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2162

    
2163
  @classmethod
2164
  def _CallMonitorCommand(cls, instance_name, command, timeout=None):
2165
    """Invoke a command on the instance monitor.
2166

2167
    """
2168
    if timeout is not None:
2169
      timeout_cmd = "timeout %s" % (timeout, )
2170
    else:
2171
      timeout_cmd = ""
2172

    
2173
    # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
2174
    # version. The monitor protocol is designed for human consumption, whereas
2175
    # QMP is made for programmatic usage. In the worst case QMP can also
2176
    # execute monitor commands. As it is, all calls to socat take at least
2177
    # 500ms and likely more: socat can't detect the end of the reply and waits
2178
    # for 500ms of no data received before exiting (500 ms is the default for
2179
    # the "-t" parameter).
2180
    socat = ("echo %s | %s %s STDIO UNIX-CONNECT:%s" %
2181
             (utils.ShellQuote(command),
2182
              timeout_cmd,
2183
              constants.SOCAT_PATH,
2184
              utils.ShellQuote(cls._InstanceMonitor(instance_name))))
2185
    result = utils.RunCmd(socat)
2186
    if result.failed:
2187
      msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
2188
             " output: %s" %
2189
             (command, instance_name, result.fail_reason, result.output))
2190
      raise errors.HypervisorError(msg)
2191

    
2192
    return result
2193

    
2194
  def _GetFreePCISlot(self, instance, dev):
2195
    """Get the first available pci slot of a runnung instance.
2196

2197
    """
2198
    slots = bitarray(32)
2199
    slots.setall(False) # pylint: disable=E1101
2200
    output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
2201
    for line in output.stdout.splitlines():
2202
      match = self._INFO_PCI_RE.search(line)
2203
      if match:
2204
        slot = int(match.group(1))
2205
        slots[slot] = True
2206

    
2207
    dev.pci = _GetFreeSlot(slots)
2208

    
2209
  def VerifyHotplugSupport(self, instance, action, dev_type):
2210
    """Verifies that hotplug is supported.
2211

2212
    Hotplug is *not* supported in case of:
2213
     - security models and chroot (disk hotplug)
2214
     - fdsend module is missing (nic hot-add)
2215

2216
    @raise errors.HypervisorError: in one of the previous cases
2217

2218
    """
2219
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2220
      hvp = instance.hvparams
2221
      security_model = hvp[constants.HV_SECURITY_MODEL]
2222
      use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
2223
      if use_chroot:
2224
        raise errors.HotplugError("Disk hotplug is not supported"
2225
                                  " in case of chroot.")
2226
      if security_model != constants.HT_SM_NONE:
2227
        raise errors.HotplugError("Disk Hotplug is not supported in case"
2228
                                  " security models are used.")
2229

    
2230
    if (dev_type == constants.HOTPLUG_TARGET_NIC and
2231
        action == constants.HOTPLUG_ACTION_ADD and not fdsend):
2232
      raise errors.HotplugError("Cannot hot-add NIC."
2233
                                " fdsend python module is missing.")
2234

    
2235
  def HotplugSupported(self, instance):
2236
    """Checks if hotplug is generally supported.
2237

2238
    Hotplug is *not* supported in case of:
2239
     - qemu versions < 1.0
2240
     - for stopped instances
2241

2242
    @raise errors.HypervisorError: in one of the previous cases
2243

2244
    """
2245
    try:
2246
      output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2247
    except errors.HypervisorError:
2248
      raise errors.HotplugError("Instance is probably down")
2249

    
2250
    # TODO: search for netdev_add, drive_add, device_add.....
2251
    match = self._INFO_VERSION_RE.search(output.stdout)
2252
    if not match:
2253
      raise errors.HotplugError("Cannot parse qemu version via monitor")
2254

    
2255
    v_major, v_min, _, _ = match.groups()
2256
    if (int(v_major), int(v_min)) < (1, 0):
2257
      raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2258

    
2259
  def _CallHotplugCommands(self, name, cmds):
2260
    for c in cmds:
2261
      self._CallMonitorCommand(name, c)
2262
      time.sleep(1)
2263

    
2264
  def _VerifyHotplugCommand(self, instance_name, device, dev_type,
2265
                            should_exist):
2266
    """Checks if a previous hotplug command has succeeded.
2267

2268
    It issues info pci monitor command and checks depending on should_exist
2269
    value if an entry with PCI slot and device ID is found or not.
2270

2271
    @raise errors.HypervisorError: if result is not the expected one
2272

2273
    """
2274
    output = self._CallMonitorCommand(instance_name, self._INFO_PCI_CMD)
2275
    kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2276
    match = \
2277
      self._FIND_PCI_DEVICE_RE(device.pci, kvm_devid).search(output.stdout)
2278
    if match and not should_exist:
2279
      msg = "Device %s should have been removed but is still there" % kvm_devid
2280
      raise errors.HypervisorError(msg)
2281

    
2282
    if not match and should_exist:
2283
      msg = "Device %s should have been added but is missing" % kvm_devid
2284
      raise errors.HypervisorError(msg)
2285

    
2286
    logging.info("Device %s has been correctly hot-plugged", kvm_devid)
2287

    
2288
  def HotAddDevice(self, instance, dev_type, device, extra, seq):
2289
    """ Helper method to hot-add a new device
2290

2291
    It gets free pci slot generates the device name and invokes the
2292
    device specific method.
2293

2294
    """
2295
    # in case of hot-mod this is given
2296
    if device.pci is None:
2297
      self._GetFreePCISlot(instance, device)
2298
    kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2299
    runtime = self._LoadKVMRuntime(instance)
2300
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2301
      cmds = ["drive_add dummy file=%s,if=none,id=%s,format=raw" %
2302
                (extra, kvm_devid)]
2303
      cmds += ["device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
2304
                (hex(device.pci), kvm_devid, kvm_devid)]
2305
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
2306
      (tap, fd) = _OpenTap()
2307
      self._ConfigureNIC(instance, seq, device, tap)
2308
      self._PassTapFd(instance, fd, device)
2309
      cmds = ["netdev_add tap,id=%s,fd=%s" % (kvm_devid, kvm_devid)]
2310
      args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
2311
               (hex(device.pci), device.mac, kvm_devid, kvm_devid)
2312
      cmds += ["device_add %s" % args]
2313
      utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
2314

    
2315
    self._CallHotplugCommands(instance.name, cmds)
2316
    self._VerifyHotplugCommand(instance.name, device, dev_type, True)
2317
    # update relevant entries in runtime file
2318
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2319
    entry = _RUNTIME_ENTRY[dev_type](device, extra)
2320
    runtime[index].append(entry)
2321
    self._SaveKVMRuntime(instance, runtime)
2322

    
2323
  def HotDelDevice(self, instance, dev_type, device, _, seq):
2324
    """ Helper method for hot-del device
2325

2326
    It gets device info from runtime file, generates the device name and
2327
    invokes the device specific method.
2328

2329
    """
2330
    runtime = self._LoadKVMRuntime(instance)
2331
    entry = _GetExistingDeviceInfo(dev_type, device, runtime)
2332
    kvm_device = _RUNTIME_DEVICE[dev_type](entry)
2333
    kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
2334
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2335
      cmds = ["device_del %s" % kvm_devid]
2336
      cmds += ["drive_del %s" % kvm_devid]
2337
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
2338
      cmds = ["device_del %s" % kvm_devid]
2339
      cmds += ["netdev_del %s" % kvm_devid]
2340
      utils.RemoveFile(self._InstanceNICFile(instance.name, seq))
2341
    self._CallHotplugCommands(instance.name, cmds)
2342
    self._VerifyHotplugCommand(instance.name, kvm_device, dev_type, False)
2343
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2344
    runtime[index].remove(entry)
2345
    self._SaveKVMRuntime(instance, runtime)
2346

    
2347
    return kvm_device.pci
2348

    
2349
  def HotModDevice(self, instance, dev_type, device, _, seq):
2350
    """ Helper method for hot-mod device
2351

2352
    It gets device info from runtime file, generates the device name and
2353
    invokes the device specific method. Currently only NICs support hot-mod
2354

2355
    """
2356
    if dev_type == constants.HOTPLUG_TARGET_NIC:
2357
      # putting it back in the same pci slot
2358
      device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2359
      self.HotAddDevice(instance, dev_type, device, _, seq)
2360

    
2361
  def _PassTapFd(self, instance, fd, nic):
2362
    """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2363

2364
    """
2365
    # TODO: factor out code related to unix sockets.
2366
    #       squash common parts between monitor and qmp
2367
    kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2368
    command = "getfd %s\n" % kvm_devid
2369
    fds = [fd]
2370
    logging.info("%s", fds)
2371
    try:
2372
      monsock = MonitorSocket(self._InstanceMonitor(instance.name))
2373
      monsock.connect()
2374
      fdsend.sendfds(monsock.sock, command, fds=fds)
2375
    finally:
2376
      monsock.close()
2377

    
2378
  @classmethod
2379
  def _ParseKVMVersion(cls, text):
2380
    """Parse the KVM version from the --help output.
2381

2382
    @type text: string
2383
    @param text: output of kvm --help
2384
    @return: (version, v_maj, v_min, v_rev)
2385
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2386

2387
    """
2388
    match = cls._VERSION_RE.search(text.splitlines()[0])
2389
    if not match:
2390
      raise errors.HypervisorError("Unable to get KVM version")
2391

    
2392
    v_all = match.group(0)
2393
    v_maj = int(match.group(1))
2394
    v_min = int(match.group(2))
2395
    if match.group(4):
2396
      v_rev = int(match.group(4))
2397
    else:
2398
      v_rev = 0
2399
    return (v_all, v_maj, v_min, v_rev)
2400

    
2401
  @classmethod
2402
  def _GetKVMOutput(cls, kvm_path, option):
2403
    """Return the output of a kvm invocation
2404

2405
    @type kvm_path: string
2406
    @param kvm_path: path to the kvm executable
2407
    @type option: a key of _KVMOPTS_CMDS
2408
    @param option: kvm option to fetch the output from
2409
    @return: output a supported kvm invocation
2410
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2411

2412
    """
2413
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2414

    
2415
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
2416

    
2417
    result = utils.RunCmd([kvm_path] + optlist)
2418
    if result.failed and not can_fail:
2419
      raise errors.HypervisorError("Unable to get KVM %s output" %
2420
                                    " ".join(optlist))
2421
    return result.output
2422

    
2423
  @classmethod
2424
  def _GetKVMVersion(cls, kvm_path):
2425
    """Return the installed KVM version.
2426

2427
    @return: (version, v_maj, v_min, v_rev)
2428
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2429

2430
    """
2431
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2432

    
2433
  @classmethod
2434
  def _GetDefaultMachineVersion(cls, kvm_path):
2435
    """Return the default hardware revision (e.g. pc-1.1)
2436

2437
    """
2438
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2439
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2440
    if match:
2441
      return match.group(1)
2442
    else:
2443
      return "pc"
2444

    
2445
  @classmethod
2446
  def _StopInstance(cls, instance, force=False, name=None, timeout=None):
2447
    """Stop an instance.
2448

2449
    """
2450
    assert(timeout is None or force is not None)
2451

    
2452
    if name is not None and not force:
2453
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2454
    if name is None:
2455
      name = instance.name
2456
      acpi = instance.hvparams[constants.HV_ACPI]
2457
    else:
2458
      acpi = False
2459
    _, pid, alive = cls._InstancePidAlive(name)
2460
    if pid > 0 and alive:
2461
      if force or not acpi:
2462
        utils.KillProcess(pid)
2463
      else:
2464
        cls._CallMonitorCommand(name, "system_powerdown", timeout)
2465
    cls._ClearUserShutdown(instance.name)
2466

    
2467
  def StopInstance(self, instance, force=False, retry=False, name=None,
2468
                   timeout=None):
2469
    """Stop an instance.
2470

2471
    """
2472
    self._StopInstance(instance, force, name=name, timeout=timeout)
2473

    
2474
  def CleanupInstance(self, instance_name):
2475
    """Cleanup after a stopped instance
2476

2477
    """
2478
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
2479
    if pid > 0 and alive:
2480
      raise errors.HypervisorError("Cannot cleanup a live instance")
2481
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2482
    self._ClearUserShutdown(instance_name)
2483

    
2484
  def RebootInstance(self, instance):
2485
    """Reboot an instance.
2486

2487
    """
2488
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2489
    # socket the instance will stop, but now power up again. So we'll resort
2490
    # to shutdown and restart.
2491
    _, _, alive = self._InstancePidAlive(instance.name)
2492
    if not alive:
2493
      raise errors.HypervisorError("Failed to reboot instance %s:"
2494
                                   " not running" % instance.name)
2495
    # StopInstance will delete the saved KVM runtime so:
2496
    # ...first load it...
2497
    kvm_runtime = self._LoadKVMRuntime(instance)
2498
    # ...now we can safely call StopInstance...
2499
    if not self.StopInstance(instance):
2500
      self.StopInstance(instance, force=True)
2501
    # ...and finally we can save it again, and execute it...
2502
    self._SaveKVMRuntime(instance, kvm_runtime)
2503
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2504
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2505
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2506

    
2507
  def MigrationInfo(self, instance):
2508
    """Get instance information to perform a migration.
2509

2510
    @type instance: L{objects.Instance}
2511
    @param instance: instance to be migrated
2512
    @rtype: string
2513
    @return: content of the KVM runtime file
2514

2515
    """
2516
    return self._ReadKVMRuntime(instance.name)
2517

    
2518
  def AcceptInstance(self, instance, info, target):
2519
    """Prepare to accept an instance.
2520

2521
    @type instance: L{objects.Instance}
2522
    @param instance: instance to be accepted
2523
    @type info: string
2524
    @param info: content of the KVM runtime file on the source node
2525
    @type target: string
2526
    @param target: target host (usually ip), on this node
2527

2528
    """
2529
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2530
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2531
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2532
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2533
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2534
                            incoming=incoming_address)
2535

    
2536
  def FinalizeMigrationDst(self, instance, info, success):
2537
    """Finalize the instance migration on the target node.
2538

2539
    Stop the incoming mode KVM.
2540

2541
    @type instance: L{objects.Instance}
2542
    @param instance: instance whose migration is being finalized
2543

2544
    """
2545
    if success:
2546
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2547
      kvm_nics = kvm_runtime[1]
2548

    
2549
      for nic_seq, nic in enumerate(kvm_nics):
2550
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2551
          # Bridged interfaces have already been configured
2552
          continue
2553
        try:
2554
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2555
        except EnvironmentError, err:
2556
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
2557
                          instance.name, nic_seq, str(err))
2558
          continue
2559
        try:
2560
          self._ConfigureNIC(instance, nic_seq, nic, tap)
2561
        except errors.HypervisorError, err:
2562
          logging.warning(str(err))
2563

    
2564
      self._WriteKVMRuntime(instance.name, info)
2565
    else:
2566
      self.StopInstance(instance, force=True)
2567

    
2568
  def MigrateInstance(self, cluster_name, instance, target, live):
2569
    """Migrate an instance to a target node.
2570

2571
    The migration will not be attempted if the instance is not
2572
    currently running.
2573

2574
    @type cluster_name: string
2575
    @param cluster_name: name of the cluster
2576
    @type instance: L{objects.Instance}
2577
    @param instance: the instance to be migrated
2578
    @type target: string
2579
    @param target: ip address of the target node
2580
    @type live: boolean
2581
    @param live: perform a live migration
2582

2583
    """
2584
    instance_name = instance.name
2585
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
2586
    _, _, alive = self._InstancePidAlive(instance_name)
2587
    if not alive:
2588
      raise errors.HypervisorError("Instance not running, cannot migrate")
2589

    
2590
    if not live:
2591
      self._CallMonitorCommand(instance_name, "stop")
2592

    
2593
    migrate_command = ("migrate_set_speed %dm" %
2594
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2595
    self._CallMonitorCommand(instance_name, migrate_command)
2596

    
2597
    migrate_command = ("migrate_set_downtime %dms" %
2598
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2599
    self._CallMonitorCommand(instance_name, migrate_command)
2600

    
2601
    migration_caps = instance.hvparams[constants.HV_KVM_MIGRATION_CAPS]
2602
    if migration_caps:
2603
      for c in migration_caps.split(_MIGRATION_CAPS_DELIM):
2604
        migrate_command = ("migrate_set_capability %s on" % c)
2605
        self._CallMonitorCommand(instance_name, migrate_command)
2606

    
2607
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2608
    self._CallMonitorCommand(instance_name, migrate_command)
2609

    
2610
  def FinalizeMigrationSource(self, instance, success, live):
2611
    """Finalize the instance migration on the source node.
2612

2613
    @type instance: L{objects.Instance}
2614
    @param instance: the instance that was migrated
2615
    @type success: bool
2616
    @param success: whether the migration succeeded or not
2617
    @type live: bool
2618
    @param live: whether the user requested a live migration or not
2619

2620
    """
2621
    if success:
2622
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2623
      utils.KillProcess(pid)
2624
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2625
    elif live:
2626
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2627
    self._ClearUserShutdown(instance.name)
2628

    
2629
  def GetMigrationStatus(self, instance):
2630
    """Get the migration status
2631

2632
    @type instance: L{objects.Instance}
2633
    @param instance: the instance that is being migrated
2634
    @rtype: L{objects.MigrationStatus}
2635
    @return: the status of the current migration (one of
2636
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2637
             progress info that can be retrieved from the hypervisor
2638

2639
    """
2640
    info_command = "info migrate"
2641
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2642
      result = self._CallMonitorCommand(instance.name, info_command)
2643
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
2644
      if not match:
2645
        if not result.stdout:
2646
          logging.info("KVM: empty 'info migrate' result")
2647
        else:
2648
          logging.warning("KVM: unknown 'info migrate' result: %s",
2649
                          result.stdout)
2650
      else:
2651
        status = match.group(1)
2652
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2653
          migration_status = objects.MigrationStatus(status=status)
2654
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2655
          if match:
2656
            migration_status.transferred_ram = match.group("transferred")
2657
            migration_status.total_ram = match.group("total")
2658

    
2659
          return migration_status
2660

    
2661
        logging.warning("KVM: unknown migration status '%s'", status)
2662

    
2663
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2664

    
2665
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2666

    
2667
  def BalloonInstanceMemory(self, instance, mem):
2668
    """Balloon an instance memory to a certain value.
2669

2670
    @type instance: L{objects.Instance}
2671
    @param instance: instance to be accepted
2672
    @type mem: int
2673
    @param mem: actual memory size to use for instance runtime
2674

2675
    """
2676
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2677

    
2678
  def GetNodeInfo(self, hvparams=None):
2679
    """Return information about the node.
2680

2681
    @type hvparams: dict of strings
2682
    @param hvparams: hypervisor parameters, not used in this class
2683

2684
    @return: a dict as returned by L{BaseHypervisor.GetLinuxNodeInfo} plus
2685
        the following keys:
2686
          - hv_version: the hypervisor version in the form (major, minor,
2687
                        revision)
2688

2689
    """
2690
    result = self.GetLinuxNodeInfo()
2691
    kvmpath = constants.KVM_PATH
2692
    if hvparams is not None:
2693
      kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2694
    _, v_major, v_min, v_rev = self._GetKVMVersion(kvmpath)
2695
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2696
    return result
2697

    
2698
  @classmethod
2699
  def GetInstanceConsole(cls, instance, primary_node, node_group,
2700
                         hvparams, beparams):
2701
    """Return a command for connecting to the console of an instance.
2702

2703
    """
2704
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2705
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2706
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2707
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2708
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2709
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2710
      ndparams = node_group.FillND(primary_node)
2711
      return objects.InstanceConsole(instance=instance.name,
2712
                                     kind=constants.CONS_SSH,
2713
                                     host=primary_node.name,
2714
                                     port=ndparams.get(constants.ND_SSH_PORT),
2715
                                     user=constants.SSH_CONSOLE_USER,
2716
                                     command=cmd)
2717

    
2718
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2719
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2720
      display = instance.network_port - constants.VNC_BASE_PORT
2721
      return objects.InstanceConsole(instance=instance.name,
2722
                                     kind=constants.CONS_VNC,
2723
                                     host=vnc_bind_address,
2724
                                     port=instance.network_port,
2725
                                     display=display)
2726

    
2727
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2728
    if spice_bind:
2729
      return objects.InstanceConsole(instance=instance.name,
2730
                                     kind=constants.CONS_SPICE,
2731
                                     host=spice_bind,
2732
                                     port=instance.network_port)
2733

    
2734
    return objects.InstanceConsole(instance=instance.name,
2735
                                   kind=constants.CONS_MESSAGE,
2736
                                   message=("No serial shell for instance %s" %
2737
                                            instance.name))
2738

    
2739
  def Verify(self, hvparams=None):
2740
    """Verify the hypervisor.
2741

2742
    Check that the required binaries exist.
2743

2744
    @type hvparams: dict of strings
2745
    @param hvparams: hypervisor parameters to be verified against, not used here
2746

2747
    @return: Problem description if something is wrong, C{None} otherwise
2748

2749
    """
2750
    msgs = []
2751
    kvmpath = constants.KVM_PATH
2752
    if hvparams is not None:
2753
      kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2754
    if not os.path.exists(kvmpath):
2755
      msgs.append("The KVM binary ('%s') does not exist" % kvmpath)
2756
    if not os.path.exists(constants.SOCAT_PATH):
2757
      msgs.append("The socat binary ('%s') does not exist" %
2758
                  constants.SOCAT_PATH)
2759

    
2760
    return self._FormatVerifyResults(msgs)
2761

    
2762
  @classmethod
2763
  def CheckParameterSyntax(cls, hvparams):
2764
    """Check the given parameters for validity.
2765

2766
    @type hvparams:  dict
2767
    @param hvparams: dictionary with parameter names/value
2768
    @raise errors.HypervisorError: when a parameter is not valid
2769

2770
    """
2771
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2772

    
2773
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2774
    if kernel_path:
2775
      if not hvparams[constants.HV_ROOT_PATH]:
2776
        raise errors.HypervisorError("Need a root partition for the instance,"
2777
                                     " if a kernel is defined")
2778

    
2779
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2780
        not hvparams[constants.HV_VNC_X509]):
2781
      raise errors.HypervisorError("%s must be defined, if %s is" %
2782
                                   (constants.HV_VNC_X509,
2783
                                    constants.HV_VNC_X509_VERIFY))
2784

    
2785
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2786
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2787
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2788
      if not serial_speed or serial_speed not in valid_speeds:
2789
        raise errors.HypervisorError("Invalid serial console speed, must be"
2790
                                     " one of: %s" %
2791
                                     utils.CommaJoin(valid_speeds))
2792

    
2793
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2794
    if (boot_order == constants.HT_BO_CDROM and
2795
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2796
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2797
                                   " ISO path")
2798

    
2799
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2800
    if security_model == constants.HT_SM_USER:
2801
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2802
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2803
                                     " must be specified")
2804
    elif (security_model == constants.HT_SM_NONE or
2805
          security_model == constants.HT_SM_POOL):
2806
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2807
        raise errors.HypervisorError("Cannot have a security domain when the"
2808
                                     " security model is 'none' or 'pool'")
2809

    
2810
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2811
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2812
    if spice_bind:
2813
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2814
        # if an IP version is specified, the spice_bind parameter must be an
2815
        # IP of that family
2816
        if (netutils.IP4Address.IsValid(spice_bind) and
2817
            spice_ip_version != constants.IP4_VERSION):
2818
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2819
                                       " the specified IP version is %s" %
2820
                                       (spice_bind, spice_ip_version))
2821

    
2822
        if (netutils.IP6Address.IsValid(spice_bind) and
2823
            spice_ip_version != constants.IP6_VERSION):
2824
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2825
                                       " the specified IP version is %s" %
2826
                                       (spice_bind, spice_ip_version))
2827
    else:
2828
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2829
      # error if any of them is set without it.
2830
      for param in _SPICE_ADDITIONAL_PARAMS:
2831
        if hvparams[param]:
2832
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2833
                                       (param, constants.HV_KVM_SPICE_BIND))
2834

    
2835
  @classmethod
2836
  def ValidateParameters(cls, hvparams):
2837
    """Check the given parameters for validity.
2838

2839
    @type hvparams:  dict
2840
    @param hvparams: dictionary with parameter names/value
2841
    @raise errors.HypervisorError: when a parameter is not valid
2842

2843
    """
2844
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2845

    
2846
    kvm_path = hvparams[constants.HV_KVM_PATH]
2847

    
2848
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2849
    if security_model == constants.HT_SM_USER:
2850
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2851
      try:
2852
        pwd.getpwnam(username)
2853
      except KeyError:
2854
        raise errors.HypervisorError("Unknown security domain user %s"
2855
                                     % username)
2856
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2857
    if vnc_bind_address:
2858
      bound_to_addr = netutils.IP4Address.IsValid(vnc_bind_address)
2859
      is_interface = netutils.IsValidInterface(vnc_bind_address)
2860
      is_path = utils.IsNormAbsPath(vnc_bind_address)
2861
      if not bound_to_addr and not is_interface and not is_path:
2862
        raise errors.HypervisorError("VNC: The %s parameter must be either"
2863
                                     " a valid IP address, an interface name,"
2864
                                     " or an absolute path" %
2865
                                     constants.HV_KVM_SPICE_BIND)
2866

    
2867
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2868
    if spice_bind:
2869
      # only one of VNC and SPICE can be used currently.
2870
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2871
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2872
                                     " only one of them can be used at a"
2873
                                     " given time")
2874

    
2875
      # check that KVM supports SPICE
2876
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2877
      if not cls._SPICE_RE.search(kvmhelp):
2878
        raise errors.HypervisorError("SPICE is configured, but it is not"
2879
                                     " supported according to 'kvm --help'")
2880

    
2881
      # if spice_bind is not an IP address, it must be a valid interface
2882
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2883
                       netutils.IP6Address.IsValid(spice_bind))
2884
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2885
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2886
                                     " a valid IP address or interface name" %
2887
                                     constants.HV_KVM_SPICE_BIND)
2888

    
2889
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2890
    if machine_version:
2891
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2892
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2893
        raise errors.HypervisorError("Unsupported machine version: %s" %
2894
                                     machine_version)
2895

    
2896
  @classmethod
2897
  def PowercycleNode(cls, hvparams=None):
2898
    """KVM powercycle, just a wrapper over Linux powercycle.
2899

2900
    @type hvparams: dict of strings
2901
    @param hvparams: hypervisor params to be used on this node
2902

2903
    """
2904
    cls.LinuxPowercycle()