Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ a182a3ed

History | View | Annotate | Download (69.7 kB)

1
#
2
#
3

    
4
# Copyright (C) 2008, 2009, 2010, 2011 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.hypervisor import hv_base
53
from ganeti import netutils
54
from ganeti.utils import wrapper as utils_wrapper
55

    
56

    
57
_KVM_NETWORK_SCRIPT = constants.SYSCONFDIR + "/ganeti/kvm-vif-bridge"
58
_KVM_START_PAUSED_FLAG = "-S"
59

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

    
70

    
71
def _ProbeTapVnetHdr(fd):
72
  """Check whether to enable the IFF_VNET_HDR flag.
73

74
  To do this, _all_ of the following conditions must be met:
75
   1. TUNGETFEATURES ioctl() *must* be implemented
76
   2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
77
   3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
78
      drivers/net/tun.c there is no way to test this until after the tap device
79
      has been created using TUNSETIFF, and there is no way to change the
80
      IFF_VNET_HDR flag after creating the interface, catch-22! However both
81
      TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
82
      thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
83

84
   @type fd: int
85
   @param fd: the file descriptor of /dev/net/tun
86

87
  """
88
  req = struct.pack("I", 0)
89
  try:
90
    res = fcntl.ioctl(fd, TUNGETFEATURES, req)
91
  except EnvironmentError:
92
    logging.warning("TUNGETFEATURES ioctl() not implemented")
93
    return False
94

    
95
  tunflags = struct.unpack("I", res)[0]
96
  if tunflags & IFF_VNET_HDR:
97
    return True
98
  else:
99
    logging.warning("Host does not support IFF_VNET_HDR, not enabling")
100
    return False
101

    
102

    
103
def _OpenTap(vnet_hdr=True):
104
  """Open a new tap device and return its file descriptor.
105

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

109
  @type vnet_hdr: boolean
110
  @param vnet_hdr: Enable the VNET Header
111
  @return: (ifname, tapfd)
112
  @rtype: tuple
113

114
  """
115
  try:
116
    tapfd = os.open("/dev/net/tun", os.O_RDWR)
117
  except EnvironmentError:
118
    raise errors.HypervisorError("Failed to open /dev/net/tun")
119

    
120
  flags = IFF_TAP | IFF_NO_PI
121

    
122
  if vnet_hdr and _ProbeTapVnetHdr(tapfd):
123
    flags |= IFF_VNET_HDR
124

    
125
  # The struct ifreq ioctl request (see netdevice(7))
126
  ifr = struct.pack("16sh", "", flags)
127

    
128
  try:
129
    res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
130
  except EnvironmentError:
131
    raise errors.HypervisorError("Failed to allocate a new TAP device")
132

    
133
  # Get the interface name from the ioctl
134
  ifname = struct.unpack("16sh", res)[0].strip("\x00")
135
  return (ifname, tapfd)
136

    
137

    
138
class QmpMessage:
139
  """QEMU Messaging Protocol (QMP) message.
140

141
  """
142

    
143
  def __init__(self, data):
144
    """Creates a new QMP message based on the passed data.
145

146
    """
147
    if not isinstance(data, dict):
148
      raise TypeError("QmpMessage must be initialized with a dict")
149

    
150
    self.data = data
151

    
152
  def __getitem__(self, field_name):
153
    """Get the value of the required field if present, or None.
154

155
    Overrides the [] operator to provide access to the message data,
156
    returning None if the required item is not in the message
157
    @return: the value of the field_name field, or None if field_name
158
             is not contained in the message
159

160
    """
161

    
162
    if field_name in self.data:
163
      return self.data[field_name]
164

    
165
    return None
166

    
167
  def __setitem__(self, field_name, field_value):
168
    """Set the value of the required field_name to field_value.
169

170
    """
171
    self.data[field_name] = field_value
172

    
173
  @staticmethod
174
  def BuildFromJsonString(json_string):
175
    """Build a QmpMessage from a JSON encoded string.
176

177
    @type json_string: str
178
    @param json_string: JSON string representing the message
179
    @rtype: L{QmpMessage}
180
    @return: a L{QmpMessage} built from json_string
181

182
    """
183
    # Parse the string
184
    data = serializer.LoadJson(json_string)
185
    return QmpMessage(data)
186

    
187
  def __str__(self):
188
    # The protocol expects the JSON object to be sent as a single line.
189
    return serializer.DumpJson(self.data)
190

    
191
  def __eq__(self, other):
192
    # When comparing two QmpMessages, we are interested in comparing
193
    # their internal representation of the message data
194
    return self.data == other.data
195

    
196

    
197
class QmpConnection:
198
  """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
199

200
  """
201
  _FIRST_MESSAGE_KEY = "QMP"
202
  _EVENT_KEY = "event"
203
  _ERROR_KEY = "error"
204
  _RETURN_KEY = RETURN_KEY = "return"
205
  _ACTUAL_KEY = ACTUAL_KEY = "actual"
206
  _ERROR_CLASS_KEY = "class"
207
  _ERROR_DATA_KEY = "data"
208
  _ERROR_DESC_KEY = "desc"
209
  _EXECUTE_KEY = "execute"
210
  _ARGUMENTS_KEY = "arguments"
211
  _CAPABILITIES_COMMAND = "qmp_capabilities"
212
  _MESSAGE_END_TOKEN = "\r\n"
213
  _SOCKET_TIMEOUT = 5
214

    
215
  def __init__(self, monitor_filename):
216
    """Instantiates the QmpConnection object.
217

218
    @type monitor_filename: string
219
    @param monitor_filename: the filename of the UNIX raw socket on which the
220
                             QMP monitor is listening
221

222
    """
223
    self.monitor_filename = monitor_filename
224
    self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
225
    # We want to fail if the server doesn't send a complete message
226
    # in a reasonable amount of time
227
    self.sock.settimeout(self._SOCKET_TIMEOUT)
228
    self._connected = False
229
    self._buf = ""
230

    
231
  def _check_socket(self):
232
    sock_stat = None
233
    try:
234
      sock_stat = os.stat(self.monitor_filename)
235
    except EnvironmentError, err:
236
      if err.errno == errno.ENOENT:
237
        raise errors.HypervisorError("No qmp socket found")
238
      else:
239
        raise errors.HypervisorError("Error checking qmp socket: %s",
240
                                     utils.ErrnoOrStr(err))
241
    if not stat.S_ISSOCK(sock_stat.st_mode):
242
      raise errors.HypervisorError("Qmp socket is not a socket")
243

    
244
  def _check_connection(self):
245
    """Make sure that the connection is established.
246

247
    """
248
    if not self._connected:
249
      raise errors.ProgrammerError("To use a QmpConnection you need to first"
250
                                   " invoke connect() on it")
251

    
252
  def connect(self):
253
    """Connects to the QMP monitor.
254

255
    Connects to the UNIX socket and makes sure that we can actually send and
256
    receive data to the kvm instance via QMP.
257

258
    @raise errors.HypervisorError: when there are communication errors
259
    @raise errors.ProgrammerError: when there are data serialization errors
260

261
    """
262
    if self._connected:
263
      raise errors.ProgrammerError("Cannot connect twice")
264

    
265
    self._check_socket()
266

    
267
    # Check file existance/stuff
268
    try:
269
      self.sock.connect(self.monitor_filename)
270
    except EnvironmentError:
271
      raise errors.HypervisorError("Can't connect to qmp socket")
272
    self._connected = True
273

    
274
    # Check if we receive a correct greeting message from the server
275
    # (As per the QEMU Protocol Specification 0.1 - section 2.2)
276
    greeting = self._Recv()
277
    if not greeting[self._FIRST_MESSAGE_KEY]:
278
      self._connected = False
279
      raise errors.HypervisorError("kvm: qmp communication error (wrong"
280
                                   " server greeting")
281

    
282
    # Let's put the monitor in command mode using the qmp_capabilities
283
    # command, or else no command will be executable.
284
    # (As per the QEMU Protocol Specification 0.1 - section 4)
285
    self.Execute(self._CAPABILITIES_COMMAND)
286

    
287
  def _ParseMessage(self, buf):
288
    """Extract and parse a QMP message from the given buffer.
289

290
    Seeks for a QMP message in the given buf. If found, it parses it and
291
    returns it together with the rest of the characters in the buf.
292
    If no message is found, returns None and the whole buffer.
293

294
    @raise errors.ProgrammerError: when there are data serialization errors
295

296
    """
297
    message = None
298
    # Check if we got the message end token (CRLF, as per the QEMU Protocol
299
    # Specification 0.1 - Section 2.1.1)
300
    pos = buf.find(self._MESSAGE_END_TOKEN)
301
    if pos >= 0:
302
      try:
303
        message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
304
      except Exception, err:
305
        raise errors.ProgrammerError("QMP data serialization error: %s" % err)
306
      buf = buf[pos + 1:]
307

    
308
    return (message, buf)
309

    
310
  def _Recv(self):
311
    """Receives a message from QMP and decodes the received JSON object.
312

313
    @rtype: QmpMessage
314
    @return: the received message
315
    @raise errors.HypervisorError: when there are communication errors
316
    @raise errors.ProgrammerError: when there are data serialization errors
317

318
    """
319
    self._check_connection()
320

    
321
    # Check if there is already a message in the buffer
322
    (message, self._buf) = self._ParseMessage(self._buf)
323
    if message:
324
      return message
325

    
326
    recv_buffer = StringIO.StringIO(self._buf)
327
    recv_buffer.seek(len(self._buf))
328
    try:
329
      while True:
330
        data = self.sock.recv(4096)
331
        if not data:
332
          break
333
        recv_buffer.write(data)
334

    
335
        (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
336
        if message:
337
          return message
338

    
339
    except socket.timeout, err:
340
      raise errors.HypervisorError("Timeout while receiving a QMP message: "
341
                                   "%s" % (err))
342
    except socket.error, err:
343
      raise errors.HypervisorError("Unable to receive data from KVM using the"
344
                                   " QMP protocol: %s" % err)
345

    
346
  def _Send(self, message):
347
    """Encodes and sends a message to KVM using QMP.
348

349
    @type message: QmpMessage
350
    @param message: message to send to KVM
351
    @raise errors.HypervisorError: when there are communication errors
352
    @raise errors.ProgrammerError: when there are data serialization errors
353

354
    """
355
    self._check_connection()
356
    try:
357
      message_str = str(message)
358
    except Exception, err:
359
      raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
360

    
361
    try:
362
      self.sock.sendall(message_str)
363
    except socket.timeout, err:
364
      raise errors.HypervisorError("Timeout while sending a QMP message: "
365
                                   "%s (%s)" % (err.string, err.errno))
366
    except socket.error, err:
367
      raise errors.HypervisorError("Unable to send data from KVM using the"
368
                                   " QMP protocol: %s" % err)
369

    
370
  def Execute(self, command, arguments=None):
371
    """Executes a QMP command and returns the response of the server.
372

373
    @type command: str
374
    @param command: the command to execute
375
    @type arguments: dict
376
    @param arguments: dictionary of arguments to be passed to the command
377
    @rtype: dict
378
    @return: dictionary representing the received JSON object
379
    @raise errors.HypervisorError: when there are communication errors
380
    @raise errors.ProgrammerError: when there are data serialization errors
381

382
    """
383
    self._check_connection()
384
    message = QmpMessage({self._EXECUTE_KEY: command})
385
    if arguments:
386
      message[self._ARGUMENTS_KEY] = arguments
387
    self._Send(message)
388

    
389
    # Events can occur between the sending of the command and the reception
390
    # of the response, so we need to filter out messages with the event key.
391
    while True:
392
      response = self._Recv()
393
      err = response[self._ERROR_KEY]
394
      if err:
395
        raise errors.HypervisorError("kvm: error executing the %s"
396
                                     " command: %s (%s, %s):" %
397
                                     (command,
398
                                      err[self._ERROR_DESC_KEY],
399
                                      err[self._ERROR_CLASS_KEY],
400
                                      err[self._ERROR_DATA_KEY]))
401

    
402
      elif not response[self._EVENT_KEY]:
403
        return response
404

    
405

    
406
class KVMHypervisor(hv_base.BaseHypervisor):
407
  """KVM hypervisor interface"""
408
  CAN_MIGRATE = True
409

    
410
  _ROOT_DIR = constants.RUN_GANETI_DIR + "/kvm-hypervisor"
411
  _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
412
  _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
413
  _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
414
  _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
415
  _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
416
  _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
417
  # KVM instances with chroot enabled are started in empty chroot directories.
418
  _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
419
  # After an instance is stopped, its chroot directory is removed.
420
  # If the chroot directory is not empty, it can't be removed.
421
  # A non-empty chroot directory indicates a possible security incident.
422
  # To support forensics, the non-empty chroot directory is quarantined in
423
  # a separate directory, called 'chroot-quarantine'.
424
  _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
425
  _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
426
           _CHROOT_DIR, _CHROOT_QUARANTINE_DIR]
427

    
428
  PARAMETERS = {
429
    constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
430
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
431
    constants.HV_ROOT_PATH: hv_base.NO_CHECK,
432
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
433
    constants.HV_ACPI: hv_base.NO_CHECK,
434
    constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
435
    constants.HV_VNC_BIND_ADDRESS:
436
      (False, lambda x: (netutils.IP4Address.IsValid(x) or
437
                         utils.IsNormAbsPath(x)),
438
       "the VNC bind address must be either a valid IP address or an absolute"
439
       " pathname", None, None),
440
    constants.HV_VNC_TLS: hv_base.NO_CHECK,
441
    constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
442
    constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
443
    constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
444
    constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
445
    constants.HV_KVM_SPICE_IP_VERSION:
446
      (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
447
                         x in constants.VALID_IP_VERSIONS),
448
       "the SPICE IP version should be 4 or 6",
449
       None, None),
450
    constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
451
    constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
452
      hv_base.ParamInSet(False,
453
        constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
454
    constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
455
      hv_base.ParamInSet(False,
456
        constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
457
    constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
458
      hv_base.ParamInSet(False,
459
        constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
460
    constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
461
      hv_base.ParamInSet(False,
462
        constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
463
    constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
464
    constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
465
    constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
466
    constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
467
    constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
468
    constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
469
    constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
470
    constants.HV_BOOT_ORDER:
471
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
472
    constants.HV_NIC_TYPE:
473
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
474
    constants.HV_DISK_TYPE:
475
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
476
    constants.HV_KVM_CDROM_DISK_TYPE:
477
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
478
    constants.HV_USB_MOUSE:
479
      hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
480
    constants.HV_KEYMAP: hv_base.NO_CHECK,
481
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
482
    constants.HV_MIGRATION_BANDWIDTH: hv_base.NO_CHECK,
483
    constants.HV_MIGRATION_DOWNTIME: hv_base.NO_CHECK,
484
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
485
    constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
486
    constants.HV_DISK_CACHE:
487
      hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
488
    constants.HV_SECURITY_MODEL:
489
      hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
490
    constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
491
    constants.HV_KVM_FLAG:
492
      hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
493
    constants.HV_VHOST_NET: hv_base.NO_CHECK,
494
    constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
495
    constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
496
    constants.HV_REBOOT_BEHAVIOR:
497
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
498
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
499
    }
500

    
501
  _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
502
                                    re.M | re.I)
503
  _MIGRATION_PROGRESS_RE = re.compile(
504
      "\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
505
      "\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
506
      "\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
507

    
508
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
509
  _MIGRATION_INFO_RETRY_DELAY = 2
510

    
511
  _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)\.(\d+)\b")
512

    
513
  _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
514
  _CPU_INFO_CMD = "info cpus"
515
  _CONT_CMD = "cont"
516

    
517
  ANCILLARY_FILES = [
518
    _KVM_NETWORK_SCRIPT,
519
    ]
520
  ANCILLARY_FILES_OPT = [
521
    _KVM_NETWORK_SCRIPT,
522
    ]
523

    
524
  def __init__(self):
525
    hv_base.BaseHypervisor.__init__(self)
526
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
527
    # in a tmpfs filesystem or has been otherwise wiped out.
528
    dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
529
    utils.EnsureDirs(dirs)
530

    
531
  @classmethod
532
  def _InstancePidFile(cls, instance_name):
533
    """Returns the instance pidfile.
534

535
    """
536
    return utils.PathJoin(cls._PIDS_DIR, instance_name)
537

    
538
  @classmethod
539
  def _InstanceUidFile(cls, instance_name):
540
    """Returns the instance uidfile.
541

542
    """
543
    return utils.PathJoin(cls._UIDS_DIR, instance_name)
544

    
545
  @classmethod
546
  def _InstancePidInfo(cls, pid):
547
    """Check pid file for instance information.
548

549
    Check that a pid file is associated with an instance, and retrieve
550
    information from its command line.
551

552
    @type pid: string or int
553
    @param pid: process id of the instance to check
554
    @rtype: tuple
555
    @return: (instance_name, memory, vcpus)
556
    @raise errors.HypervisorError: when an instance cannot be found
557

558
    """
559
    alive = utils.IsProcessAlive(pid)
560
    if not alive:
561
      raise errors.HypervisorError("Cannot get info for pid %s" % pid)
562

    
563
    cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
564
    try:
565
      cmdline = utils.ReadFile(cmdline_file)
566
    except EnvironmentError, err:
567
      raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
568
                                   (pid, err))
569

    
570
    instance = None
571
    memory = 0
572
    vcpus = 0
573

    
574
    arg_list = cmdline.split("\x00")
575
    while arg_list:
576
      arg = arg_list.pop(0)
577
      if arg == "-name":
578
        instance = arg_list.pop(0)
579
      elif arg == "-m":
580
        memory = int(arg_list.pop(0))
581
      elif arg == "-smp":
582
        vcpus = int(arg_list.pop(0))
583

    
584
    if instance is None:
585
      raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
586
                                   " instance" % pid)
587

    
588
    return (instance, memory, vcpus)
589

    
590
  def _InstancePidAlive(self, instance_name):
591
    """Returns the instance pidfile, pid, and liveness.
592

593
    @type instance_name: string
594
    @param instance_name: instance name
595
    @rtype: tuple
596
    @return: (pid file name, pid, liveness)
597

598
    """
599
    pidfile = self._InstancePidFile(instance_name)
600
    pid = utils.ReadPidFile(pidfile)
601

    
602
    alive = False
603
    try:
604
      cmd_instance = self._InstancePidInfo(pid)[0]
605
      alive = (cmd_instance == instance_name)
606
    except errors.HypervisorError:
607
      pass
608

    
609
    return (pidfile, pid, alive)
610

    
611
  def _CheckDown(self, instance_name):
612
    """Raises an error unless the given instance is down.
613

614
    """
615
    alive = self._InstancePidAlive(instance_name)[2]
616
    if alive:
617
      raise errors.HypervisorError("Failed to start instance %s: %s" %
618
                                   (instance_name, "already running"))
619

    
620
  @classmethod
621
  def _InstanceMonitor(cls, instance_name):
622
    """Returns the instance monitor socket name
623

624
    """
625
    return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
626

    
627
  @classmethod
628
  def _InstanceSerial(cls, instance_name):
629
    """Returns the instance serial socket name
630

631
    """
632
    return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
633

    
634
  @classmethod
635
  def _InstanceQmpMonitor(cls, instance_name):
636
    """Returns the instance serial QMP socket name
637

638
    """
639
    return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
640

    
641
  @staticmethod
642
  def _SocatUnixConsoleParams():
643
    """Returns the correct parameters for socat
644

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

647
    """
648
    if constants.SOCAT_USE_ESCAPE:
649
      return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
650
    else:
651
      return "echo=0,icanon=0"
652

    
653
  @classmethod
654
  def _InstanceKVMRuntime(cls, instance_name):
655
    """Returns the instance KVM runtime filename
656

657
    """
658
    return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
659

    
660
  @classmethod
661
  def _InstanceChrootDir(cls, instance_name):
662
    """Returns the name of the KVM chroot dir of the instance
663

664
    """
665
    return utils.PathJoin(cls._CHROOT_DIR, instance_name)
666

    
667
  @classmethod
668
  def _InstanceNICDir(cls, instance_name):
669
    """Returns the name of the directory holding the tap device files for a
670
    given instance.
671

672
    """
673
    return utils.PathJoin(cls._NICS_DIR, instance_name)
674

    
675
  @classmethod
676
  def _InstanceNICFile(cls, instance_name, seq):
677
    """Returns the name of the file containing the tap device for a given NIC
678

679
    """
680
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
681

    
682
  @classmethod
683
  def _InstanceKeymapFile(cls, instance_name):
684
    """Returns the name of the file containing the keymap for a given instance
685

686
    """
687
    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
688

    
689
  @classmethod
690
  def _TryReadUidFile(cls, uid_file):
691
    """Try to read a uid file
692

693
    """
694
    if os.path.exists(uid_file):
695
      try:
696
        uid = int(utils.ReadOneLineFile(uid_file))
697
        return uid
698
      except EnvironmentError:
699
        logging.warning("Can't read uid file", exc_info=True)
700
      except (TypeError, ValueError):
701
        logging.warning("Can't parse uid file contents", exc_info=True)
702
    return None
703

    
704
  @classmethod
705
  def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
706
    """Removes an instance's rutime sockets/files/dirs.
707

708
    """
709
    utils.RemoveFile(pidfile)
710
    utils.RemoveFile(cls._InstanceMonitor(instance_name))
711
    utils.RemoveFile(cls._InstanceSerial(instance_name))
712
    utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
713
    utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
714
    utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
715
    uid_file = cls._InstanceUidFile(instance_name)
716
    uid = cls._TryReadUidFile(uid_file)
717
    utils.RemoveFile(uid_file)
718
    if uid is not None:
719
      uidpool.ReleaseUid(uid)
720
    try:
721
      shutil.rmtree(cls._InstanceNICDir(instance_name))
722
    except OSError, err:
723
      if err.errno != errno.ENOENT:
724
        raise
725
    try:
726
      chroot_dir = cls._InstanceChrootDir(instance_name)
727
      utils.RemoveDir(chroot_dir)
728
    except OSError, err:
729
      if err.errno == errno.ENOTEMPTY:
730
        # The chroot directory is expected to be empty, but it isn't.
731
        new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
732
                                          prefix="%s-%s-" %
733
                                          (instance_name,
734
                                           utils.TimestampForFilename()))
735
        logging.warning("The chroot directory of instance %s can not be"
736
                        " removed as it is not empty. Moving it to the"
737
                        " quarantine instead. Please investigate the"
738
                        " contents (%s) and clean up manually",
739
                        instance_name, new_chroot_dir)
740
        utils.RenameFile(chroot_dir, new_chroot_dir)
741
      else:
742
        raise
743

    
744
  @staticmethod
745
  def _ConfigureNIC(instance, seq, nic, tap):
746
    """Run the network configuration script for a specified NIC
747

748
    @param instance: instance we're acting on
749
    @type instance: instance object
750
    @param seq: nic sequence number
751
    @type seq: int
752
    @param nic: nic we're acting on
753
    @type nic: nic object
754
    @param tap: the host's tap interface this NIC corresponds to
755
    @type tap: str
756

757
    """
758

    
759
    if instance.tags:
760
      tags = " ".join(instance.tags)
761
    else:
762
      tags = ""
763

    
764
    env = {
765
      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
766
      "INSTANCE": instance.name,
767
      "MAC": nic.mac,
768
      "MODE": nic.nicparams[constants.NIC_MODE],
769
      "INTERFACE": tap,
770
      "INTERFACE_INDEX": str(seq),
771
      "TAGS": tags,
772
    }
773

    
774
    if nic.ip:
775
      env["IP"] = nic.ip
776

    
777
    if nic.nicparams[constants.NIC_LINK]:
778
      env["LINK"] = nic.nicparams[constants.NIC_LINK]
779

    
780
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
781
      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
782

    
783
    result = utils.RunCmd([constants.KVM_IFUP, tap], env=env)
784
    if result.failed:
785
      raise errors.HypervisorError("Failed to configure interface %s: %s."
786
                                   " Network configuration script output: %s" %
787
                                   (tap, result.fail_reason, result.output))
788

    
789
  @staticmethod
790
  def _VerifyAffinityPackage():
791
    if affinity is None:
792
      raise errors.HypervisorError("affinity Python package not"
793
        " found; cannot use CPU pinning under KVM")
794

    
795
  @staticmethod
796
  def _BuildAffinityCpuMask(cpu_list):
797
    """Create a CPU mask suitable for sched_setaffinity from a list of
798
    CPUs.
799

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

803
    @type cpu_list: list of int
804
    @param cpu_list: list of physical CPU numbers to map to vCPUs in order
805
    @rtype: int
806
    @return: a bit mask of CPU affinities
807

808
    """
809
    if cpu_list == constants.CPU_PINNING_OFF:
810
      return constants.CPU_PINNING_ALL_KVM
811
    else:
812
      return sum(2 ** cpu for cpu in cpu_list)
813

    
814
  @classmethod
815
  def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
816
    """Change CPU affinity for running VM according to given CPU mask.
817

818
    @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
819
    @type cpu_mask: string
820
    @param process_id: process ID of KVM process. Used to pin entire VM
821
                       to physical CPUs.
822
    @type process_id: int
823
    @param thread_dict: map of virtual CPUs to KVM thread IDs
824
    @type thread_dict: dict int:int
825

826
    """
827

    
828
    # Convert the string CPU mask to a list of list of int's
829
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
830

    
831
    if len(cpu_list) == 1:
832
      all_cpu_mapping = cpu_list[0]
833
      if all_cpu_mapping == constants.CPU_PINNING_OFF:
834
        # If CPU pinning has 1 entry that's "all", then do nothing
835
        pass
836
      else:
837
        # If CPU pinning has one non-all entry, map the entire VM to
838
        # one set of physical CPUs
839
        cls._VerifyAffinityPackage()
840
        affinity.set_process_affinity_mask(process_id,
841
          cls._BuildAffinityCpuMask(all_cpu_mapping))
842
    else:
843
      # The number of vCPUs mapped should match the number of vCPUs
844
      # reported by KVM. This was already verified earlier, so
845
      # here only as a sanity check.
846
      assert len(thread_dict) == len(cpu_list)
847
      cls._VerifyAffinityPackage()
848

    
849
      # For each vCPU, map it to the proper list of physical CPUs
850
      for vcpu, i in zip(cpu_list, range(len(cpu_list))):
851
        affinity.set_process_affinity_mask(thread_dict[i],
852
          cls._BuildAffinityCpuMask(vcpu))
853

    
854
  def _GetVcpuThreadIds(self, instance_name):
855
    """Get a mapping of vCPU no. to thread IDs for the instance
856

857
    @type instance_name: string
858
    @param instance_name: instance in question
859
    @rtype: dictionary of int:int
860
    @return: a dictionary mapping vCPU numbers to thread IDs
861

862
    """
863
    result = {}
864
    output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
865
    for line in output.stdout.splitlines():
866
      match = self._CPU_INFO_RE.search(line)
867
      if not match:
868
        continue
869
      grp = map(int, match.groups())
870
      result[grp[0]] = grp[1]
871

    
872
    return result
873

    
874
  def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
875
    """Complete CPU pinning.
876

877
    @type instance_name: string
878
    @param instance_name: name of instance
879
    @type cpu_mask: string
880
    @param cpu_mask: CPU pinning mask as entered by user
881

882
    """
883
    # Get KVM process ID, to be used if need to pin entire VM
884
    _, pid, _ = self._InstancePidAlive(instance_name)
885
    # Get vCPU thread IDs, to be used if need to pin vCPUs separately
886
    thread_dict = self._GetVcpuThreadIds(instance_name)
887
    # Run CPU pinning, based on configured mask
888
    self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
889

    
890
  def ListInstances(self):
891
    """Get the list of running instances.
892

893
    We can do this by listing our live instances directory and
894
    checking whether the associated kvm process is still alive.
895

896
    """
897
    result = []
898
    for name in os.listdir(self._PIDS_DIR):
899
      if self._InstancePidAlive(name)[2]:
900
        result.append(name)
901
    return result
902

    
903
  def GetInstanceInfo(self, instance_name):
904
    """Get instance properties.
905

906
    @type instance_name: string
907
    @param instance_name: the instance name
908
    @rtype: tuple of strings
909
    @return: (name, id, memory, vcpus, stat, times)
910

911
    """
912
    _, pid, alive = self._InstancePidAlive(instance_name)
913
    if not alive:
914
      return None
915

    
916
    _, memory, vcpus = self._InstancePidInfo(pid)
917
    istat = "---b-"
918
    times = "0"
919

    
920
    try:
921
      qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
922
      qmp.connect()
923
      vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
924
      # Will fail if ballooning is not enabled, but we can then just resort to
925
      # the value above.
926
      mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
927
      memory = mem_bytes / 1048576
928
    except errors.HypervisorError:
929
      pass
930

    
931
    return (instance_name, pid, memory, vcpus, istat, times)
932

    
933
  def GetAllInstancesInfo(self):
934
    """Get properties of all instances.
935

936
    @return: list of tuples (name, id, memory, vcpus, stat, times)
937

938
    """
939
    data = []
940
    for name in os.listdir(self._PIDS_DIR):
941
      try:
942
        info = self.GetInstanceInfo(name)
943
      except errors.HypervisorError:
944
        continue
945
      if info:
946
        data.append(info)
947
    return data
948

    
949
  def _GenerateKVMRuntime(self, instance, block_devices, startup_paused):
950
    """Generate KVM information to start an instance.
951

952
    """
953
    # pylint: disable=R0914,R0915
954
    _, v_major, v_min, _ = self._GetKVMVersion()
955

    
956
    pidfile = self._InstancePidFile(instance.name)
957
    kvm = constants.KVM_PATH
958
    kvm_cmd = [kvm]
959
    # used just by the vnc server, if enabled
960
    kvm_cmd.extend(["-name", instance.name])
961
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
962
    kvm_cmd.extend(["-smp", instance.beparams[constants.BE_VCPUS]])
963
    kvm_cmd.extend(["-pidfile", pidfile])
964
    kvm_cmd.extend(["-balloon", "virtio"])
965
    kvm_cmd.extend(["-daemonize"])
966
    if not instance.hvparams[constants.HV_ACPI]:
967
      kvm_cmd.extend(["-no-acpi"])
968
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
969
        constants.INSTANCE_REBOOT_EXIT:
970
      kvm_cmd.extend(["-no-reboot"])
971

    
972
    hvp = instance.hvparams
973
    boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
974
    boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
975
    boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
976
    boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
977

    
978
    self.ValidateParameters(hvp)
979

    
980
    if startup_paused:
981
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
982

    
983
    if hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED:
984
      kvm_cmd.extend(["-enable-kvm"])
985
    elif hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED:
986
      kvm_cmd.extend(["-disable-kvm"])
987

    
988
    if boot_network:
989
      kvm_cmd.extend(["-boot", "n"])
990

    
991
    disk_type = hvp[constants.HV_DISK_TYPE]
992
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
993
      if_val = ",if=virtio"
994
    else:
995
      if_val = ",if=%s" % disk_type
996
    # Cache mode
997
    disk_cache = hvp[constants.HV_DISK_CACHE]
998
    if instance.disk_template in constants.DTS_EXT_MIRROR:
999
      if disk_cache != "none":
1000
        # TODO: make this a hard error, instead of a silent overwrite
1001
        logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1002
                        " to prevent shared storage corruption on migration",
1003
                        disk_cache)
1004
      cache_val = ",cache=none"
1005
    elif disk_cache != constants.HT_CACHE_DEFAULT:
1006
      cache_val = ",cache=%s" % disk_cache
1007
    else:
1008
      cache_val = ""
1009
    for cfdev, dev_path in block_devices:
1010
      if cfdev.mode != constants.DISK_RDWR:
1011
        raise errors.HypervisorError("Instance has read-only disks which"
1012
                                     " are not supported by KVM")
1013
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
1014
      boot_val = ""
1015
      if boot_disk:
1016
        kvm_cmd.extend(["-boot", "c"])
1017
        boot_disk = False
1018
        if (v_major, v_min) < (0, 14) and disk_type != constants.HT_DISK_IDE:
1019
          boot_val = ",boot=on"
1020

    
1021
      drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
1022
                                                cache_val)
1023
      kvm_cmd.extend(["-drive", drive_val])
1024

    
1025
    #Now we can specify a different device type for CDROM devices.
1026
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1027
    if not cdrom_disk_type:
1028
      cdrom_disk_type = disk_type
1029

    
1030
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1031
    if iso_image:
1032
      options = ",format=raw,media=cdrom"
1033
      if boot_cdrom:
1034
        kvm_cmd.extend(["-boot", "d"])
1035
        if cdrom_disk_type != constants.HT_DISK_IDE:
1036
          options = "%s,boot=on,if=%s" % (options, constants.HT_DISK_IDE)
1037
        else:
1038
          options = "%s,boot=on" % options
1039
      else:
1040
        if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1041
          if_val = ",if=virtio"
1042
        else:
1043
          if_val = ",if=%s" % cdrom_disk_type
1044
        options = "%s%s" % (options, if_val)
1045
      drive_val = "file=%s%s" % (iso_image, options)
1046
      kvm_cmd.extend(["-drive", drive_val])
1047

    
1048
    iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1049
    if iso_image2:
1050
      options = ",format=raw,media=cdrom"
1051
      if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1052
        if_val = ",if=virtio"
1053
      else:
1054
        if_val = ",if=%s" % cdrom_disk_type
1055
      options = "%s%s" % (options, if_val)
1056
      drive_val = "file=%s%s" % (iso_image2, options)
1057
      kvm_cmd.extend(["-drive", drive_val])
1058

    
1059
    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1060
    if floppy_image:
1061
      options = ",format=raw,media=disk"
1062
      if boot_floppy:
1063
        kvm_cmd.extend(["-boot", "a"])
1064
        options = "%s,boot=on" % options
1065
      if_val = ",if=floppy"
1066
      options = "%s%s" % (options, if_val)
1067
      drive_val = "file=%s%s" % (floppy_image, options)
1068
      kvm_cmd.extend(["-drive", drive_val])
1069

    
1070
    kernel_path = hvp[constants.HV_KERNEL_PATH]
1071
    if kernel_path:
1072
      kvm_cmd.extend(["-kernel", kernel_path])
1073
      initrd_path = hvp[constants.HV_INITRD_PATH]
1074
      if initrd_path:
1075
        kvm_cmd.extend(["-initrd", initrd_path])
1076
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1077
                     hvp[constants.HV_KERNEL_ARGS]]
1078
      if hvp[constants.HV_SERIAL_CONSOLE]:
1079
        root_append.append("console=ttyS0,38400")
1080
      kvm_cmd.extend(["-append", " ".join(root_append)])
1081

    
1082
    mem_path = hvp[constants.HV_MEM_PATH]
1083
    if mem_path:
1084
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1085

    
1086
    mouse_type = hvp[constants.HV_USB_MOUSE]
1087
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1088

    
1089
    if mouse_type:
1090
      kvm_cmd.extend(["-usb"])
1091
      kvm_cmd.extend(["-usbdevice", mouse_type])
1092
    elif vnc_bind_address:
1093
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1094

    
1095
    keymap = hvp[constants.HV_KEYMAP]
1096
    if keymap:
1097
      keymap_path = self._InstanceKeymapFile(instance.name)
1098
      # If a keymap file is specified, KVM won't use its internal defaults. By
1099
      # first including the "en-us" layout, an error on loading the actual
1100
      # layout (e.g. because it can't be found) won't lead to a non-functional
1101
      # keyboard. A keyboard with incorrect keys is still better than none.
1102
      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1103
      kvm_cmd.extend(["-k", keymap_path])
1104

    
1105
    if vnc_bind_address:
1106
      if netutils.IP4Address.IsValid(vnc_bind_address):
1107
        if instance.network_port > constants.VNC_BASE_PORT:
1108
          display = instance.network_port - constants.VNC_BASE_PORT
1109
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1110
            vnc_arg = ":%d" % (display)
1111
          else:
1112
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
1113
        else:
1114
          logging.error("Network port is not a valid VNC display (%d < %d)."
1115
                        " Not starting VNC", instance.network_port,
1116
                        constants.VNC_BASE_PORT)
1117
          vnc_arg = "none"
1118

    
1119
        # Only allow tls and other option when not binding to a file, for now.
1120
        # kvm/qemu gets confused otherwise about the filename to use.
1121
        vnc_append = ""
1122
        if hvp[constants.HV_VNC_TLS]:
1123
          vnc_append = "%s,tls" % vnc_append
1124
          if hvp[constants.HV_VNC_X509_VERIFY]:
1125
            vnc_append = "%s,x509verify=%s" % (vnc_append,
1126
                                               hvp[constants.HV_VNC_X509])
1127
          elif hvp[constants.HV_VNC_X509]:
1128
            vnc_append = "%s,x509=%s" % (vnc_append,
1129
                                         hvp[constants.HV_VNC_X509])
1130
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
1131
          vnc_append = "%s,password" % vnc_append
1132

    
1133
        vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1134

    
1135
      else:
1136
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1137

    
1138
      kvm_cmd.extend(["-vnc", vnc_arg])
1139
    else:
1140
      kvm_cmd.extend(["-nographic"])
1141

    
1142
    monitor_dev = ("unix:%s,server,nowait" %
1143
                   self._InstanceMonitor(instance.name))
1144
    kvm_cmd.extend(["-monitor", monitor_dev])
1145
    if hvp[constants.HV_SERIAL_CONSOLE]:
1146
      serial_dev = ("unix:%s,server,nowait" %
1147
                    self._InstanceSerial(instance.name))
1148
      kvm_cmd.extend(["-serial", serial_dev])
1149
    else:
1150
      kvm_cmd.extend(["-serial", "none"])
1151

    
1152
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1153
    spice_ip_version = None
1154
    if spice_bind:
1155
      if netutils.IsValidInterface(spice_bind):
1156
        # The user specified a network interface, we have to figure out the IP
1157
        # address.
1158
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1159
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1160

    
1161
        # if the user specified an IP version and the interface does not
1162
        # have that kind of IP addresses, throw an exception
1163
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1164
          if not addresses[spice_ip_version]:
1165
            raise errors.HypervisorError("spice: unable to get an IPv%s address"
1166
                                         " for %s" % (spice_ip_version,
1167
                                                      spice_bind))
1168

    
1169
        # the user did not specify an IP version, we have to figure it out
1170
        elif (addresses[constants.IP4_VERSION] and
1171
              addresses[constants.IP6_VERSION]):
1172
          # we have both ipv4 and ipv6, let's use the cluster default IP
1173
          # version
1174
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1175
          spice_ip_version = netutils.IPAddress.GetVersionFromAddressFamily(
1176
              cluster_family)
1177
        elif addresses[constants.IP4_VERSION]:
1178
          spice_ip_version = constants.IP4_VERSION
1179
        elif addresses[constants.IP6_VERSION]:
1180
          spice_ip_version = constants.IP6_VERSION
1181
        else:
1182
          raise errors.HypervisorError("spice: unable to get an IP address"
1183
                                       " for %s" % (spice_bind))
1184

    
1185
        spice_address = addresses[spice_ip_version][0]
1186

    
1187
      else:
1188
        # spice_bind is known to be a valid IP address, because
1189
        # ValidateParameters checked it.
1190
        spice_address = spice_bind
1191

    
1192
      spice_arg = "addr=%s" % spice_address
1193
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1194
        spice_arg = "%s,tls-port=%s,x509-cacert-file=%s" % (spice_arg,
1195
            instance.network_port, constants.SPICE_CACERT_FILE)
1196
        spice_arg = "%s,x509-key-file=%s,x509-cert-file=%s" % (spice_arg,
1197
            constants.SPICE_CERT_FILE, constants.SPICE_CERT_FILE)
1198
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1199
        if tls_ciphers:
1200
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1201
      else:
1202
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1203

    
1204
      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1205
        spice_arg = "%s,disable-ticketing" % spice_arg
1206

    
1207
      if spice_ip_version:
1208
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1209

    
1210
      # Image compression options
1211
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1212
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1213
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1214
      if img_lossless:
1215
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1216
      if img_jpeg:
1217
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1218
      if img_zlib_glz:
1219
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1220

    
1221
      # Video stream detection
1222
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1223
      if video_streaming:
1224
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1225

    
1226
      # Audio compression, by default in qemu-kvm it is on
1227
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1228
        spice_arg = "%s,playback-compression=off" % spice_arg
1229
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1230
        spice_arg = "%s,agent-mouse=off" % spice_arg
1231

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

    
1235
      # Tell kvm to use the paravirtualized graphic card, optimized for SPICE
1236
      kvm_cmd.extend(["-vga", "qxl"])
1237

    
1238
    if hvp[constants.HV_USE_LOCALTIME]:
1239
      kvm_cmd.extend(["-localtime"])
1240

    
1241
    if hvp[constants.HV_KVM_USE_CHROOT]:
1242
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1243

    
1244
    # Save the current instance nics, but defer their expansion as parameters,
1245
    # as we'll need to generate executable temp files for them.
1246
    kvm_nics = instance.nics
1247
    hvparams = hvp
1248

    
1249
    return (kvm_cmd, kvm_nics, hvparams)
1250

    
1251
  def _WriteKVMRuntime(self, instance_name, data):
1252
    """Write an instance's KVM runtime
1253

1254
    """
1255
    try:
1256
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1257
                      data=data)
1258
    except EnvironmentError, err:
1259
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1260

    
1261
  def _ReadKVMRuntime(self, instance_name):
1262
    """Read an instance's KVM runtime
1263

1264
    """
1265
    try:
1266
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1267
    except EnvironmentError, err:
1268
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1269
    return file_content
1270

    
1271
  def _SaveKVMRuntime(self, instance, kvm_runtime):
1272
    """Save an instance's KVM runtime
1273

1274
    """
1275
    kvm_cmd, kvm_nics, hvparams = kvm_runtime
1276
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1277
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1278
    self._WriteKVMRuntime(instance.name, serialized_form)
1279

    
1280
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1281
    """Load an instance's KVM runtime
1282

1283
    """
1284
    if not serialized_runtime:
1285
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1286
    loaded_runtime = serializer.Load(serialized_runtime)
1287
    kvm_cmd, serialized_nics, hvparams = loaded_runtime
1288
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1289
    return (kvm_cmd, kvm_nics, hvparams)
1290

    
1291
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1292
    """Run the KVM cmd and check for errors
1293

1294
    @type name: string
1295
    @param name: instance name
1296
    @type kvm_cmd: list of strings
1297
    @param kvm_cmd: runcmd input for kvm
1298
    @type tap_fds: list of int
1299
    @param tap_fds: fds of tap devices opened by Ganeti
1300

1301
    """
1302
    try:
1303
      result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1304
    finally:
1305
      for fd in tap_fds:
1306
        utils_wrapper.CloseFdNoError(fd)
1307

    
1308
    if result.failed:
1309
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1310
                                   (name, result.fail_reason, result.output))
1311
    if not self._InstancePidAlive(name)[2]:
1312
      raise errors.HypervisorError("Failed to start instance %s" % name)
1313

    
1314
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
1315
    """Execute a KVM cmd, after completing it with some last minute data
1316

1317
    @type incoming: tuple of strings
1318
    @param incoming: (target_host_ip, port)
1319

1320
    """
1321
    # Small _ExecuteKVMRuntime hv parameters programming howto:
1322
    #  - conf_hvp contains the parameters as configured on ganeti. they might
1323
    #    have changed since the instance started; only use them if the change
1324
    #    won't affect the inside of the instance (which hasn't been rebooted).
1325
    #  - up_hvp contains the parameters as they were when the instance was
1326
    #    started, plus any new parameter which has been added between ganeti
1327
    #    versions: it is paramount that those default to a value which won't
1328
    #    affect the inside of the instance as well.
1329
    conf_hvp = instance.hvparams
1330
    name = instance.name
1331
    self._CheckDown(name)
1332

    
1333
    temp_files = []
1334

    
1335
    kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1336
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1337

    
1338
    _, v_major, v_min, _ = self._GetKVMVersion()
1339

    
1340
    # We know it's safe to run as a different user upon migration, so we'll use
1341
    # the latest conf, from conf_hvp.
1342
    security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1343
    if security_model == constants.HT_SM_USER:
1344
      kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1345

    
1346
    # We have reasons to believe changing something like the nic driver/type
1347
    # upon migration won't exactly fly with the instance kernel, so for nic
1348
    # related parameters we'll use up_hvp
1349
    tapfds = []
1350
    taps = []
1351
    if not kvm_nics:
1352
      kvm_cmd.extend(["-net", "none"])
1353
    else:
1354
      vnet_hdr = False
1355
      tap_extra = ""
1356
      nic_type = up_hvp[constants.HV_NIC_TYPE]
1357
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
1358
        # From version 0.12.0, kvm uses a new sintax for network configuration.
1359
        if (v_major, v_min) >= (0, 12):
1360
          nic_model = "virtio-net-pci"
1361
          vnet_hdr = True
1362
        else:
1363
          nic_model = "virtio"
1364

    
1365
        if up_hvp[constants.HV_VHOST_NET]:
1366
          # vhost_net is only available from version 0.13.0 or newer
1367
          if (v_major, v_min) >= (0, 13):
1368
            tap_extra = ",vhost=on"
1369
          else:
1370
            raise errors.HypervisorError("vhost_net is configured"
1371
                                        " but it is not available")
1372
      else:
1373
        nic_model = nic_type
1374

    
1375
      for nic_seq, nic in enumerate(kvm_nics):
1376
        tapname, tapfd = _OpenTap(vnet_hdr)
1377
        tapfds.append(tapfd)
1378
        taps.append(tapname)
1379
        if (v_major, v_min) >= (0, 12):
1380
          nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1381
          tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1382
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1383
        else:
1384
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1385
                                                         nic.mac, nic_model)
1386
          tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1387
          kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1388

    
1389
    if incoming:
1390
      target, port = incoming
1391
      kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1392

    
1393
    # Changing the vnc password doesn't bother the guest that much. At most it
1394
    # will surprise people who connect to it. Whether positively or negatively
1395
    # it's debatable.
1396
    vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1397
    vnc_pwd = None
1398
    if vnc_pwd_file:
1399
      try:
1400
        vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1401
      except EnvironmentError, err:
1402
        raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1403
                                     % (vnc_pwd_file, err))
1404

    
1405
    if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1406
      utils.EnsureDirs([(self._InstanceChrootDir(name),
1407
                         constants.SECURE_DIR_MODE)])
1408

    
1409
    # Automatically enable QMP if version is >= 0.14
1410
    if (v_major, v_min) >= (0, 14):
1411
      logging.debug("Enabling QMP")
1412
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1413
                    self._InstanceQmpMonitor(instance.name)])
1414

    
1415
    # Configure the network now for starting instances and bridged interfaces,
1416
    # during FinalizeMigration for incoming instances' routed interfaces
1417
    for nic_seq, nic in enumerate(kvm_nics):
1418
      if (incoming and
1419
          nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1420
        continue
1421
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1422

    
1423
    # CPU affinity requires kvm to start paused, so we set this flag if the
1424
    # instance is not already paused and if we are not going to accept a
1425
    # migrating instance. In the latter case, pausing is not needed.
1426
    start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1427

    
1428
    # Note: CPU pinning is using up_hvp since changes take effect
1429
    # during instance startup anyway, and to avoid problems when soft
1430
    # rebooting the instance.
1431
    cpu_pinning = False
1432
    if up_hvp.get(constants.HV_CPU_MASK, None):
1433
      cpu_pinning = True
1434
      if start_kvm_paused:
1435
        kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1436

    
1437
    if security_model == constants.HT_SM_POOL:
1438
      ss = ssconf.SimpleStore()
1439
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1440
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
1441
      uid = uidpool.RequestUnusedUid(all_uids)
1442
      try:
1443
        username = pwd.getpwuid(uid.GetUid()).pw_name
1444
        kvm_cmd.extend(["-runas", username])
1445
        self._RunKVMCmd(name, kvm_cmd, tapfds)
1446
      except:
1447
        uidpool.ReleaseUid(uid)
1448
        raise
1449
      else:
1450
        uid.Unlock()
1451
        utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1452
    else:
1453
      self._RunKVMCmd(name, kvm_cmd, tapfds)
1454

    
1455
    utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1456
                     constants.RUN_DIRS_MODE)])
1457
    for nic_seq, tap in enumerate(taps):
1458
      utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1459
                      data=tap)
1460

    
1461
    if vnc_pwd:
1462
      change_cmd = "change vnc password %s" % vnc_pwd
1463
      self._CallMonitorCommand(instance.name, change_cmd)
1464

    
1465
    # Setting SPICE password. We are not vulnerable to malicious passwordless
1466
    # connection attempts because SPICE by default does not allow connections
1467
    # if neither a password nor the "disable_ticketing" options are specified.
1468
    # As soon as we send the password via QMP, that password is a valid ticket
1469
    # for connection.
1470
    spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1471
    if spice_password_file:
1472
      spice_pwd = ""
1473
      try:
1474
        spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1475
      except EnvironmentError, err:
1476
        raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1477
                                     % (spice_password_file, err))
1478

    
1479
      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1480
      qmp.connect()
1481
      arguments = {
1482
          "protocol": "spice",
1483
          "password": spice_pwd,
1484
      }
1485
      qmp.Execute("set_password", arguments)
1486

    
1487
    for filename in temp_files:
1488
      utils.RemoveFile(filename)
1489

    
1490
    # If requested, set CPU affinity and resume instance execution
1491
    if cpu_pinning:
1492
      try:
1493
        self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1494
      finally:
1495
        if start_kvm_paused:
1496
          # To control CPU pinning, the VM was started frozen, so we need
1497
          # to resume its execution, but only if freezing was not
1498
          # explicitly requested.
1499
          # Note: this is done even when an exception occurred so the VM
1500
          # is not unintentionally frozen.
1501
          self._CallMonitorCommand(instance.name, self._CONT_CMD)
1502

    
1503
  def StartInstance(self, instance, block_devices, startup_paused):
1504
    """Start an instance.
1505

1506
    """
1507
    self._CheckDown(instance.name)
1508
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1509
                                           startup_paused)
1510
    self._SaveKVMRuntime(instance, kvm_runtime)
1511
    self._ExecuteKVMRuntime(instance, kvm_runtime)
1512

    
1513
  def _CallMonitorCommand(self, instance_name, command):
1514
    """Invoke a command on the instance monitor.
1515

1516
    """
1517
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1518
             (utils.ShellQuote(command),
1519
              constants.SOCAT_PATH,
1520
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
1521
    result = utils.RunCmd(socat)
1522
    if result.failed:
1523
      msg = ("Failed to send command '%s' to instance %s."
1524
             " output: %s, error: %s, fail_reason: %s" %
1525
             (command, instance_name,
1526
              result.stdout, result.stderr, result.fail_reason))
1527
      raise errors.HypervisorError(msg)
1528

    
1529
    return result
1530

    
1531
  @classmethod
1532
  def _GetKVMVersion(cls):
1533
    """Return the installed KVM version.
1534

1535
    @return: (version, v_maj, v_min, v_rev)
1536
    @raise L{errors.HypervisorError}: when the KVM version cannot be retrieved
1537

1538
    """
1539
    result = utils.RunCmd([constants.KVM_PATH, "--help"])
1540
    if result.failed:
1541
      raise errors.HypervisorError("Unable to get KVM version")
1542
    match = cls._VERSION_RE.search(result.output.splitlines()[0])
1543
    if not match:
1544
      raise errors.HypervisorError("Unable to get KVM version")
1545

    
1546
    return (match.group(0), int(match.group(1)), int(match.group(2)),
1547
            int(match.group(3)))
1548

    
1549
  def StopInstance(self, instance, force=False, retry=False, name=None):
1550
    """Stop an instance.
1551

1552
    """
1553
    if name is not None and not force:
1554
      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1555
    if name is None:
1556
      name = instance.name
1557
      acpi = instance.hvparams[constants.HV_ACPI]
1558
    else:
1559
      acpi = False
1560
    _, pid, alive = self._InstancePidAlive(name)
1561
    if pid > 0 and alive:
1562
      if force or not acpi:
1563
        utils.KillProcess(pid)
1564
      else:
1565
        self._CallMonitorCommand(name, "system_powerdown")
1566

    
1567
  def CleanupInstance(self, instance_name):
1568
    """Cleanup after a stopped instance
1569

1570
    """
1571
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
1572
    if pid > 0 and alive:
1573
      raise errors.HypervisorError("Cannot cleanup a live instance")
1574
    self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1575

    
1576
  def RebootInstance(self, instance):
1577
    """Reboot an instance.
1578

1579
    """
1580
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1581
    # socket the instance will stop, but now power up again. So we'll resort
1582
    # to shutdown and restart.
1583
    _, _, alive = self._InstancePidAlive(instance.name)
1584
    if not alive:
1585
      raise errors.HypervisorError("Failed to reboot instance %s:"
1586
                                   " not running" % instance.name)
1587
    # StopInstance will delete the saved KVM runtime so:
1588
    # ...first load it...
1589
    kvm_runtime = self._LoadKVMRuntime(instance)
1590
    # ...now we can safely call StopInstance...
1591
    if not self.StopInstance(instance):
1592
      self.StopInstance(instance, force=True)
1593
    # ...and finally we can save it again, and execute it...
1594
    self._SaveKVMRuntime(instance, kvm_runtime)
1595
    self._ExecuteKVMRuntime(instance, kvm_runtime)
1596

    
1597
  def MigrationInfo(self, instance):
1598
    """Get instance information to perform a migration.
1599

1600
    @type instance: L{objects.Instance}
1601
    @param instance: instance to be migrated
1602
    @rtype: string
1603
    @return: content of the KVM runtime file
1604

1605
    """
1606
    return self._ReadKVMRuntime(instance.name)
1607

    
1608
  def AcceptInstance(self, instance, info, target):
1609
    """Prepare to accept an instance.
1610

1611
    @type instance: L{objects.Instance}
1612
    @param instance: instance to be accepted
1613
    @type info: string
1614
    @param info: content of the KVM runtime file on the source node
1615
    @type target: string
1616
    @param target: target host (usually ip), on this node
1617

1618
    """
1619
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1620
    incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1621
    self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
1622

    
1623
  def FinalizeMigrationDst(self, instance, info, success):
1624
    """Finalize the instance migration on the target node.
1625

1626
    Stop the incoming mode KVM.
1627

1628
    @type instance: L{objects.Instance}
1629
    @param instance: instance whose migration is being finalized
1630

1631
    """
1632
    if success:
1633
      kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1634
      kvm_nics = kvm_runtime[1]
1635

    
1636
      for nic_seq, nic in enumerate(kvm_nics):
1637
        if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1638
          # Bridged interfaces have already been configured
1639
          continue
1640
        try:
1641
          tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1642
        except EnvironmentError, err:
1643
          logging.warning("Failed to find host interface for %s NIC #%d: %s",
1644
                          instance.name, nic_seq, str(err))
1645
          continue
1646
        try:
1647
          self._ConfigureNIC(instance, nic_seq, nic, tap)
1648
        except errors.HypervisorError, err:
1649
          logging.warning(str(err))
1650

    
1651
      self._WriteKVMRuntime(instance.name, info)
1652
    else:
1653
      self.StopInstance(instance, force=True)
1654

    
1655
  def MigrateInstance(self, instance, target, live):
1656
    """Migrate an instance to a target node.
1657

1658
    The migration will not be attempted if the instance is not
1659
    currently running.
1660

1661
    @type instance: L{objects.Instance}
1662
    @param instance: the instance to be migrated
1663
    @type target: string
1664
    @param target: ip address of the target node
1665
    @type live: boolean
1666
    @param live: perform a live migration
1667

1668
    """
1669
    instance_name = instance.name
1670
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
1671
    _, _, alive = self._InstancePidAlive(instance_name)
1672
    if not alive:
1673
      raise errors.HypervisorError("Instance not running, cannot migrate")
1674

    
1675
    if not live:
1676
      self._CallMonitorCommand(instance_name, "stop")
1677

    
1678
    migrate_command = ("migrate_set_speed %dm" %
1679
        instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1680
    self._CallMonitorCommand(instance_name, migrate_command)
1681

    
1682
    migrate_command = ("migrate_set_downtime %dms" %
1683
        instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1684
    self._CallMonitorCommand(instance_name, migrate_command)
1685

    
1686
    migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1687
    self._CallMonitorCommand(instance_name, migrate_command)
1688

    
1689
  def FinalizeMigrationSource(self, instance, success, live):
1690
    """Finalize the instance migration on the source node.
1691

1692
    @type instance: L{objects.Instance}
1693
    @param instance: the instance that was migrated
1694
    @type success: bool
1695
    @param success: whether the migration succeeded or not
1696
    @type live: bool
1697
    @param live: whether the user requested a live migration or not
1698

1699
    """
1700
    if success:
1701
      pidfile, pid, _ = self._InstancePidAlive(instance.name)
1702
      utils.KillProcess(pid)
1703
      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1704
    elif live:
1705
      self._CallMonitorCommand(instance.name, self._CONT_CMD)
1706

    
1707
  def GetMigrationStatus(self, instance):
1708
    """Get the migration status
1709

1710
    @type instance: L{objects.Instance}
1711
    @param instance: the instance that is being migrated
1712
    @rtype: L{objects.MigrationStatus}
1713
    @return: the status of the current migration (one of
1714
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1715
             progress info that can be retrieved from the hypervisor
1716

1717
    """
1718
    info_command = "info migrate"
1719
    for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
1720
      result = self._CallMonitorCommand(instance.name, info_command)
1721
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
1722
      if not match:
1723
        if not result.stdout:
1724
          logging.info("KVM: empty 'info migrate' result")
1725
        else:
1726
          logging.warning("KVM: unknown 'info migrate' result: %s",
1727
                          result.stdout)
1728
      else:
1729
        status = match.group(1)
1730
        if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
1731
          migration_status = objects.MigrationStatus(status=status)
1732
          match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
1733
          if match:
1734
            migration_status.transferred_ram = match.group("transferred")
1735
            migration_status.total_ram = match.group("total")
1736

    
1737
          return migration_status
1738

    
1739
        logging.warning("KVM: unknown migration status '%s'", status)
1740

    
1741
      time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1742

    
1743
    return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED,
1744
                                  info="Too many 'info migrate' broken answers")
1745

    
1746
  def GetNodeInfo(self):
1747
    """Return information about the node.
1748

1749
    @return: a dict with the following keys (values in MiB):
1750
          - memory_total: the total memory size on the node
1751
          - memory_free: the available memory on the node for instances
1752
          - memory_dom0: the memory used by the node itself, if available
1753
          - hv_version: the hypervisor version in the form (major, minor,
1754
                        revision)
1755

1756
    """
1757
    result = self.GetLinuxNodeInfo()
1758
    _, v_major, v_min, v_rev = self._GetKVMVersion()
1759
    result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
1760
    return result
1761

    
1762
  @classmethod
1763
  def GetInstanceConsole(cls, instance, hvparams, beparams):
1764
    """Return a command for connecting to the console of an instance.
1765

1766
    """
1767
    if hvparams[constants.HV_SERIAL_CONSOLE]:
1768
      cmd = [constants.KVM_CONSOLE_WRAPPER,
1769
             constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1770
             utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1771
             "STDIO,%s" % cls._SocatUnixConsoleParams(),
1772
             "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1773
      return objects.InstanceConsole(instance=instance.name,
1774
                                     kind=constants.CONS_SSH,
1775
                                     host=instance.primary_node,
1776
                                     user=constants.GANETI_RUNAS,
1777
                                     command=cmd)
1778

    
1779
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1780
    if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1781
      display = instance.network_port - constants.VNC_BASE_PORT
1782
      return objects.InstanceConsole(instance=instance.name,
1783
                                     kind=constants.CONS_VNC,
1784
                                     host=vnc_bind_address,
1785
                                     port=instance.network_port,
1786
                                     display=display)
1787

    
1788
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1789
    if spice_bind:
1790
      return objects.InstanceConsole(instance=instance.name,
1791
                                     kind=constants.CONS_SPICE,
1792
                                     host=spice_bind,
1793
                                     port=instance.network_port)
1794

    
1795
    return objects.InstanceConsole(instance=instance.name,
1796
                                   kind=constants.CONS_MESSAGE,
1797
                                   message=("No serial shell for instance %s" %
1798
                                            instance.name))
1799

    
1800
  def Verify(self):
1801
    """Verify the hypervisor.
1802

1803
    Check that the binary exists.
1804

1805
    """
1806
    if not os.path.exists(constants.KVM_PATH):
1807
      return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
1808
    if not os.path.exists(constants.SOCAT_PATH):
1809
      return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
1810

    
1811
  @classmethod
1812
  def CheckParameterSyntax(cls, hvparams):
1813
    """Check the given parameters for validity.
1814

1815
    @type hvparams:  dict
1816
    @param hvparams: dictionary with parameter names/value
1817
    @raise errors.HypervisorError: when a parameter is not valid
1818

1819
    """
1820
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
1821

    
1822
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
1823
    if kernel_path:
1824
      if not hvparams[constants.HV_ROOT_PATH]:
1825
        raise errors.HypervisorError("Need a root partition for the instance,"
1826
                                     " if a kernel is defined")
1827

    
1828
    if (hvparams[constants.HV_VNC_X509_VERIFY] and
1829
        not hvparams[constants.HV_VNC_X509]):
1830
      raise errors.HypervisorError("%s must be defined, if %s is" %
1831
                                   (constants.HV_VNC_X509,
1832
                                    constants.HV_VNC_X509_VERIFY))
1833

    
1834
    boot_order = hvparams[constants.HV_BOOT_ORDER]
1835
    if (boot_order == constants.HT_BO_CDROM and
1836
        not hvparams[constants.HV_CDROM_IMAGE_PATH]):
1837
      raise errors.HypervisorError("Cannot boot from cdrom without an"
1838
                                   " ISO path")
1839

    
1840
    security_model = hvparams[constants.HV_SECURITY_MODEL]
1841
    if security_model == constants.HT_SM_USER:
1842
      if not hvparams[constants.HV_SECURITY_DOMAIN]:
1843
        raise errors.HypervisorError("A security domain (user to run kvm as)"
1844
                                     " must be specified")
1845
    elif (security_model == constants.HT_SM_NONE or
1846
          security_model == constants.HT_SM_POOL):
1847
      if hvparams[constants.HV_SECURITY_DOMAIN]:
1848
        raise errors.HypervisorError("Cannot have a security domain when the"
1849
                                     " security model is 'none' or 'pool'")
1850

    
1851
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1852
    spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
1853
    if spice_bind:
1854
      if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1855
        # if an IP version is specified, the spice_bind parameter must be an
1856
        # IP of that family
1857
        if (netutils.IP4Address.IsValid(spice_bind) and
1858
            spice_ip_version != constants.IP4_VERSION):
1859
          raise errors.HypervisorError("spice: got an IPv4 address (%s), but"
1860
                                       " the specified IP version is %s" %
1861
                                       (spice_bind, spice_ip_version))
1862

    
1863
        if (netutils.IP6Address.IsValid(spice_bind) and
1864
            spice_ip_version != constants.IP6_VERSION):
1865
          raise errors.HypervisorError("spice: got an IPv6 address (%s), but"
1866
                                       " the specified IP version is %s" %
1867
                                       (spice_bind, spice_ip_version))
1868
    else:
1869
      # All the other SPICE parameters depend on spice_bind being set. Raise an
1870
      # error if any of them is set without it.
1871
      spice_additional_params = frozenset([
1872
        constants.HV_KVM_SPICE_IP_VERSION,
1873
        constants.HV_KVM_SPICE_PASSWORD_FILE,
1874
        constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR,
1875
        constants.HV_KVM_SPICE_JPEG_IMG_COMPR,
1876
        constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR,
1877
        constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION,
1878
        constants.HV_KVM_SPICE_USE_TLS,
1879
        ])
1880
      for param in spice_additional_params:
1881
        if hvparams[param]:
1882
          raise errors.HypervisorError("spice: %s requires %s to be set" %
1883
                                       (param, constants.HV_KVM_SPICE_BIND))
1884

    
1885
  @classmethod
1886
  def ValidateParameters(cls, hvparams):
1887
    """Check the given parameters for validity.
1888

1889
    @type hvparams:  dict
1890
    @param hvparams: dictionary with parameter names/value
1891
    @raise errors.HypervisorError: when a parameter is not valid
1892

1893
    """
1894
    super(KVMHypervisor, cls).ValidateParameters(hvparams)
1895

    
1896
    security_model = hvparams[constants.HV_SECURITY_MODEL]
1897
    if security_model == constants.HT_SM_USER:
1898
      username = hvparams[constants.HV_SECURITY_DOMAIN]
1899
      try:
1900
        pwd.getpwnam(username)
1901
      except KeyError:
1902
        raise errors.HypervisorError("Unknown security domain user %s"
1903
                                     % username)
1904

    
1905
    spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1906
    if spice_bind:
1907
      # only one of VNC and SPICE can be used currently.
1908
      if hvparams[constants.HV_VNC_BIND_ADDRESS]:
1909
        raise errors.HypervisorError("both SPICE and VNC are configured, but"
1910
                                     " only one of them can be used at a"
1911
                                     " given time.")
1912

    
1913
      # KVM version should be >= 0.14.0
1914
      _, v_major, v_min, _ = cls._GetKVMVersion()
1915
      if (v_major, v_min) < (0, 14):
1916
        raise errors.HypervisorError("spice is configured, but it is not"
1917
                                     " available in versions of KVM < 0.14")
1918

    
1919
      # if spice_bind is not an IP address, it must be a valid interface
1920
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind)
1921
                       or netutils.IP6Address.IsValid(spice_bind))
1922
      if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
1923
        raise errors.HypervisorError("spice: the %s parameter must be either"
1924
                                     " a valid IP address or interface name" %
1925
                                     constants.HV_KVM_SPICE_BIND)
1926

    
1927
  @classmethod
1928
  def PowercycleNode(cls):
1929
    """KVM powercycle, just a wrapper over Linux powercycle.
1930

1931
    """
1932
    cls.LinuxPowercycle()