Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 81c717cd

History | View | Annotate | Download (101.2 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, name=""):
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

295
  @type name: string
296
  @param name: name for the TAP interface being created; if an empty
297
               string is passed, the OS will generate a unique name
298

299
  @return: (ifname, tapfd)
300
  @rtype: tuple
301

302
  """
303
  try:
304
    tapfd = os.open("/dev/net/tun", os.O_RDWR)
305
  except EnvironmentError:
306
    raise errors.HypervisorError("Failed to open /dev/net/tun")
307

    
308
  flags = IFF_TAP | IFF_NO_PI
309

    
310
  if vnet_hdr and _ProbeTapVnetHdr(tapfd):
311
    flags |= IFF_VNET_HDR
312

    
313
  # The struct ifreq ioctl request (see netdevice(7))
314
  ifr = struct.pack("16sh", name, flags)
315

    
316
  try:
317
    res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
318
  except EnvironmentError, err:
319
    raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
320
                                 err)
321

    
322
  # Get the interface name from the ioctl
323
  ifname = struct.unpack("16sh", res)[0].strip("\x00")
324
  return (ifname, tapfd)
325

    
326

    
327
class HeadRequest(urllib2.Request):
328
  def get_method(self):
329
    return "HEAD"
330

    
331

    
332
def _CheckUrl(url):
333
  """Check if a given URL exists on the server
334

335
  """
336
  try:
337
    urllib2.urlopen(HeadRequest(url))
338
    return True
339
  except urllib2.URLError:
340
    return False
341

    
342

    
343
class QmpMessage:
344
  """QEMU Messaging Protocol (QMP) message.
345

346
  """
347
  def __init__(self, data):
348
    """Creates a new QMP message based on the passed data.
349

350
    """
351
    if not isinstance(data, dict):
352
      raise TypeError("QmpMessage must be initialized with a dict")
353

    
354
    self.data = data
355

    
356
  def __getitem__(self, field_name):
357
    """Get the value of the required field if present, or None.
358

359
    Overrides the [] operator to provide access to the message data,
360
    returning None if the required item is not in the message
361
    @return: the value of the field_name field, or None if field_name
362
             is not contained in the message
363

364
    """
365
    return self.data.get(field_name, None)
366

    
367
  def __setitem__(self, field_name, field_value):
368
    """Set the value of the required field_name to field_value.
369

370
    """
371
    self.data[field_name] = field_value
372

    
373
  def __len__(self):
374
    """Return the number of fields stored in this QmpMessage.
375

376
    """
377
    return len(self.data)
378

    
379
  def __delitem__(self, key):
380
    """Delete the specified element from the QmpMessage.
381

382
    """
383
    del(self.data[key])
384

    
385
  @staticmethod
386
  def BuildFromJsonString(json_string):
387
    """Build a QmpMessage from a JSON encoded string.
388

389
    @type json_string: str
390
    @param json_string: JSON string representing the message
391
    @rtype: L{QmpMessage}
392
    @return: a L{QmpMessage} built from json_string
393

394
    """
395
    # Parse the string
396
    data = serializer.LoadJson(json_string)
397
    return QmpMessage(data)
398

    
399
  def __str__(self):
400
    # The protocol expects the JSON object to be sent as a single line.
401
    return serializer.DumpJson(self.data)
402

    
403
  def __eq__(self, other):
404
    # When comparing two QmpMessages, we are interested in comparing
405
    # their internal representation of the message data
406
    return self.data == other.data
407

    
408

    
409
class MonitorSocket(object):
410
  _SOCKET_TIMEOUT = 5
411

    
412
  def __init__(self, monitor_filename):
413
    """Instantiates the MonitorSocket object.
414

415
    @type monitor_filename: string
416
    @param monitor_filename: the filename of the UNIX raw socket on which the
417
                             monitor (QMP or simple one) is listening
418

419
    """
420
    self.monitor_filename = monitor_filename
421
    self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
422
    # We want to fail if the server doesn't send a complete message
423
    # in a reasonable amount of time
424
    self.sock.settimeout(self._SOCKET_TIMEOUT)
425
    self._connected = False
426

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

    
440
  def _check_connection(self):
441
    """Make sure that the connection is established.
442

443
    """
444
    if not self._connected:
445
      raise errors.ProgrammerError("To use a MonitorSocket you need to first"
446
                                   " invoke connect() on it")
447

    
448
  def connect(self):
449
    """Connects to the monitor.
450

451
    Connects to the UNIX socket
452

453
    @raise errors.HypervisorError: when there are communication errors
454

455
    """
456
    if self._connected:
457
      raise errors.ProgrammerError("Cannot connect twice")
458

    
459
    self._check_socket()
460

    
461
    # Check file existance/stuff
462
    try:
463
      self.sock.connect(self.monitor_filename)
464
    except EnvironmentError:
465
      raise errors.HypervisorError("Can't connect to qmp socket")
466
    self._connected = True
467

    
468
  def close(self):
469
    """Closes the socket
470

471
    It cannot be used after this call.
472

473
    """
474
    self.sock.close()
475

    
476

    
477
class QmpConnection(MonitorSocket):
478
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
479

480
  """
481
  _FIRST_MESSAGE_KEY = "QMP"
482
  _EVENT_KEY = "event"
483
  _ERROR_KEY = "error"
484
  _RETURN_KEY = RETURN_KEY = "return"
485
  _ACTUAL_KEY = ACTUAL_KEY = "actual"
486
  _ERROR_CLASS_KEY = "class"
487
  _ERROR_DESC_KEY = "desc"
488
  _EXECUTE_KEY = "execute"
489
  _ARGUMENTS_KEY = "arguments"
490
  _CAPABILITIES_COMMAND = "qmp_capabilities"
491
  _MESSAGE_END_TOKEN = "\r\n"
492

    
493
  def __init__(self, monitor_filename):
494
    super(QmpConnection, self).__init__(monitor_filename)
495
    self._buf = ""
496

    
497
  def connect(self):
498
    """Connects to the QMP monitor.
499

500
    Connects to the UNIX socket and makes sure that we can actually send and
501
    receive data to the kvm instance via QMP.
502

503
    @raise errors.HypervisorError: when there are communication errors
504
    @raise errors.ProgrammerError: when there are data serialization errors
505

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

    
516
    # Let's put the monitor in command mode using the qmp_capabilities
517
    # command, or else no command will be executable.
518
    # (As per the QEMU Protocol Specification 0.1 - section 4)
519
    self.Execute(self._CAPABILITIES_COMMAND)
520

    
521
  def _ParseMessage(self, buf):
522
    """Extract and parse a QMP message from the given buffer.
523

524
    Seeks for a QMP message in the given buf. If found, it parses it and
525
    returns it together with the rest of the characters in the buf.
526
    If no message is found, returns None and the whole buffer.
527

528
    @raise errors.ProgrammerError: when there are data serialization errors
529

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

    
542
    return (message, buf)
543

    
544
  def _Recv(self):
545
    """Receives a message from QMP and decodes the received JSON object.
546

547
    @rtype: QmpMessage
548
    @return: the received message
549
    @raise errors.HypervisorError: when there are communication errors
550
    @raise errors.ProgrammerError: when there are data serialization errors
551

552
    """
553
    self._check_connection()
554

    
555
    # Check if there is already a message in the buffer
556
    (message, self._buf) = self._ParseMessage(self._buf)
557
    if message:
558
      return message
559

    
560
    recv_buffer = StringIO.StringIO(self._buf)
561
    recv_buffer.seek(len(self._buf))
562
    try:
563
      while True:
564
        data = self.sock.recv(4096)
565
        if not data:
566
          break
567
        recv_buffer.write(data)
568

    
569
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
570
        if message:
571
          return message
572

    
573
    except socket.timeout, err:
574
      raise errors.HypervisorError("Timeout while receiving a QMP message: "
575
                                   "%s" % (err))
576
    except socket.error, err:
577
      raise errors.HypervisorError("Unable to receive data from KVM using the"
578
                                   " QMP protocol: %s" % err)
579

    
580
  def _Send(self, message):
581
    """Encodes and sends a message to KVM using QMP.
582

583
    @type message: QmpMessage
584
    @param message: message to send to KVM
585
    @raise errors.HypervisorError: when there are communication errors
586
    @raise errors.ProgrammerError: when there are data serialization errors
587

588
    """
589
    self._check_connection()
590
    try:
591
      message_str = str(message)
592
    except Exception, err:
593
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
594

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

    
604
  def Execute(self, command, arguments=None):
605
    """Executes a QMP command and returns the response of the server.
606

607
    @type command: str
608
    @param command: the command to execute
609
    @type arguments: dict
610
    @param arguments: dictionary of arguments to be passed to the command
611
    @rtype: dict
612
    @return: dictionary representing the received JSON object
613
    @raise errors.HypervisorError: when there are communication errors
614
    @raise errors.ProgrammerError: when there are data serialization errors
615

616
    """
617
    self._check_connection()
618
    message = QmpMessage({self._EXECUTE_KEY: command})
619
    if arguments:
620
      message[self._ARGUMENTS_KEY] = arguments
621
    self._Send(message)
622

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

    
635
      elif not response[self._EVENT_KEY]:
636
        return response
637

    
638

    
639
class KVMHypervisor(hv_base.BaseHypervisor):
640
  """KVM hypervisor interface
641

642
  """
643
  CAN_MIGRATE = True
644

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

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

    
745
  _VIRTIO = "virtio"
746
  _VIRTIO_NET_PCI = "virtio-net-pci"
747
  _VIRTIO_BLK_PCI = "virtio-blk-pci"
748

    
749
  _MIGRATION_STATUS_RE = re.compile(r"Migration\s+status:\s+(\w+)",
750
                                    re.M | re.I)
751
  _MIGRATION_PROGRESS_RE = \
752
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
753
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
754
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
755

    
756
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
757
  _MIGRATION_INFO_RETRY_DELAY = 2
758

    
759
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
760

    
761
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
762
  _CPU_INFO_CMD = "info cpus"
763
  _CONT_CMD = "cont"
764

    
765
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
766
  _CHECK_MACHINE_VERSION_RE = \
767
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
768

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

    
785
  _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
786
  _INFO_PCI_CMD = "info pci"
787
  _INFO_VERSION_RE = \
788
    re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
789
  _INFO_VERSION_CMD = "info version"
790

    
791
  _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
792

    
793
  ANCILLARY_FILES = [
794
    _KVM_NETWORK_SCRIPT,
795
    ]
796
  ANCILLARY_FILES_OPT = [
797
    _KVM_NETWORK_SCRIPT,
798
    ]
799

    
800
  # Supported kvm options to get output from
801
  _KVMOPT_HELP = "help"
802
  _KVMOPT_MLIST = "mlist"
803
  _KVMOPT_DEVICELIST = "devicelist"
804

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

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

    
820
  @classmethod
821
  def _InstancePidFile(cls, instance_name):
822
    """Returns the instance pidfile.
823

824
    """
825
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
826

    
827
  @classmethod
828
  def _InstanceUidFile(cls, instance_name):
829
    """Returns the instance uidfile.
830

831
    """
832
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
833

    
834
  @classmethod
835
  def _InstancePidInfo(cls, pid):
836
    """Check pid file for instance information.
837

838
    Check that a pid file is associated with an instance, and retrieve
839
    information from its command line.
840

841
    @type pid: string or int
842
    @param pid: process id of the instance to check
843
    @rtype: tuple
844
    @return: (instance_name, memory, vcpus)
845
    @raise errors.HypervisorError: when an instance cannot be found
846

847
    """
848
    alive = utils.IsProcessAlive(pid)
849
    if not alive:
850
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
851

    
852
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
853
    try:
854
      cmdline = utils.ReadFile(cmdline_file)
855
    except EnvironmentError, err:
856
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
857
                                   (pid, err))
858

    
859
    instance = None
860
    memory = 0
861
    vcpus = 0
862

    
863
    arg_list = cmdline.split("\x00")
864
    while arg_list:
865
      arg = arg_list.pop(0)
866
      if arg == "-name":
867
        instance = arg_list.pop(0)
868
      elif arg == "-m":
869
        memory = int(arg_list.pop(0))
870
      elif arg == "-smp":
871
        vcpus = int(arg_list.pop(0).split(",")[0])
872

    
873
    if instance is None:
874
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
875
                                   " instance" % pid)
876

    
877
    return (instance, memory, vcpus)
878

    
879
  @classmethod
880
  def _InstancePidAlive(cls, instance_name):
881
    """Returns the instance pidfile, pid, and liveness.
882

883
    @type instance_name: string
884
    @param instance_name: instance name
885
    @rtype: tuple
886
    @return: (pid file name, pid, liveness)
887

888
    """
889
    pidfile = cls._InstancePidFile(instance_name)
890
    pid = utils.ReadPidFile(pidfile)
891

    
892
    alive = False
893
    try:
894
      cmd_instance = cls._InstancePidInfo(pid)[0]
895
      alive = (cmd_instance == instance_name)
896
    except errors.HypervisorError:
897
      pass
898

    
899
    return (pidfile, pid, alive)
900

    
901
  @classmethod
902
  def _CheckDown(cls, instance_name):
903
    """Raises an error unless the given instance is down.
904

905
    """
906
    alive = cls._InstancePidAlive(instance_name)[2]
907
    if alive:
908
      raise errors.HypervisorError("Failed to start instance %s: %s" %
909
                                   (instance_name, "already running"))
910

    
911
  @classmethod
912
  def _InstanceMonitor(cls, instance_name):
913
    """Returns the instance monitor socket name
914

915
    """
916
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
917

    
918
  @classmethod
919
  def _InstanceSerial(cls, instance_name):
920
    """Returns the instance serial socket name
921

922
    """
923
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
924

    
925
  @classmethod
926
  def _InstanceQmpMonitor(cls, instance_name):
927
    """Returns the instance serial QMP socket name
928

929
    """
930
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
931

    
932
  @classmethod
933
  def _InstanceShutdownMonitor(cls, instance_name):
934
    """Returns the instance QMP output filename
935

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

    
939
  @staticmethod
940
  def _SocatUnixConsoleParams():
941
    """Returns the correct parameters for socat
942

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

945
    """
946
    if constants.SOCAT_USE_ESCAPE:
947
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
948
    else:
949
      return "echo=0,icanon=0"
950

    
951
  @classmethod
952
  def _InstanceKVMRuntime(cls, instance_name):
953
    """Returns the instance KVM runtime filename
954

955
    """
956
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
957

    
958
  @classmethod
959
  def _InstanceChrootDir(cls, instance_name):
960
    """Returns the name of the KVM chroot dir of the instance
961

962
    """
963
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
964

    
965
  @classmethod
966
  def _InstanceNICDir(cls, instance_name):
967
    """Returns the name of the directory holding the tap device files for a
968
    given instance.
969

970
    """
971
    return utils.PathJoin(cls._NICS_DIR, instance_name)
972

    
973
  @classmethod
974
  def _InstanceNICFile(cls, instance_name, seq):
975
    """Returns the name of the file containing the tap device for a given NIC
976

977
    """
978
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
979

    
980
  @classmethod
981
  def _InstanceKeymapFile(cls, instance_name):
982
    """Returns the name of the file containing the keymap for a given instance
983

984
    """
985
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
986

    
987
  @classmethod
988
  def _TryReadUidFile(cls, uid_file):
989
    """Try to read a uid file
990

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

    
1002
  @classmethod
1003
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
1004
    """Removes an instance's rutime sockets/files/dirs.
1005

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

    
1042
  @staticmethod
1043
  def _ConfigureNIC(instance, seq, nic, tap):
1044
    """Run the network configuration script for a specified NIC
1045

1046
    @param instance: instance we're acting on
1047
    @type instance: instance object
1048
    @param seq: nic sequence number
1049
    @type seq: int
1050
    @param nic: nic we're acting on
1051
    @type nic: nic object
1052
    @param tap: the host's tap interface this NIC corresponds to
1053
    @type tap: str
1054

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

    
1067
    if nic.ip:
1068
      env["IP"] = nic.ip
1069

    
1070
    if nic.name:
1071
      env["INTERFACE_NAME"] = nic.name
1072

    
1073
    if nic.nicparams[constants.NIC_LINK]:
1074
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
1075

    
1076
    if nic.network:
1077
      n = objects.Network.FromDict(nic.netinfo)
1078
      env.update(n.HooksDict())
1079

    
1080
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1081
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
1082

    
1083
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
1084
    if result.failed:
1085
      raise errors.HypervisorError("Failed to configure interface %s: %s;"
1086
                                   " network configuration script output: %s" %
1087
                                   (tap, result.fail_reason, result.output))
1088

    
1089
  @staticmethod
1090
  def _VerifyAffinityPackage():
1091
    if affinity is None:
1092
      raise errors.HypervisorError("affinity Python package not"
1093
                                   " found; cannot use CPU pinning under KVM")
1094

    
1095
  @staticmethod
1096
  def _BuildAffinityCpuMask(cpu_list):
1097
    """Create a CPU mask suitable for sched_setaffinity from a list of
1098
    CPUs.
1099

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

1103
    @type cpu_list: list of int
1104
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
1105
    @rtype: int
1106
    @return: a bit mask of CPU affinities
1107

1108
    """
1109
    if cpu_list == constants.CPU_PINNING_OFF:
1110
      return constants.CPU_PINNING_ALL_KVM
1111
    else:
1112
      return sum(2 ** cpu for cpu in cpu_list)
1113

    
1114
  @classmethod
1115
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
1116
    """Change CPU affinity for running VM according to given CPU mask.
1117

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

1126
    """
1127
    # Convert the string CPU mask to a list of list of int's
1128
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
1129

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

    
1148
      # For each vCPU, map it to the proper list of physical CPUs
1149
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1150
        affinity.set_process_affinity_mask(thread_dict[i],
1151
                                           cls._BuildAffinityCpuMask(vcpu))
1152

    
1153
  def _GetVcpuThreadIds(self, instance_name):
1154
    """Get a mapping of vCPU no. to thread IDs for the instance
1155

1156
    @type instance_name: string
1157
    @param instance_name: instance in question
1158
    @rtype: dictionary of int:int
1159
    @return: a dictionary mapping vCPU numbers to thread IDs
1160

1161
    """
1162
    result = {}
1163
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1164
    for line in output.stdout.splitlines():
1165
      match = self._CPU_INFO_RE.search(line)
1166
      if not match:
1167
        continue
1168
      grp = map(int, match.groups())
1169
      result[grp[0]] = grp[1]
1170

    
1171
    return result
1172

    
1173
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1174
    """Complete CPU pinning.
1175

1176
    @type instance_name: string
1177
    @param instance_name: name of instance
1178
    @type cpu_mask: string
1179
    @param cpu_mask: CPU pinning mask as entered by user
1180

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

    
1189
  def ListInstances(self, hvparams=None):
1190
    """Get the list of running instances.
1191

1192
    We can do this by listing our live instances directory and
1193
    checking whether the associated kvm process is still alive.
1194

1195
    """
1196
    result = []
1197
    for name in os.listdir(self._PIDS_DIR):
1198
      if self._InstancePidAlive(name)[2] or self._IsUserShutdown(name):
1199
        result.append(name)
1200
    return result
1201

    
1202
  @classmethod
1203
  def _IsUserShutdown(cls, instance_name):
1204
    return os.path.exists(cls._InstanceShutdownMonitor(instance_name))
1205

    
1206
  @classmethod
1207
  def _ClearUserShutdown(cls, instance_name):
1208
    utils.RemoveFile(cls._InstanceShutdownMonitor(instance_name))
1209

    
1210
  def GetInstanceInfo(self, instance_name, hvparams=None):
1211
    """Get instance properties.
1212

1213
    @type instance_name: string
1214
    @param instance_name: the instance name
1215
    @type hvparams: dict of strings
1216
    @param hvparams: hvparams to be used with this instance
1217
    @rtype: tuple of strings
1218
    @return: (name, id, memory, vcpus, stat, times)
1219

1220
    """
1221
    _, pid, alive = self._InstancePidAlive(instance_name)
1222
    if not alive:
1223
      if self._IsUserShutdown(instance_name):
1224
        return (instance_name, -1, 0, 0, hv_base.HvInstanceState.SHUTDOWN, 0)
1225
      else:
1226
        return None
1227

    
1228
    _, memory, vcpus = self._InstancePidInfo(pid)
1229
    istat = hv_base.HvInstanceState.RUNNING
1230
    times = 0
1231

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

    
1243
    return (instance_name, pid, memory, vcpus, istat, times)
1244

    
1245
  def GetAllInstancesInfo(self, hvparams=None):
1246
    """Get properties of all instances.
1247

1248
    @type hvparams: dict of strings
1249
    @param hvparams: hypervisor parameter
1250
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1251

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

    
1264
  def _GenerateKVMBlockDevicesOptions(self, instance, kvm_disks,
1265
                                      kvmhelp, devlist):
1266
    """Generate KVM options regarding instance's block devices.
1267

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

1279
    """
1280
    hvp = instance.hvparams
1281
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1282
    if kernel_path:
1283
      boot_disk = False
1284
    else:
1285
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1286

    
1287
    # whether this is an older KVM version that uses the boot=on flag
1288
    # on devices
1289
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1290

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

    
1330
      access_mode = cfdev.params.get(constants.LDP_ACCESS,
1331
                                     constants.DISK_KERNELSPACE)
1332
      if (uri and access_mode == constants.DISK_USERSPACE):
1333
        drive_uri = uri
1334
      else:
1335
        drive_uri = link_name
1336

    
1337
      drive_val = "file=%s,format=raw%s%s%s" % \
1338
                  (drive_uri, if_val, boot_val, cache_val)
1339

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

    
1352
      dev_opts.extend(["-drive", drive_val])
1353

    
1354
    return dev_opts
1355

    
1356
  @staticmethod
1357
  def _CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image, cdrom_boot,
1358
                   needs_boot_flag):
1359
    """Extends L{kvm_cmd} with the '-drive' option for a cdrom, and
1360
    optionally the '-boot' option.
1361

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

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

1366
    Example: -drive file=http://hostname.com/cdrom.iso,media=cdrom
1367

1368
    @type kvm_cmd: string
1369
    @param kvm_cmd: KVM command line
1370

1371
    @type cdrom_disk_type:
1372
    @param cdrom_disk_type:
1373

1374
    @type cdrom_image:
1375
    @param cdrom_image:
1376

1377
    @type cdrom_boot:
1378
    @param cdrom_boot:
1379

1380
    @type needs_boot_flag:
1381
    @param needs_boot_flag:
1382

1383
    """
1384
    # Check that the ISO image is accessible
1385
    # See https://bugs.launchpad.net/qemu/+bug/597575
1386
    if utils.IsUrl(cdrom_image) and not _CheckUrl(cdrom_image):
1387
      raise errors.HypervisorError("Cdrom ISO image '%s' is not accessible" %
1388
                                   cdrom_image)
1389

    
1390
    # set cdrom 'media' and 'format', if needed
1391
    if utils.IsUrl(cdrom_image):
1392
      options = ",media=cdrom"
1393
    else:
1394
      options = ",media=cdrom,format=raw"
1395

    
1396
    # set cdrom 'if' type
1397
    if cdrom_boot:
1398
      if_val = ",if=" + constants.HT_DISK_IDE
1399
    elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1400
      if_val = ",if=virtio"
1401
    else:
1402
      if_val = ",if=" + cdrom_disk_type
1403

    
1404
    # set boot flag, if needed
1405
    boot_val = ""
1406
    if cdrom_boot:
1407
      kvm_cmd.extend(["-boot", "d"])
1408

    
1409
      # whether this is an older KVM version that requires the 'boot=on' flag
1410
      # on devices
1411
      if needs_boot_flag:
1412
        boot_val = ",boot=on"
1413

    
1414
    # build '-drive' option
1415
    drive_val = "file=%s%s%s%s" % (cdrom_image, options, if_val, boot_val)
1416
    kvm_cmd.extend(["-drive", drive_val])
1417

    
1418
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1419
                          kvmhelp):
1420
    """Generate KVM information to start an instance.
1421

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

1431
    """
1432
    # pylint: disable=R0912,R0914,R0915
1433
    hvp = instance.hvparams
1434
    self.ValidateParameters(hvp)
1435

    
1436
    pidfile = self._InstancePidFile(instance.name)
1437
    kvm = hvp[constants.HV_KVM_PATH]
1438
    kvm_cmd = [kvm]
1439
    # used just by the vnc server, if enabled
1440
    kvm_cmd.extend(["-name", instance.name])
1441
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1442

    
1443
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1444
    if hvp[constants.HV_CPU_CORES]:
1445
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1446
    if hvp[constants.HV_CPU_THREADS]:
1447
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1448
    if hvp[constants.HV_CPU_SOCKETS]:
1449
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1450

    
1451
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1452

    
1453
    kvm_cmd.extend(["-pidfile", pidfile])
1454
    kvm_cmd.extend(["-balloon", "virtio"])
1455
    kvm_cmd.extend(["-daemonize"])
1456
    if not instance.hvparams[constants.HV_ACPI]:
1457
      kvm_cmd.extend(["-no-acpi"])
1458
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1459
        constants.INSTANCE_REBOOT_EXIT:
1460
      kvm_cmd.extend(["-no-reboot"])
1461

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

    
1484
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1485
    if kernel_path:
1486
      boot_cdrom = boot_floppy = boot_network = False
1487
    else:
1488
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1489
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1490
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1491

    
1492
    if startup_paused:
1493
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1494

    
1495
    if boot_network:
1496
      kvm_cmd.extend(["-boot", "n"])
1497

    
1498
    disk_type = hvp[constants.HV_DISK_TYPE]
1499

    
1500
    # Now we can specify a different device type for CDROM devices.
1501
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1502
    if not cdrom_disk_type:
1503
      cdrom_disk_type = disk_type
1504

    
1505
    cdrom_image1 = hvp[constants.HV_CDROM_IMAGE_PATH]
1506
    if cdrom_image1:
1507
      needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1508
      self._CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image1, boot_cdrom,
1509
                        needs_boot_flag)
1510

    
1511
    cdrom_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1512
    if cdrom_image2:
1513
      self._CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image2, False, False)
1514

    
1515
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1516
    if floppy_image:
1517
      options = ",format=raw,media=disk"
1518
      if boot_floppy:
1519
        kvm_cmd.extend(["-boot", "a"])
1520
        options = "%s,boot=on" % options
1521
      if_val = ",if=floppy"
1522
      options = "%s%s" % (options, if_val)
1523
      drive_val = "file=%s%s" % (floppy_image, options)
1524
      kvm_cmd.extend(["-drive", drive_val])
1525

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

    
1538
    mem_path = hvp[constants.HV_MEM_PATH]
1539
    if mem_path:
1540
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1541

    
1542
    monitor_dev = ("unix:%s,server,nowait" %
1543
                   self._InstanceMonitor(instance.name))
1544
    kvm_cmd.extend(["-monitor", monitor_dev])
1545
    if hvp[constants.HV_SERIAL_CONSOLE]:
1546
      serial_dev = ("unix:%s,server,nowait" %
1547
                    self._InstanceSerial(instance.name))
1548
      kvm_cmd.extend(["-serial", serial_dev])
1549
    else:
1550
      kvm_cmd.extend(["-serial", "none"])
1551

    
1552
    mouse_type = hvp[constants.HV_USB_MOUSE]
1553
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1554
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1555
    spice_ip_version = None
1556

    
1557
    kvm_cmd.extend(["-usb"])
1558

    
1559
    if mouse_type:
1560
      kvm_cmd.extend(["-usbdevice", mouse_type])
1561
    elif vnc_bind_address:
1562
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1563

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

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

    
1600
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1601

    
1602
      else:
1603
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1604

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

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

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

    
1639
        spice_address = addresses[spice_ip_version][0]
1640

    
1641
      else:
1642
        # spice_bind is known to be a valid IP address, because
1643
        # ValidateParameters checked it.
1644
        spice_address = spice_bind
1645

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

    
1660
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1661
        spice_arg = "%s,disable-ticketing" % spice_arg
1662

    
1663
      if spice_ip_version:
1664
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1665

    
1666
      # Image compression options
1667
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1668
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1669
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1670
      if img_lossless:
1671
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1672
      if img_jpeg:
1673
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1674
      if img_zlib_glz:
1675
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1676

    
1677
      # Video stream detection
1678
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1679
      if video_streaming:
1680
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1681

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

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

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

    
1708
    if hvp[constants.HV_USE_LOCALTIME]:
1709
      kvm_cmd.extend(["-localtime"])
1710

    
1711
    if hvp[constants.HV_KVM_USE_CHROOT]:
1712
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1713

    
1714
    # Add qemu-KVM -cpu param
1715
    if hvp[constants.HV_CPU_TYPE]:
1716
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1717

    
1718
    # As requested by music lovers
1719
    if hvp[constants.HV_SOUNDHW]:
1720
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1721

    
1722
    # Pass a -vga option if requested, or if spice is used, for backwards
1723
    # compatibility.
1724
    if hvp[constants.HV_VGA]:
1725
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1726
    elif spice_bind:
1727
      kvm_cmd.extend(["-vga", "qxl"])
1728

    
1729
    # Various types of usb devices, comma separated
1730
    if hvp[constants.HV_USB_DEVICES]:
1731
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1732
        kvm_cmd.extend(["-usbdevice", dev])
1733

    
1734
    # Set system UUID to instance UUID
1735
    if self._UUID_RE.search(kvmhelp):
1736
      kvm_cmd.extend(["-uuid", instance.uuid])
1737

    
1738
    if hvp[constants.HV_KVM_EXTRA]:
1739
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1740

    
1741
    pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1742
    kvm_disks = []
1743
    for disk, link_name, uri in block_devices:
1744
      _UpdatePCISlots(disk, pci_reservations)
1745
      kvm_disks.append((disk, link_name, uri))
1746

    
1747
    kvm_nics = []
1748
    for nic in instance.nics:
1749
      _UpdatePCISlots(nic, pci_reservations)
1750
      kvm_nics.append(nic)
1751

    
1752
    hvparams = hvp
1753

    
1754
    return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1755

    
1756
  def _WriteKVMRuntime(self, instance_name, data):
1757
    """Write an instance's KVM runtime
1758

1759
    """
1760
    try:
1761
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1762
                      data=data)
1763
    except EnvironmentError, err:
1764
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1765

    
1766
  def _ReadKVMRuntime(self, instance_name):
1767
    """Read an instance's KVM runtime
1768

1769
    """
1770
    try:
1771
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1772
    except EnvironmentError, err:
1773
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1774
    return file_content
1775

    
1776
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1777
    """Save an instance's KVM runtime
1778

1779
    """
1780
    kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1781

    
1782
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1783
    serialized_disks = [(blk.ToDict(), link, uri)
1784
                        for blk, link, uri in kvm_disks]
1785
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1786
                                      serialized_disks))
1787

    
1788
    self._WriteKVMRuntime(instance.name, serialized_form)
1789

    
1790
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1791
    """Load an instance's KVM runtime
1792

1793
    """
1794
    if not serialized_runtime:
1795
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1796

    
1797
    return _AnalyzeSerializedRuntime(serialized_runtime)
1798

    
1799
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1800
    """Run the KVM cmd and check for errors
1801

1802
    @type name: string
1803
    @param name: instance name
1804
    @type kvm_cmd: list of strings
1805
    @param kvm_cmd: runcmd input for kvm
1806
    @type tap_fds: list of int
1807
    @param tap_fds: fds of tap devices opened by Ganeti
1808

1809
    """
1810
    try:
1811
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1812
    finally:
1813
      for fd in tap_fds:
1814
        utils_wrapper.CloseFdNoError(fd)
1815

    
1816
    if result.failed:
1817
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1818
                                   (name, result.fail_reason, result.output))
1819
    if not self._InstancePidAlive(name)[2]:
1820
      raise errors.HypervisorError("Failed to start instance %s" % name)
1821

    
1822
  @staticmethod
1823
  def _GenerateTapName(nic):
1824
    """Generate a TAP network interface name for a NIC.
1825

1826
    This helper function generates a special TAP network interface
1827
    name for NICs that are meant to be used in instance communication.
1828
    This function checks the existing TAP interfaces in order to find
1829
    a unique name for the new TAP network interface.  The TAP network
1830
    interface names are of the form 'gnt.com.%d', where '%d' is a
1831
    unique number within the node.
1832

1833
    @type nic: ganeti.objects.NIC
1834
    @param nic: NIC object for the name should be generated
1835

1836
    @rtype: string
1837
    @return: TAP network interface name, or the empty string if the
1838
             NIC is not used in instance communication
1839

1840
    """
1841
    if nic.name is None or not \
1842
          nic.name.startswith(constants.INSTANCE_COMMUNICATION_NIC_PREFIX):
1843
      return ""
1844

    
1845
    result = utils.RunCmd(["ip", "tuntap", "list"])
1846

    
1847
    if result.failed:
1848
      raise errors.HypervisorError("Failed to list TUN/TAP interfaces")
1849

    
1850
    idxs = set()
1851

    
1852
    for line in result.output.splitlines():
1853
      parts = line.split(": ", 1)
1854

    
1855
      if len(parts) < 2:
1856
        raise errors.HypervisorError("Failed to parse TUN/TAP interfaces")
1857

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

    
1860
      if r is not None:
1861
        idxs.add(int(r.group(1)))
1862

    
1863
    if idxs:
1864
      idx = max(idxs) + 1
1865
    else:
1866
      idx = 0
1867

    
1868
    return "gnt.com.%d" % idx
1869

    
1870
  # too many local variables
1871
  # pylint: disable=R0914
1872
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1873
    """Execute a KVM cmd, after completing it with some last minute data.
1874

1875
    @type incoming: tuple of strings
1876
    @param incoming: (target_host_ip, port)
1877
    @type kvmhelp: string
1878
    @param kvmhelp: output of kvm --help
1879

1880
    """
1881
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1882
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1883
    #    have changed since the instance started; only use them if the change
1884
    #    won't affect the inside of the instance (which hasn't been rebooted).
1885
    #  - up_hvp contains the parameters as they were when the instance was
1886
    #    started, plus any new parameter which has been added between ganeti
1887
    #    versions: it is paramount that those default to a value which won't
1888
    #    affect the inside of the instance as well.
1889
    conf_hvp = instance.hvparams
1890
    name = instance.name
1891
    self._CheckDown(name)
1892

    
1893
    self._ClearUserShutdown(instance.name)
1894
    self._StartKvmd(instance.hvparams)
1895

    
1896
    temp_files = []
1897

    
1898
    kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1899
    # the first element of kvm_cmd is always the path to the kvm binary
1900
    kvm_path = kvm_cmd[0]
1901
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1902

    
1903
    # We know it's safe to run as a different user upon migration, so we'll use
1904
    # the latest conf, from conf_hvp.
1905
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1906
    if security_model == constants.HT_SM_USER:
1907
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1908

    
1909
    keymap = conf_hvp[constants.HV_KEYMAP]
1910
    if keymap:
1911
      keymap_path = self._InstanceKeymapFile(name)
1912
      # If a keymap file is specified, KVM won't use its internal defaults. By
1913
      # first including the "en-us" layout, an error on loading the actual
1914
      # layout (e.g. because it can't be found) won't lead to a non-functional
1915
      # keyboard. A keyboard with incorrect keys is still better than none.
1916
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1917
      kvm_cmd.extend(["-k", keymap_path])
1918

    
1919
    # We have reasons to believe changing something like the nic driver/type
1920
    # upon migration won't exactly fly with the instance kernel, so for nic
1921
    # related parameters we'll use up_hvp
1922
    tapfds = []
1923
    taps = []
1924
    devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1925
    if not kvm_nics:
1926
      kvm_cmd.extend(["-net", "none"])
1927
    else:
1928
      vnet_hdr = False
1929
      tap_extra = ""
1930
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1931
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1932
        nic_model = self._VIRTIO
1933
        try:
1934
          if self._VIRTIO_NET_RE.search(devlist):
1935
            nic_model = self._VIRTIO_NET_PCI
1936
            vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1937
        except errors.HypervisorError, _:
1938
          # Older versions of kvm don't support DEVICE_LIST, but they don't
1939
          # have new virtio syntax either.
1940
          pass
1941

    
1942
        if up_hvp[constants.HV_VHOST_NET]:
1943
          # check for vhost_net support
1944
          if self._VHOST_RE.search(kvmhelp):
1945
            tap_extra = ",vhost=on"
1946
          else:
1947
            raise errors.HypervisorError("vhost_net is configured"
1948
                                         " but it is not available")
1949
      else:
1950
        nic_model = nic_type
1951

    
1952
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1953

    
1954
      for nic_seq, nic in enumerate(kvm_nics):
1955
        tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr,
1956
                                  name=self._GenerateTapName(nic))
1957
        tapfds.append(tapfd)
1958
        taps.append(tapname)
1959
        if kvm_supports_netdev:
1960
          nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1961
          try:
1962
            # kvm_nics already exist in old runtime files and thus there might
1963
            # be some entries without pci slot (therefore try: except:)
1964
            kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1965
            netdev = kvm_devid
1966
            nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1967
          except errors.HotplugError:
1968
            netdev = "netdev%d" % nic_seq
1969
          nic_val += (",netdev=%s" % netdev)
1970
          tap_val = ("type=tap,id=%s,fd=%d%s" %
1971
                     (netdev, tapfd, tap_extra))
1972
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1973
        else:
1974
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1975
                                                         nic.mac, nic_model)
1976
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1977
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1978

    
1979
    if incoming:
1980
      target, port = incoming
1981
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1982

    
1983
    # Changing the vnc password doesn't bother the guest that much. At most it
1984
    # will surprise people who connect to it. Whether positively or negatively
1985
    # it's debatable.
1986
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1987
    vnc_pwd = None
1988
    if vnc_pwd_file:
1989
      try:
1990
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1991
      except EnvironmentError, err:
1992
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1993
                                     % (vnc_pwd_file, err))
1994

    
1995
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1996
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1997
                         constants.SECURE_DIR_MODE)])
1998

    
1999
    # Automatically enable QMP if version is >= 0.14
2000
    if self._QMP_RE.search(kvmhelp):
2001
      logging.debug("Enabling QMP")
2002
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
2003
                      self._InstanceQmpMonitor(instance.name)])
2004

    
2005
    # Configure the network now for starting instances and bridged interfaces,
2006
    # during FinalizeMigration for incoming instances' routed interfaces
2007
    for nic_seq, nic in enumerate(kvm_nics):
2008
      if (incoming and
2009
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
2010
        continue
2011
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
2012

    
2013
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
2014
                                                     kvm_disks,
2015
                                                     kvmhelp,
2016
                                                     devlist)
2017
    kvm_cmd.extend(bdev_opts)
2018
    # CPU affinity requires kvm to start paused, so we set this flag if the
2019
    # instance is not already paused and if we are not going to accept a
2020
    # migrating instance. In the latter case, pausing is not needed.
2021
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
2022
    if start_kvm_paused:
2023
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
2024

    
2025
    # Note: CPU pinning is using up_hvp since changes take effect
2026
    # during instance startup anyway, and to avoid problems when soft
2027
    # rebooting the instance.
2028
    cpu_pinning = False
2029
    if up_hvp.get(constants.HV_CPU_MASK, None):
2030
      cpu_pinning = True
2031

    
2032
    if security_model == constants.HT_SM_POOL:
2033
      ss = ssconf.SimpleStore()
2034
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
2035
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
2036
      uid = uidpool.RequestUnusedUid(all_uids)
2037
      try:
2038
        username = pwd.getpwuid(uid.GetUid()).pw_name
2039
        kvm_cmd.extend(["-runas", username])
2040
        self._RunKVMCmd(name, kvm_cmd, tapfds)
2041
      except:
2042
        uidpool.ReleaseUid(uid)
2043
        raise
2044
      else:
2045
        uid.Unlock()
2046
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
2047
    else:
2048
      self._RunKVMCmd(name, kvm_cmd, tapfds)
2049

    
2050
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
2051
                     constants.RUN_DIRS_MODE)])
2052
    for nic_seq, tap in enumerate(taps):
2053
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
2054
                      data=tap)
2055

    
2056
    if vnc_pwd:
2057
      change_cmd = "change vnc password %s" % vnc_pwd
2058
      self._CallMonitorCommand(instance.name, change_cmd)
2059

    
2060
    # Setting SPICE password. We are not vulnerable to malicious passwordless
2061
    # connection attempts because SPICE by default does not allow connections
2062
    # if neither a password nor the "disable_ticketing" options are specified.
2063
    # As soon as we send the password via QMP, that password is a valid ticket
2064
    # for connection.
2065
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
2066
    if spice_password_file:
2067
      spice_pwd = ""
2068
      try:
2069
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
2070
      except EnvironmentError, err:
2071
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
2072
                                     % (spice_password_file, err))
2073

    
2074
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
2075
      qmp.connect()
2076
      arguments = {
2077
          "protocol": "spice",
2078
          "password": spice_pwd,
2079
      }
2080
      qmp.Execute("set_password", arguments)
2081

    
2082
    for filename in temp_files:
2083
      utils.RemoveFile(filename)
2084

    
2085
    # If requested, set CPU affinity and resume instance execution
2086
    if cpu_pinning:
2087
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
2088

    
2089
    start_memory = self._InstanceStartupMemory(instance)
2090
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
2091
      self.BalloonInstanceMemory(instance, start_memory)
2092

    
2093
    if start_kvm_paused:
2094
      # To control CPU pinning, ballooning, and vnc/spice passwords
2095
      # the VM was started in a frozen state. If freezing was not
2096
      # explicitly requested resume the vm status.
2097
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2098

    
2099
  @staticmethod
2100
  def _StartKvmd(hvparams):
2101
    """Ensure that the Kvm daemon is running.
2102

2103
    """
2104
    if hvparams is None \
2105
          or not hvparams[constants.HV_KVM_USER_SHUTDOWN] \
2106
          or utils.IsDaemonAlive(constants.KVMD):
2107
      return
2108

    
2109
    result = utils.RunCmd(constants.KVMD)
2110

    
2111
    if result.failed:
2112
      raise errors.HypervisorError("Failed to start KVM daemon")
2113

    
2114
  def StartInstance(self, instance, block_devices, startup_paused):
2115
    """Start an instance.
2116

2117
    """
2118
    self._CheckDown(instance.name)
2119
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2120
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2121
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
2122
                                           startup_paused, kvmhelp)
2123
    self._SaveKVMRuntime(instance, kvm_runtime)
2124
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2125

    
2126
  @classmethod
2127
  def _CallMonitorCommand(cls, instance_name, command):
2128
    """Invoke a command on the instance monitor.
2129

2130
    """
2131
    # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
2132
    # version. The monitor protocol is designed for human consumption, whereas
2133
    # QMP is made for programmatic usage. In the worst case QMP can also
2134
    # execute monitor commands. As it is, all calls to socat take at least
2135
    # 500ms and likely more: socat can't detect the end of the reply and waits
2136
    # for 500ms of no data received before exiting (500 ms is the default for
2137
    # the "-t" parameter).
2138
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
2139
             (utils.ShellQuote(command),
2140
              constants.SOCAT_PATH,
2141
              utils.ShellQuote(cls._InstanceMonitor(instance_name))))
2142
    result = utils.RunCmd(socat)
2143
    if result.failed:
2144
      msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
2145
             " output: %s" %
2146
             (command, instance_name, result.fail_reason, result.output))
2147
      raise errors.HypervisorError(msg)
2148

    
2149
    return result
2150

    
2151
  def _GetFreePCISlot(self, instance, dev):
2152
    """Get the first available pci slot of a runnung instance.
2153

2154
    """
2155
    slots = bitarray(32)
2156
    slots.setall(False) # pylint: disable=E1101
2157
    output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
2158
    for line in output.stdout.splitlines():
2159
      match = self._INFO_PCI_RE.search(line)
2160
      if match:
2161
        slot = int(match.group(1))
2162
        slots[slot] = True
2163

    
2164
    [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
2165
    if not free:
2166
      raise errors.HypervisorError("All PCI slots occupied")
2167

    
2168
    dev.pci = int(free)
2169

    
2170
  def VerifyHotplugSupport(self, instance, action, dev_type):
2171
    """Verifies that hotplug is supported.
2172

2173
    Hotplug is *not* supported in case of:
2174
     - security models and chroot (disk hotplug)
2175
     - fdsend module is missing (nic hot-add)
2176

2177
    @raise errors.HypervisorError: in one of the previous cases
2178

2179
    """
2180
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2181
      hvp = instance.hvparams
2182
      security_model = hvp[constants.HV_SECURITY_MODEL]
2183
      use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
2184
      if use_chroot:
2185
        raise errors.HotplugError("Disk hotplug is not supported"
2186
                                  " in case of chroot.")
2187
      if security_model != constants.HT_SM_NONE:
2188
        raise errors.HotplugError("Disk Hotplug is not supported in case"
2189
                                  " security models are used.")
2190

    
2191
    if (dev_type == constants.HOTPLUG_TARGET_NIC and
2192
        action == constants.HOTPLUG_ACTION_ADD and not fdsend):
2193
      raise errors.HotplugError("Cannot hot-add NIC."
2194
                                " fdsend python module is missing.")
2195

    
2196
  def HotplugSupported(self, instance):
2197
    """Checks if hotplug is generally supported.
2198

2199
    Hotplug is *not* supported in case of:
2200
     - qemu versions < 1.0
2201
     - for stopped instances
2202

2203
    @raise errors.HypervisorError: in one of the previous cases
2204

2205
    """
2206
    try:
2207
      output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2208
    except errors.HypervisorError:
2209
      raise errors.HotplugError("Instance is probably down")
2210

    
2211
    # TODO: search for netdev_add, drive_add, device_add.....
2212
    match = self._INFO_VERSION_RE.search(output.stdout)
2213
    if not match:
2214
      raise errors.HotplugError("Cannot parse qemu version via monitor")
2215

    
2216
    v_major, v_min, _, _ = match.groups()
2217
    if (int(v_major), int(v_min)) < (1, 0):
2218
      raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2219

    
2220
  def _CallHotplugCommand(self, name, cmd):
2221
    output = self._CallMonitorCommand(name, cmd)
2222
    # TODO: parse output and check if succeeded
2223
    for line in output.stdout.splitlines():
2224
      logging.info("%s", line)
2225

    
2226
  def HotAddDevice(self, instance, dev_type, device, extra, seq):
2227
    """ Helper method to hot-add a new device
2228

2229
    It gets free pci slot generates the device name and invokes the
2230
    device specific method.
2231

2232
    """
2233
    # in case of hot-mod this is given
2234
    if device.pci is None:
2235
      self._GetFreePCISlot(instance, device)
2236
    kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2237
    runtime = self._LoadKVMRuntime(instance)
2238
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2239
      command = "drive_add dummy file=%s,if=none,id=%s,format=raw\n" % \
2240
                 (extra, kvm_devid)
2241
      command += ("device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
2242
                  (hex(device.pci), kvm_devid, kvm_devid))
2243
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
2244
      (tap, fd) = _OpenTap()
2245
      self._ConfigureNIC(instance, seq, device, tap)
2246
      self._PassTapFd(instance, fd, device)
2247
      command = "netdev_add tap,id=%s,fd=%s\n" % (kvm_devid, kvm_devid)
2248
      args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
2249
               (hex(device.pci), device.mac, kvm_devid, kvm_devid)
2250
      command += "device_add %s" % args
2251
      utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
2252

    
2253
    self._CallHotplugCommand(instance.name, command)
2254
    # update relevant entries in runtime file
2255
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2256
    entry = _RUNTIME_ENTRY[dev_type](device, extra)
2257
    runtime[index].append(entry)
2258
    self._SaveKVMRuntime(instance, runtime)
2259

    
2260
  def HotDelDevice(self, instance, dev_type, device, _, seq):
2261
    """ Helper method for hot-del device
2262

2263
    It gets device info from runtime file, generates the device name and
2264
    invokes the device specific method.
2265

2266
    """
2267
    runtime = self._LoadKVMRuntime(instance)
2268
    entry = _GetExistingDeviceInfo(dev_type, device, runtime)
2269
    kvm_device = _RUNTIME_DEVICE[dev_type](entry)
2270
    kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
2271
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2272
      command = "device_del %s\n" % kvm_devid
2273
      command += "drive_del %s" % kvm_devid
2274
    elif dev_type == constants.HOTPLUG_TARGET_NIC:
2275
      command = "device_del %s\n" % kvm_devid
2276
      command += "netdev_del %s" % kvm_devid
2277
      utils.RemoveFile(self._InstanceNICFile(instance.name, seq))
2278
    self._CallHotplugCommand(instance.name, command)
2279
    index = _DEVICE_RUNTIME_INDEX[dev_type]
2280
    runtime[index].remove(entry)
2281
    self._SaveKVMRuntime(instance, runtime)
2282

    
2283
    return kvm_device.pci
2284

    
2285
  def HotModDevice(self, instance, dev_type, device, _, seq):
2286
    """ Helper method for hot-mod device
2287

2288
    It gets device info from runtime file, generates the device name and
2289
    invokes the device specific method. Currently only NICs support hot-mod
2290

2291
    """
2292
    if dev_type == constants.HOTPLUG_TARGET_NIC:
2293
      # putting it back in the same pci slot
2294
      device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2295
      # TODO: remove sleep when socat gets removed
2296
      time.sleep(2)
2297
      self.HotAddDevice(instance, dev_type, device, _, seq)
2298

    
2299
  def _PassTapFd(self, instance, fd, nic):
2300
    """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2301

2302
    """
2303
    # TODO: factor out code related to unix sockets.
2304
    #       squash common parts between monitor and qmp
2305
    kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2306
    command = "getfd %s\n" % kvm_devid
2307
    fds = [fd]
2308
    logging.info("%s", fds)
2309
    try:
2310
      monsock = MonitorSocket(self._InstanceMonitor(instance.name))
2311
      monsock.connect()
2312
      fdsend.sendfds(monsock.sock, command, fds=fds)
2313
    finally:
2314
      monsock.close()
2315

    
2316
  @classmethod
2317
  def _ParseKVMVersion(cls, text):
2318
    """Parse the KVM version from the --help output.
2319

2320
    @type text: string
2321
    @param text: output of kvm --help
2322
    @return: (version, v_maj, v_min, v_rev)
2323
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2324

2325
    """
2326
    match = cls._VERSION_RE.search(text.splitlines()[0])
2327
    if not match:
2328
      raise errors.HypervisorError("Unable to get KVM version")
2329

    
2330
    v_all = match.group(0)
2331
    v_maj = int(match.group(1))
2332
    v_min = int(match.group(2))
2333
    if match.group(4):
2334
      v_rev = int(match.group(4))
2335
    else:
2336
      v_rev = 0
2337
    return (v_all, v_maj, v_min, v_rev)
2338

    
2339
  @classmethod
2340
  def _GetKVMOutput(cls, kvm_path, option):
2341
    """Return the output of a kvm invocation
2342

2343
    @type kvm_path: string
2344
    @param kvm_path: path to the kvm executable
2345
    @type option: a key of _KVMOPTS_CMDS
2346
    @param option: kvm option to fetch the output from
2347
    @return: output a supported kvm invocation
2348
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2349

2350
    """
2351
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2352

    
2353
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
2354

    
2355
    result = utils.RunCmd([kvm_path] + optlist)
2356
    if result.failed and not can_fail:
2357
      raise errors.HypervisorError("Unable to get KVM %s output" %
2358
                                    " ".join(optlist))
2359
    return result.output
2360

    
2361
  @classmethod
2362
  def _GetKVMVersion(cls, kvm_path):
2363
    """Return the installed KVM version.
2364

2365
    @return: (version, v_maj, v_min, v_rev)
2366
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
2367

2368
    """
2369
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2370

    
2371
  @classmethod
2372
  def _GetDefaultMachineVersion(cls, kvm_path):
2373
    """Return the default hardware revision (e.g. pc-1.1)
2374

2375
    """
2376
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2377
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2378
    if match:
2379
      return match.group(1)
2380
    else:
2381
      return "pc"
2382

    
2383
  @classmethod
2384
  def _StopInstance(cls, instance, force=False, name=None):
2385
    """Stop an instance.
2386

2387
    """
2388
    if name is not None and not force:
2389
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2390
    if name is None:
2391
      name = instance.name
2392
      acpi = instance.hvparams[constants.HV_ACPI]
2393
    else:
2394
      acpi = False
2395
    _, pid, alive = cls._InstancePidAlive(name)
2396
    if pid > 0 and alive:
2397
      if force or not acpi:
2398
        utils.KillProcess(pid)
2399
      else:
2400
        cls._CallMonitorCommand(name, "system_powerdown")
2401
    cls._ClearUserShutdown(instance.name)
2402

    
2403
  def StopInstance(self, instance, force=False, retry=False, name=None):
2404
    """Stop an instance.
2405

2406
    """
2407
    self._StopInstance(instance, force, name)
2408

    
2409
  def CleanupInstance(self, instance_name):
2410
    """Cleanup after a stopped instance
2411

2412
    """
2413
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
2414
    if pid > 0 and alive:
2415
      raise errors.HypervisorError("Cannot cleanup a live instance")
2416
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2417
    self._ClearUserShutdown(instance_name)
2418

    
2419
  def RebootInstance(self, instance):
2420
    """Reboot an instance.
2421

2422
    """
2423
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2424
    # socket the instance will stop, but now power up again. So we'll resort
2425
    # to shutdown and restart.
2426
    _, _, alive = self._InstancePidAlive(instance.name)
2427
    if not alive:
2428
      raise errors.HypervisorError("Failed to reboot instance %s:"
2429
                                   " not running" % instance.name)
2430
    # StopInstance will delete the saved KVM runtime so:
2431
    # ...first load it...
2432
    kvm_runtime = self._LoadKVMRuntime(instance)
2433
    # ...now we can safely call StopInstance...
2434
    if not self.StopInstance(instance):
2435
      self.StopInstance(instance, force=True)
2436
    # ...and finally we can save it again, and execute it...
2437
    self._SaveKVMRuntime(instance, kvm_runtime)
2438
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2439
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2440
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2441

    
2442
  def MigrationInfo(self, instance):
2443
    """Get instance information to perform a migration.
2444

2445
    @type instance: L{objects.Instance}
2446
    @param instance: instance to be migrated
2447
    @rtype: string
2448
    @return: content of the KVM runtime file
2449

2450
    """
2451
    return self._ReadKVMRuntime(instance.name)
2452

    
2453
  def AcceptInstance(self, instance, info, target):
2454
    """Prepare to accept an instance.
2455

2456
    @type instance: L{objects.Instance}
2457
    @param instance: instance to be accepted
2458
    @type info: string
2459
    @param info: content of the KVM runtime file on the source node
2460
    @type target: string
2461
    @param target: target host (usually ip), on this node
2462

2463
    """
2464
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2465
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2466
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2467
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2468
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2469
                            incoming=incoming_address)
2470

    
2471
  def FinalizeMigrationDst(self, instance, info, success):
2472
    """Finalize the instance migration on the target node.
2473

2474
    Stop the incoming mode KVM.
2475

2476
    @type instance: L{objects.Instance}
2477
    @param instance: instance whose migration is being finalized
2478

2479
    """
2480
    if success:
2481
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2482
      kvm_nics = kvm_runtime[1]
2483

    
2484
      for nic_seq, nic in enumerate(kvm_nics):
2485
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2486
          # Bridged interfaces have already been configured
2487
          continue
2488
        try:
2489
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2490
        except EnvironmentError, err:
2491
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
2492
                          instance.name, nic_seq, str(err))
2493
          continue
2494
        try:
2495
          self._ConfigureNIC(instance, nic_seq, nic, tap)
2496
        except errors.HypervisorError, err:
2497
          logging.warning(str(err))
2498

    
2499
      self._WriteKVMRuntime(instance.name, info)
2500
    else:
2501
      self.StopInstance(instance, force=True)
2502

    
2503
  def MigrateInstance(self, cluster_name, instance, target, live):
2504
    """Migrate an instance to a target node.
2505

2506
    The migration will not be attempted if the instance is not
2507
    currently running.
2508

2509
    @type cluster_name: string
2510
    @param cluster_name: name of the cluster
2511
    @type instance: L{objects.Instance}
2512
    @param instance: the instance to be migrated
2513
    @type target: string
2514
    @param target: ip address of the target node
2515
    @type live: boolean
2516
    @param live: perform a live migration
2517

2518
    """
2519
    instance_name = instance.name
2520
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
2521
    _, _, alive = self._InstancePidAlive(instance_name)
2522
    if not alive:
2523
      raise errors.HypervisorError("Instance not running, cannot migrate")
2524

    
2525
    if not live:
2526
      self._CallMonitorCommand(instance_name, "stop")
2527

    
2528
    migrate_command = ("migrate_set_speed %dm" %
2529
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2530
    self._CallMonitorCommand(instance_name, migrate_command)
2531

    
2532
    migrate_command = ("migrate_set_downtime %dms" %
2533
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2534
    self._CallMonitorCommand(instance_name, migrate_command)
2535

    
2536
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2537
    self._CallMonitorCommand(instance_name, migrate_command)
2538

    
2539
  def FinalizeMigrationSource(self, instance, success, live):
2540
    """Finalize the instance migration on the source node.
2541

2542
    @type instance: L{objects.Instance}
2543
    @param instance: the instance that was migrated
2544
    @type success: bool
2545
    @param success: whether the migration succeeded or not
2546
    @type live: bool
2547
    @param live: whether the user requested a live migration or not
2548

2549
    """
2550
    if success:
2551
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
2552
      utils.KillProcess(pid)
2553
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2554
    elif live:
2555
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
2556
    self._ClearUserShutdown(instance.name)
2557

    
2558
  def GetMigrationStatus(self, instance):
2559
    """Get the migration status
2560

2561
    @type instance: L{objects.Instance}
2562
    @param instance: the instance that is being migrated
2563
    @rtype: L{objects.MigrationStatus}
2564
    @return: the status of the current migration (one of
2565
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2566
             progress info that can be retrieved from the hypervisor
2567

2568
    """
2569
    info_command = "info migrate"
2570
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2571
      result = self._CallMonitorCommand(instance.name, info_command)
2572
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
2573
      if not match:
2574
        if not result.stdout:
2575
          logging.info("KVM: empty 'info migrate' result")
2576
        else:
2577
          logging.warning("KVM: unknown 'info migrate' result: %s",
2578
                          result.stdout)
2579
      else:
2580
        status = match.group(1)
2581
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2582
          migration_status = objects.MigrationStatus(status=status)
2583
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2584
          if match:
2585
            migration_status.transferred_ram = match.group("transferred")
2586
            migration_status.total_ram = match.group("total")
2587

    
2588
          return migration_status
2589

    
2590
        logging.warning("KVM: unknown migration status '%s'", status)
2591

    
2592
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2593

    
2594
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2595

    
2596
  def BalloonInstanceMemory(self, instance, mem):
2597
    """Balloon an instance memory to a certain value.
2598

2599
    @type instance: L{objects.Instance}
2600
    @param instance: instance to be accepted
2601
    @type mem: int
2602
    @param mem: actual memory size to use for instance runtime
2603

2604
    """
2605
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2606

    
2607
  def GetNodeInfo(self, hvparams=None):
2608
    """Return information about the node.
2609

2610
    @type hvparams: dict of strings
2611
    @param hvparams: hypervisor parameters, not used in this class
2612

2613
    @return: a dict as returned by L{BaseHypervisor.GetLinuxNodeInfo} plus
2614
        the following keys:
2615
          - hv_version: the hypervisor version in the form (major, minor,
2616
                        revision)
2617

2618
    """
2619
    result = self.GetLinuxNodeInfo()
2620
    kvmpath = constants.KVM_PATH
2621
    if hvparams is not None:
2622
      kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2623
    _, v_major, v_min, v_rev = self._GetKVMVersion(kvmpath)
2624
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2625
    return result
2626

    
2627
  @classmethod
2628
  def GetInstanceConsole(cls, instance, primary_node, node_group,
2629
                         hvparams, beparams):
2630
    """Return a command for connecting to the console of an instance.
2631

2632
    """
2633
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2634
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2635
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2636
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2637
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2638
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2639
      ndparams = node_group.FillND(primary_node)
2640
      return objects.InstanceConsole(instance=instance.name,
2641
                                     kind=constants.CONS_SSH,
2642
                                     host=primary_node.name,
2643
                                     port=ndparams.get(constants.ND_SSH_PORT),
2644
                                     user=constants.SSH_CONSOLE_USER,
2645
                                     command=cmd)
2646

    
2647
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2648
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2649
      display = instance.network_port - constants.VNC_BASE_PORT
2650
      return objects.InstanceConsole(instance=instance.name,
2651
                                     kind=constants.CONS_VNC,
2652
                                     host=vnc_bind_address,
2653
                                     port=instance.network_port,
2654
                                     display=display)
2655

    
2656
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2657
    if spice_bind:
2658
      return objects.InstanceConsole(instance=instance.name,
2659
                                     kind=constants.CONS_SPICE,
2660
                                     host=spice_bind,
2661
                                     port=instance.network_port)
2662

    
2663
    return objects.InstanceConsole(instance=instance.name,
2664
                                   kind=constants.CONS_MESSAGE,
2665
                                   message=("No serial shell for instance %s" %
2666
                                            instance.name))
2667

    
2668
  def Verify(self, hvparams=None):
2669
    """Verify the hypervisor.
2670

2671
    Check that the required binaries exist.
2672

2673
    @type hvparams: dict of strings
2674
    @param hvparams: hypervisor parameters to be verified against, not used here
2675

2676
    @return: Problem description if something is wrong, C{None} otherwise
2677

2678
    """
2679
    msgs = []
2680
    kvmpath = constants.KVM_PATH
2681
    if hvparams is not None:
2682
      kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2683
    if not os.path.exists(kvmpath):
2684
      msgs.append("The KVM binary ('%s') does not exist" % kvmpath)
2685
    if not os.path.exists(constants.SOCAT_PATH):
2686
      msgs.append("The socat binary ('%s') does not exist" %
2687
                  constants.SOCAT_PATH)
2688

    
2689
    return self._FormatVerifyResults(msgs)
2690

    
2691
  @classmethod
2692
  def CheckParameterSyntax(cls, hvparams):
2693
    """Check the given parameters for validity.
2694

2695
    @type hvparams:  dict
2696
    @param hvparams: dictionary with parameter names/value
2697
    @raise errors.HypervisorError: when a parameter is not valid
2698

2699
    """
2700
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2701

    
2702
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2703
    if kernel_path:
2704
      if not hvparams[constants.HV_ROOT_PATH]:
2705
        raise errors.HypervisorError("Need a root partition for the instance,"
2706
                                     " if a kernel is defined")
2707

    
2708
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2709
        not hvparams[constants.HV_VNC_X509]):
2710
      raise errors.HypervisorError("%s must be defined, if %s is" %
2711
                                   (constants.HV_VNC_X509,
2712
                                    constants.HV_VNC_X509_VERIFY))
2713

    
2714
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2715
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2716
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2717
      if not serial_speed or serial_speed not in valid_speeds:
2718
        raise errors.HypervisorError("Invalid serial console speed, must be"
2719
                                     " one of: %s" %
2720
                                     utils.CommaJoin(valid_speeds))
2721

    
2722
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2723
    if (boot_order == constants.HT_BO_CDROM and
2724
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2725
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2726
                                   " ISO path")
2727

    
2728
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2729
    if security_model == constants.HT_SM_USER:
2730
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2731
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2732
                                     " must be specified")
2733
    elif (security_model == constants.HT_SM_NONE or
2734
          security_model == constants.HT_SM_POOL):
2735
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2736
        raise errors.HypervisorError("Cannot have a security domain when the"
2737
                                     " security model is 'none' or 'pool'")
2738

    
2739
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2740
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2741
    if spice_bind:
2742
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2743
        # if an IP version is specified, the spice_bind parameter must be an
2744
        # IP of that family
2745
        if (netutils.IP4Address.IsValid(spice_bind) and
2746
            spice_ip_version != constants.IP4_VERSION):
2747
          raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2748
                                       " the specified IP version is %s" %
2749
                                       (spice_bind, spice_ip_version))
2750

    
2751
        if (netutils.IP6Address.IsValid(spice_bind) and
2752
            spice_ip_version != constants.IP6_VERSION):
2753
          raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2754
                                       " the specified IP version is %s" %
2755
                                       (spice_bind, spice_ip_version))
2756
    else:
2757
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2758
      # error if any of them is set without it.
2759
      for param in _SPICE_ADDITIONAL_PARAMS:
2760
        if hvparams[param]:
2761
          raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2762
                                       (param, constants.HV_KVM_SPICE_BIND))
2763

    
2764
  @classmethod
2765
  def ValidateParameters(cls, hvparams):
2766
    """Check the given parameters for validity.
2767

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

2772
    """
2773
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2774

    
2775
    kvm_path = hvparams[constants.HV_KVM_PATH]
2776

    
2777
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2778
    if security_model == constants.HT_SM_USER:
2779
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2780
      try:
2781
        pwd.getpwnam(username)
2782
      except KeyError:
2783
        raise errors.HypervisorError("Unknown security domain user %s"
2784
                                     % username)
2785
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2786
    if vnc_bind_address:
2787
      bound_to_addr = netutils.IP4Address.IsValid(vnc_bind_address)
2788
      is_interface = netutils.IsValidInterface(vnc_bind_address)
2789
      is_path = utils.IsNormAbsPath(vnc_bind_address)
2790
      if not bound_to_addr and not is_interface and not is_path:
2791
        raise errors.HypervisorError("VNC: The %s parameter must be either"
2792
                                     " a valid IP address, an interface name,"
2793
                                     " or an absolute path" %
2794
                                     constants.HV_KVM_SPICE_BIND)
2795

    
2796
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2797
    if spice_bind:
2798
      # only one of VNC and SPICE can be used currently.
2799
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2800
        raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2801
                                     " only one of them can be used at a"
2802
                                     " given time")
2803

    
2804
      # check that KVM supports SPICE
2805
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2806
      if not cls._SPICE_RE.search(kvmhelp):
2807
        raise errors.HypervisorError("SPICE is configured, but it is not"
2808
                                     " supported according to 'kvm --help'")
2809

    
2810
      # if spice_bind is not an IP address, it must be a valid interface
2811
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2812
                       netutils.IP6Address.IsValid(spice_bind))
2813
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2814
        raise errors.HypervisorError("SPICE: The %s parameter must be either"
2815
                                     " a valid IP address or interface name" %
2816
                                     constants.HV_KVM_SPICE_BIND)
2817

    
2818
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2819
    if machine_version:
2820
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2821
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2822
        raise errors.HypervisorError("Unsupported machine version: %s" %
2823
                                     machine_version)
2824

    
2825
  @classmethod
2826
  def PowercycleNode(cls, hvparams=None):
2827
    """KVM powercycle, just a wrapper over Linux powercycle.
2828

2829
    @type hvparams: dict of strings
2830
    @param hvparams: hypervisor params to be used on this node
2831

2832
    """
2833
    cls.LinuxPowercycle()