Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 472cc1e9

History | View | Annotate | Download (99.5 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

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

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

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

132
  """
133

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

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

    
140

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

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

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

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

    
163
  pci_reservations[free] = True
164

    
165

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

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

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

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

    
189
  return found[0]
190

    
191

    
192
def _UpgradeSerializedRuntime(serialized_runtime):
193
  """Upgrade runtime data
194

195
  Remove any deprecated fields or change the format of the data.
196
  The runtime files are not upgraded when Ganeti is upgraded, so the required
197
  modification have to be performed here.
198

199
  @type serialized_runtime: string
200
  @param serialized_runtime: raw text data read from actual runtime file
201
  @return: (cmd, nic dicts, hvparams, bdev dicts)
202
  @rtype: tuple
203

204
  """
205
  loaded_runtime = serializer.Load(serialized_runtime)
206
  kvm_cmd, serialized_nics, hvparams = loaded_runtime[:3]
207
  if len(loaded_runtime) >= 4:
208
    serialized_disks = loaded_runtime[3]
209
  else:
210
    serialized_disks = []
211

    
212
  for nic in serialized_nics:
213
    # Add a dummy uuid slot if an pre-2.8 NIC is found
214
    if "uuid" not in nic:
215
      nic["uuid"] = utils.NewUUID()
216

    
217
  return kvm_cmd, serialized_nics, hvparams, serialized_disks
218

    
219

    
220
def _AnalyzeSerializedRuntime(serialized_runtime):
221
  """Return runtime entries for a serialized runtime file
222

223
  @type serialized_runtime: string
224
  @param serialized_runtime: raw text data read from actual runtime file
225
  @return: (cmd, nics, hvparams, bdevs)
226
  @rtype: tuple
227

228
  """
229
  kvm_cmd, serialized_nics, hvparams, serialized_disks = \
230
    _UpgradeSerializedRuntime(serialized_runtime)
231
  kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
232
  kvm_disks = [(objects.Disk.FromDict(sdisk), link, uri)
233
               for sdisk, link, uri in serialized_disks]
234

    
235
  return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
236

    
237

    
238
def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
239
  """Retrieves supported TUN features from file descriptor.
240

241
  @see: L{_ProbeTapVnetHdr}
242

243
  """
244
  req = struct.pack("I", 0)
245
  try:
246
    buf = _ioctl(fd, TUNGETFEATURES, req)
247
  except EnvironmentError, err:
248
    logging.warning("ioctl(TUNGETFEATURES) failed: %s", err)
249
    return None
250
  else:
251
    (flags, ) = struct.unpack("I", buf)
252
    return flags
253

    
254

    
255
def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
256
  """Check whether to enable the IFF_VNET_HDR flag.
257

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

268
   @type fd: int
269
   @param fd: the file descriptor of /dev/net/tun
270

271
  """
272
  flags = _features_fn(fd)
273

    
274
  if flags is None:
275
    # Not supported
276
    return False
277

    
278
  result = bool(flags & IFF_VNET_HDR)
279

    
280
  if not result:
281
    logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
282

    
283
  return result
284

    
285

    
286
def _OpenTap(vnet_hdr=True):
287
  """Open a new tap device and return its file descriptor.
288

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

292
  @type vnet_hdr: boolean
293
  @param vnet_hdr: Enable the VNET Header
294
  @return: (ifname, tapfd)
295
  @rtype: tuple
296

297
  """
298
  try:
299
    tapfd = os.open("/dev/net/tun", os.O_RDWR)
300
  except EnvironmentError:
301
    raise errors.HypervisorError("Failed to open /dev/net/tun")
302

    
303
  flags = IFF_TAP | IFF_NO_PI
304

    
305
  if vnet_hdr and _ProbeTapVnetHdr(tapfd):
306
    flags |= IFF_VNET_HDR
307

    
308
  # The struct ifreq ioctl request (see netdevice(7))
309
  ifr = struct.pack("16sh", "", flags)
310

    
311
  try:
312
    res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
313
  except EnvironmentError, err:
314
    raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
315
                                 err)
316

    
317
  # Get the interface name from the ioctl
318
  ifname = struct.unpack("16sh", res)[0].strip("\x00")
319
  return (ifname, tapfd)
320

    
321

    
322
class HeadRequest(urllib2.Request):
323
  def get_method(self):
324
    return "HEAD"
325

    
326

    
327
def _CheckUrl(url):
328
  """Check if a given URL exists on the server
329

330
  """
331
  try:
332
    urllib2.urlopen(HeadRequest(url))
333
    return True
334
  except urllib2.URLError:
335
    return False
336

    
337

    
338
class QmpMessage:
339
  """QEMU Messaging Protocol (QMP) message.
340

341
  """
342
  def __init__(self, data):
343
    """Creates a new QMP message based on the passed data.
344

345
    """
346
    if not isinstance(data, dict):
347
      raise TypeError("QmpMessage must be initialized with a dict")
348

    
349
    self.data = data
350

    
351
  def __getitem__(self, field_name):
352
    """Get the value of the required field if present, or None.
353

354
    Overrides the [] operator to provide access to the message data,
355
    returning None if the required item is not in the message
356
    @return: the value of the field_name field, or None if field_name
357
             is not contained in the message
358

359
    """
360
    return self.data.get(field_name, None)
361

    
362
  def __setitem__(self, field_name, field_value):
363
    """Set the value of the required field_name to field_value.
364

365
    """
366
    self.data[field_name] = field_value
367

    
368
  def __len__(self):
369
    """Return the number of fields stored in this QmpMessage.
370

371
    """
372
    return len(self.data)
373

    
374
  def __delitem__(self, key):
375
    """Delete the specified element from the QmpMessage.
376

377
    """
378
    del(self.data[key])
379

    
380
  @staticmethod
381
  def BuildFromJsonString(json_string):
382
    """Build a QmpMessage from a JSON encoded string.
383

384
    @type json_string: str
385
    @param json_string: JSON string representing the message
386
    @rtype: L{QmpMessage}
387
    @return: a L{QmpMessage} built from json_string
388

389
    """
390
    # Parse the string
391
    data = serializer.LoadJson(json_string)
392
    return QmpMessage(data)
393

    
394
  def __str__(self):
395
    # The protocol expects the JSON object to be sent as a single line.
396
    return serializer.DumpJson(self.data)
397

    
398
  def __eq__(self, other):
399
    # When comparing two QmpMessages, we are interested in comparing
400
    # their internal representation of the message data
401
    return self.data == other.data
402

    
403

    
404
class MonitorSocket(object):
405
  _SOCKET_TIMEOUT = 5
406

    
407
  def __init__(self, monitor_filename):
408
    """Instantiates the MonitorSocket object.
409

410
    @type monitor_filename: string
411
    @param monitor_filename: the filename of the UNIX raw socket on which the
412
                             monitor (QMP or simple one) is listening
413

414
    """
415
    self.monitor_filename = monitor_filename
416
    self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
417
    # We want to fail if the server doesn't send a complete message
418
    # in a reasonable amount of time
419
    self.sock.settimeout(self._SOCKET_TIMEOUT)
420
    self._connected = False
421

    
422
  def _check_socket(self):
423
    sock_stat = None
424
    try:
425
      sock_stat = os.stat(self.monitor_filename)
426
    except EnvironmentError, err:
427
      if err.errno == errno.ENOENT:
428
        raise errors.HypervisorError("No monitor socket found")
429
      else:
430
        raise errors.HypervisorError("Error checking monitor socket: %s",
431
                                     utils.ErrnoOrStr(err))
432
    if not stat.S_ISSOCK(sock_stat.st_mode):
433
      raise errors.HypervisorError("Monitor socket is not a socket")
434

    
435
  def _check_connection(self):
436
    """Make sure that the connection is established.
437

438
    """
439
    if not self._connected:
440
      raise errors.ProgrammerError("To use a MonitorSocket you need to first"
441
                                   " invoke connect() on it")
442

    
443
  def connect(self):
444
    """Connects to the monitor.
445

446
    Connects to the UNIX socket
447

448
    @raise errors.HypervisorError: when there are communication errors
449

450
    """
451
    if self._connected:
452
      raise errors.ProgrammerError("Cannot connect twice")
453

    
454
    self._check_socket()
455

    
456
    # Check file existance/stuff
457
    try:
458
      self.sock.connect(self.monitor_filename)
459
    except EnvironmentError:
460
      raise errors.HypervisorError("Can't connect to qmp socket")
461
    self._connected = True
462

    
463
  def close(self):
464
    """Closes the socket
465

466
    It cannot be used after this call.
467

468
    """
469
    self.sock.close()
470

    
471

    
472
class QmpConnection(MonitorSocket):
473
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
474

475
  """
476
  _FIRST_MESSAGE_KEY = "QMP"
477
  _EVENT_KEY = "event"
478
  _ERROR_KEY = "error"
479
  _RETURN_KEY = RETURN_KEY = "return"
480
  _ACTUAL_KEY = ACTUAL_KEY = "actual"
481
  _ERROR_CLASS_KEY = "class"
482
  _ERROR_DESC_KEY = "desc"
483
  _EXECUTE_KEY = "execute"
484
  _ARGUMENTS_KEY = "arguments"
485
  _CAPABILITIES_COMMAND = "qmp_capabilities"
486
  _MESSAGE_END_TOKEN = "\r\n"
487

    
488
  def __init__(self, monitor_filename):
489
    super(QmpConnection, self).__init__(monitor_filename)
490
    self._buf = ""
491

    
492
  def connect(self):
493
    """Connects to the QMP monitor.
494

495
    Connects to the UNIX socket and makes sure that we can actually send and
496
    receive data to the kvm instance via QMP.
497

498
    @raise errors.HypervisorError: when there are communication errors
499
    @raise errors.ProgrammerError: when there are data serialization errors
500

501
    """
502
    super(QmpConnection, self).connect()
503
    # Check if we receive a correct greeting message from the server
504
    # (As per the QEMU Protocol Specification 0.1 - section 2.2)
505
    greeting = self._Recv()
506
    if not greeting[self._FIRST_MESSAGE_KEY]:
507
      self._connected = False
508
      raise errors.HypervisorError("kvm: QMP communication error (wrong"
509
                                   " server greeting")
510

    
511
    # Let's put the monitor in command mode using the qmp_capabilities
512
    # command, or else no command will be executable.
513
    # (As per the QEMU Protocol Specification 0.1 - section 4)
514
    self.Execute(self._CAPABILITIES_COMMAND)
515

    
516
  def _ParseMessage(self, buf):
517
    """Extract and parse a QMP message from the given buffer.
518

519
    Seeks for a QMP message in the given buf. If found, it parses it and
520
    returns it together with the rest of the characters in the buf.
521
    If no message is found, returns None and the whole buffer.
522

523
    @raise errors.ProgrammerError: when there are data serialization errors
524

525
    """
526
    message = None
527
    # Check if we got the message end token (CRLF, as per the QEMU Protocol
528
    # Specification 0.1 - Section 2.1.1)
529
    pos = buf.find(self._MESSAGE_END_TOKEN)
530
    if pos >= 0:
531
      try:
532
        message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
533
      except Exception, err:
534
        raise errors.ProgrammerError("QMP data serialization error: %s" % err)
535
      buf = buf[pos + 1:]
536

    
537
    return (message, buf)
538

    
539
  def _Recv(self):
540
    """Receives a message from QMP and decodes the received JSON object.
541

542
    @rtype: QmpMessage
543
    @return: the received message
544
    @raise errors.HypervisorError: when there are communication errors
545
    @raise errors.ProgrammerError: when there are data serialization errors
546

547
    """
548
    self._check_connection()
549

    
550
    # Check if there is already a message in the buffer
551
    (message, self._buf) = self._ParseMessage(self._buf)
552
    if message:
553
      return message
554

    
555
    recv_buffer = StringIO.StringIO(self._buf)
556
    recv_buffer.seek(len(self._buf))
557
    try:
558
      while True:
559
        data = self.sock.recv(4096)
560
        if not data:
561
          break
562
        recv_buffer.write(data)
563

    
564
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
565
        if message:
566
          return message
567

    
568
    except socket.timeout, err:
569
      raise errors.HypervisorError("Timeout while receiving a QMP message: "
570
                                   "%s" % (err))
571
    except socket.error, err:
572
      raise errors.HypervisorError("Unable to receive data from KVM using the"
573
                                   " QMP protocol: %s" % err)
574

    
575
  def _Send(self, message):
576
    """Encodes and sends a message to KVM using QMP.
577

578
    @type message: QmpMessage
579
    @param message: message to send to KVM
580
    @raise errors.HypervisorError: when there are communication errors
581
    @raise errors.ProgrammerError: when there are data serialization errors
582

583
    """
584
    self._check_connection()
585
    try:
586
      message_str = str(message)
587
    except Exception, err:
588
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
589

    
590
    try:
591
      self.sock.sendall(message_str)
592
    except socket.timeout, err:
593
      raise errors.HypervisorError("Timeout while sending a QMP message: "
594
                                   "%s (%s)" % (err.string, err.errno))
595
    except socket.error, err:
596
      raise errors.HypervisorError("Unable to send data from KVM using the"
597
                                   " QMP protocol: %s" % err)
598

    
599
  def Execute(self, command, arguments=None):
600
    """Executes a QMP command and returns the response of the server.
601

602
    @type command: str
603
    @param command: the command to execute
604
    @type arguments: dict
605
    @param arguments: dictionary of arguments to be passed to the command
606
    @rtype: dict
607
    @return: dictionary representing the received JSON object
608
    @raise errors.HypervisorError: when there are communication errors
609
    @raise errors.ProgrammerError: when there are data serialization errors
610

611
    """
612
    self._check_connection()
613
    message = QmpMessage({self._EXECUTE_KEY: command})
614
    if arguments:
615
      message[self._ARGUMENTS_KEY] = arguments
616
    self._Send(message)
617

    
618
    # Events can occur between the sending of the command and the reception
619
    # of the response, so we need to filter out messages with the event key.
620
    while True:
621
      response = self._Recv()
622
      err = response[self._ERROR_KEY]
623
      if err:
624
        raise errors.HypervisorError("kvm: error executing the %s"
625
                                     " command: %s (%s):" %
626
                                     (command,
627
                                      err[self._ERROR_DESC_KEY],
628
                                      err[self._ERROR_CLASS_KEY]))
629

    
630
      elif not response[self._EVENT_KEY]:
631
        return response
632

    
633

    
634
class KVMHypervisor(hv_base.BaseHypervisor):
635
  """KVM hypervisor interface
636

637
  """
638
  CAN_MIGRATE = True
639

    
640
  _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
641
  _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
642
  _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
643
  _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
644
  _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
645
  _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
646
  _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
647
  # KVM instances with chroot enabled are started in empty chroot directories.
648
  _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
649
  # After an instance is stopped, its chroot directory is removed.
650
  # If the chroot directory is not empty, it can't be removed.
651
  # A non-empty chroot directory indicates a possible security incident.
652
  # To support forensics, the non-empty chroot directory is quarantined in
653
  # a separate directory, called 'chroot-quarantine'.
654
  _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
655
  _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
656
           _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
657

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

    
740
  _VIRTIO = "virtio"
741
  _VIRTIO_NET_PCI = "virtio-net-pci"
742
  _VIRTIO_BLK_PCI = "virtio-blk-pci"
743

    
744
  _MIGRATION_STATUS_RE = re.compile(r"Migration\s+status:\s+(\w+)",
745
                                    re.M | re.I)
746
  _MIGRATION_PROGRESS_RE = \
747
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
748
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
749
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
750

    
751
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
752
  _MIGRATION_INFO_RETRY_DELAY = 2
753

    
754
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
755

    
756
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
757
  _CPU_INFO_CMD = "info cpus"
758
  _CONT_CMD = "cont"
759

    
760
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
761
  _CHECK_MACHINE_VERSION_RE = \
762
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
763

    
764
  _QMP_RE = re.compile(r"^-qmp\s", re.M)
765
  _SPICE_RE = re.compile(r"^-spice\s", re.M)
766
  _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
767
  _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
768
  _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
769
  _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
770
  _DISPLAY_RE = re.compile(r"^-display\s", re.M)
771
  _MACHINE_RE = re.compile(r"^-machine\s", re.M)
772
  _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
773
  _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M)
774
  # match  -drive.*boot=on|off on different lines, but in between accept only
775
  # dashes not preceeded by a new line (which would mean another option
776
  # different than -drive is starting)
777
  _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
778
  _UUID_RE = re.compile(r"^-uuid\s", re.M)
779

    
780
  _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
781
  _INFO_PCI_CMD = "info pci"
782
  _INFO_VERSION_RE = \
783
    re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
784
  _INFO_VERSION_CMD = "info version"
785

    
786
  _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
787

    
788
  ANCILLARY_FILES = [
789
    _KVM_NETWORK_SCRIPT,
790
    ]
791
  ANCILLARY_FILES_OPT = [
792
    _KVM_NETWORK_SCRIPT,
793
    ]
794

    
795
  # Supported kvm options to get output from
796
  _KVMOPT_HELP = "help"
797
  _KVMOPT_MLIST = "mlist"
798
  _KVMOPT_DEVICELIST = "devicelist"
799

    
800
  # Command to execute to get the output from kvm, and whether to
801
  # accept the output even on failure.
802
  _KVMOPTS_CMDS = {
803
    _KVMOPT_HELP: (["--help"], False),
804
    _KVMOPT_MLIST: (["-M", "?"], False),
805
    _KVMOPT_DEVICELIST: (["-device", "?"], True),
806
  }
807

    
808
  def __init__(self):
809
    hv_base.BaseHypervisor.__init__(self)
810
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
811
    # in a tmpfs filesystem or has been otherwise wiped out.
812
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
813
    utils.EnsureDirs(dirs)
814

    
815
  @classmethod
816
  def _InstancePidFile(cls, instance_name):
817
    """Returns the instance pidfile.
818

819
    """
820
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
821

    
822
  @classmethod
823
  def _InstanceUidFile(cls, instance_name):
824
    """Returns the instance uidfile.
825

826
    """
827
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
828

    
829
  @classmethod
830
  def _InstancePidInfo(cls, pid):
831
    """Check pid file for instance information.
832

833
    Check that a pid file is associated with an instance, and retrieve
834
    information from its command line.
835

836
    @type pid: string or int
837
    @param pid: process id of the instance to check
838
    @rtype: tuple
839
    @return: (instance_name, memory, vcpus)
840
    @raise errors.HypervisorError: when an instance cannot be found
841

842
    """
843
    alive = utils.IsProcessAlive(pid)
844
    if not alive:
845
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
846

    
847
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
848
    try:
849
      cmdline = utils.ReadFile(cmdline_file)
850
    except EnvironmentError, err:
851
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
852
                                   (pid, err))
853

    
854
    instance = None
855
    memory = 0
856
    vcpus = 0
857

    
858
    arg_list = cmdline.split("\x00")
859
    while arg_list:
860
      arg = arg_list.pop(0)
861
      if arg == "-name":
862
        instance = arg_list.pop(0)
863
      elif arg == "-m":
864
        memory = int(arg_list.pop(0))
865
      elif arg == "-smp":
866
        vcpus = int(arg_list.pop(0).split(",")[0])
867

    
868
    if instance is None:
869
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
870
                                   " instance" % pid)
871

    
872
    return (instance, memory, vcpus)
873

    
874
  @classmethod
875
  def _InstancePidAlive(cls, instance_name):
876
    """Returns the instance pidfile, pid, and liveness.
877

878
    @type instance_name: string
879
    @param instance_name: instance name
880
    @rtype: tuple
881
    @return: (pid file name, pid, liveness)
882

883
    """
884
    pidfile = cls._InstancePidFile(instance_name)
885
    pid = utils.ReadPidFile(pidfile)
886

    
887
    alive = False
888
    try:
889
      cmd_instance = cls._InstancePidInfo(pid)[0]
890
      alive = (cmd_instance == instance_name)
891
    except errors.HypervisorError:
892
      pass
893

    
894
    return (pidfile, pid, alive)
895

    
896
  @classmethod
897
  def _CheckDown(cls, instance_name):
898
    """Raises an error unless the given instance is down.
899

900
    """
901
    alive = cls._InstancePidAlive(instance_name)[2]
902
    if alive:
903
      raise errors.HypervisorError("Failed to start instance %s: %s" %
904
                                   (instance_name, "already running"))
905

    
906
  @classmethod
907
  def _InstanceMonitor(cls, instance_name):
908
    """Returns the instance monitor socket name
909

910
    """
911
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
912

    
913
  @classmethod
914
  def _InstanceSerial(cls, instance_name):
915
    """Returns the instance serial socket name
916

917
    """
918
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
919

    
920
  @classmethod
921
  def _InstanceQmpMonitor(cls, instance_name):
922
    """Returns the instance serial QMP socket name
923

924
    """
925
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
926

    
927
  @classmethod
928
  def _InstanceShutdownMonitor(cls, instance_name):
929
    """Returns the instance QMP output filename
930

931
    """
932
    return utils.PathJoin(cls._CTRL_DIR, "%s.shutdown" % instance_name)
933

    
934
  @staticmethod
935
  def _SocatUnixConsoleParams():
936
    """Returns the correct parameters for socat
937

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

940
    """
941
    if constants.SOCAT_USE_ESCAPE:
942
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
943
    else:
944
      return "echo=0,icanon=0"
945

    
946
  @classmethod
947
  def _InstanceKVMRuntime(cls, instance_name):
948
    """Returns the instance KVM runtime filename
949

950
    """
951
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
952

    
953
  @classmethod
954
  def _InstanceChrootDir(cls, instance_name):
955
    """Returns the name of the KVM chroot dir of the instance
956

957
    """
958
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
959

    
960
  @classmethod
961
  def _InstanceNICDir(cls, instance_name):
962
    """Returns the name of the directory holding the tap device files for a
963
    given instance.
964

965
    """
966
    return utils.PathJoin(cls._NICS_DIR, instance_name)
967

    
968
  @classmethod
969
  def _InstanceNICFile(cls, instance_name, seq):
970
    """Returns the name of the file containing the tap device for a given NIC
971

972
    """
973
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
974

    
975
  @classmethod
976
  def _InstanceKeymapFile(cls, instance_name):
977
    """Returns the name of the file containing the keymap for a given instance
978

979
    """
980
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
981

    
982
  @classmethod
983
  def _TryReadUidFile(cls, uid_file):
984
    """Try to read a uid file
985

986
    """
987
    if os.path.exists(uid_file):
988
      try:
989
        uid = int(utils.ReadOneLineFile(uid_file))
990
        return uid
991
      except EnvironmentError:
992
        logging.warning("Can't read uid file", exc_info=True)
993
      except (TypeError, ValueError):
994
        logging.warning("Can't parse uid file contents", exc_info=True)
995
    return None
996

    
997
  @classmethod
998
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
999
    """Removes an instance's rutime sockets/files/dirs.
1000

1001
    """
1002
    utils.RemoveFile(pidfile)
1003
    utils.RemoveFile(cls._InstanceMonitor(instance_name))
1004
    utils.RemoveFile(cls._InstanceSerial(instance_name))
1005
    utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
1006
    utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
1007
    utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
1008
    uid_file = cls._InstanceUidFile(instance_name)
1009
    uid = cls._TryReadUidFile(uid_file)
1010
    utils.RemoveFile(uid_file)
1011
    if uid is not None:
1012
      uidpool.ReleaseUid(uid)
1013
    try:
1014
      shutil.rmtree(cls._InstanceNICDir(instance_name))
1015
    except OSError, err:
1016
      if err.errno != errno.ENOENT:
1017
        raise
1018
    try:
1019
      chroot_dir = cls._InstanceChrootDir(instance_name)
1020
      utils.RemoveDir(chroot_dir)
1021
    except OSError, err:
1022
      if err.errno == errno.ENOTEMPTY:
1023
        # The chroot directory is expected to be empty, but it isn't.
1024
        new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
1025
                                          prefix="%s-%s-" %
1026
                                          (instance_name,
1027
                                           utils.TimestampForFilename()))
1028
        logging.warning("The chroot directory of instance %s can not be"
1029
                        " removed as it is not empty. Moving it to the"
1030
                        " quarantine instead. Please investigate the"
1031
                        " contents (%s) and clean up manually",
1032
                        instance_name, new_chroot_dir)
1033
        utils.RenameFile(chroot_dir, new_chroot_dir)
1034
      else:
1035
        raise
1036

    
1037
  @staticmethod
1038
  def _ConfigureNIC(instance, seq, nic, tap):
1039
    """Run the network configuration script for a specified NIC
1040

1041
    @param instance: instance we're acting on
1042
    @type instance: instance object
1043
    @param seq: nic sequence number
1044
    @type seq: int
1045
    @param nic: nic we're acting on
1046
    @type nic: nic object
1047
    @param tap: the host's tap interface this NIC corresponds to
1048
    @type tap: str
1049

1050
    """
1051
    env = {
1052
      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
1053
      "INSTANCE": instance.name,
1054
      "MAC": nic.mac,
1055
      "MODE": nic.nicparams[constants.NIC_MODE],
1056
      "INTERFACE": tap,
1057
      "INTERFACE_INDEX": str(seq),
1058
      "INTERFACE_UUID": nic.uuid,
1059
      "TAGS": " ".join(instance.GetTags()),
1060
    }
1061

    
1062
    if nic.ip:
1063
      env["IP"] = nic.ip
1064

    
1065
    if nic.name:
1066
      env["INTERFACE_NAME"] = nic.name
1067

    
1068
    if nic.nicparams[constants.NIC_LINK]:
1069
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
1070

    
1071
    if nic.network:
1072
      n = objects.Network.FromDict(nic.netinfo)
1073
      env.update(n.HooksDict())
1074

    
1075
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1076
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
1077

    
1078
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
1079
    if result.failed:
1080
      raise errors.HypervisorError("Failed to configure interface %s: %s;"
1081
                                   " network configuration script output: %s" %
1082
                                   (tap, result.fail_reason, result.output))
1083

    
1084
  @staticmethod
1085
  def _VerifyAffinityPackage():
1086
    if affinity is None:
1087
      raise errors.HypervisorError("affinity Python package not"
1088
                                   " found; cannot use CPU pinning under KVM")
1089

    
1090
  @staticmethod
1091
  def _BuildAffinityCpuMask(cpu_list):
1092
    """Create a CPU mask suitable for sched_setaffinity from a list of
1093
    CPUs.
1094

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

1098
    @type cpu_list: list of int
1099
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
1100
    @rtype: int
1101
    @return: a bit mask of CPU affinities
1102

1103
    """
1104
    if cpu_list == constants.CPU_PINNING_OFF:
1105
      return constants.CPU_PINNING_ALL_KVM
1106
    else:
1107
      return sum(2 ** cpu for cpu in cpu_list)
1108

    
1109
  @classmethod
1110
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
1111
    """Change CPU affinity for running VM according to given CPU mask.
1112

1113
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
1114
    @type cpu_mask: string
1115
    @param process_id: process ID of KVM process. Used to pin entire VM
1116
                       to physical CPUs.
1117
    @type process_id: int
1118
    @param thread_dict: map of virtual CPUs to KVM thread IDs
1119
    @type thread_dict: dict int:int
1120

1121
    """
1122
    # Convert the string CPU mask to a list of list of int's
1123
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
1124

    
1125
    if len(cpu_list) == 1:
1126
      all_cpu_mapping = cpu_list[0]
1127
      if all_cpu_mapping == constants.CPU_PINNING_OFF:
1128
        # If CPU pinning has 1 entry that's "all", then do nothing
1129
        pass
1130
      else:
1131
        # If CPU pinning has one non-all entry, map the entire VM to
1132
        # one set of physical CPUs
1133
        cls._VerifyAffinityPackage()
1134
        affinity.set_process_affinity_mask(
1135
          process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
1136
    else:
1137
      # The number of vCPUs mapped should match the number of vCPUs
1138
      # reported by KVM. This was already verified earlier, so
1139
      # here only as a sanity check.
1140
      assert len(thread_dict) == len(cpu_list)
1141
      cls._VerifyAffinityPackage()
1142

    
1143
      # For each vCPU, map it to the proper list of physical CPUs
1144
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1145
        affinity.set_process_affinity_mask(thread_dict[i],
1146
                                           cls._BuildAffinityCpuMask(vcpu))
1147

    
1148
  def _GetVcpuThreadIds(self, instance_name):
1149
    """Get a mapping of vCPU no. to thread IDs for the instance
1150

1151
    @type instance_name: string
1152
    @param instance_name: instance in question
1153
    @rtype: dictionary of int:int
1154
    @return: a dictionary mapping vCPU numbers to thread IDs
1155

1156
    """
1157
    result = {}
1158
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1159
    for line in output.stdout.splitlines():
1160
      match = self._CPU_INFO_RE.search(line)
1161
      if not match:
1162
        continue
1163
      grp = map(int, match.groups())
1164
      result[grp[0]] = grp[1]
1165

    
1166
    return result
1167

    
1168
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1169
    """Complete CPU pinning.
1170

1171
    @type instance_name: string
1172
    @param instance_name: name of instance
1173
    @type cpu_mask: string
1174
    @param cpu_mask: CPU pinning mask as entered by user
1175

1176
    """
1177
    # Get KVM process ID, to be used if need to pin entire VM
1178
    _, pid, _ = self._InstancePidAlive(instance_name)
1179
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1180
    thread_dict = self._GetVcpuThreadIds(instance_name)
1181
    # Run CPU pinning, based on configured mask
1182
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1183

    
1184
  def ListInstances(self, hvparams=None):
1185
    """Get the list of running instances.
1186

1187
    We can do this by listing our live instances directory and
1188
    checking whether the associated kvm process is still alive.
1189

1190
    """
1191
    result = []
1192
    for name in os.listdir(self._PIDS_DIR):
1193
      if self._InstancePidAlive(name)[2] or self._IsUserShutdown(name):
1194
        result.append(name)
1195
    return result
1196

    
1197
  @classmethod
1198
  def _IsUserShutdown(cls, instance_name):
1199
    return os.path.exists(cls._InstanceShutdownMonitor(instance_name))
1200

    
1201
  @classmethod
1202
  def _ClearUserShutdown(cls, instance_name):
1203
    utils.RemoveFile(cls._InstanceShutdownMonitor(instance_name))
1204

    
1205
  def GetInstanceInfo(self, instance_name, hvparams=None):
1206
    """Get instance properties.
1207

1208
    @type instance_name: string
1209
    @param instance_name: the instance name
1210
    @type hvparams: dict of strings
1211
    @param hvparams: hvparams to be used with this instance
1212
    @rtype: tuple of strings
1213
    @return: (name, id, memory, vcpus, stat, times)
1214

1215
    """
1216
    _, pid, alive = self._InstancePidAlive(instance_name)
1217
    if not alive:
1218
      if self._IsUserShutdown(instance_name):
1219
        return (instance_name, -1, 0, 0, hv_base.HvInstanceState.SHUTDOWN, 0)
1220
      else:
1221
        return None
1222

    
1223
    _, memory, vcpus = self._InstancePidInfo(pid)
1224
    istat = hv_base.HvInstanceState.RUNNING
1225
    times = 0
1226

    
1227
    try:
1228
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1229
      qmp.connect()
1230
      vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1231
      # Will fail if ballooning is not enabled, but we can then just resort to
1232
      # the value above.
1233
      mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1234
      memory = mem_bytes / 1048576
1235
    except errors.HypervisorError:
1236
      pass
1237

    
1238
    return (instance_name, pid, memory, vcpus, istat, times)
1239

    
1240
  def GetAllInstancesInfo(self, hvparams=None):
1241
    """Get properties of all instances.
1242

1243
    @type hvparams: dict of strings
1244
    @param hvparams: hypervisor parameter
1245
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1246

1247
    """
1248
    data = []
1249
    for name in os.listdir(self._PIDS_DIR):
1250
      try:
1251
        info = self.GetInstanceInfo(name)
1252
      except errors.HypervisorError:
1253
        # Ignore exceptions due to instances being shut down
1254
        continue
1255
      if info:
1256
        data.append(info)
1257
    return data
1258

    
1259
  def _GenerateKVMBlockDevicesOptions(self, instance, kvm_disks,
1260
                                      kvmhelp, devlist):
1261
    """Generate KVM options regarding instance's block devices.
1262

1263
    @type instance: L{objects.Instance}
1264
    @param instance: the instance object
1265
    @type kvm_disks: list of tuples
1266
    @param kvm_disks: list of tuples [(disk, link_name, uri)..]
1267
    @type kvmhelp: string
1268
    @param kvmhelp: output of kvm --help
1269
    @type devlist: string
1270
    @param devlist: output of kvm -device ?
1271
    @rtype: list
1272
    @return: list of command line options eventually used by kvm executable
1273

1274
    """
1275
    hvp = instance.hvparams
1276
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1277
    if kernel_path:
1278
      boot_disk = False
1279
    else:
1280
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1281

    
1282
    # whether this is an older KVM version that uses the boot=on flag
1283
    # on devices
1284
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1285

    
1286
    dev_opts = []
1287
    device_driver = None
1288
    disk_type = hvp[constants.HV_DISK_TYPE]
1289
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
1290
      if_val = ",if=%s" % self._VIRTIO
1291
      try:
1292
        if self._VIRTIO_BLK_RE.search(devlist):
1293
          if_val = ",if=none"
1294
          # will be passed in -device option as driver
1295
          device_driver = self._VIRTIO_BLK_PCI
1296
      except errors.HypervisorError, _:
1297
        pass
1298
    else:
1299
      if_val = ",if=%s" % disk_type
1300
    # Cache mode
1301
    disk_cache = hvp[constants.HV_DISK_CACHE]
1302
    if instance.disk_template in constants.DTS_EXT_MIRROR:
1303
      if disk_cache != "none":
1304
        # TODO: make this a hard error, instead of a silent overwrite
1305
        logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1306
                        " to prevent shared storage corruption on migration",
1307
                        disk_cache)
1308
      cache_val = ",cache=none"
1309
    elif disk_cache != constants.HT_CACHE_DEFAULT:
1310
      cache_val = ",cache=%s" % disk_cache
1311
    else:
1312
      cache_val = ""
1313
    for cfdev, link_name, uri in kvm_disks:
1314
      if cfdev.mode != constants.DISK_RDWR:
1315
        raise errors.HypervisorError("Instance has read-only disks which"
1316
                                     " are not supported by KVM")
1317
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
1318
      boot_val = ""
1319
      if boot_disk:
1320
        dev_opts.extend(["-boot", "c"])
1321
        boot_disk = False
1322
        if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1323
          boot_val = ",boot=on"
1324

    
1325
      access_mode = cfdev.params.get(constants.LDP_ACCESS,
1326
                                     constants.DISK_KERNELSPACE)
1327
      if (uri and access_mode == constants.DISK_USERSPACE):
1328
        drive_uri = uri
1329
      else:
1330
        drive_uri = link_name
1331

    
1332
      drive_val = "file=%s,format=raw%s%s%s" % \
1333
                  (drive_uri, if_val, boot_val, cache_val)
1334

    
1335
      if device_driver:
1336
        # kvm_disks are the 4th entry of runtime file that did not exist in
1337
        # the past. That means that cfdev should always have pci slot and
1338
        # _GenerateDeviceKVMId() will not raise a exception.
1339
        kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_DISK, cfdev)
1340
        drive_val += (",id=%s" % kvm_devid)
1341
        drive_val += (",bus=0,unit=%d" % cfdev.pci)
1342
        dev_val = ("%s,drive=%s,id=%s" %
1343
                   (device_driver, kvm_devid, kvm_devid))
1344
        dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci)
1345
        dev_opts.extend(["-device", dev_val])
1346

    
1347
      dev_opts.extend(["-drive", drive_val])
1348

    
1349
    return dev_opts
1350

    
1351
  @staticmethod
1352
  def _CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image, cdrom_boot,
1353
                   needs_boot_flag):
1354
    """Extends L{kvm_cmd} with the '-drive' option for a cdrom, and
1355
    optionally the '-boot' option.
1356

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

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

1361
    Example: -drive file=http://hostname.com/cdrom.iso,media=cdrom
1362

1363
    @type kvm_cmd: string
1364
    @param kvm_cmd: KVM command line
1365

1366
    @type cdrom_disk_type:
1367
    @param cdrom_disk_type:
1368

1369
    @type cdrom_image:
1370
    @param cdrom_image:
1371

1372
    @type cdrom_boot:
1373
    @param cdrom_boot:
1374

1375
    @type needs_boot_flag:
1376
    @param needs_boot_flag:
1377

1378
    """
1379
    # Check that the ISO image is accessible
1380
    # See https://bugs.launchpad.net/qemu/+bug/597575
1381
    if utils.IsUrl(cdrom_image) and not _CheckUrl(cdrom_image):
1382
      raise errors.HypervisorError("Cdrom ISO image '%s' is not accessible" %
1383
                                   cdrom_image)
1384

    
1385
    # set cdrom 'media' and 'format', if needed
1386
    if utils.IsUrl(cdrom_image):
1387
      options = ",media=cdrom"
1388
    else:
1389
      options = ",media=cdrom,format=raw"
1390

    
1391
    # set cdrom 'if' type
1392
    if cdrom_boot:
1393
      if_val = ",if=" + constants.HT_DISK_IDE
1394
    elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1395
      if_val = ",if=virtio"
1396
    else:
1397
      if_val = ",if=" + cdrom_disk_type
1398

    
1399
    # set boot flag, if needed
1400
    boot_val = ""
1401
    if cdrom_boot:
1402
      kvm_cmd.extend(["-boot", "d"])
1403

    
1404
      # whether this is an older KVM version that requires the 'boot=on' flag
1405
      # on devices
1406
      if needs_boot_flag:
1407
        boot_val = ",boot=on"
1408

    
1409
    # build '-drive' option
1410
    drive_val = "file=%s%s%s%s" % (cdrom_image, options, if_val, boot_val)
1411
    kvm_cmd.extend(["-drive", drive_val])
1412

    
1413
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1414
                          kvmhelp):
1415
    """Generate KVM information to start an instance.
1416

1417
    @type kvmhelp: string
1418
    @param kvmhelp: output of kvm --help
1419
    @attention: this function must not have any side-effects; for
1420
        example, it must not write to the filesystem, or read values
1421
        from the current system the are expected to differ between
1422
        nodes, since it is only run once at instance startup;
1423
        actions/kvm arguments that can vary between systems should be
1424
        done in L{_ExecuteKVMRuntime}
1425

1426
    """
1427
    # pylint: disable=R0912,R0914,R0915
1428
    hvp = instance.hvparams
1429
    self.ValidateParameters(hvp)
1430

    
1431
    pidfile = self._InstancePidFile(instance.name)
1432
    kvm = hvp[constants.HV_KVM_PATH]
1433
    kvm_cmd = [kvm]
1434
    # used just by the vnc server, if enabled
1435
    kvm_cmd.extend(["-name", instance.name])
1436
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1437

    
1438
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1439
    if hvp[constants.HV_CPU_CORES]:
1440
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1441
    if hvp[constants.HV_CPU_THREADS]:
1442
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1443
    if hvp[constants.HV_CPU_SOCKETS]:
1444
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1445

    
1446
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1447

    
1448
    kvm_cmd.extend(["-pidfile", pidfile])
1449
    kvm_cmd.extend(["-balloon", "virtio"])
1450
    kvm_cmd.extend(["-daemonize"])
1451
    if not instance.hvparams[constants.HV_ACPI]:
1452
      kvm_cmd.extend(["-no-acpi"])
1453
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1454
        constants.INSTANCE_REBOOT_EXIT:
1455
      kvm_cmd.extend(["-no-reboot"])
1456

    
1457
    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1458
    if not mversion:
1459
      mversion = self._GetDefaultMachineVersion(kvm)
1460
    if self._MACHINE_RE.search(kvmhelp):
1461
      # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1462
      # extra hypervisor parameters. We should also investigate whether and how
1463
      # shadow_mem should be considered for the resource model.
1464
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1465
        specprop = ",accel=kvm"
1466
      else:
1467
        specprop = ""
1468
      machinespec = "%s%s" % (mversion, specprop)
1469
      kvm_cmd.extend(["-machine", machinespec])
1470
    else:
1471
      kvm_cmd.extend(["-M", mversion])
1472
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1473
          self._ENABLE_KVM_RE.search(kvmhelp)):
1474
        kvm_cmd.extend(["-enable-kvm"])
1475
      elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1476
            self._DISABLE_KVM_RE.search(kvmhelp)):
1477
        kvm_cmd.extend(["-disable-kvm"])
1478

    
1479
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1480
    if kernel_path:
1481
      boot_cdrom = boot_floppy = boot_network = False
1482
    else:
1483
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1484
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1485
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1486

    
1487
    if startup_paused:
1488
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1489

    
1490
    if boot_network:
1491
      kvm_cmd.extend(["-boot", "n"])
1492

    
1493
    disk_type = hvp[constants.HV_DISK_TYPE]
1494

    
1495
    # Now we can specify a different device type for CDROM devices.
1496
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1497
    if not cdrom_disk_type:
1498
      cdrom_disk_type = disk_type
1499

    
1500
    cdrom_image1 = hvp[constants.HV_CDROM_IMAGE_PATH]
1501
    if cdrom_image1:
1502
      needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1503
      self._CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image1, boot_cdrom,
1504
                        needs_boot_flag)
1505

    
1506
    cdrom_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1507
    if cdrom_image2:
1508
      self._CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image2, False, False)
1509

    
1510
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1511
    if floppy_image:
1512
      options = ",format=raw,media=disk"
1513
      if boot_floppy:
1514
        kvm_cmd.extend(["-boot", "a"])
1515
        options = "%s,boot=on" % options
1516
      if_val = ",if=floppy"
1517
      options = "%s%s" % (options, if_val)
1518
      drive_val = "file=%s%s" % (floppy_image, options)
1519
      kvm_cmd.extend(["-drive", drive_val])
1520

    
1521
    if kernel_path:
1522
      kvm_cmd.extend(["-kernel", kernel_path])
1523
      initrd_path = hvp[constants.HV_INITRD_PATH]
1524
      if initrd_path:
1525
        kvm_cmd.extend(["-initrd", initrd_path])
1526
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1527
                     hvp[constants.HV_KERNEL_ARGS]]
1528
      if hvp[constants.HV_SERIAL_CONSOLE]:
1529
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1530
        root_append.append("console=ttyS0,%s" % serial_speed)
1531
      kvm_cmd.extend(["-append", " ".join(root_append)])
1532

    
1533
    mem_path = hvp[constants.HV_MEM_PATH]
1534
    if mem_path:
1535
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1536

    
1537
    monitor_dev = ("unix:%s,server,nowait" %
1538
                   self._InstanceMonitor(instance.name))
1539
    kvm_cmd.extend(["-monitor", monitor_dev])
1540
    if hvp[constants.HV_SERIAL_CONSOLE]:
1541
      serial_dev = ("unix:%s,server,nowait" %
1542
                    self._InstanceSerial(instance.name))
1543
      kvm_cmd.extend(["-serial", serial_dev])
1544
    else:
1545
      kvm_cmd.extend(["-serial", "none"])
1546

    
1547
    mouse_type = hvp[constants.HV_USB_MOUSE]
1548
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1549
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1550
    spice_ip_version = None
1551

    
1552
    kvm_cmd.extend(["-usb"])
1553

    
1554
    if mouse_type:
1555
      kvm_cmd.extend(["-usbdevice", mouse_type])
1556
    elif vnc_bind_address:
1557
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1558

    
1559
    if vnc_bind_address:
1560
      if netutils.IsValidInterface(vnc_bind_address):
1561
        if_addresses = netutils.GetInterfaceIpAddresses(vnc_bind_address)
1562
        if_ip4_addresses = if_addresses[constants.IP4_VERSION]
1563
        if len(if_ip4_addresses) < 1:
1564
          logging.error("Could not determine IPv4 address of interface %s",
1565
                        vnc_bind_address)
1566
        else:
1567
          vnc_bind_address = if_ip4_addresses[0]
1568
      if netutils.IP4Address.IsValid(vnc_bind_address):
1569
        if instance.network_port > constants.VNC_BASE_PORT:
1570
          display = instance.network_port - constants.VNC_BASE_PORT
1571
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1572
            vnc_arg = ":%d" % (display)
1573
          else:
1574
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1575
        else:
1576
          logging.error("Network port is not a valid VNC display (%d < %d),"
1577
                        " not starting VNC",
1578
                        instance.network_port, constants.VNC_BASE_PORT)
1579
          vnc_arg = "none"
1580

    
1581
        # Only allow tls and other option when not binding to a file, for now.
1582
        # kvm/qemu gets confused otherwise about the filename to use.
1583
        vnc_append = ""
1584
        if hvp[constants.HV_VNC_TLS]:
1585
          vnc_append = "%s,tls" % vnc_append
1586
          if hvp[constants.HV_VNC_X509_VERIFY]:
1587
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1588
                                               hvp[constants.HV_VNC_X509])
1589
          elif hvp[constants.HV_VNC_X509]:
1590
            vnc_append = "%s,x509=%s" % (vnc_append,
1591
                                         hvp[constants.HV_VNC_X509])
1592
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1593
          vnc_append = "%s,password" % vnc_append
1594

    
1595
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1596

    
1597
      else:
1598
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1599

    
1600
      kvm_cmd.extend(["-vnc", vnc_arg])
1601
    elif spice_bind:
1602
      # FIXME: this is wrong here; the iface ip address differs
1603
      # between systems, so it should be done in _ExecuteKVMRuntime
1604
      if netutils.IsValidInterface(spice_bind):
1605
        # The user specified a network interface, we have to figure out the IP
1606
        # address.
1607
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1608
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1609

    
1610
        # if the user specified an IP version and the interface does not
1611
        # have that kind of IP addresses, throw an exception
1612
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1613
          if not addresses[spice_ip_version]:
1614
            raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1615
                                         " for %s" % (spice_ip_version,
1616
                                                      spice_bind))
1617

    
1618
        # the user did not specify an IP version, we have to figure it out
1619
        elif (addresses[constants.IP4_VERSION] and
1620
              addresses[constants.IP6_VERSION]):
1621
          # we have both ipv4 and ipv6, let's use the cluster default IP
1622
          # version
1623
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1624
          spice_ip_version = \
1625
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1626
        elif addresses[constants.IP4_VERSION]:
1627
          spice_ip_version = constants.IP4_VERSION
1628
        elif addresses[constants.IP6_VERSION]:
1629
          spice_ip_version = constants.IP6_VERSION
1630
        else:
1631
          raise errors.HypervisorError("SPICE: Unable to get an IP address"
1632
                                       " for %s" % (spice_bind))
1633

    
1634
        spice_address = addresses[spice_ip_version][0]
1635

    
1636
      else:
1637
        # spice_bind is known to be a valid IP address, because
1638
        # ValidateParameters checked it.
1639
        spice_address = spice_bind
1640

    
1641
      spice_arg = "addr=%s" % spice_address
1642
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1643
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1644
                     (spice_arg, instance.network_port,
1645
                      pathutils.SPICE_CACERT_FILE))
1646
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1647
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1648
                      pathutils.SPICE_CERT_FILE))
1649
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1650
        if tls_ciphers:
1651
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1652
      else:
1653
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1654

    
1655
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1656
        spice_arg = "%s,disable-ticketing" % spice_arg
1657

    
1658
      if spice_ip_version:
1659
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1660

    
1661
      # Image compression options
1662
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1663
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1664
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1665
      if img_lossless:
1666
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1667
      if img_jpeg:
1668
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1669
      if img_zlib_glz:
1670
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1671

    
1672
      # Video stream detection
1673
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1674
      if video_streaming:
1675
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1676

    
1677
      # Audio compression, by default in qemu-kvm it is on
1678
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1679
        spice_arg = "%s,playback-compression=off" % spice_arg
1680
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1681
        spice_arg = "%s,agent-mouse=off" % spice_arg
1682
      else:
1683
        # Enable the spice agent communication channel between the host and the
1684
        # agent.
1685
        kvm_cmd.extend(["-device", "virtio-serial-pci"])
1686
        kvm_cmd.extend([
1687
          "-device",
1688
          "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1689
          ])
1690
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1691

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

    
1695
    else:
1696
      # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1697
      # also works in earlier versions though (tested with 1.1 and 1.3)
1698
      if self._DISPLAY_RE.search(kvmhelp):
1699
        kvm_cmd.extend(["-display", "none"])
1700
      else:
1701
        kvm_cmd.extend(["-nographic"])
1702

    
1703
    if hvp[constants.HV_USE_LOCALTIME]:
1704
      kvm_cmd.extend(["-localtime"])
1705

    
1706
    if hvp[constants.HV_KVM_USE_CHROOT]:
1707
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1708

    
1709
    # Add qemu-KVM -cpu param
1710
    if hvp[constants.HV_CPU_TYPE]:
1711
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1712

    
1713
    # As requested by music lovers
1714
    if hvp[constants.HV_SOUNDHW]:
1715
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1716

    
1717
    # Pass a -vga option if requested, or if spice is used, for backwards
1718
    # compatibility.
1719
    if hvp[constants.HV_VGA]:
1720
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1721
    elif spice_bind:
1722
      kvm_cmd.extend(["-vga", "qxl"])
1723

    
1724
    # Various types of usb devices, comma separated
1725
    if hvp[constants.HV_USB_DEVICES]:
1726
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1727
        kvm_cmd.extend(["-usbdevice", dev])
1728

    
1729
    # Set system UUID to instance UUID
1730
    if self._UUID_RE.search(kvmhelp):
1731
      kvm_cmd.extend(["-uuid", instance.uuid])
1732

    
1733
    if hvp[constants.HV_KVM_EXTRA]:
1734
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1735

    
1736
    pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1737
    kvm_disks = []
1738
    for disk, link_name, uri in block_devices:
1739
      _UpdatePCISlots(disk, pci_reservations)
1740
      kvm_disks.append((disk, link_name, uri))
1741

    
1742
    kvm_nics = []
1743
    for nic in instance.nics:
1744
      _UpdatePCISlots(nic, pci_reservations)
1745
      kvm_nics.append(nic)
1746

    
1747
    hvparams = hvp
1748

    
1749
    return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1750

    
1751
  def _WriteKVMRuntime(self, instance_name, data):
1752
    """Write an instance's KVM runtime
1753

1754
    """
1755
    try:
1756
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1757
                      data=data)
1758
    except EnvironmentError, err:
1759
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1760

    
1761
  def _ReadKVMRuntime(self, instance_name):
1762
    """Read an instance's KVM runtime
1763

1764
    """
1765
    try:
1766
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1767
    except EnvironmentError, err:
1768
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1769
    return file_content
1770

    
1771
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1772
    """Save an instance's KVM runtime
1773

1774
    """
1775
    kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1776

    
1777
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1778
    serialized_disks = [(blk.ToDict(), link, uri)
1779
                        for blk, link, uri in kvm_disks]
1780
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1781
                                      serialized_disks))
1782

    
1783
    self._WriteKVMRuntime(instance.name, serialized_form)
1784

    
1785
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1786
    """Load an instance's KVM runtime
1787

1788
    """
1789
    if not serialized_runtime:
1790
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1791

    
1792
    return _AnalyzeSerializedRuntime(serialized_runtime)
1793

    
1794
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1795
    """Run the KVM cmd and check for errors
1796

1797
    @type name: string
1798
    @param name: instance name
1799
    @type kvm_cmd: list of strings
1800
    @param kvm_cmd: runcmd input for kvm
1801
    @type tap_fds: list of int
1802
    @param tap_fds: fds of tap devices opened by Ganeti
1803

1804
    """
1805
    try:
1806
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1807
    finally:
1808
      for fd in tap_fds:
1809
        utils_wrapper.CloseFdNoError(fd)
1810

    
1811
    if result.failed:
1812
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1813
                                   (name, result.fail_reason, result.output))
1814
    if not self._InstancePidAlive(name)[2]:
1815
      raise errors.HypervisorError("Failed to start instance %s" % name)
1816

    
1817
  # too many local variables
1818
  # pylint: disable=R0914
1819
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1820
    """Execute a KVM cmd, after completing it with some last minute data.
1821

1822
    @type incoming: tuple of strings
1823
    @param incoming: (target_host_ip, port)
1824
    @type kvmhelp: string
1825
    @param kvmhelp: output of kvm --help
1826

1827
    """
1828
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1829
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1830
    #    have changed since the instance started; only use them if the change
1831
    #    won't affect the inside of the instance (which hasn't been rebooted).
1832
    #  - up_hvp contains the parameters as they were when the instance was
1833
    #    started, plus any new parameter which has been added between ganeti
1834
    #    versions: it is paramount that those default to a value which won't
1835
    #    affect the inside of the instance as well.
1836
    conf_hvp = instance.hvparams
1837
    name = instance.name
1838
    self._CheckDown(name)
1839

    
1840
    self._ClearUserShutdown(instance.name)
1841
    self._StartKvmd(instance.hvparams)
1842

    
1843
    temp_files = []
1844

    
1845
    kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1846
    # the first element of kvm_cmd is always the path to the kvm binary
1847
    kvm_path = kvm_cmd[0]
1848
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1849

    
1850
    # We know it's safe to run as a different user upon migration, so we'll use
1851
    # the latest conf, from conf_hvp.
1852
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1853
    if security_model == constants.HT_SM_USER:
1854
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1855

    
1856
    keymap = conf_hvp[constants.HV_KEYMAP]
1857
    if keymap:
1858
      keymap_path = self._InstanceKeymapFile(name)
1859
      # If a keymap file is specified, KVM won't use its internal defaults. By
1860
      # first including the "en-us" layout, an error on loading the actual
1861
      # layout (e.g. because it can't be found) won't lead to a non-functional
1862
      # keyboard. A keyboard with incorrect keys is still better than none.
1863
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1864
      kvm_cmd.extend(["-k", keymap_path])
1865

    
1866
    # We have reasons to believe changing something like the nic driver/type
1867
    # upon migration won't exactly fly with the instance kernel, so for nic
1868
    # related parameters we'll use up_hvp
1869
    tapfds = []
1870
    taps = []
1871
    devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1872
    if not kvm_nics:
1873
      kvm_cmd.extend(["-net", "none"])
1874
    else:
1875
      vnet_hdr = False
1876
      tap_extra = ""
1877
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1878
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1879
        nic_model = self._VIRTIO
1880
        try:
1881
          if self._VIRTIO_NET_RE.search(devlist):
1882
            nic_model = self._VIRTIO_NET_PCI
1883
            vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1884
        except errors.HypervisorError, _:
1885
          # Older versions of kvm don't support DEVICE_LIST, but they don't
1886
          # have new virtio syntax either.
1887
          pass
1888

    
1889
        if up_hvp[constants.HV_VHOST_NET]:
1890
          # check for vhost_net support
1891
          if self._VHOST_RE.search(kvmhelp):
1892
            tap_extra = ",vhost=on"
1893
          else:
1894
            raise errors.HypervisorError("vhost_net is configured"
1895
                                         " but it is not available")
1896
      else:
1897
        nic_model = nic_type
1898

    
1899
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1900

    
1901
      for nic_seq, nic in enumerate(kvm_nics):
1902
        tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1903
        tapfds.append(tapfd)
1904
        taps.append(tapname)
1905
        if kvm_supports_netdev:
1906
          nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1907
          try:
1908
            # kvm_nics already exist in old runtime files and thus there might
1909
            # be some entries without pci slot (therefore try: except:)
1910
            kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1911
            netdev = kvm_devid
1912
            nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1913
          except errors.HotplugError:
1914
            netdev = "netdev%d" % nic_seq
1915
          nic_val += (",netdev=%s" % netdev)
1916
          tap_val = ("type=tap,id=%s,fd=%d%s" %
1917
                     (netdev, tapfd, tap_extra))
1918
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1919
        else:
1920
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1921
                                                         nic.mac, nic_model)
1922
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1923
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1924

    
1925
    if incoming:
1926
      target, port = incoming
1927
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1928

    
1929
    # Changing the vnc password doesn't bother the guest that much. At most it
1930
    # will surprise people who connect to it. Whether positively or negatively
1931
    # it's debatable.
1932
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1933
    vnc_pwd = None
1934
    if vnc_pwd_file:
1935
      try:
1936
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1937
      except EnvironmentError, err:
1938
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1939
                                     % (vnc_pwd_file, err))
1940

    
1941
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1942
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1943
                         constants.SECURE_DIR_MODE)])
1944

    
1945
    # Automatically enable QMP if version is >= 0.14
1946
    if self._QMP_RE.search(kvmhelp):
1947
      logging.debug("Enabling QMP")
1948
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1949
                      self._InstanceQmpMonitor(instance.name)])
1950

    
1951
    # Configure the network now for starting instances and bridged interfaces,
1952
    # during FinalizeMigration for incoming instances' routed interfaces
1953
    for nic_seq, nic in enumerate(kvm_nics):
1954
      if (incoming and
1955
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1956
        continue
1957
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1958

    
1959
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1960
                                                     kvm_disks,
1961
                                                     kvmhelp,
1962
                                                     devlist)
1963
    kvm_cmd.extend(bdev_opts)
1964
    # CPU affinity requires kvm to start paused, so we set this flag if the
1965
    # instance is not already paused and if we are not going to accept a
1966
    # migrating instance. In the latter case, pausing is not needed.
1967
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1968
    if start_kvm_paused:
1969
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1970

    
1971
    # Note: CPU pinning is using up_hvp since changes take effect
1972
    # during instance startup anyway, and to avoid problems when soft
1973
    # rebooting the instance.
1974
    cpu_pinning = False
1975
    if up_hvp.get(constants.HV_CPU_MASK, None):
1976
      cpu_pinning = True
1977

    
1978
    if security_model == constants.HT_SM_POOL:
1979
      ss = ssconf.SimpleStore()
1980
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1981
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1982
      uid = uidpool.RequestUnusedUid(all_uids)
1983
      try:
1984
        username = pwd.getpwuid(uid.GetUid()).pw_name
1985
        kvm_cmd.extend(["-runas", username])
1986
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1987
      except:
1988
        uidpool.ReleaseUid(uid)
1989
        raise
1990
      else:
1991
        uid.Unlock()
1992
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1993
    else:
1994
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1995

    
1996
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1997
                     constants.RUN_DIRS_MODE)])
1998
    for nic_seq, tap in enumerate(taps):
1999
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
2000
                      data=tap)
2001

    
2002
    if vnc_pwd:
2003
      change_cmd = "change vnc password %s" % vnc_pwd
2004
      self._CallMonitorCommand(instance.name, change_cmd)
2005

    
2006
    # Setting SPICE password. We are not vulnerable to malicious passwordless
2007
    # connection attempts because SPICE by default does not allow connections
2008
    # if neither a password nor the "disable_ticketing" options are specified.
2009
    # As soon as we send the password via QMP, that password is a valid ticket
2010
    # for connection.
2011
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
2012
    if spice_password_file:
2013
      spice_pwd = ""
2014
      try:
2015
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
2016
      except EnvironmentError, err:
2017
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
2018
                                     % (spice_password_file, err))
2019

    
2020
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
2021
      qmp.connect()
2022
      arguments = {
2023
          "protocol": "spice",
2024
          "password": spice_pwd,
2025
      }
2026
      qmp.Execute("set_password", arguments)
2027

    
2028
    for filename in temp_files:
2029
      utils.RemoveFile(filename)
2030

    
2031
    # If requested, set CPU affinity and resume instance execution
2032
    if cpu_pinning:
2033
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
2034

    
2035
    start_memory = self._InstanceStartupMemory(instance)
2036
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
2037
      self.BalloonInstanceMemory(instance, start_memory)
2038

    
2039
    if start_kvm_paused:
2040
      # To control CPU pinning, ballooning, and vnc/spice passwords
2041
      # the VM was started in a frozen state. If freezing was not
2042
      # explicitly requested resume the vm status.
2043
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2044

    
2045
  @staticmethod
2046
  def _StartKvmd(hvparams):
2047
    """Ensure that the Kvm daemon is running.
2048

2049
    """
2050
    if hvparams is None \
2051
          or not hvparams[constants.HV_KVM_USER_SHUTDOWN] \
2052
          or utils.IsDaemonAlive(constants.KVMD):
2053
      return
2054

    
2055
    result = utils.RunCmd(constants.KVMD)
2056

    
2057
    if result.failed:
2058
      raise errors.HypervisorError("Failed to start KVM daemon")
2059

    
2060
  def StartInstance(self, instance, block_devices, startup_paused):
2061
    """Start an instance.
2062

2063
    """
2064
    self._CheckDown(instance.name)
2065
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2066
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2067
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
2068
                                           startup_paused, kvmhelp)
2069
    self._SaveKVMRuntime(instance, kvm_runtime)
2070
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2071

    
2072
  @classmethod
2073
  def _CallMonitorCommand(cls, instance_name, command):
2074
    """Invoke a command on the instance monitor.
2075

2076
    """
2077
    # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
2078
    # version. The monitor protocol is designed for human consumption, whereas
2079
    # QMP is made for programmatic usage. In the worst case QMP can also
2080
    # execute monitor commands. As it is, all calls to socat take at least
2081
    # 500ms and likely more: socat can't detect the end of the reply and waits
2082
    # for 500ms of no data received before exiting (500 ms is the default for
2083
    # the "-t" parameter).
2084
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
2085
             (utils.ShellQuote(command),
2086
              constants.SOCAT_PATH,
2087
              utils.ShellQuote(cls._InstanceMonitor(instance_name))))
2088
    result = utils.RunCmd(socat)
2089
    if result.failed:
2090
      msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
2091
             " output: %s" %
2092
             (command, instance_name, result.fail_reason, result.output))
2093
      raise errors.HypervisorError(msg)
2094

    
2095
    return result
2096

    
2097
  def _GetFreePCISlot(self, instance, dev):
2098
    """Get the first available pci slot of a runnung instance.
2099

2100
    """
2101
    slots = bitarray(32)
2102
    slots.setall(False) # pylint: disable=E1101
2103
    output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
2104
    for line in output.stdout.splitlines():
2105
      match = self._INFO_PCI_RE.search(line)
2106
      if match:
2107
        slot = int(match.group(1))
2108
        slots[slot] = True
2109

    
2110
    [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
2111
    if not free:
2112
      raise errors.HypervisorError("All PCI slots occupied")
2113

    
2114
    dev.pci = int(free)
2115

    
2116
  def VerifyHotplugSupport(self, instance, action, dev_type):
2117
    """Verifies that hotplug is supported.
2118

2119
    Hotplug is *not* supported in case of:
2120
     - security models and chroot (disk hotplug)
2121
     - fdsend module is missing (nic hot-add)
2122

2123
    @raise errors.HypervisorError: in one of the previous cases
2124

2125
    """
2126
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2127
      hvp = instance.hvparams
2128
      security_model = hvp[constants.HV_SECURITY_MODEL]
2129
      use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
2130
      if use_chroot:
2131
        raise errors.HotplugError("Disk hotplug is not supported"
2132
                                  " in case of chroot.")
2133
      if security_model != constants.HT_SM_NONE:
2134
        raise errors.HotplugError("Disk Hotplug is not supported in case"
2135
                                  " security models are used.")
2136

    
2137
    if (dev_type == constants.HOTPLUG_TARGET_NIC and
2138
        action == constants.HOTPLUG_ACTION_ADD and not fdsend):
2139
      raise errors.HotplugError("Cannot hot-add NIC."
2140
                                " fdsend python module is missing.")
2141

    
2142
  def HotplugSupported(self, instance):
2143
    """Checks if hotplug is generally supported.
2144

2145
    Hotplug is *not* supported in case of:
2146
     - qemu versions < 1.0
2147
     - for stopped instances
2148

2149
    @raise errors.HypervisorError: in one of the previous cases
2150

2151
    """
2152
    try:
2153
      output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2154
    except errors.HypervisorError:
2155
      raise errors.HotplugError("Instance is probably down")
2156

    
2157
    # TODO: search for netdev_add, drive_add, device_add.....
2158
    match = self._INFO_VERSION_RE.search(output.stdout)
2159
    if not match:
2160
      raise errors.HotplugError("Cannot parse qemu version via monitor")
2161

    
2162
    v_major, v_min, _, _ = match.groups()
2163
    if (int(v_major), int(v_min)) < (1, 0):
2164
      raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2165

    
2166
  def _CallHotplugCommand(self, name, cmd):
2167
    output = self._CallMonitorCommand(name, cmd)
2168
    # TODO: parse output and check if succeeded
2169
    for line in output.stdout.splitlines():
2170
      logging.info("%s", line)
2171

    
2172
  def HotAddDevice(self, instance, dev_type, device, extra, seq):
2173
    """ Helper method to hot-add a new device
2174

2175
    It gets free pci slot generates the device name and invokes the
2176
    device specific method.
2177

2178
    """
2179
    # in case of hot-mod this is given
2180
    if device.pci is None:
2181
      self._GetFreePCISlot(instance, device)
2182
    kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2183
    runtime = self._LoadKVMRuntime(instance)
2184
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2185
      command = "drive_add dummy file=%s,if=none,id=%s,format=raw\n" % \
2186
                 (extra, kvm_devid)
2187
      command += ("device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
2188
                  (hex(device.pci), kvm_devid, kvm_devid))
2189
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
2190
      (tap, fd) = _OpenTap()
2191
      self._ConfigureNIC(instance, seq, device, tap)
2192
      self._PassTapFd(instance, fd, device)
2193
      command = "netdev_add tap,id=%s,fd=%s\n" % (kvm_devid, kvm_devid)
2194
      args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
2195
               (hex(device.pci), device.mac, kvm_devid, kvm_devid)
2196
      command += "device_add %s" % args
2197
      utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
2198

    
2199
    self._CallHotplugCommand(instance.name, command)
2200
    # update relevant entries in runtime file
2201
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2202
    entry = _RUNTIME_ENTRY[dev_type](device, extra)
2203
    runtime[index].append(entry)
2204
    self._SaveKVMRuntime(instance, runtime)
2205

    
2206
  def HotDelDevice(self, instance, dev_type, device, _, seq):
2207
    """ Helper method for hot-del device
2208

2209
    It gets device info from runtime file, generates the device name and
2210
    invokes the device specific method.
2211

2212
    """
2213
    runtime = self._LoadKVMRuntime(instance)
2214
    entry = _GetExistingDeviceInfo(dev_type, device, runtime)
2215
    kvm_device = _RUNTIME_DEVICE[dev_type](entry)
2216
    kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
2217
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2218
      command = "device_del %s\n" % kvm_devid
2219
      command += "drive_del %s" % kvm_devid
2220
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
2221
      command = "device_del %s\n" % kvm_devid
2222
      command += "netdev_del %s" % kvm_devid
2223
      utils.RemoveFile(self._InstanceNICFile(instance.name, seq))
2224
    self._CallHotplugCommand(instance.name, command)
2225
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2226
    runtime[index].remove(entry)
2227
    self._SaveKVMRuntime(instance, runtime)
2228

    
2229
    return kvm_device.pci
2230

    
2231
  def HotModDevice(self, instance, dev_type, device, _, seq):
2232
    """ Helper method for hot-mod device
2233

2234
    It gets device info from runtime file, generates the device name and
2235
    invokes the device specific method. Currently only NICs support hot-mod
2236

2237
    """
2238
    if dev_type == constants.HOTPLUG_TARGET_NIC:
2239
      # putting it back in the same pci slot
2240
      device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2241
      # TODO: remove sleep when socat gets removed
2242
      time.sleep(2)
2243
      self.HotAddDevice(instance, dev_type, device, _, seq)
2244

    
2245
  def _PassTapFd(self, instance, fd, nic):
2246
    """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2247

2248
    """
2249
    # TODO: factor out code related to unix sockets.
2250
    #       squash common parts between monitor and qmp
2251
    kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2252
    command = "getfd %s\n" % kvm_devid
2253
    fds = [fd]
2254
    logging.info("%s", fds)
2255
    try:
2256
      monsock = MonitorSocket(self._InstanceMonitor(instance.name))
2257
      monsock.connect()
2258
      fdsend.sendfds(monsock.sock, command, fds=fds)
2259
    finally:
2260
      monsock.close()
2261

    
2262
  @classmethod
2263
  def _ParseKVMVersion(cls, text):
2264
    """Parse the KVM version from the --help output.
2265

2266
    @type text: string
2267
    @param text: output of kvm --help
2268
    @return: (version, v_maj, v_min, v_rev)
2269
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2270

2271
    """
2272
    match = cls._VERSION_RE.search(text.splitlines()[0])
2273
    if not match:
2274
      raise errors.HypervisorError("Unable to get KVM version")
2275

    
2276
    v_all = match.group(0)
2277
    v_maj = int(match.group(1))
2278
    v_min = int(match.group(2))
2279
    if match.group(4):
2280
      v_rev = int(match.group(4))
2281
    else:
2282
      v_rev = 0
2283
    return (v_all, v_maj, v_min, v_rev)
2284

    
2285
  @classmethod
2286
  def _GetKVMOutput(cls, kvm_path, option):
2287
    """Return the output of a kvm invocation
2288

2289
    @type kvm_path: string
2290
    @param kvm_path: path to the kvm executable
2291
    @type option: a key of _KVMOPTS_CMDS
2292
    @param option: kvm option to fetch the output from
2293
    @return: output a supported kvm invocation
2294
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2295

2296
    """
2297
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2298

    
2299
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
2300

    
2301
    result = utils.RunCmd([kvm_path] + optlist)
2302
    if result.failed and not can_fail:
2303
      raise errors.HypervisorError("Unable to get KVM %s output" %
2304
                                    " ".join(optlist))
2305
    return result.output
2306

    
2307
  @classmethod
2308
  def _GetKVMVersion(cls, kvm_path):
2309
    """Return the installed KVM version.
2310

2311
    @return: (version, v_maj, v_min, v_rev)
2312
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2313

2314
    """
2315
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2316

    
2317
  @classmethod
2318
  def _GetDefaultMachineVersion(cls, kvm_path):
2319
    """Return the default hardware revision (e.g. pc-1.1)
2320

2321
    """
2322
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2323
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2324
    if match:
2325
      return match.group(1)
2326
    else:
2327
      return "pc"
2328

    
2329
  @classmethod
2330
  def _StopInstance(cls, instance, force=False, name=None):
2331
    """Stop an instance.
2332

2333
    """
2334
    if name is not None and not force:
2335
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2336
    if name is None:
2337
      name = instance.name
2338
      acpi = instance.hvparams[constants.HV_ACPI]
2339
    else:
2340
      acpi = False
2341
    _, pid, alive = cls._InstancePidAlive(name)
2342
    if pid > 0 and alive:
2343
      if force or not acpi:
2344
        utils.KillProcess(pid)
2345
      else:
2346
        cls._CallMonitorCommand(name, "system_powerdown")
2347
    cls._ClearUserShutdown(instance.name)
2348

    
2349
  def StopInstance(self, instance, force=False, retry=False, name=None):
2350
    """Stop an instance.
2351

2352
    """
2353
    self._StopInstance(instance, force, name)
2354

    
2355
  def CleanupInstance(self, instance_name):
2356
    """Cleanup after a stopped instance
2357

2358
    """
2359
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
2360
    if pid > 0 and alive:
2361
      raise errors.HypervisorError("Cannot cleanup a live instance")
2362
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2363
    self._ClearUserShutdown(instance_name)
2364

    
2365
  def RebootInstance(self, instance):
2366
    """Reboot an instance.
2367

2368
    """
2369
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2370
    # socket the instance will stop, but now power up again. So we'll resort
2371
    # to shutdown and restart.
2372
    _, _, alive = self._InstancePidAlive(instance.name)
2373
    if not alive:
2374
      raise errors.HypervisorError("Failed to reboot instance %s:"
2375
                                   " not running" % instance.name)
2376
    # StopInstance will delete the saved KVM runtime so:
2377
    # ...first load it...
2378
    kvm_runtime = self._LoadKVMRuntime(instance)
2379
    # ...now we can safely call StopInstance...
2380
    if not self.StopInstance(instance):
2381
      self.StopInstance(instance, force=True)
2382
    # ...and finally we can save it again, and execute it...
2383
    self._SaveKVMRuntime(instance, kvm_runtime)
2384
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2385
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2386
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2387

    
2388
  def MigrationInfo(self, instance):
2389
    """Get instance information to perform a migration.
2390

2391
    @type instance: L{objects.Instance}
2392
    @param instance: instance to be migrated
2393
    @rtype: string
2394
    @return: content of the KVM runtime file
2395

2396
    """
2397
    return self._ReadKVMRuntime(instance.name)
2398

    
2399
  def AcceptInstance(self, instance, info, target):
2400
    """Prepare to accept an instance.
2401

2402
    @type instance: L{objects.Instance}
2403
    @param instance: instance to be accepted
2404
    @type info: string
2405
    @param info: content of the KVM runtime file on the source node
2406
    @type target: string
2407
    @param target: target host (usually ip), on this node
2408

2409
    """
2410
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2411
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2412
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2413
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2414
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2415
                            incoming=incoming_address)
2416

    
2417
  def FinalizeMigrationDst(self, instance, info, success):
2418
    """Finalize the instance migration on the target node.
2419

2420
    Stop the incoming mode KVM.
2421

2422
    @type instance: L{objects.Instance}
2423
    @param instance: instance whose migration is being finalized
2424

2425
    """
2426
    if success:
2427
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2428
      kvm_nics = kvm_runtime[1]
2429

    
2430
      for nic_seq, nic in enumerate(kvm_nics):
2431
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2432
          # Bridged interfaces have already been configured
2433
          continue
2434
        try:
2435
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2436
        except EnvironmentError, err:
2437
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
2438
                          instance.name, nic_seq, str(err))
2439
          continue
2440
        try:
2441
          self._ConfigureNIC(instance, nic_seq, nic, tap)
2442
        except errors.HypervisorError, err:
2443
          logging.warning(str(err))
2444

    
2445
      self._WriteKVMRuntime(instance.name, info)
2446
    else:
2447
      self.StopInstance(instance, force=True)
2448

    
2449
  def MigrateInstance(self, cluster_name, instance, target, live):
2450
    """Migrate an instance to a target node.
2451

2452
    The migration will not be attempted if the instance is not
2453
    currently running.
2454

2455
    @type cluster_name: string
2456
    @param cluster_name: name of the cluster
2457
    @type instance: L{objects.Instance}
2458
    @param instance: the instance to be migrated
2459
    @type target: string
2460
    @param target: ip address of the target node
2461
    @type live: boolean
2462
    @param live: perform a live migration
2463

2464
    """
2465
    instance_name = instance.name
2466
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
2467
    _, _, alive = self._InstancePidAlive(instance_name)
2468
    if not alive:
2469
      raise errors.HypervisorError("Instance not running, cannot migrate")
2470

    
2471
    if not live:
2472
      self._CallMonitorCommand(instance_name, "stop")
2473

    
2474
    migrate_command = ("migrate_set_speed %dm" %
2475
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2476
    self._CallMonitorCommand(instance_name, migrate_command)
2477

    
2478
    migrate_command = ("migrate_set_downtime %dms" %
2479
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2480
    self._CallMonitorCommand(instance_name, migrate_command)
2481

    
2482
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2483
    self._CallMonitorCommand(instance_name, migrate_command)
2484

    
2485
  def FinalizeMigrationSource(self, instance, success, live):
2486
    """Finalize the instance migration on the source node.
2487

2488
    @type instance: L{objects.Instance}
2489
    @param instance: the instance that was migrated
2490
    @type success: bool
2491
    @param success: whether the migration succeeded or not
2492
    @type live: bool
2493
    @param live: whether the user requested a live migration or not
2494

2495
    """
2496
    if success:
2497
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2498
      utils.KillProcess(pid)
2499
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2500
    elif live:
2501
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2502
    self._ClearUserShutdown(instance.name)
2503

    
2504
  def GetMigrationStatus(self, instance):
2505
    """Get the migration status
2506

2507
    @type instance: L{objects.Instance}
2508
    @param instance: the instance that is being migrated
2509
    @rtype: L{objects.MigrationStatus}
2510
    @return: the status of the current migration (one of
2511
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2512
             progress info that can be retrieved from the hypervisor
2513

2514
    """
2515
    info_command = "info migrate"
2516
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2517
      result = self._CallMonitorCommand(instance.name, info_command)
2518
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
2519
      if not match:
2520
        if not result.stdout:
2521
          logging.info("KVM: empty 'info migrate' result")
2522
        else:
2523
          logging.warning("KVM: unknown 'info migrate' result: %s",
2524
                          result.stdout)
2525
      else:
2526
        status = match.group(1)
2527
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2528
          migration_status = objects.MigrationStatus(status=status)
2529
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2530
          if match:
2531
            migration_status.transferred_ram = match.group("transferred")
2532
            migration_status.total_ram = match.group("total")
2533

    
2534
          return migration_status
2535

    
2536
        logging.warning("KVM: unknown migration status '%s'", status)
2537

    
2538
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2539

    
2540
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2541

    
2542
  def BalloonInstanceMemory(self, instance, mem):
2543
    """Balloon an instance memory to a certain value.
2544

2545
    @type instance: L{objects.Instance}
2546
    @param instance: instance to be accepted
2547
    @type mem: int
2548
    @param mem: actual memory size to use for instance runtime
2549

2550
    """
2551
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2552

    
2553
  def GetNodeInfo(self, hvparams=None):
2554
    """Return information about the node.
2555

2556
    @type hvparams: dict of strings
2557
    @param hvparams: hypervisor parameters, not used in this class
2558

2559
    @return: a dict as returned by L{BaseHypervisor.GetLinuxNodeInfo} plus
2560
        the following keys:
2561
          - hv_version: the hypervisor version in the form (major, minor,
2562
                        revision)
2563

2564
    """
2565
    result = self.GetLinuxNodeInfo()
2566
    kvmpath = constants.KVM_PATH
2567
    if hvparams is not None:
2568
      kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2569
    _, v_major, v_min, v_rev = self._GetKVMVersion(kvmpath)
2570
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2571
    return result
2572

    
2573
  @classmethod
2574
  def GetInstanceConsole(cls, instance, primary_node, node_group,
2575
                         hvparams, beparams):
2576
    """Return a command for connecting to the console of an instance.
2577

2578
    """
2579
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2580
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2581
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2582
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2583
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2584
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2585
      ndparams = node_group.FillND(primary_node)
2586
      return objects.InstanceConsole(instance=instance.name,
2587
                                     kind=constants.CONS_SSH,
2588
                                     host=primary_node.name,
2589
                                     port=ndparams.get(constants.ND_SSH_PORT),
2590
                                     user=constants.SSH_CONSOLE_USER,
2591
                                     command=cmd)
2592

    
2593
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2594
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2595
      display = instance.network_port - constants.VNC_BASE_PORT
2596
      return objects.InstanceConsole(instance=instance.name,
2597
                                     kind=constants.CONS_VNC,
2598
                                     host=vnc_bind_address,
2599
                                     port=instance.network_port,
2600
                                     display=display)
2601

    
2602
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2603
    if spice_bind:
2604
      return objects.InstanceConsole(instance=instance.name,
2605
                                     kind=constants.CONS_SPICE,
2606
                                     host=spice_bind,
2607
                                     port=instance.network_port)
2608

    
2609
    return objects.InstanceConsole(instance=instance.name,
2610
                                   kind=constants.CONS_MESSAGE,
2611
                                   message=("No serial shell for instance %s" %
2612
                                            instance.name))
2613

    
2614
  def Verify(self, hvparams=None):
2615
    """Verify the hypervisor.
2616

2617
    Check that the required binaries exist.
2618

2619
    @type hvparams: dict of strings
2620
    @param hvparams: hypervisor parameters to be verified against, not used here
2621

2622
    @return: Problem description if something is wrong, C{None} otherwise
2623

2624
    """
2625
    msgs = []
2626
    kvmpath = constants.KVM_PATH
2627
    if hvparams is not None:
2628
      kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2629
    if not os.path.exists(kvmpath):
2630
      msgs.append("The KVM binary ('%s') does not exist" % kvmpath)
2631
    if not os.path.exists(constants.SOCAT_PATH):
2632
      msgs.append("The socat binary ('%s') does not exist" %
2633
                  constants.SOCAT_PATH)
2634

    
2635
    return self._FormatVerifyResults(msgs)
2636

    
2637
  @classmethod
2638
  def CheckParameterSyntax(cls, hvparams):
2639
    """Check the given parameters for validity.
2640

2641
    @type hvparams:  dict
2642
    @param hvparams: dictionary with parameter names/value
2643
    @raise errors.HypervisorError: when a parameter is not valid
2644

2645
    """
2646
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2647

    
2648
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2649
    if kernel_path:
2650
      if not hvparams[constants.HV_ROOT_PATH]:
2651
        raise errors.HypervisorError("Need a root partition for the instance,"
2652
                                     " if a kernel is defined")
2653

    
2654
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2655
        not hvparams[constants.HV_VNC_X509]):
2656
      raise errors.HypervisorError("%s must be defined, if %s is" %
2657
                                   (constants.HV_VNC_X509,
2658
                                    constants.HV_VNC_X509_VERIFY))
2659

    
2660
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2661
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2662
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2663
      if not serial_speed or serial_speed not in valid_speeds:
2664
        raise errors.HypervisorError("Invalid serial console speed, must be"
2665
                                     " one of: %s" %
2666
                                     utils.CommaJoin(valid_speeds))
2667

    
2668
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2669
    if (boot_order == constants.HT_BO_CDROM and
2670
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2671
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2672
                                   " ISO path")
2673

    
2674
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2675
    if security_model == constants.HT_SM_USER:
2676
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2677
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2678
                                     " must be specified")
2679
    elif (security_model == constants.HT_SM_NONE or
2680
          security_model == constants.HT_SM_POOL):
2681
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2682
        raise errors.HypervisorError("Cannot have a security domain when the"
2683
                                     " security model is 'none' or 'pool'")
2684

    
2685
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2686
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2687
    if spice_bind:
2688
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2689
        # if an IP version is specified, the spice_bind parameter must be an
2690
        # IP of that family
2691
        if (netutils.IP4Address.IsValid(spice_bind) and
2692
            spice_ip_version != constants.IP4_VERSION):
2693
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2694
                                       " the specified IP version is %s" %
2695
                                       (spice_bind, spice_ip_version))
2696

    
2697
        if (netutils.IP6Address.IsValid(spice_bind) and
2698
            spice_ip_version != constants.IP6_VERSION):
2699
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2700
                                       " the specified IP version is %s" %
2701
                                       (spice_bind, spice_ip_version))
2702
    else:
2703
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2704
      # error if any of them is set without it.
2705
      for param in _SPICE_ADDITIONAL_PARAMS:
2706
        if hvparams[param]:
2707
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2708
                                       (param, constants.HV_KVM_SPICE_BIND))
2709

    
2710
  @classmethod
2711
  def ValidateParameters(cls, hvparams):
2712
    """Check the given parameters for validity.
2713

2714
    @type hvparams:  dict
2715
    @param hvparams: dictionary with parameter names/value
2716
    @raise errors.HypervisorError: when a parameter is not valid
2717

2718
    """
2719
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2720

    
2721
    kvm_path = hvparams[constants.HV_KVM_PATH]
2722

    
2723
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2724
    if security_model == constants.HT_SM_USER:
2725
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2726
      try:
2727
        pwd.getpwnam(username)
2728
      except KeyError:
2729
        raise errors.HypervisorError("Unknown security domain user %s"
2730
                                     % username)
2731
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2732
    if vnc_bind_address:
2733
      bound_to_addr = netutils.IP4Address.IsValid(vnc_bind_address)
2734
      is_interface = netutils.IsValidInterface(vnc_bind_address)
2735
      is_path = utils.IsNormAbsPath(vnc_bind_address)
2736
      if not bound_to_addr and not is_interface and not is_path:
2737
        raise errors.HypervisorError("VNC: The %s parameter must be either"
2738
                                     " a valid IP address, an interface name,"
2739
                                     " or an absolute path" %
2740
                                     constants.HV_KVM_SPICE_BIND)
2741

    
2742
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2743
    if spice_bind:
2744
      # only one of VNC and SPICE can be used currently.
2745
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2746
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2747
                                     " only one of them can be used at a"
2748
                                     " given time")
2749

    
2750
      # check that KVM supports SPICE
2751
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2752
      if not cls._SPICE_RE.search(kvmhelp):
2753
        raise errors.HypervisorError("SPICE is configured, but it is not"
2754
                                     " supported according to 'kvm --help'")
2755

    
2756
      # if spice_bind is not an IP address, it must be a valid interface
2757
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2758
                       netutils.IP6Address.IsValid(spice_bind))
2759
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2760
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2761
                                     " a valid IP address or interface name" %
2762
                                     constants.HV_KVM_SPICE_BIND)
2763

    
2764
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2765
    if machine_version:
2766
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2767
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2768
        raise errors.HypervisorError("Unsupported machine version: %s" %
2769
                                     machine_version)
2770

    
2771
  @classmethod
2772
  def PowercycleNode(cls, hvparams=None):
2773
    """KVM powercycle, just a wrapper over Linux powercycle.
2774

2775
    @type hvparams: dict of strings
2776
    @param hvparams: hypervisor params to be used on this node
2777

2778
    """
2779
    cls.LinuxPowercycle()