Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 6f1e1921

History | View | Annotate | Download (78.9 kB)

1
#
2
#
3

    
4
# Copyright (C) 2008, 2009, 2010, 2011, 2012 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

    
21

    
22
"""KVM hypervisor
23

24
"""
25

    
26
import errno
27
import os
28
import os.path
29
import re
30
import tempfile
31
import time
32
import logging
33
import pwd
34
import struct
35
import fcntl
36
import shutil
37
import socket
38
import stat
39
import StringIO
40
try:
41
  import affinity   # pylint: disable=F0401
42
except ImportError:
43
  affinity = None
44

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

    
57

    
58
_KVM_NETWORK_SCRIPT = pathutils.CONF_DIR + "/kvm-vif-bridge"
59
_KVM_START_PAUSED_FLAG = "-S"
60

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

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

    
82

    
83
def _ProbeTapVnetHdr(fd):
84
  """Check whether to enable the IFF_VNET_HDR flag.
85

86
  To do this, _all_ of the following conditions must be met:
87
   1. TUNGETFEATURES ioctl() *must* be implemented
88
   2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
89
   3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
90
      drivers/net/tun.c there is no way to test this until after the tap device
91
      has been created using TUNSETIFF, and there is no way to change the
92
      IFF_VNET_HDR flag after creating the interface, catch-22! However both
93
      TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
94
      thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
95

96
   @type fd: int
97
   @param fd: the file descriptor of /dev/net/tun
98

99
  """
100
  req = struct.pack("I", 0)
101
  try:
102
    res = fcntl.ioctl(fd, TUNGETFEATURES, req)
103
  except EnvironmentError:
104
    logging.warning("TUNGETFEATURES ioctl() not implemented")
105
    return False
106

    
107
  tunflags = struct.unpack("I", res)[0]
108
  if tunflags & IFF_VNET_HDR:
109
    return True
110
  else:
111
    logging.warning("Host does not support IFF_VNET_HDR, not enabling")
112
    return False
113

    
114

    
115
def _OpenTap(vnet_hdr=True):
116
  """Open a new tap device and return its file descriptor.
117

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

121
  @type vnet_hdr: boolean
122
  @param vnet_hdr: Enable the VNET Header
123
  @return: (ifname, tapfd)
124
  @rtype: tuple
125

126
  """
127
  try:
128
    tapfd = os.open("/dev/net/tun", os.O_RDWR)
129
  except EnvironmentError:
130
    raise errors.HypervisorError("Failed to open /dev/net/tun")
131

    
132
  flags = IFF_TAP | IFF_NO_PI
133

    
134
  if vnet_hdr and _ProbeTapVnetHdr(tapfd):
135
    flags |= IFF_VNET_HDR
136

    
137
  # The struct ifreq ioctl request (see netdevice(7))
138
  ifr = struct.pack("16sh", "", flags)
139

    
140
  try:
141
    res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
142
  except EnvironmentError, err:
143
    raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
144
                                 err)
145

    
146
  # Get the interface name from the ioctl
147
  ifname = struct.unpack("16sh", res)[0].strip("\x00")
148
  return (ifname, tapfd)
149

    
150

    
151
def _BuildNetworkEnv(name, network, gateway, network6, gateway6,
152
                     network_type, mac_prefix, tags, env):
153
  """Build environment variables concerning a Network.
154

155
  """
156
  if name:
157
    env["NETWORK_NAME"] = name
158
  if network:
159
    env["NETWORK_SUBNET"] = network
160
  if gateway:
161
    env["NETWORK_GATEWAY"] = gateway
162
  if network6:
163
    env["NETWORK_SUBNET6"] = network6
164
  if gateway6:
165
    env["NETWORK_GATEWAY6"] = gateway6
166
  if mac_prefix:
167
    env["NETWORK_MAC_PREFIX"] = mac_prefix
168
  if network_type:
169
    env["NETWORK_TYPE"] = network_type
170
  if tags:
171
    env["NETWORK_TAGS"] = " ".join(tags)
172

    
173
  return env
174

    
175

    
176
class QmpMessage:
177
  """QEMU Messaging Protocol (QMP) message.
178

179
  """
180
  def __init__(self, data):
181
    """Creates a new QMP message based on the passed data.
182

183
    """
184
    if not isinstance(data, dict):
185
      raise TypeError("QmpMessage must be initialized with a dict")
186

    
187
    self.data = data
188

    
189
  def __getitem__(self, field_name):
190
    """Get the value of the required field if present, or None.
191

192
    Overrides the [] operator to provide access to the message data,
193
    returning None if the required item is not in the message
194
    @return: the value of the field_name field, or None if field_name
195
             is not contained in the message
196

197
    """
198
    return self.data.get(field_name, None)
199

    
200
  def __setitem__(self, field_name, field_value):
201
    """Set the value of the required field_name to field_value.
202

203
    """
204
    self.data[field_name] = field_value
205

    
206
  @staticmethod
207
  def BuildFromJsonString(json_string):
208
    """Build a QmpMessage from a JSON encoded string.
209

210
    @type json_string: str
211
    @param json_string: JSON string representing the message
212
    @rtype: L{QmpMessage}
213
    @return: a L{QmpMessage} built from json_string
214

215
    """
216
    # Parse the string
217
    data = serializer.LoadJson(json_string)
218
    return QmpMessage(data)
219

    
220
  def __str__(self):
221
    # The protocol expects the JSON object to be sent as a single line.
222
    return serializer.DumpJson(self.data)
223

    
224
  def __eq__(self, other):
225
    # When comparing two QmpMessages, we are interested in comparing
226
    # their internal representation of the message data
227
    return self.data == other.data
228

    
229

    
230
class QmpConnection:
231
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
232

233
  """
234
  _FIRST_MESSAGE_KEY = "QMP"
235
  _EVENT_KEY = "event"
236
  _ERROR_KEY = "error"
237
  _RETURN_KEY = RETURN_KEY = "return"
238
  _ACTUAL_KEY = ACTUAL_KEY = "actual"
239
  _ERROR_CLASS_KEY = "class"
240
  _ERROR_DATA_KEY = "data"
241
  _ERROR_DESC_KEY = "desc"
242
  _EXECUTE_KEY = "execute"
243
  _ARGUMENTS_KEY = "arguments"
244
  _CAPABILITIES_COMMAND = "qmp_capabilities"
245
  _MESSAGE_END_TOKEN = "\r\n"
246
  _SOCKET_TIMEOUT = 5
247

    
248
  def __init__(self, monitor_filename):
249
    """Instantiates the QmpConnection object.
250

251
    @type monitor_filename: string
252
    @param monitor_filename: the filename of the UNIX raw socket on which the
253
                             QMP monitor is listening
254

255
    """
256
    self.monitor_filename = monitor_filename
257
    self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
258
    # We want to fail if the server doesn't send a complete message
259
    # in a reasonable amount of time
260
    self.sock.settimeout(self._SOCKET_TIMEOUT)
261
    self._connected = False
262
    self._buf = ""
263

    
264
  def _check_socket(self):
265
    sock_stat = None
266
    try:
267
      sock_stat = os.stat(self.monitor_filename)
268
    except EnvironmentError, err:
269
      if err.errno == errno.ENOENT:
270
        raise errors.HypervisorError("No qmp socket found")
271
      else:
272
        raise errors.HypervisorError("Error checking qmp socket: %s",
273
                                     utils.ErrnoOrStr(err))
274
    if not stat.S_ISSOCK(sock_stat.st_mode):
275
      raise errors.HypervisorError("Qmp socket is not a socket")
276

    
277
  def _check_connection(self):
278
    """Make sure that the connection is established.
279

280
    """
281
    if not self._connected:
282
      raise errors.ProgrammerError("To use a QmpConnection you need to first"
283
                                   " invoke connect() on it")
284

    
285
  def connect(self):
286
    """Connects to the QMP monitor.
287

288
    Connects to the UNIX socket and makes sure that we can actually send and
289
    receive data to the kvm instance via QMP.
290

291
    @raise errors.HypervisorError: when there are communication errors
292
    @raise errors.ProgrammerError: when there are data serialization errors
293

294
    """
295
    if self._connected:
296
      raise errors.ProgrammerError("Cannot connect twice")
297

    
298
    self._check_socket()
299

    
300
    # Check file existance/stuff
301
    try:
302
      self.sock.connect(self.monitor_filename)
303
    except EnvironmentError:
304
      raise errors.HypervisorError("Can't connect to qmp socket")
305
    self._connected = True
306

    
307
    # Check if we receive a correct greeting message from the server
308
    # (As per the QEMU Protocol Specification 0.1 - section 2.2)
309
    greeting = self._Recv()
310
    if not greeting[self._FIRST_MESSAGE_KEY]:
311
      self._connected = False
312
      raise errors.HypervisorError("kvm: qmp communication error (wrong"
313
                                   " server greeting")
314

    
315
    # Let's put the monitor in command mode using the qmp_capabilities
316
    # command, or else no command will be executable.
317
    # (As per the QEMU Protocol Specification 0.1 - section 4)
318
    self.Execute(self._CAPABILITIES_COMMAND)
319

    
320
  def _ParseMessage(self, buf):
321
    """Extract and parse a QMP message from the given buffer.
322

323
    Seeks for a QMP message in the given buf. If found, it parses it and
324
    returns it together with the rest of the characters in the buf.
325
    If no message is found, returns None and the whole buffer.
326

327
    @raise errors.ProgrammerError: when there are data serialization errors
328

329
    """
330
    message = None
331
    # Check if we got the message end token (CRLF, as per the QEMU Protocol
332
    # Specification 0.1 - Section 2.1.1)
333
    pos = buf.find(self._MESSAGE_END_TOKEN)
334
    if pos >= 0:
335
      try:
336
        message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
337
      except Exception, err:
338
        raise errors.ProgrammerError("QMP data serialization error: %s" % err)
339
      buf = buf[pos + 1:]
340

    
341
    return (message, buf)
342

    
343
  def _Recv(self):
344
    """Receives a message from QMP and decodes the received JSON object.
345

346
    @rtype: QmpMessage
347
    @return: the received message
348
    @raise errors.HypervisorError: when there are communication errors
349
    @raise errors.ProgrammerError: when there are data serialization errors
350

351
    """
352
    self._check_connection()
353

    
354
    # Check if there is already a message in the buffer
355
    (message, self._buf) = self._ParseMessage(self._buf)
356
    if message:
357
      return message
358

    
359
    recv_buffer = StringIO.StringIO(self._buf)
360
    recv_buffer.seek(len(self._buf))
361
    try:
362
      while True:
363
        data = self.sock.recv(4096)
364
        if not data:
365
          break
366
        recv_buffer.write(data)
367

    
368
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
369
        if message:
370
          return message
371

    
372
    except socket.timeout, err:
373
      raise errors.HypervisorError("Timeout while receiving a QMP message: "
374
                                   "%s" % (err))
375
    except socket.error, err:
376
      raise errors.HypervisorError("Unable to receive data from KVM using the"
377
                                   " QMP protocol: %s" % err)
378

    
379
  def _Send(self, message):
380
    """Encodes and sends a message to KVM using QMP.
381

382
    @type message: QmpMessage
383
    @param message: message to send to KVM
384
    @raise errors.HypervisorError: when there are communication errors
385
    @raise errors.ProgrammerError: when there are data serialization errors
386

387
    """
388
    self._check_connection()
389
    try:
390
      message_str = str(message)
391
    except Exception, err:
392
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
393

    
394
    try:
395
      self.sock.sendall(message_str)
396
    except socket.timeout, err:
397
      raise errors.HypervisorError("Timeout while sending a QMP message: "
398
                                   "%s (%s)" % (err.string, err.errno))
399
    except socket.error, err:
400
      raise errors.HypervisorError("Unable to send data from KVM using the"
401
                                   " QMP protocol: %s" % err)
402

    
403
  def Execute(self, command, arguments=None):
404
    """Executes a QMP command and returns the response of the server.
405

406
    @type command: str
407
    @param command: the command to execute
408
    @type arguments: dict
409
    @param arguments: dictionary of arguments to be passed to the command
410
    @rtype: dict
411
    @return: dictionary representing the received JSON object
412
    @raise errors.HypervisorError: when there are communication errors
413
    @raise errors.ProgrammerError: when there are data serialization errors
414

415
    """
416
    self._check_connection()
417
    message = QmpMessage({self._EXECUTE_KEY: command})
418
    if arguments:
419
      message[self._ARGUMENTS_KEY] = arguments
420
    self._Send(message)
421

    
422
    # Events can occur between the sending of the command and the reception
423
    # of the response, so we need to filter out messages with the event key.
424
    while True:
425
      response = self._Recv()
426
      err = response[self._ERROR_KEY]
427
      if err:
428
        raise errors.HypervisorError("kvm: error executing the %s"
429
                                     " command: %s (%s, %s):" %
430
                                     (command,
431
                                      err[self._ERROR_DESC_KEY],
432
                                      err[self._ERROR_CLASS_KEY],
433
                                      err[self._ERROR_DATA_KEY]))
434

    
435
      elif not response[self._EVENT_KEY]:
436
        return response
437

    
438

    
439
class KVMHypervisor(hv_base.BaseHypervisor):
440
  """KVM hypervisor interface
441

442
  """
443
  CAN_MIGRATE = True
444

    
445
  _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
446
  _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
447
  _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
448
  _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
449
  _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
450
  _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
451
  _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
452
  # KVM instances with chroot enabled are started in empty chroot directories.
453
  _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
454
  # After an instance is stopped, its chroot directory is removed.
455
  # If the chroot directory is not empty, it can't be removed.
456
  # A non-empty chroot directory indicates a possible security incident.
457
  # To support forensics, the non-empty chroot directory is quarantined in
458
  # a separate directory, called 'chroot-quarantine'.
459
  _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
460
  _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
461
           _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
462

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

    
547
  _VIRTIO = "virtio"
548
  _VIRTIO_NET_PCI = "virtio-net-pci"
549

    
550
  _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
551
                                    re.M | re.I)
552
  _MIGRATION_PROGRESS_RE = \
553
    re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
554
               r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
555
               r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
556

    
557
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
558
  _MIGRATION_INFO_RETRY_DELAY = 2
559

    
560
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
561

    
562
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
563
  _CPU_INFO_CMD = "info cpus"
564
  _CONT_CMD = "cont"
565

    
566
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
567
  _CHECK_MACHINE_VERSION_RE = \
568
    staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
569

    
570
  _QMP_RE = re.compile(r"^-qmp\s", re.M)
571
  _SPICE_RE = re.compile(r"^-spice\s", re.M)
572
  _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
573
  _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
574
  _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
575
  _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
576
  _NEW_VIRTIO_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
577
  # match  -drive.*boot=on|off on different lines, but in between accept only
578
  # dashes not preceeded by a new line (which would mean another option
579
  # different than -drive is starting)
580
  _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
581

    
582
  ANCILLARY_FILES = [
583
    _KVM_NETWORK_SCRIPT,
584
    ]
585
  ANCILLARY_FILES_OPT = [
586
    _KVM_NETWORK_SCRIPT,
587
    ]
588

    
589
  # Supported kvm options to get output from
590
  _KVMOPT_HELP = "help"
591
  _KVMOPT_MLIST = "mlist"
592
  _KVMOPT_DEVICELIST = "devicelist"
593

    
594
  # Command to execute to get the output from kvm, and whether to
595
  # accept the output even on failure.
596
  _KVMOPTS_CMDS = {
597
    _KVMOPT_HELP: (["--help"], False),
598
    _KVMOPT_MLIST: (["-M", "?"], False),
599
    _KVMOPT_DEVICELIST: (["-device", "?"], True),
600
  }
601

    
602
  def __init__(self):
603
    hv_base.BaseHypervisor.__init__(self)
604
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
605
    # in a tmpfs filesystem or has been otherwise wiped out.
606
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
607
    utils.EnsureDirs(dirs)
608

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

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

    
616
  @classmethod
617
  def _InstanceUidFile(cls, instance_name):
618
    """Returns the instance uidfile.
619

620
    """
621
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
622

    
623
  @classmethod
624
  def _InstancePidInfo(cls, pid):
625
    """Check pid file for instance information.
626

627
    Check that a pid file is associated with an instance, and retrieve
628
    information from its command line.
629

630
    @type pid: string or int
631
    @param pid: process id of the instance to check
632
    @rtype: tuple
633
    @return: (instance_name, memory, vcpus)
634
    @raise errors.HypervisorError: when an instance cannot be found
635

636
    """
637
    alive = utils.IsProcessAlive(pid)
638
    if not alive:
639
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
640

    
641
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
642
    try:
643
      cmdline = utils.ReadFile(cmdline_file)
644
    except EnvironmentError, err:
645
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
646
                                   (pid, err))
647

    
648
    instance = None
649
    memory = 0
650
    vcpus = 0
651

    
652
    arg_list = cmdline.split("\x00")
653
    while arg_list:
654
      arg = arg_list.pop(0)
655
      if arg == "-name":
656
        instance = arg_list.pop(0)
657
      elif arg == "-m":
658
        memory = int(arg_list.pop(0))
659
      elif arg == "-smp":
660
        vcpus = int(arg_list.pop(0).split(",")[0])
661

    
662
    if instance is None:
663
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
664
                                   " instance" % pid)
665

    
666
    return (instance, memory, vcpus)
667

    
668
  def _InstancePidAlive(self, instance_name):
669
    """Returns the instance pidfile, pid, and liveness.
670

671
    @type instance_name: string
672
    @param instance_name: instance name
673
    @rtype: tuple
674
    @return: (pid file name, pid, liveness)
675

676
    """
677
    pidfile = self._InstancePidFile(instance_name)
678
    pid = utils.ReadPidFile(pidfile)
679

    
680
    alive = False
681
    try:
682
      cmd_instance = self._InstancePidInfo(pid)[0]
683
      alive = (cmd_instance == instance_name)
684
    except errors.HypervisorError:
685
      pass
686

    
687
    return (pidfile, pid, alive)
688

    
689
  def _CheckDown(self, instance_name):
690
    """Raises an error unless the given instance is down.
691

692
    """
693
    alive = self._InstancePidAlive(instance_name)[2]
694
    if alive:
695
      raise errors.HypervisorError("Failed to start instance %s: %s" %
696
                                   (instance_name, "already running"))
697

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

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

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

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

    
712
  @classmethod
713
  def _InstanceQmpMonitor(cls, instance_name):
714
    """Returns the instance serial QMP socket name
715

716
    """
717
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
718

    
719
  @staticmethod
720
  def _SocatUnixConsoleParams():
721
    """Returns the correct parameters for socat
722

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

725
    """
726
    if constants.SOCAT_USE_ESCAPE:
727
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
728
    else:
729
      return "echo=0,icanon=0"
730

    
731
  @classmethod
732
  def _InstanceKVMRuntime(cls, instance_name):
733
    """Returns the instance KVM runtime filename
734

735
    """
736
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
737

    
738
  @classmethod
739
  def _InstanceChrootDir(cls, instance_name):
740
    """Returns the name of the KVM chroot dir of the instance
741

742
    """
743
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
744

    
745
  @classmethod
746
  def _InstanceNICDir(cls, instance_name):
747
    """Returns the name of the directory holding the tap device files for a
748
    given instance.
749

750
    """
751
    return utils.PathJoin(cls._NICS_DIR, instance_name)
752

    
753
  @classmethod
754
  def _InstanceNICFile(cls, instance_name, seq):
755
    """Returns the name of the file containing the tap device for a given NIC
756

757
    """
758
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
759

    
760
  @classmethod
761
  def _InstanceKeymapFile(cls, instance_name):
762
    """Returns the name of the file containing the keymap for a given instance
763

764
    """
765
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
766

    
767
  @classmethod
768
  def _TryReadUidFile(cls, uid_file):
769
    """Try to read a uid file
770

771
    """
772
    if os.path.exists(uid_file):
773
      try:
774
        uid = int(utils.ReadOneLineFile(uid_file))
775
        return uid
776
      except EnvironmentError:
777
        logging.warning("Can't read uid file", exc_info=True)
778
      except (TypeError, ValueError):
779
        logging.warning("Can't parse uid file contents", exc_info=True)
780
    return None
781

    
782
  @classmethod
783
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
784
    """Removes an instance's rutime sockets/files/dirs.
785

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

    
822
  @staticmethod
823
  def _ConfigureNIC(instance, seq, nic, tap):
824
    """Run the network configuration script for a specified NIC
825

826
    @param instance: instance we're acting on
827
    @type instance: instance object
828
    @param seq: nic sequence number
829
    @type seq: int
830
    @param nic: nic we're acting on
831
    @type nic: nic object
832
    @param tap: the host's tap interface this NIC corresponds to
833
    @type tap: str
834

835
    """
836
    if instance.tags:
837
      tags = " ".join(instance.tags)
838
    else:
839
      tags = ""
840

    
841
    env = {
842
      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
843
      "INSTANCE": instance.name,
844
      "MAC": nic.mac,
845
      "MODE": nic.nicparams[constants.NIC_MODE],
846
      "INTERFACE": tap,
847
      "INTERFACE_INDEX": str(seq),
848
      "TAGS": tags,
849
    }
850

    
851
    if nic.ip:
852
      env["IP"] = nic.ip
853

    
854
    if nic.nicparams[constants.NIC_LINK]:
855
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
856

    
857
    if nic.network:
858
      n = objects.Network.FromDict(nic.netinfo)
859
      _BuildNetworkEnv(nic.network, n.network, n.gateway,
860
                       n.network6, n.gateway6, n.network_type,
861
                       n.mac_prefix, n.tags, env)
862

    
863
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
864
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
865

    
866
    result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
867
    if result.failed:
868
      raise errors.HypervisorError("Failed to configure interface %s: %s."
869
                                   " Network configuration script output: %s" %
870
                                   (tap, result.fail_reason, result.output))
871

    
872
  @staticmethod
873
  def _VerifyAffinityPackage():
874
    if affinity is None:
875
      raise errors.HypervisorError("affinity Python package not"
876
                                   " found; cannot use CPU pinning under KVM")
877

    
878
  @staticmethod
879
  def _BuildAffinityCpuMask(cpu_list):
880
    """Create a CPU mask suitable for sched_setaffinity from a list of
881
    CPUs.
882

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

886
    @type cpu_list: list of int
887
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
888
    @rtype: int
889
    @return: a bit mask of CPU affinities
890

891
    """
892
    if cpu_list == constants.CPU_PINNING_OFF:
893
      return constants.CPU_PINNING_ALL_KVM
894
    else:
895
      return sum(2 ** cpu for cpu in cpu_list)
896

    
897
  @classmethod
898
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
899
    """Change CPU affinity for running VM according to given CPU mask.
900

901
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
902
    @type cpu_mask: string
903
    @param process_id: process ID of KVM process. Used to pin entire VM
904
                       to physical CPUs.
905
    @type process_id: int
906
    @param thread_dict: map of virtual CPUs to KVM thread IDs
907
    @type thread_dict: dict int:int
908

909
    """
910
    # Convert the string CPU mask to a list of list of int's
911
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
912

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

    
931
      # For each vCPU, map it to the proper list of physical CPUs
932
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
933
        affinity.set_process_affinity_mask(thread_dict[i],
934
                                           cls._BuildAffinityCpuMask(vcpu))
935

    
936
  def _GetVcpuThreadIds(self, instance_name):
937
    """Get a mapping of vCPU no. to thread IDs for the instance
938

939
    @type instance_name: string
940
    @param instance_name: instance in question
941
    @rtype: dictionary of int:int
942
    @return: a dictionary mapping vCPU numbers to thread IDs
943

944
    """
945
    result = {}
946
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
947
    for line in output.stdout.splitlines():
948
      match = self._CPU_INFO_RE.search(line)
949
      if not match:
950
        continue
951
      grp = map(int, match.groups())
952
      result[grp[0]] = grp[1]
953

    
954
    return result
955

    
956
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
957
    """Complete CPU pinning.
958

959
    @type instance_name: string
960
    @param instance_name: name of instance
961
    @type cpu_mask: string
962
    @param cpu_mask: CPU pinning mask as entered by user
963

964
    """
965
    # Get KVM process ID, to be used if need to pin entire VM
966
    _, pid, _ = self._InstancePidAlive(instance_name)
967
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
968
    thread_dict = self._GetVcpuThreadIds(instance_name)
969
    # Run CPU pinning, based on configured mask
970
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
971

    
972
  def ListInstances(self):
973
    """Get the list of running instances.
974

975
    We can do this by listing our live instances directory and
976
    checking whether the associated kvm process is still alive.
977

978
    """
979
    result = []
980
    for name in os.listdir(self._PIDS_DIR):
981
      if self._InstancePidAlive(name)[2]:
982
        result.append(name)
983
    return result
984

    
985
  def GetInstanceInfo(self, instance_name):
986
    """Get instance properties.
987

988
    @type instance_name: string
989
    @param instance_name: the instance name
990
    @rtype: tuple of strings
991
    @return: (name, id, memory, vcpus, stat, times)
992

993
    """
994
    _, pid, alive = self._InstancePidAlive(instance_name)
995
    if not alive:
996
      return None
997

    
998
    _, memory, vcpus = self._InstancePidInfo(pid)
999
    istat = "---b-"
1000
    times = "0"
1001

    
1002
    try:
1003
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1004
      qmp.connect()
1005
      vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1006
      # Will fail if ballooning is not enabled, but we can then just resort to
1007
      # the value above.
1008
      mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1009
      memory = mem_bytes / 1048576
1010
    except errors.HypervisorError:
1011
      pass
1012

    
1013
    return (instance_name, pid, memory, vcpus, istat, times)
1014

    
1015
  def GetAllInstancesInfo(self):
1016
    """Get properties of all instances.
1017

1018
    @return: list of tuples (name, id, memory, vcpus, stat, times)
1019

1020
    """
1021
    data = []
1022
    for name in os.listdir(self._PIDS_DIR):
1023
      try:
1024
        info = self.GetInstanceInfo(name)
1025
      except errors.HypervisorError:
1026
        # Ignore exceptions due to instances being shut down
1027
        continue
1028
      if info:
1029
        data.append(info)
1030
    return data
1031

    
1032
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1033
                          kvmhelp):
1034
    """Generate KVM information to start an instance.
1035

1036
    @type kvmhelp: string
1037
    @param kvmhelp: output of kvm --help
1038
    @attention: this function must not have any side-effects; for
1039
        example, it must not write to the filesystem, or read values
1040
        from the current system the are expected to differ between
1041
        nodes, since it is only run once at instance startup;
1042
        actions/kvm arguments that can vary between systems should be
1043
        done in L{_ExecuteKVMRuntime}
1044

1045
    """
1046
    # pylint: disable=R0912,R0914,R0915
1047
    hvp = instance.hvparams
1048

    
1049
    pidfile = self._InstancePidFile(instance.name)
1050
    kvm = hvp[constants.HV_KVM_PATH]
1051
    kvm_cmd = [kvm]
1052
    # used just by the vnc server, if enabled
1053
    kvm_cmd.extend(["-name", instance.name])
1054
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1055

    
1056
    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1057
    if hvp[constants.HV_CPU_CORES]:
1058
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1059
    if hvp[constants.HV_CPU_THREADS]:
1060
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1061
    if hvp[constants.HV_CPU_SOCKETS]:
1062
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1063

    
1064
    kvm_cmd.extend(["-smp", ",".join(smp_list)])
1065

    
1066
    kvm_cmd.extend(["-pidfile", pidfile])
1067
    kvm_cmd.extend(["-balloon", "virtio"])
1068
    kvm_cmd.extend(["-daemonize"])
1069
    if not instance.hvparams[constants.HV_ACPI]:
1070
      kvm_cmd.extend(["-no-acpi"])
1071
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1072
        constants.INSTANCE_REBOOT_EXIT:
1073
      kvm_cmd.extend(["-no-reboot"])
1074

    
1075
    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1076
    if not mversion:
1077
      mversion = self._GetDefaultMachineVersion(kvm)
1078
    kvm_cmd.extend(["-M", mversion])
1079

    
1080
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1081
    if kernel_path:
1082
      boot_disk = boot_cdrom = boot_floppy = boot_network = False
1083
    else:
1084
      boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1085
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1086
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1087
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1088

    
1089
    self.ValidateParameters(hvp)
1090

    
1091
    if startup_paused:
1092
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1093

    
1094
    if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1095
        self._ENABLE_KVM_RE.search(kvmhelp)):
1096
      kvm_cmd.extend(["-enable-kvm"])
1097
    elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1098
          self._DISABLE_KVM_RE.search(kvmhelp)):
1099
      kvm_cmd.extend(["-disable-kvm"])
1100

    
1101
    if boot_network:
1102
      kvm_cmd.extend(["-boot", "n"])
1103

    
1104
    # whether this is an older KVM version that uses the boot=on flag
1105
    # on devices
1106
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1107

    
1108
    disk_type = hvp[constants.HV_DISK_TYPE]
1109
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
1110
      if_val = ",if=virtio"
1111
    else:
1112
      if_val = ",if=%s" % disk_type
1113
    # Cache mode
1114
    disk_cache = hvp[constants.HV_DISK_CACHE]
1115
    if instance.disk_template in constants.DTS_EXT_MIRROR:
1116
      if disk_cache != "none":
1117
        # TODO: make this a hard error, instead of a silent overwrite
1118
        logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1119
                        " to prevent shared storage corruption on migration",
1120
                        disk_cache)
1121
      cache_val = ",cache=none"
1122
    elif disk_cache != constants.HT_CACHE_DEFAULT:
1123
      cache_val = ",cache=%s" % disk_cache
1124
    else:
1125
      cache_val = ""
1126
    for cfdev, dev_path in block_devices:
1127
      if cfdev.mode != constants.DISK_RDWR:
1128
        raise errors.HypervisorError("Instance has read-only disks which"
1129
                                     " are not supported by KVM")
1130
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
1131
      boot_val = ""
1132
      if boot_disk:
1133
        kvm_cmd.extend(["-boot", "c"])
1134
        boot_disk = False
1135
        if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1136
          boot_val = ",boot=on"
1137

    
1138
      drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
1139
                                                cache_val)
1140
      kvm_cmd.extend(["-drive", drive_val])
1141

    
1142
    #Now we can specify a different device type for CDROM devices.
1143
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1144
    if not cdrom_disk_type:
1145
      cdrom_disk_type = disk_type
1146

    
1147
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1148
    if iso_image:
1149
      options = ",format=raw,media=cdrom"
1150
      # set cdrom 'if' type
1151
      if boot_cdrom:
1152
        actual_cdrom_type = constants.HT_DISK_IDE
1153
      elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1154
        actual_cdrom_type = "virtio"
1155
      else:
1156
        actual_cdrom_type = cdrom_disk_type
1157
      if_val = ",if=%s" % actual_cdrom_type
1158
      # set boot flag, if needed
1159
      boot_val = ""
1160
      if boot_cdrom:
1161
        kvm_cmd.extend(["-boot", "d"])
1162
        if needs_boot_flag:
1163
          boot_val = ",boot=on"
1164
      # and finally build the entire '-drive' value
1165
      drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1166
      kvm_cmd.extend(["-drive", drive_val])
1167

    
1168
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1169
    if iso_image2:
1170
      options = ",format=raw,media=cdrom"
1171
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1172
        if_val = ",if=virtio"
1173
      else:
1174
        if_val = ",if=%s" % cdrom_disk_type
1175
      drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1176
      kvm_cmd.extend(["-drive", drive_val])
1177

    
1178
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1179
    if floppy_image:
1180
      options = ",format=raw,media=disk"
1181
      if boot_floppy:
1182
        kvm_cmd.extend(["-boot", "a"])
1183
        options = "%s,boot=on" % options
1184
      if_val = ",if=floppy"
1185
      options = "%s%s" % (options, if_val)
1186
      drive_val = "file=%s%s" % (floppy_image, options)
1187
      kvm_cmd.extend(["-drive", drive_val])
1188

    
1189
    if kernel_path:
1190
      kvm_cmd.extend(["-kernel", kernel_path])
1191
      initrd_path = hvp[constants.HV_INITRD_PATH]
1192
      if initrd_path:
1193
        kvm_cmd.extend(["-initrd", initrd_path])
1194
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1195
                     hvp[constants.HV_KERNEL_ARGS]]
1196
      if hvp[constants.HV_SERIAL_CONSOLE]:
1197
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
1198
        root_append.append("console=ttyS0,%s" % serial_speed)
1199
      kvm_cmd.extend(["-append", " ".join(root_append)])
1200

    
1201
    mem_path = hvp[constants.HV_MEM_PATH]
1202
    if mem_path:
1203
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1204

    
1205
    monitor_dev = ("unix:%s,server,nowait" %
1206
                   self._InstanceMonitor(instance.name))
1207
    kvm_cmd.extend(["-monitor", monitor_dev])
1208
    if hvp[constants.HV_SERIAL_CONSOLE]:
1209
      serial_dev = ("unix:%s,server,nowait" %
1210
                    self._InstanceSerial(instance.name))
1211
      kvm_cmd.extend(["-serial", serial_dev])
1212
    else:
1213
      kvm_cmd.extend(["-serial", "none"])
1214

    
1215
    mouse_type = hvp[constants.HV_USB_MOUSE]
1216
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1217
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1218
    spice_ip_version = None
1219

    
1220
    kvm_cmd.extend(["-usb"])
1221

    
1222
    if mouse_type:
1223
      kvm_cmd.extend(["-usbdevice", mouse_type])
1224
    elif vnc_bind_address:
1225
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1226

    
1227
    if vnc_bind_address:
1228
      if netutils.IP4Address.IsValid(vnc_bind_address):
1229
        if instance.network_port > constants.VNC_BASE_PORT:
1230
          display = instance.network_port - constants.VNC_BASE_PORT
1231
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1232
            vnc_arg = ":%d" % (display)
1233
          else:
1234
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1235
        else:
1236
          logging.error("Network port is not a valid VNC display (%d < %d)."
1237
                        " Not starting VNC", instance.network_port,
1238
                        constants.VNC_BASE_PORT)
1239
          vnc_arg = "none"
1240

    
1241
        # Only allow tls and other option when not binding to a file, for now.
1242
        # kvm/qemu gets confused otherwise about the filename to use.
1243
        vnc_append = ""
1244
        if hvp[constants.HV_VNC_TLS]:
1245
          vnc_append = "%s,tls" % vnc_append
1246
          if hvp[constants.HV_VNC_X509_VERIFY]:
1247
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1248
                                               hvp[constants.HV_VNC_X509])
1249
          elif hvp[constants.HV_VNC_X509]:
1250
            vnc_append = "%s,x509=%s" % (vnc_append,
1251
                                         hvp[constants.HV_VNC_X509])
1252
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1253
          vnc_append = "%s,password" % vnc_append
1254

    
1255
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1256

    
1257
      else:
1258
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1259

    
1260
      kvm_cmd.extend(["-vnc", vnc_arg])
1261
    elif spice_bind:
1262
      # FIXME: this is wrong here; the iface ip address differs
1263
      # between systems, so it should be done in _ExecuteKVMRuntime
1264
      if netutils.IsValidInterface(spice_bind):
1265
        # The user specified a network interface, we have to figure out the IP
1266
        # address.
1267
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1268
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1269

    
1270
        # if the user specified an IP version and the interface does not
1271
        # have that kind of IP addresses, throw an exception
1272
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1273
          if not addresses[spice_ip_version]:
1274
            raise errors.HypervisorError("spice: unable to get an IPv%s address"
1275
                                         " for %s" % (spice_ip_version,
1276
                                                      spice_bind))
1277

    
1278
        # the user did not specify an IP version, we have to figure it out
1279
        elif (addresses[constants.IP4_VERSION] and
1280
              addresses[constants.IP6_VERSION]):
1281
          # we have both ipv4 and ipv6, let's use the cluster default IP
1282
          # version
1283
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1284
          spice_ip_version = \
1285
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1286
        elif addresses[constants.IP4_VERSION]:
1287
          spice_ip_version = constants.IP4_VERSION
1288
        elif addresses[constants.IP6_VERSION]:
1289
          spice_ip_version = constants.IP6_VERSION
1290
        else:
1291
          raise errors.HypervisorError("spice: unable to get an IP address"
1292
                                       " for %s" % (spice_bind))
1293

    
1294
        spice_address = addresses[spice_ip_version][0]
1295

    
1296
      else:
1297
        # spice_bind is known to be a valid IP address, because
1298
        # ValidateParameters checked it.
1299
        spice_address = spice_bind
1300

    
1301
      spice_arg = "addr=%s" % spice_address
1302
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1303
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1304
                     (spice_arg, instance.network_port,
1305
                      pathutils.SPICE_CACERT_FILE))
1306
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1307
                     (spice_arg, pathutils.SPICE_CERT_FILE,
1308
                      pathutils.SPICE_CERT_FILE))
1309
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1310
        if tls_ciphers:
1311
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1312
      else:
1313
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1314

    
1315
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1316
        spice_arg = "%s,disable-ticketing" % spice_arg
1317

    
1318
      if spice_ip_version:
1319
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1320

    
1321
      # Image compression options
1322
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1323
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1324
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1325
      if img_lossless:
1326
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1327
      if img_jpeg:
1328
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1329
      if img_zlib_glz:
1330
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1331

    
1332
      # Video stream detection
1333
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1334
      if video_streaming:
1335
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1336

    
1337
      # Audio compression, by default in qemu-kvm it is on
1338
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1339
        spice_arg = "%s,playback-compression=off" % spice_arg
1340
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1341
        spice_arg = "%s,agent-mouse=off" % spice_arg
1342
      else:
1343
        # Enable the spice agent communication channel between the host and the
1344
        # agent.
1345
        kvm_cmd.extend(["-device", "virtio-serial-pci"])
1346
        kvm_cmd.extend(["-device", "virtserialport,chardev=spicechannel0,"
1347
                                                   "name=com.redhat.spice.0"])
1348
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1349

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

    
1353
    else:
1354
      kvm_cmd.extend(["-nographic"])
1355

    
1356
    if hvp[constants.HV_USE_LOCALTIME]:
1357
      kvm_cmd.extend(["-localtime"])
1358

    
1359
    if hvp[constants.HV_KVM_USE_CHROOT]:
1360
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1361

    
1362
    # Add qemu-KVM -cpu param
1363
    if hvp[constants.HV_CPU_TYPE]:
1364
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1365

    
1366
    # As requested by music lovers
1367
    if hvp[constants.HV_SOUNDHW]:
1368
      kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1369

    
1370
    # Pass a -vga option if requested, or if spice is used, for backwards
1371
    # compatibility.
1372
    if hvp[constants.HV_VGA]:
1373
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1374
    elif spice_bind:
1375
      kvm_cmd.extend(["-vga", "qxl"])
1376

    
1377
    # Various types of usb devices, comma separated
1378
    if hvp[constants.HV_USB_DEVICES]:
1379
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
1380
        kvm_cmd.extend(["-usbdevice", dev])
1381

    
1382
    if hvp[constants.HV_KVM_EXTRA]:
1383
      kvm_cmd.extend([hvp[constants.HV_KVM_EXTRA]])
1384

    
1385
    # Save the current instance nics, but defer their expansion as parameters,
1386
    # as we'll need to generate executable temp files for them.
1387
    kvm_nics = instance.nics
1388
    hvparams = hvp
1389

    
1390
    return (kvm_cmd, kvm_nics, hvparams)
1391

    
1392
  def _WriteKVMRuntime(self, instance_name, data):
1393
    """Write an instance's KVM runtime
1394

1395
    """
1396
    try:
1397
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1398
                      data=data)
1399
    except EnvironmentError, err:
1400
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1401

    
1402
  def _ReadKVMRuntime(self, instance_name):
1403
    """Read an instance's KVM runtime
1404

1405
    """
1406
    try:
1407
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1408
    except EnvironmentError, err:
1409
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1410
    return file_content
1411

    
1412
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1413
    """Save an instance's KVM runtime
1414

1415
    """
1416
    kvm_cmd, kvm_nics, hvparams = kvm_runtime
1417
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1418
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1419
    self._WriteKVMRuntime(instance.name, serialized_form)
1420

    
1421
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1422
    """Load an instance's KVM runtime
1423

1424
    """
1425
    if not serialized_runtime:
1426
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1427
    loaded_runtime = serializer.Load(serialized_runtime)
1428
    kvm_cmd, serialized_nics, hvparams = loaded_runtime
1429
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1430
    return (kvm_cmd, kvm_nics, hvparams)
1431

    
1432
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1433
    """Run the KVM cmd and check for errors
1434

1435
    @type name: string
1436
    @param name: instance name
1437
    @type kvm_cmd: list of strings
1438
    @param kvm_cmd: runcmd input for kvm
1439
    @type tap_fds: list of int
1440
    @param tap_fds: fds of tap devices opened by Ganeti
1441

1442
    """
1443
    try:
1444
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1445
    finally:
1446
      for fd in tap_fds:
1447
        utils_wrapper.CloseFdNoError(fd)
1448

    
1449
    if result.failed:
1450
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1451
                                   (name, result.fail_reason, result.output))
1452
    if not self._InstancePidAlive(name)[2]:
1453
      raise errors.HypervisorError("Failed to start instance %s" % name)
1454

    
1455
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1456
    """Execute a KVM cmd, after completing it with some last minute data.
1457

1458
    @type incoming: tuple of strings
1459
    @param incoming: (target_host_ip, port)
1460
    @type kvmhelp: string
1461
    @param kvmhelp: output of kvm --help
1462

1463
    """
1464
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1465
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1466
    #    have changed since the instance started; only use them if the change
1467
    #    won't affect the inside of the instance (which hasn't been rebooted).
1468
    #  - up_hvp contains the parameters as they were when the instance was
1469
    #    started, plus any new parameter which has been added between ganeti
1470
    #    versions: it is paramount that those default to a value which won't
1471
    #    affect the inside of the instance as well.
1472
    conf_hvp = instance.hvparams
1473
    name = instance.name
1474
    self._CheckDown(name)
1475

    
1476
    temp_files = []
1477

    
1478
    kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1479
    # the first element of kvm_cmd is always the path to the kvm binary
1480
    kvm_path = kvm_cmd[0]
1481
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1482

    
1483
    # We know it's safe to run as a different user upon migration, so we'll use
1484
    # the latest conf, from conf_hvp.
1485
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1486
    if security_model == constants.HT_SM_USER:
1487
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1488

    
1489
    keymap = conf_hvp[constants.HV_KEYMAP]
1490
    if keymap:
1491
      keymap_path = self._InstanceKeymapFile(name)
1492
      # If a keymap file is specified, KVM won't use its internal defaults. By
1493
      # first including the "en-us" layout, an error on loading the actual
1494
      # layout (e.g. because it can't be found) won't lead to a non-functional
1495
      # keyboard. A keyboard with incorrect keys is still better than none.
1496
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1497
      kvm_cmd.extend(["-k", keymap_path])
1498

    
1499
    # We have reasons to believe changing something like the nic driver/type
1500
    # upon migration won't exactly fly with the instance kernel, so for nic
1501
    # related parameters we'll use up_hvp
1502
    tapfds = []
1503
    taps = []
1504
    if not kvm_nics:
1505
      kvm_cmd.extend(["-net", "none"])
1506
    else:
1507
      vnet_hdr = False
1508
      tap_extra = ""
1509
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1510
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1511
        nic_model = self._VIRTIO
1512
        try:
1513
          devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1514
          if self._NEW_VIRTIO_RE.search(devlist):
1515
            nic_model = self._VIRTIO_NET_PCI
1516
            vnet_hdr = True
1517
        except errors.HypervisorError, _:
1518
          # Older versions of kvm don't support DEVICE_LIST, but they don't
1519
          # have new virtio syntax either.
1520
          pass
1521

    
1522
        if up_hvp[constants.HV_VHOST_NET]:
1523
          # check for vhost_net support
1524
          if self._VHOST_RE.search(kvmhelp):
1525
            tap_extra = ",vhost=on"
1526
          else:
1527
            raise errors.HypervisorError("vhost_net is configured"
1528
                                         " but it is not available")
1529
      else:
1530
        nic_model = nic_type
1531

    
1532
      kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1533

    
1534
      for nic_seq, nic in enumerate(kvm_nics):
1535
        tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1536
        tapfds.append(tapfd)
1537
        taps.append(tapname)
1538
        if kvm_supports_netdev:
1539
          nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1540
          tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1541
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1542
        else:
1543
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1544
                                                         nic.mac, nic_model)
1545
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1546
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1547

    
1548
    if incoming:
1549
      target, port = incoming
1550
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1551

    
1552
    # Changing the vnc password doesn't bother the guest that much. At most it
1553
    # will surprise people who connect to it. Whether positively or negatively
1554
    # it's debatable.
1555
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1556
    vnc_pwd = None
1557
    if vnc_pwd_file:
1558
      try:
1559
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1560
      except EnvironmentError, err:
1561
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1562
                                     % (vnc_pwd_file, err))
1563

    
1564
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1565
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1566
                         constants.SECURE_DIR_MODE)])
1567

    
1568
    # Automatically enable QMP if version is >= 0.14
1569
    if self._QMP_RE.search(kvmhelp):
1570
      logging.debug("Enabling QMP")
1571
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1572
                      self._InstanceQmpMonitor(instance.name)])
1573

    
1574
    # Configure the network now for starting instances and bridged interfaces,
1575
    # during FinalizeMigration for incoming instances' routed interfaces
1576
    for nic_seq, nic in enumerate(kvm_nics):
1577
      if (incoming and
1578
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1579
        continue
1580
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1581

    
1582
    # CPU affinity requires kvm to start paused, so we set this flag if the
1583
    # instance is not already paused and if we are not going to accept a
1584
    # migrating instance. In the latter case, pausing is not needed.
1585
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1586
    if start_kvm_paused:
1587
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1588

    
1589
    # Note: CPU pinning is using up_hvp since changes take effect
1590
    # during instance startup anyway, and to avoid problems when soft
1591
    # rebooting the instance.
1592
    cpu_pinning = False
1593
    if up_hvp.get(constants.HV_CPU_MASK, None):
1594
      cpu_pinning = True
1595

    
1596
    if security_model == constants.HT_SM_POOL:
1597
      ss = ssconf.SimpleStore()
1598
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1599
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1600
      uid = uidpool.RequestUnusedUid(all_uids)
1601
      try:
1602
        username = pwd.getpwuid(uid.GetUid()).pw_name
1603
        kvm_cmd.extend(["-runas", username])
1604
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1605
      except:
1606
        uidpool.ReleaseUid(uid)
1607
        raise
1608
      else:
1609
        uid.Unlock()
1610
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1611
    else:
1612
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1613

    
1614
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1615
                     constants.RUN_DIRS_MODE)])
1616
    for nic_seq, tap in enumerate(taps):
1617
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1618
                      data=tap)
1619

    
1620
    if vnc_pwd:
1621
      change_cmd = "change vnc password %s" % vnc_pwd
1622
      self._CallMonitorCommand(instance.name, change_cmd)
1623

    
1624
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1625
    # connection attempts because SPICE by default does not allow connections
1626
    # if neither a password nor the "disable_ticketing" options are specified.
1627
    # As soon as we send the password via QMP, that password is a valid ticket
1628
    # for connection.
1629
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1630
    if spice_password_file:
1631
      spice_pwd = ""
1632
      try:
1633
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1634
      except EnvironmentError, err:
1635
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1636
                                     % (spice_password_file, err))
1637

    
1638
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1639
      qmp.connect()
1640
      arguments = {
1641
          "protocol": "spice",
1642
          "password": spice_pwd,
1643
      }
1644
      qmp.Execute("set_password", arguments)
1645

    
1646
    for filename in temp_files:
1647
      utils.RemoveFile(filename)
1648

    
1649
    # If requested, set CPU affinity and resume instance execution
1650
    if cpu_pinning:
1651
      self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1652

    
1653
    start_memory = self._InstanceStartupMemory(instance)
1654
    if start_memory < instance.beparams[constants.BE_MAXMEM]:
1655
      self.BalloonInstanceMemory(instance, start_memory)
1656

    
1657
    if start_kvm_paused:
1658
      # To control CPU pinning, ballooning, and vnc/spice passwords
1659
      # the VM was started in a frozen state. If freezing was not
1660
      # explicitly requested resume the vm status.
1661
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1662

    
1663
  def StartInstance(self, instance, block_devices, startup_paused):
1664
    """Start an instance.
1665

1666
    """
1667
    self._CheckDown(instance.name)
1668
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1669
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1670
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1671
                                           startup_paused, kvmhelp)
1672
    self._SaveKVMRuntime(instance, kvm_runtime)
1673
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1674

    
1675
  def _CallMonitorCommand(self, instance_name, command):
1676
    """Invoke a command on the instance monitor.
1677

1678
    """
1679
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1680
             (utils.ShellQuote(command),
1681
              constants.SOCAT_PATH,
1682
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1683
    result = utils.RunCmd(socat)
1684
    if result.failed:
1685
      msg = ("Failed to send command '%s' to instance %s."
1686
             " output: %s, error: %s, fail_reason: %s" %
1687
             (command, instance_name,
1688
              result.stdout, result.stderr, result.fail_reason))
1689
      raise errors.HypervisorError(msg)
1690

    
1691
    return result
1692

    
1693
  @classmethod
1694
  def _ParseKVMVersion(cls, text):
1695
    """Parse the KVM version from the --help output.
1696

1697
    @type text: string
1698
    @param text: output of kvm --help
1699
    @return: (version, v_maj, v_min, v_rev)
1700
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1701

1702
    """
1703
    match = cls._VERSION_RE.search(text.splitlines()[0])
1704
    if not match:
1705
      raise errors.HypervisorError("Unable to get KVM version")
1706

    
1707
    v_all = match.group(0)
1708
    v_maj = int(match.group(1))
1709
    v_min = int(match.group(2))
1710
    if match.group(4):
1711
      v_rev = int(match.group(4))
1712
    else:
1713
      v_rev = 0
1714
    return (v_all, v_maj, v_min, v_rev)
1715

    
1716
  @classmethod
1717
  def _GetKVMOutput(cls, kvm_path, option):
1718
    """Return the output of a kvm invocation
1719

1720
    @type kvm_path: string
1721
    @param kvm_path: path to the kvm executable
1722
    @type option: a key of _KVMOPTS_CMDS
1723
    @param option: kvm option to fetch the output from
1724
    @return: output a supported kvm invocation
1725
    @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1726

1727
    """
1728
    assert option in cls._KVMOPTS_CMDS, "Invalid output option"
1729

    
1730
    optlist, can_fail = cls._KVMOPTS_CMDS[option]
1731

    
1732
    result = utils.RunCmd([kvm_path] + optlist)
1733
    if result.failed and not can_fail:
1734
      raise errors.HypervisorError("Unable to get KVM %s output" %
1735
                                    " ".join(cls._KVMOPTS_CMDS[option]))
1736
    return result.output
1737

    
1738
  @classmethod
1739
  def _GetKVMVersion(cls, kvm_path):
1740
    """Return the installed KVM version.
1741

1742
    @return: (version, v_maj, v_min, v_rev)
1743
    @raise errors.HypervisorError: when the KVM version cannot be retrieved
1744

1745
    """
1746
    return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
1747

    
1748
  @classmethod
1749
  def _GetDefaultMachineVersion(cls, kvm_path):
1750
    """Return the default hardware revision (e.g. pc-1.1)
1751

1752
    """
1753
    output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
1754
    match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
1755
    if match:
1756
      return match.group(1)
1757
    else:
1758
      return "pc"
1759

    
1760
  def StopInstance(self, instance, force=False, retry=False, name=None):
1761
    """Stop an instance.
1762

1763
    """
1764
    if name is not None and not force:
1765
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1766
    if name is None:
1767
      name = instance.name
1768
      acpi = instance.hvparams[constants.HV_ACPI]
1769
    else:
1770
      acpi = False
1771
    _, pid, alive = self._InstancePidAlive(name)
1772
    if pid > 0 and alive:
1773
      if force or not acpi:
1774
        utils.KillProcess(pid)
1775
      else:
1776
        self._CallMonitorCommand(name, "system_powerdown")
1777

    
1778
  def CleanupInstance(self, instance_name):
1779
    """Cleanup after a stopped instance
1780

1781
    """
1782
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
1783
    if pid > 0 and alive:
1784
      raise errors.HypervisorError("Cannot cleanup a live instance")
1785
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1786

    
1787
  def RebootInstance(self, instance):
1788
    """Reboot an instance.
1789

1790
    """
1791
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1792
    # socket the instance will stop, but now power up again. So we'll resort
1793
    # to shutdown and restart.
1794
    _, _, alive = self._InstancePidAlive(instance.name)
1795
    if not alive:
1796
      raise errors.HypervisorError("Failed to reboot instance %s:"
1797
                                   " not running" % instance.name)
1798
    # StopInstance will delete the saved KVM runtime so:
1799
    # ...first load it...
1800
    kvm_runtime = self._LoadKVMRuntime(instance)
1801
    # ...now we can safely call StopInstance...
1802
    if not self.StopInstance(instance):
1803
      self.StopInstance(instance, force=True)
1804
    # ...and finally we can save it again, and execute it...
1805
    self._SaveKVMRuntime(instance, kvm_runtime)
1806
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1807
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1808
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1809

    
1810
  def MigrationInfo(self, instance):
1811
    """Get instance information to perform a migration.
1812

1813
    @type instance: L{objects.Instance}
1814
    @param instance: instance to be migrated
1815
    @rtype: string
1816
    @return: content of the KVM runtime file
1817

1818
    """
1819
    return self._ReadKVMRuntime(instance.name)
1820

    
1821
  def AcceptInstance(self, instance, info, target):
1822
    """Prepare to accept an instance.
1823

1824
    @type instance: L{objects.Instance}
1825
    @param instance: instance to be accepted
1826
    @type info: string
1827
    @param info: content of the KVM runtime file on the source node
1828
    @type target: string
1829
    @param target: target host (usually ip), on this node
1830

1831
    """
1832
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1833
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1834
    kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1835
    kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1836
    self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
1837
                            incoming=incoming_address)
1838

    
1839
  def FinalizeMigrationDst(self, instance, info, success):
1840
    """Finalize the instance migration on the target node.
1841

1842
    Stop the incoming mode KVM.
1843

1844
    @type instance: L{objects.Instance}
1845
    @param instance: instance whose migration is being finalized
1846

1847
    """
1848
    if success:
1849
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1850
      kvm_nics = kvm_runtime[1]
1851

    
1852
      for nic_seq, nic in enumerate(kvm_nics):
1853
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1854
          # Bridged interfaces have already been configured
1855
          continue
1856
        try:
1857
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1858
        except EnvironmentError, err:
1859
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
1860
                          instance.name, nic_seq, str(err))
1861
          continue
1862
        try:
1863
          self._ConfigureNIC(instance, nic_seq, nic, tap)
1864
        except errors.HypervisorError, err:
1865
          logging.warning(str(err))
1866

    
1867
      self._WriteKVMRuntime(instance.name, info)
1868
    else:
1869
      self.StopInstance(instance, force=True)
1870

    
1871
  def MigrateInstance(self, instance, target, live):
1872
    """Migrate an instance to a target node.
1873

1874
    The migration will not be attempted if the instance is not
1875
    currently running.
1876

1877
    @type instance: L{objects.Instance}
1878
    @param instance: the instance to be migrated
1879
    @type target: string
1880
    @param target: ip address of the target node
1881
    @type live: boolean
1882
    @param live: perform a live migration
1883

1884
    """
1885
    instance_name = instance.name
1886
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
1887
    _, _, alive = self._InstancePidAlive(instance_name)
1888
    if not alive:
1889
      raise errors.HypervisorError("Instance not running, cannot migrate")
1890

    
1891
    if not live:
1892
      self._CallMonitorCommand(instance_name, "stop")
1893

    
1894
    migrate_command = ("migrate_set_speed %dm" %
1895
                       instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1896
    self._CallMonitorCommand(instance_name, migrate_command)
1897

    
1898
    migrate_command = ("migrate_set_downtime %dms" %
1899
                       instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1900
    self._CallMonitorCommand(instance_name, migrate_command)
1901

    
1902
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1903
    self._CallMonitorCommand(instance_name, migrate_command)
1904

    
1905
  def FinalizeMigrationSource(self, instance, success, live):
1906
    """Finalize the instance migration on the source node.
1907

1908
    @type instance: L{objects.Instance}
1909
    @param instance: the instance that was migrated
1910
    @type success: bool
1911
    @param success: whether the migration succeeded or not
1912
    @type live: bool
1913
    @param live: whether the user requested a live migration or not
1914

1915
    """
1916
    if success:
1917
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
1918
      utils.KillProcess(pid)
1919
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1920
    elif live:
1921
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1922

    
1923
  def GetMigrationStatus(self, instance):
1924
    """Get the migration status
1925

1926
    @type instance: L{objects.Instance}
1927
    @param instance: the instance that is being migrated
1928
    @rtype: L{objects.MigrationStatus}
1929
    @return: the status of the current migration (one of
1930
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1931
             progress info that can be retrieved from the hypervisor
1932

1933
    """
1934
    info_command = "info migrate"
1935
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
1936
      result = self._CallMonitorCommand(instance.name, info_command)
1937
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
1938
      if not match:
1939
        if not result.stdout:
1940
          logging.info("KVM: empty 'info migrate' result")
1941
        else:
1942
          logging.warning("KVM: unknown 'info migrate' result: %s",
1943
                          result.stdout)
1944
      else:
1945
        status = match.group(1)
1946
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
1947
          migration_status = objects.MigrationStatus(status=status)
1948
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
1949
          if match:
1950
            migration_status.transferred_ram = match.group("transferred")
1951
            migration_status.total_ram = match.group("total")
1952

    
1953
          return migration_status
1954

    
1955
        logging.warning("KVM: unknown migration status '%s'", status)
1956

    
1957
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1958

    
1959
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
1960

    
1961
  def BalloonInstanceMemory(self, instance, mem):
1962
    """Balloon an instance memory to a certain value.
1963

1964
    @type instance: L{objects.Instance}
1965
    @param instance: instance to be accepted
1966
    @type mem: int
1967
    @param mem: actual memory size to use for instance runtime
1968

1969
    """
1970
    self._CallMonitorCommand(instance.name, "balloon %d" % mem)
1971

    
1972
  def GetNodeInfo(self):
1973
    """Return information about the node.
1974

1975
    @return: a dict with the following keys (values in MiB):
1976
          - memory_total: the total memory size on the node
1977
          - memory_free: the available memory on the node for instances
1978
          - memory_dom0: the memory used by the node itself, if available
1979
          - hv_version: the hypervisor version in the form (major, minor,
1980
                        revision)
1981

1982
    """
1983
    result = self.GetLinuxNodeInfo()
1984
    # FIXME: this is the global kvm version, but the actual version can be
1985
    # customized as an hv parameter. we should use the nodegroup's default kvm
1986
    # path parameter here.
1987
    _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
1988
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
1989
    return result
1990

    
1991
  @classmethod
1992
  def GetInstanceConsole(cls, instance, hvparams, beparams):
1993
    """Return a command for connecting to the console of an instance.
1994

1995
    """
1996
    if hvparams[constants.HV_SERIAL_CONSOLE]:
1997
      cmd = [pathutils.KVM_CONSOLE_WRAPPER,
1998
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1999
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2000
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
2001
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2002
      return objects.InstanceConsole(instance=instance.name,
2003
                                     kind=constants.CONS_SSH,
2004
                                     host=instance.primary_node,
2005
                                     user=constants.SSH_CONSOLE_USER,
2006
                                     command=cmd)
2007

    
2008
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2009
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2010
      display = instance.network_port - constants.VNC_BASE_PORT
2011
      return objects.InstanceConsole(instance=instance.name,
2012
                                     kind=constants.CONS_VNC,
2013
                                     host=vnc_bind_address,
2014
                                     port=instance.network_port,
2015
                                     display=display)
2016

    
2017
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2018
    if spice_bind:
2019
      return objects.InstanceConsole(instance=instance.name,
2020
                                     kind=constants.CONS_SPICE,
2021
                                     host=spice_bind,
2022
                                     port=instance.network_port)
2023

    
2024
    return objects.InstanceConsole(instance=instance.name,
2025
                                   kind=constants.CONS_MESSAGE,
2026
                                   message=("No serial shell for instance %s" %
2027
                                            instance.name))
2028

    
2029
  def Verify(self):
2030
    """Verify the hypervisor.
2031

2032
    Check that the required binaries exist.
2033

2034
    @return: Problem description if something is wrong, C{None} otherwise
2035

2036
    """
2037
    # FIXME: this is the global kvm version, but the actual version can be
2038
    # customized as an hv parameter. we should use the nodegroup's default kvm
2039
    # path parameter here.
2040
    if not os.path.exists(constants.KVM_PATH):
2041
      return "The KVM binary ('%s') does not exist" % constants.KVM_PATH
2042
    if not os.path.exists(constants.SOCAT_PATH):
2043
      return "The socat binary ('%s') does not exist" % constants.SOCAT_PATH
2044
    return None
2045

    
2046
  @classmethod
2047
  def CheckParameterSyntax(cls, hvparams):
2048
    """Check the given parameters for validity.
2049

2050
    @type hvparams:  dict
2051
    @param hvparams: dictionary with parameter names/value
2052
    @raise errors.HypervisorError: when a parameter is not valid
2053

2054
    """
2055
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2056

    
2057
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
2058
    if kernel_path:
2059
      if not hvparams[constants.HV_ROOT_PATH]:
2060
        raise errors.HypervisorError("Need a root partition for the instance,"
2061
                                     " if a kernel is defined")
2062

    
2063
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
2064
        not hvparams[constants.HV_VNC_X509]):
2065
      raise errors.HypervisorError("%s must be defined, if %s is" %
2066
                                   (constants.HV_VNC_X509,
2067
                                    constants.HV_VNC_X509_VERIFY))
2068

    
2069
    if hvparams[constants.HV_SERIAL_CONSOLE]:
2070
      serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2071
      valid_speeds = constants.VALID_SERIAL_SPEEDS
2072
      if not serial_speed or serial_speed not in valid_speeds:
2073
        raise errors.HypervisorError("Invalid serial console speed, must be"
2074
                                     " one of: %s" %
2075
                                     utils.CommaJoin(valid_speeds))
2076

    
2077
    boot_order = hvparams[constants.HV_BOOT_ORDER]
2078
    if (boot_order == constants.HT_BO_CDROM and
2079
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2080
      raise errors.HypervisorError("Cannot boot from cdrom without an"
2081
                                   " ISO path")
2082

    
2083
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2084
    if security_model == constants.HT_SM_USER:
2085
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
2086
        raise errors.HypervisorError("A security domain (user to run kvm as)"
2087
                                     " must be specified")
2088
    elif (security_model == constants.HT_SM_NONE or
2089
          security_model == constants.HT_SM_POOL):
2090
      if hvparams[constants.HV_SECURITY_DOMAIN]:
2091
        raise errors.HypervisorError("Cannot have a security domain when the"
2092
                                     " security model is 'none' or 'pool'")
2093

    
2094
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2095
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2096
    if spice_bind:
2097
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2098
        # if an IP version is specified, the spice_bind parameter must be an
2099
        # IP of that family
2100
        if (netutils.IP4Address.IsValid(spice_bind) and
2101
            spice_ip_version != constants.IP4_VERSION):
2102
          raise errors.HypervisorError("spice: got an IPv4 address (%s), but"
2103
                                       " the specified IP version is %s" %
2104
                                       (spice_bind, spice_ip_version))
2105

    
2106
        if (netutils.IP6Address.IsValid(spice_bind) and
2107
            spice_ip_version != constants.IP6_VERSION):
2108
          raise errors.HypervisorError("spice: got an IPv6 address (%s), but"
2109
                                       " the specified IP version is %s" %
2110
                                       (spice_bind, spice_ip_version))
2111
    else:
2112
      # All the other SPICE parameters depend on spice_bind being set. Raise an
2113
      # error if any of them is set without it.
2114
      for param in _SPICE_ADDITIONAL_PARAMS:
2115
        if hvparams[param]:
2116
          raise errors.HypervisorError("spice: %s requires %s to be set" %
2117
                                       (param, constants.HV_KVM_SPICE_BIND))
2118

    
2119
  @classmethod
2120
  def ValidateParameters(cls, hvparams):
2121
    """Check the given parameters for validity.
2122

2123
    @type hvparams:  dict
2124
    @param hvparams: dictionary with parameter names/value
2125
    @raise errors.HypervisorError: when a parameter is not valid
2126

2127
    """
2128
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
2129

    
2130
    kvm_path = hvparams[constants.HV_KVM_PATH]
2131

    
2132
    security_model = hvparams[constants.HV_SECURITY_MODEL]
2133
    if security_model == constants.HT_SM_USER:
2134
      username = hvparams[constants.HV_SECURITY_DOMAIN]
2135
      try:
2136
        pwd.getpwnam(username)
2137
      except KeyError:
2138
        raise errors.HypervisorError("Unknown security domain user %s"
2139
                                     % username)
2140

    
2141
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2142
    if spice_bind:
2143
      # only one of VNC and SPICE can be used currently.
2144
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2145
        raise errors.HypervisorError("both SPICE and VNC are configured, but"
2146
                                     " only one of them can be used at a"
2147
                                     " given time.")
2148

    
2149
      # check that KVM supports SPICE
2150
      kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2151
      if not cls._SPICE_RE.search(kvmhelp):
2152
        raise errors.HypervisorError("spice is configured, but it is not"
2153
                                     " supported according to kvm --help")
2154

    
2155
      # if spice_bind is not an IP address, it must be a valid interface
2156
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind)
2157
                       or netutils.IP6Address.IsValid(spice_bind))
2158
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2159
        raise errors.HypervisorError("spice: the %s parameter must be either"
2160
                                     " a valid IP address or interface name" %
2161
                                     constants.HV_KVM_SPICE_BIND)
2162

    
2163
    machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2164
    if machine_version:
2165
      output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2166
      if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2167
        raise errors.HypervisorError("Unsupported machine version: %s" %
2168
                                     machine_version)
2169

    
2170
  @classmethod
2171
  def PowercycleNode(cls):
2172
    """KVM powercycle, just a wrapper over Linux powercycle.
2173

2174
    """
2175
    cls.LinuxPowercycle()