Implementation of TLS-protected SPICE connections
[ganeti-local] / lib / hypervisor / hv_kvm.py
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 StringIO
39
40 from ganeti import utils
41 from ganeti import constants
42 from ganeti import errors
43 from ganeti import serializer
44 from ganeti import objects
45 from ganeti import uidpool
46 from ganeti import ssconf
47 from ganeti.hypervisor import hv_base
48 from ganeti import netutils
49 from ganeti.utils import wrapper as utils_wrapper
50
51
52 _KVM_NETWORK_SCRIPT = constants.SYSCONFDIR + "/ganeti/kvm-vif-bridge"
53
54 # TUN/TAP driver constants, taken from <linux/if_tun.h>
55 # They are architecture-independent and already hardcoded in qemu-kvm source,
56 # so we can safely include them here.
57 TUNSETIFF = 0x400454ca
58 TUNGETIFF = 0x800454d2
59 TUNGETFEATURES = 0x800454cf
60 IFF_TAP = 0x0002
61 IFF_NO_PI = 0x1000
62 IFF_VNET_HDR = 0x4000
63
64
65 def _ProbeTapVnetHdr(fd):
66   """Check whether to enable the IFF_VNET_HDR flag.
67
68   To do this, _all_ of the following conditions must be met:
69    1. TUNGETFEATURES ioctl() *must* be implemented
70    2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
71    3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
72       drivers/net/tun.c there is no way to test this until after the tap device
73       has been created using TUNSETIFF, and there is no way to change the
74       IFF_VNET_HDR flag after creating the interface, catch-22! However both
75       TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
76       thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
77
78    @type fd: int
79    @param fd: the file descriptor of /dev/net/tun
80
81   """
82   req = struct.pack("I", 0)
83   try:
84     res = fcntl.ioctl(fd, TUNGETFEATURES, req)
85   except EnvironmentError:
86     logging.warning("TUNGETFEATURES ioctl() not implemented")
87     return False
88
89   tunflags = struct.unpack("I", res)[0]
90   if tunflags & IFF_VNET_HDR:
91     return True
92   else:
93     logging.warning("Host does not support IFF_VNET_HDR, not enabling")
94     return False
95
96
97 def _OpenTap(vnet_hdr=True):
98   """Open a new tap device and return its file descriptor.
99
100   This is intended to be used by a qemu-type hypervisor together with the -net
101   tap,fd=<fd> command line parameter.
102
103   @type vnet_hdr: boolean
104   @param vnet_hdr: Enable the VNET Header
105   @return: (ifname, tapfd)
106   @rtype: tuple
107
108   """
109   try:
110     tapfd = os.open("/dev/net/tun", os.O_RDWR)
111   except EnvironmentError:
112     raise errors.HypervisorError("Failed to open /dev/net/tun")
113
114   flags = IFF_TAP | IFF_NO_PI
115
116   if vnet_hdr and _ProbeTapVnetHdr(tapfd):
117     flags |= IFF_VNET_HDR
118
119   # The struct ifreq ioctl request (see netdevice(7))
120   ifr = struct.pack("16sh", "", flags)
121
122   try:
123     res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
124   except EnvironmentError:
125     raise errors.HypervisorError("Failed to allocate a new TAP device")
126
127   # Get the interface name from the ioctl
128   ifname = struct.unpack("16sh", res)[0].strip("\x00")
129   return (ifname, tapfd)
130
131
132 class QmpMessage:
133   """QEMU Messaging Protocol (QMP) message.
134
135   """
136
137   def __init__(self, data):
138     """Creates a new QMP message based on the passed data.
139
140     """
141     if not isinstance(data, dict):
142       raise TypeError("QmpMessage must be initialized with a dict")
143
144     self.data = data
145
146   def __getitem__(self, field_name):
147     """Get the value of the required field if present, or None.
148
149     Overrides the [] operator to provide access to the message data,
150     returning None if the required item is not in the message
151     @return: the value of the field_name field, or None if field_name
152              is not contained in the message
153
154     """
155
156     if field_name in self.data:
157       return self.data[field_name]
158
159     return None
160
161   def __setitem__(self, field_name, field_value):
162     """Set the value of the required field_name to field_value.
163
164     """
165     self.data[field_name] = field_value
166
167   @staticmethod
168   def BuildFromJsonString(json_string):
169     """Build a QmpMessage from a JSON encoded string.
170
171     @type json_string: str
172     @param json_string: JSON string representing the message
173     @rtype: L{QmpMessage}
174     @return: a L{QmpMessage} built from json_string
175
176     """
177     # Parse the string
178     data = serializer.LoadJson(json_string)
179     return QmpMessage(data)
180
181   def __str__(self):
182     # The protocol expects the JSON object to be sent as a single
183     # line, hence the need for indent=False.
184     return serializer.DumpJson(self.data, indent=False)
185
186   def __eq__(self, other):
187     # When comparing two QmpMessages, we are interested in comparing
188     # their internal representation of the message data
189     return self.data == other.data
190
191
192 class QmpConnection:
193   """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
194
195   """
196   _FIRST_MESSAGE_KEY = "QMP"
197   _EVENT_KEY = "event"
198   _ERROR_KEY = "error"
199   _ERROR_CLASS_KEY = "class"
200   _ERROR_DATA_KEY = "data"
201   _ERROR_DESC_KEY = "desc"
202   _EXECUTE_KEY = "execute"
203   _ARGUMENTS_KEY = "arguments"
204   _CAPABILITIES_COMMAND = "qmp_capabilities"
205   _MESSAGE_END_TOKEN = "\r\n"
206   _SOCKET_TIMEOUT = 5
207
208   def __init__(self, monitor_filename):
209     """Instantiates the QmpConnection object.
210
211     @type monitor_filename: string
212     @param monitor_filename: the filename of the UNIX raw socket on which the
213                              QMP monitor is listening
214
215     """
216     self.monitor_filename = monitor_filename
217     self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
218     # We want to fail if the server doesn't send a complete message
219     # in a reasonable amount of time
220     self.sock.settimeout(self._SOCKET_TIMEOUT)
221     self._connected = False
222     self._buf = ""
223
224   def _check_connection(self):
225     """Make sure that the connection is established.
226
227     """
228     if not self._connected:
229       raise errors.ProgrammerError("To use a QmpConnection you need to first"
230                                    " invoke connect() on it")
231
232   def connect(self):
233     """Connects to the QMP monitor.
234
235     Connects to the UNIX socket and makes sure that we can actually send and
236     receive data to the kvm instance via QMP.
237
238     @raise errors.HypervisorError: when there are communication errors
239     @raise errors.ProgrammerError: when there are data serialization errors
240
241     """
242     self.sock.connect(self.monitor_filename)
243     self._connected = True
244
245     # Check if we receive a correct greeting message from the server
246     # (As per the QEMU Protocol Specification 0.1 - section 2.2)
247     greeting = self._Recv()
248     if not greeting[self._FIRST_MESSAGE_KEY]:
249       self._connected = False
250       raise errors.HypervisorError("kvm: qmp communication error (wrong"
251                                    " server greeting")
252
253     # Let's put the monitor in command mode using the qmp_capabilities
254     # command, or else no command will be executable.
255     # (As per the QEMU Protocol Specification 0.1 - section 4)
256     self.Execute(self._CAPABILITIES_COMMAND)
257
258   def _ParseMessage(self, buf):
259     """Extract and parse a QMP message from the given buffer.
260
261     Seeks for a QMP message in the given buf. If found, it parses it and
262     returns it together with the rest of the characters in the buf.
263     If no message is found, returns None and the whole buffer.
264
265     @raise errors.ProgrammerError: when there are data serialization errors
266
267     """
268     message = None
269     # Check if we got the message end token (CRLF, as per the QEMU Protocol
270     # Specification 0.1 - Section 2.1.1)
271     pos = buf.find(self._MESSAGE_END_TOKEN)
272     if pos >= 0:
273       try:
274         message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
275       except Exception, err:
276         raise errors.ProgrammerError("QMP data serialization error: %s" % err)
277       buf = buf[pos + 1:]
278
279     return (message, buf)
280
281   def _Recv(self):
282     """Receives a message from QMP and decodes the received JSON object.
283
284     @rtype: QmpMessage
285     @return: the received message
286     @raise errors.HypervisorError: when there are communication errors
287     @raise errors.ProgrammerError: when there are data serialization errors
288
289     """
290     self._check_connection()
291
292     # Check if there is already a message in the buffer
293     (message, self._buf) = self._ParseMessage(self._buf)
294     if message:
295       return message
296
297     recv_buffer = StringIO.StringIO(self._buf)
298     recv_buffer.seek(len(self._buf))
299     try:
300       while True:
301         data = self.sock.recv(4096)
302         if not data:
303           break
304         recv_buffer.write(data)
305
306         (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
307         if message:
308           return message
309
310     except socket.timeout, err:
311       raise errors.HypervisorError("Timeout while receiving a QMP message: "
312                                    "%s" % (err))
313     except socket.error, err:
314       raise errors.HypervisorError("Unable to receive data from KVM using the"
315                                    " QMP protocol: %s" % err)
316
317   def _Send(self, message):
318     """Encodes and sends a message to KVM using QMP.
319
320     @type message: QmpMessage
321     @param message: message to send to KVM
322     @raise errors.HypervisorError: when there are communication errors
323     @raise errors.ProgrammerError: when there are data serialization errors
324
325     """
326     self._check_connection()
327     try:
328       message_str = str(message)
329     except Exception, err:
330       raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
331
332     try:
333       self.sock.sendall(message_str)
334     except socket.timeout, err:
335       raise errors.HypervisorError("Timeout while sending a QMP message: "
336                                    "%s (%s)" % (err.string, err.errno))
337     except socket.error, err:
338       raise errors.HypervisorError("Unable to send data from KVM using the"
339                                    " QMP protocol: %s" % err)
340
341   def Execute(self, command, arguments=None):
342     """Executes a QMP command and returns the response of the server.
343
344     @type command: str
345     @param command: the command to execute
346     @type arguments: dict
347     @param arguments: dictionary of arguments to be passed to the command
348     @rtype: dict
349     @return: dictionary representing the received JSON object
350     @raise errors.HypervisorError: when there are communication errors
351     @raise errors.ProgrammerError: when there are data serialization errors
352
353     """
354     self._check_connection()
355     message = QmpMessage({self._EXECUTE_KEY: command})
356     if arguments:
357       message[self._ARGUMENTS_KEY] = arguments
358     self._Send(message)
359
360     # Events can occur between the sending of the command and the reception
361     # of the response, so we need to filter out messages with the event key.
362     while True:
363       response = self._Recv()
364       err = response[self._ERROR_KEY]
365       if err:
366         raise errors.HypervisorError("kvm: error executing the %s"
367                                      " command: %s (%s, %s):" %
368                                      (command,
369                                       err[self._ERROR_DESC_KEY],
370                                       err[self._ERROR_CLASS_KEY],
371                                       err[self._ERROR_DATA_KEY]))
372
373       elif not response[self._EVENT_KEY]:
374         return response
375
376
377 class KVMHypervisor(hv_base.BaseHypervisor):
378   """KVM hypervisor interface"""
379   CAN_MIGRATE = True
380
381   _ROOT_DIR = constants.RUN_GANETI_DIR + "/kvm-hypervisor"
382   _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
383   _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
384   _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
385   _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
386   _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
387   _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
388   # KVM instances with chroot enabled are started in empty chroot directories.
389   _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
390   # After an instance is stopped, its chroot directory is removed.
391   # If the chroot directory is not empty, it can't be removed.
392   # A non-empty chroot directory indicates a possible security incident.
393   # To support forensics, the non-empty chroot directory is quarantined in
394   # a separate directory, called 'chroot-quarantine'.
395   _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
396   _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
397            _CHROOT_DIR, _CHROOT_QUARANTINE_DIR]
398
399   PARAMETERS = {
400     constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
401     constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
402     constants.HV_ROOT_PATH: hv_base.NO_CHECK,
403     constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
404     constants.HV_ACPI: hv_base.NO_CHECK,
405     constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
406     constants.HV_VNC_BIND_ADDRESS:
407       (False, lambda x: (netutils.IP4Address.IsValid(x) or
408                          utils.IsNormAbsPath(x)),
409        "the VNC bind address must be either a valid IP address or an absolute"
410        " pathname", None, None),
411     constants.HV_VNC_TLS: hv_base.NO_CHECK,
412     constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
413     constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
414     constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
415     constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
416     constants.HV_KVM_SPICE_IP_VERSION:
417       (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
418                          x in constants.VALID_IP_VERSIONS),
419        "the SPICE IP version should be 4 or 6",
420        None, None),
421     constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
422     constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
423       hv_base.ParamInSet(False,
424         constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
425     constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
426       hv_base.ParamInSet(False,
427         constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
428     constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
429       hv_base.ParamInSet(False,
430         constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
431     constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
432       hv_base.ParamInSet(False,
433         constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
434     constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
435     constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
436     constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
437     constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
438     constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
439     constants.HV_BOOT_ORDER:
440       hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
441     constants.HV_NIC_TYPE:
442       hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
443     constants.HV_DISK_TYPE:
444       hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
445     constants.HV_KVM_CDROM_DISK_TYPE:
446       hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
447     constants.HV_USB_MOUSE:
448       hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
449     constants.HV_KEYMAP: hv_base.NO_CHECK,
450     constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
451     constants.HV_MIGRATION_BANDWIDTH: hv_base.NO_CHECK,
452     constants.HV_MIGRATION_DOWNTIME: hv_base.NO_CHECK,
453     constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
454     constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
455     constants.HV_DISK_CACHE:
456       hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
457     constants.HV_SECURITY_MODEL:
458       hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
459     constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
460     constants.HV_KVM_FLAG:
461       hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
462     constants.HV_VHOST_NET: hv_base.NO_CHECK,
463     constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
464     constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
465     constants.HV_REBOOT_BEHAVIOR:
466       hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS)
467     }
468
469   _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
470                                     re.M | re.I)
471   _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
472   _MIGRATION_INFO_RETRY_DELAY = 2
473
474   _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)\.(\d+)\b")
475
476   ANCILLARY_FILES = [
477     _KVM_NETWORK_SCRIPT,
478     ]
479
480   def __init__(self):
481     hv_base.BaseHypervisor.__init__(self)
482     # Let's make sure the directories we need exist, even if the RUN_DIR lives
483     # in a tmpfs filesystem or has been otherwise wiped out.
484     dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
485     utils.EnsureDirs(dirs)
486
487   @classmethod
488   def _InstancePidFile(cls, instance_name):
489     """Returns the instance pidfile.
490
491     """
492     return utils.PathJoin(cls._PIDS_DIR, instance_name)
493
494   @classmethod
495   def _InstanceUidFile(cls, instance_name):
496     """Returns the instance uidfile.
497
498     """
499     return utils.PathJoin(cls._UIDS_DIR, instance_name)
500
501   @classmethod
502   def _InstancePidInfo(cls, pid):
503     """Check pid file for instance information.
504
505     Check that a pid file is associated with an instance, and retrieve
506     information from its command line.
507
508     @type pid: string or int
509     @param pid: process id of the instance to check
510     @rtype: tuple
511     @return: (instance_name, memory, vcpus)
512     @raise errors.HypervisorError: when an instance cannot be found
513
514     """
515     alive = utils.IsProcessAlive(pid)
516     if not alive:
517       raise errors.HypervisorError("Cannot get info for pid %s" % pid)
518
519     cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
520     try:
521       cmdline = utils.ReadFile(cmdline_file)
522     except EnvironmentError, err:
523       raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
524                                    (pid, err))
525
526     instance = None
527     memory = 0
528     vcpus = 0
529
530     arg_list = cmdline.split("\x00")
531     while arg_list:
532       arg = arg_list.pop(0)
533       if arg == "-name":
534         instance = arg_list.pop(0)
535       elif arg == "-m":
536         memory = int(arg_list.pop(0))
537       elif arg == "-smp":
538         vcpus = int(arg_list.pop(0))
539
540     if instance is None:
541       raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
542                                    " instance" % pid)
543
544     return (instance, memory, vcpus)
545
546   def _InstancePidAlive(self, instance_name):
547     """Returns the instance pidfile, pid, and liveness.
548
549     @type instance_name: string
550     @param instance_name: instance name
551     @rtype: tuple
552     @return: (pid file name, pid, liveness)
553
554     """
555     pidfile = self._InstancePidFile(instance_name)
556     pid = utils.ReadPidFile(pidfile)
557
558     alive = False
559     try:
560       cmd_instance = self._InstancePidInfo(pid)[0]
561       alive = (cmd_instance == instance_name)
562     except errors.HypervisorError:
563       pass
564
565     return (pidfile, pid, alive)
566
567   def _CheckDown(self, instance_name):
568     """Raises an error unless the given instance is down.
569
570     """
571     alive = self._InstancePidAlive(instance_name)[2]
572     if alive:
573       raise errors.HypervisorError("Failed to start instance %s: %s" %
574                                    (instance_name, "already running"))
575
576   @classmethod
577   def _InstanceMonitor(cls, instance_name):
578     """Returns the instance monitor socket name
579
580     """
581     return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
582
583   @classmethod
584   def _InstanceSerial(cls, instance_name):
585     """Returns the instance serial socket name
586
587     """
588     return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
589
590   @classmethod
591   def _InstanceQmpMonitor(cls, instance_name):
592     """Returns the instance serial QMP socket name
593
594     """
595     return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
596
597   @staticmethod
598   def _SocatUnixConsoleParams():
599     """Returns the correct parameters for socat
600
601     If we have a new-enough socat we can use raw mode with an escape character.
602
603     """
604     if constants.SOCAT_USE_ESCAPE:
605       return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
606     else:
607       return "echo=0,icanon=0"
608
609   @classmethod
610   def _InstanceKVMRuntime(cls, instance_name):
611     """Returns the instance KVM runtime filename
612
613     """
614     return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
615
616   @classmethod
617   def _InstanceChrootDir(cls, instance_name):
618     """Returns the name of the KVM chroot dir of the instance
619
620     """
621     return utils.PathJoin(cls._CHROOT_DIR, instance_name)
622
623   @classmethod
624   def _InstanceNICDir(cls, instance_name):
625     """Returns the name of the directory holding the tap device files for a
626     given instance.
627
628     """
629     return utils.PathJoin(cls._NICS_DIR, instance_name)
630
631   @classmethod
632   def _InstanceNICFile(cls, instance_name, seq):
633     """Returns the name of the file containing the tap device for a given NIC
634
635     """
636     return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
637
638   @classmethod
639   def _InstanceKeymapFile(cls, instance_name):
640     """Returns the name of the file containing the keymap for a given instance
641
642     """
643     return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
644
645   @classmethod
646   def _TryReadUidFile(cls, uid_file):
647     """Try to read a uid file
648
649     """
650     if os.path.exists(uid_file):
651       try:
652         uid = int(utils.ReadOneLineFile(uid_file))
653         return uid
654       except EnvironmentError:
655         logging.warning("Can't read uid file", exc_info=True)
656       except (TypeError, ValueError):
657         logging.warning("Can't parse uid file contents", exc_info=True)
658     return None
659
660   @classmethod
661   def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
662     """Removes an instance's rutime sockets/files/dirs.
663
664     """
665     utils.RemoveFile(pidfile)
666     utils.RemoveFile(cls._InstanceMonitor(instance_name))
667     utils.RemoveFile(cls._InstanceSerial(instance_name))
668     utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
669     utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
670     utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
671     uid_file = cls._InstanceUidFile(instance_name)
672     uid = cls._TryReadUidFile(uid_file)
673     utils.RemoveFile(uid_file)
674     if uid is not None:
675       uidpool.ReleaseUid(uid)
676     try:
677       shutil.rmtree(cls._InstanceNICDir(instance_name))
678     except OSError, err:
679       if err.errno != errno.ENOENT:
680         raise
681     try:
682       chroot_dir = cls._InstanceChrootDir(instance_name)
683       utils.RemoveDir(chroot_dir)
684     except OSError, err:
685       if err.errno == errno.ENOTEMPTY:
686         # The chroot directory is expected to be empty, but it isn't.
687         new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
688                                           prefix="%s-%s-" %
689                                           (instance_name,
690                                            utils.TimestampForFilename()))
691         logging.warning("The chroot directory of instance %s can not be"
692                         " removed as it is not empty. Moving it to the"
693                         " quarantine instead. Please investigate the"
694                         " contents (%s) and clean up manually",
695                         instance_name, new_chroot_dir)
696         utils.RenameFile(chroot_dir, new_chroot_dir)
697       else:
698         raise
699
700   @staticmethod
701   def _ConfigureNIC(instance, seq, nic, tap):
702     """Run the network configuration script for a specified NIC
703
704     @param instance: instance we're acting on
705     @type instance: instance object
706     @param seq: nic sequence number
707     @type seq: int
708     @param nic: nic we're acting on
709     @type nic: nic object
710     @param tap: the host's tap interface this NIC corresponds to
711     @type tap: str
712
713     """
714
715     if instance.tags:
716       tags = " ".join(instance.tags)
717     else:
718       tags = ""
719
720     env = {
721       "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
722       "INSTANCE": instance.name,
723       "MAC": nic.mac,
724       "MODE": nic.nicparams[constants.NIC_MODE],
725       "INTERFACE": tap,
726       "INTERFACE_INDEX": str(seq),
727       "TAGS": tags,
728     }
729
730     if nic.ip:
731       env["IP"] = nic.ip
732
733     if nic.nicparams[constants.NIC_LINK]:
734       env["LINK"] = nic.nicparams[constants.NIC_LINK]
735
736     if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
737       env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
738
739     result = utils.RunCmd([constants.KVM_IFUP, tap], env=env)
740     if result.failed:
741       raise errors.HypervisorError("Failed to configure interface %s: %s."
742                                    " Network configuration script output: %s" %
743                                    (tap, result.fail_reason, result.output))
744
745   def ListInstances(self):
746     """Get the list of running instances.
747
748     We can do this by listing our live instances directory and
749     checking whether the associated kvm process is still alive.
750
751     """
752     result = []
753     for name in os.listdir(self._PIDS_DIR):
754       if self._InstancePidAlive(name)[2]:
755         result.append(name)
756     return result
757
758   def GetInstanceInfo(self, instance_name):
759     """Get instance properties.
760
761     @type instance_name: string
762     @param instance_name: the instance name
763     @rtype: tuple of strings
764     @return: (name, id, memory, vcpus, stat, times)
765
766     """
767     _, pid, alive = self._InstancePidAlive(instance_name)
768     if not alive:
769       return None
770
771     _, memory, vcpus = self._InstancePidInfo(pid)
772     stat = "---b-"
773     times = "0"
774
775     return (instance_name, pid, memory, vcpus, stat, times)
776
777   def GetAllInstancesInfo(self):
778     """Get properties of all instances.
779
780     @return: list of tuples (name, id, memory, vcpus, stat, times)
781
782     """
783     data = []
784     for name in os.listdir(self._PIDS_DIR):
785       try:
786         info = self.GetInstanceInfo(name)
787       except errors.HypervisorError:
788         continue
789       if info:
790         data.append(info)
791     return data
792
793   def _GenerateKVMRuntime(self, instance, block_devices, startup_paused):
794     """Generate KVM information to start an instance.
795
796     """
797     # pylint: disable=R0914,R0915
798     _, v_major, v_min, _ = self._GetKVMVersion()
799
800     pidfile = self._InstancePidFile(instance.name)
801     kvm = constants.KVM_PATH
802     kvm_cmd = [kvm]
803     # used just by the vnc server, if enabled
804     kvm_cmd.extend(["-name", instance.name])
805     kvm_cmd.extend(["-m", instance.beparams[constants.BE_MEMORY]])
806     kvm_cmd.extend(["-smp", instance.beparams[constants.BE_VCPUS]])
807     kvm_cmd.extend(["-pidfile", pidfile])
808     kvm_cmd.extend(["-daemonize"])
809     if not instance.hvparams[constants.HV_ACPI]:
810       kvm_cmd.extend(["-no-acpi"])
811     if startup_paused:
812       kvm_cmd.extend(["-S"])
813     if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
814         constants.INSTANCE_REBOOT_EXIT:
815       kvm_cmd.extend(["-no-reboot"])
816
817     hvp = instance.hvparams
818     boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
819     boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
820     boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
821     boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
822
823     self.ValidateParameters(hvp)
824
825     if hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED:
826       kvm_cmd.extend(["-enable-kvm"])
827     elif hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED:
828       kvm_cmd.extend(["-disable-kvm"])
829
830     if boot_network:
831       kvm_cmd.extend(["-boot", "n"])
832
833     disk_type = hvp[constants.HV_DISK_TYPE]
834     if disk_type == constants.HT_DISK_PARAVIRTUAL:
835       if_val = ",if=virtio"
836     else:
837       if_val = ",if=%s" % disk_type
838     # Cache mode
839     disk_cache = hvp[constants.HV_DISK_CACHE]
840     if instance.disk_template in constants.DTS_EXT_MIRROR:
841       if disk_cache != "none":
842         # TODO: make this a hard error, instead of a silent overwrite
843         logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
844                         " to prevent shared storage corruption on migration",
845                         disk_cache)
846       cache_val = ",cache=none"
847     elif disk_cache != constants.HT_CACHE_DEFAULT:
848       cache_val = ",cache=%s" % disk_cache
849     else:
850       cache_val = ""
851     for cfdev, dev_path in block_devices:
852       if cfdev.mode != constants.DISK_RDWR:
853         raise errors.HypervisorError("Instance has read-only disks which"
854                                      " are not supported by KVM")
855       # TODO: handle FD_LOOP and FD_BLKTAP (?)
856       boot_val = ""
857       if boot_disk:
858         kvm_cmd.extend(["-boot", "c"])
859         boot_disk = False
860         if (v_major, v_min) < (0, 14) and disk_type != constants.HT_DISK_IDE:
861           boot_val = ",boot=on"
862
863       drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
864                                                 cache_val)
865       kvm_cmd.extend(["-drive", drive_val])
866
867     #Now we can specify a different device type for CDROM devices.
868     cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
869     if not cdrom_disk_type:
870       cdrom_disk_type = disk_type
871
872     iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
873     if iso_image:
874       options = ",format=raw,media=cdrom"
875       if boot_cdrom:
876         kvm_cmd.extend(["-boot", "d"])
877         if cdrom_disk_type != constants.HT_DISK_IDE:
878           options = "%s,boot=on,if=%s" % (options, constants.HT_DISK_IDE)
879         else:
880           options = "%s,boot=on" % options
881       else:
882         if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
883           if_val = ",if=virtio"
884         else:
885           if_val = ",if=%s" % cdrom_disk_type
886         options = "%s%s" % (options, if_val)
887       drive_val = "file=%s%s" % (iso_image, options)
888       kvm_cmd.extend(["-drive", drive_val])
889
890     iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
891     if iso_image2:
892       options = ",format=raw,media=cdrom"
893       if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
894         if_val = ",if=virtio"
895       else:
896         if_val = ",if=%s" % cdrom_disk_type
897       options = "%s%s" % (options, if_val)
898       drive_val = "file=%s%s" % (iso_image2, options)
899       kvm_cmd.extend(["-drive", drive_val])
900
901     floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
902     if floppy_image:
903       options = ",format=raw,media=disk"
904       if boot_floppy:
905         kvm_cmd.extend(["-boot", "a"])
906         options = "%s,boot=on" % options
907       if_val = ",if=floppy"
908       options = "%s%s" % (options, if_val)
909       drive_val = "file=%s%s" % (floppy_image, options)
910       kvm_cmd.extend(["-drive", drive_val])
911
912     kernel_path = hvp[constants.HV_KERNEL_PATH]
913     if kernel_path:
914       kvm_cmd.extend(["-kernel", kernel_path])
915       initrd_path = hvp[constants.HV_INITRD_PATH]
916       if initrd_path:
917         kvm_cmd.extend(["-initrd", initrd_path])
918       root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
919                      hvp[constants.HV_KERNEL_ARGS]]
920       if hvp[constants.HV_SERIAL_CONSOLE]:
921         root_append.append("console=ttyS0,38400")
922       kvm_cmd.extend(["-append", " ".join(root_append)])
923
924     mem_path = hvp[constants.HV_MEM_PATH]
925     if mem_path:
926       kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
927
928     mouse_type = hvp[constants.HV_USB_MOUSE]
929     vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
930
931     if mouse_type:
932       kvm_cmd.extend(["-usb"])
933       kvm_cmd.extend(["-usbdevice", mouse_type])
934     elif vnc_bind_address:
935       kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
936
937     keymap = hvp[constants.HV_KEYMAP]
938     if keymap:
939       keymap_path = self._InstanceKeymapFile(instance.name)
940       # If a keymap file is specified, KVM won't use its internal defaults. By
941       # first including the "en-us" layout, an error on loading the actual
942       # layout (e.g. because it can't be found) won't lead to a non-functional
943       # keyboard. A keyboard with incorrect keys is still better than none.
944       utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
945       kvm_cmd.extend(["-k", keymap_path])
946
947     if vnc_bind_address:
948       if netutils.IP4Address.IsValid(vnc_bind_address):
949         if instance.network_port > constants.VNC_BASE_PORT:
950           display = instance.network_port - constants.VNC_BASE_PORT
951           if vnc_bind_address == constants.IP4_ADDRESS_ANY:
952             vnc_arg = ":%d" % (display)
953           else:
954             vnc_arg = "%s:%d" % (vnc_bind_address, display)
955         else:
956           logging.error("Network port is not a valid VNC display (%d < %d)."
957                         " Not starting VNC", instance.network_port,
958                         constants.VNC_BASE_PORT)
959           vnc_arg = "none"
960
961         # Only allow tls and other option when not binding to a file, for now.
962         # kvm/qemu gets confused otherwise about the filename to use.
963         vnc_append = ""
964         if hvp[constants.HV_VNC_TLS]:
965           vnc_append = "%s,tls" % vnc_append
966           if hvp[constants.HV_VNC_X509_VERIFY]:
967             vnc_append = "%s,x509verify=%s" % (vnc_append,
968                                                hvp[constants.HV_VNC_X509])
969           elif hvp[constants.HV_VNC_X509]:
970             vnc_append = "%s,x509=%s" % (vnc_append,
971                                          hvp[constants.HV_VNC_X509])
972         if hvp[constants.HV_VNC_PASSWORD_FILE]:
973           vnc_append = "%s,password" % vnc_append
974
975         vnc_arg = "%s%s" % (vnc_arg, vnc_append)
976
977       else:
978         vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
979
980       kvm_cmd.extend(["-vnc", vnc_arg])
981     else:
982       kvm_cmd.extend(["-nographic"])
983
984     monitor_dev = ("unix:%s,server,nowait" %
985                    self._InstanceMonitor(instance.name))
986     kvm_cmd.extend(["-monitor", monitor_dev])
987     if hvp[constants.HV_SERIAL_CONSOLE]:
988       serial_dev = ("unix:%s,server,nowait" %
989                     self._InstanceSerial(instance.name))
990       kvm_cmd.extend(["-serial", serial_dev])
991     else:
992       kvm_cmd.extend(["-serial", "none"])
993
994     spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
995     spice_ip_version = None
996     if spice_bind:
997       if netutils.IsValidInterface(spice_bind):
998         # The user specified a network interface, we have to figure out the IP
999         # address.
1000         addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1001         spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1002
1003         # if the user specified an IP version and the interface does not
1004         # have that kind of IP addresses, throw an exception
1005         if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1006           if not addresses[spice_ip_version]:
1007             raise errors.HypervisorError("spice: unable to get an IPv%s address"
1008                                          " for %s" % (spice_ip_version,
1009                                                       spice_bind))
1010
1011         # the user did not specify an IP version, we have to figure it out
1012         elif (addresses[constants.IP4_VERSION] and
1013               addresses[constants.IP6_VERSION]):
1014           # we have both ipv4 and ipv6, let's use the cluster default IP
1015           # version
1016           cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1017           spice_ip_version = netutils.IPAddress.GetVersionFromAddressFamily(
1018               cluster_family)
1019         elif addresses[constants.IP4_VERSION]:
1020           spice_ip_version = constants.IP4_VERSION
1021         elif addresses[constants.IP6_VERSION]:
1022           spice_ip_version = constants.IP6_VERSION
1023         else:
1024           raise errors.HypervisorError("spice: unable to get an IP address"
1025                                        " for %s" % (spice_bind))
1026
1027         spice_address = addresses[spice_ip_version][0]
1028
1029       else:
1030         # spice_bind is known to be a valid IP address, because
1031         # ValidateParameters checked it.
1032         spice_address = spice_bind
1033
1034       spice_arg = "addr=%s" % spice_address
1035       if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1036         spice_arg = "%s,tls-port=%s,x509-cacert-file=%s" % (spice_arg,
1037             instance.network_port, constants.SPICE_CACERT_FILE)
1038         spice_arg = "%s,x509-key-file=%s,x509-cert-file=%s" % (spice_arg,
1039             constants.SPICE_CERT_FILE, constants.SPICE_CERT_FILE)
1040       else:
1041         spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1042
1043       if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1044         spice_arg = "%s,disable-ticketing" % spice_arg
1045
1046       if spice_ip_version:
1047         spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1048
1049       # Image compression options
1050       img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1051       img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1052       img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1053       if img_lossless:
1054         spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1055       if img_jpeg:
1056         spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1057       if img_zlib_glz:
1058         spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1059
1060       # Video stream detection
1061       video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1062       if video_streaming:
1063         spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1064
1065       # Audio compression, by default in qemu-kvm it is on
1066       if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1067         spice_arg = "%s,playback-compression=off" % spice_arg
1068
1069       logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1070       kvm_cmd.extend(["-spice", spice_arg])
1071
1072       # Tell kvm to use the paravirtualized graphic card, optimized for SPICE
1073       kvm_cmd.extend(["-vga", "qxl"])
1074
1075     if hvp[constants.HV_USE_LOCALTIME]:
1076       kvm_cmd.extend(["-localtime"])
1077
1078     if hvp[constants.HV_KVM_USE_CHROOT]:
1079       kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1080
1081     # Save the current instance nics, but defer their expansion as parameters,
1082     # as we'll need to generate executable temp files for them.
1083     kvm_nics = instance.nics
1084     hvparams = hvp
1085
1086     return (kvm_cmd, kvm_nics, hvparams)
1087
1088   def _WriteKVMRuntime(self, instance_name, data):
1089     """Write an instance's KVM runtime
1090
1091     """
1092     try:
1093       utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1094                       data=data)
1095     except EnvironmentError, err:
1096       raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1097
1098   def _ReadKVMRuntime(self, instance_name):
1099     """Read an instance's KVM runtime
1100
1101     """
1102     try:
1103       file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1104     except EnvironmentError, err:
1105       raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1106     return file_content
1107
1108   def _SaveKVMRuntime(self, instance, kvm_runtime):
1109     """Save an instance's KVM runtime
1110
1111     """
1112     kvm_cmd, kvm_nics, hvparams = kvm_runtime
1113     serialized_nics = [nic.ToDict() for nic in kvm_nics]
1114     serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1115     self._WriteKVMRuntime(instance.name, serialized_form)
1116
1117   def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1118     """Load an instance's KVM runtime
1119
1120     """
1121     if not serialized_runtime:
1122       serialized_runtime = self._ReadKVMRuntime(instance.name)
1123     loaded_runtime = serializer.Load(serialized_runtime)
1124     kvm_cmd, serialized_nics, hvparams = loaded_runtime
1125     kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1126     return (kvm_cmd, kvm_nics, hvparams)
1127
1128   def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1129     """Run the KVM cmd and check for errors
1130
1131     @type name: string
1132     @param name: instance name
1133     @type kvm_cmd: list of strings
1134     @param kvm_cmd: runcmd input for kvm
1135     @type tap_fds: list of int
1136     @param tap_fds: fds of tap devices opened by Ganeti
1137
1138     """
1139     try:
1140       result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1141     finally:
1142       for fd in tap_fds:
1143         utils_wrapper.CloseFdNoError(fd)
1144
1145     if result.failed:
1146       raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1147                                    (name, result.fail_reason, result.output))
1148     if not self._InstancePidAlive(name)[2]:
1149       raise errors.HypervisorError("Failed to start instance %s" % name)
1150
1151   def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
1152     """Execute a KVM cmd, after completing it with some last minute data
1153
1154     @type incoming: tuple of strings
1155     @param incoming: (target_host_ip, port)
1156
1157     """
1158     # Small _ExecuteKVMRuntime hv parameters programming howto:
1159     #  - conf_hvp contains the parameters as configured on ganeti. they might
1160     #    have changed since the instance started; only use them if the change
1161     #    won't affect the inside of the instance (which hasn't been rebooted).
1162     #  - up_hvp contains the parameters as they were when the instance was
1163     #    started, plus any new parameter which has been added between ganeti
1164     #    versions: it is paramount that those default to a value which won't
1165     #    affect the inside of the instance as well.
1166     conf_hvp = instance.hvparams
1167     name = instance.name
1168     self._CheckDown(name)
1169
1170     temp_files = []
1171
1172     kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1173     up_hvp = objects.FillDict(conf_hvp, up_hvp)
1174
1175     _, v_major, v_min, _ = self._GetKVMVersion()
1176
1177     # We know it's safe to run as a different user upon migration, so we'll use
1178     # the latest conf, from conf_hvp.
1179     security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1180     if security_model == constants.HT_SM_USER:
1181       kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1182
1183     # We have reasons to believe changing something like the nic driver/type
1184     # upon migration won't exactly fly with the instance kernel, so for nic
1185     # related parameters we'll use up_hvp
1186     tapfds = []
1187     taps = []
1188     if not kvm_nics:
1189       kvm_cmd.extend(["-net", "none"])
1190     else:
1191       vnet_hdr = False
1192       tap_extra = ""
1193       nic_type = up_hvp[constants.HV_NIC_TYPE]
1194       if nic_type == constants.HT_NIC_PARAVIRTUAL:
1195         # From version 0.12.0, kvm uses a new sintax for network configuration.
1196         if (v_major, v_min) >= (0, 12):
1197           nic_model = "virtio-net-pci"
1198           vnet_hdr = True
1199         else:
1200           nic_model = "virtio"
1201
1202         if up_hvp[constants.HV_VHOST_NET]:
1203           # vhost_net is only available from version 0.13.0 or newer
1204           if (v_major, v_min) >= (0, 13):
1205             tap_extra = ",vhost=on"
1206           else:
1207             raise errors.HypervisorError("vhost_net is configured"
1208                                         " but it is not available")
1209       else:
1210         nic_model = nic_type
1211
1212       for nic_seq, nic in enumerate(kvm_nics):
1213         tapname, tapfd = _OpenTap(vnet_hdr)
1214         tapfds.append(tapfd)
1215         taps.append(tapname)
1216         if (v_major, v_min) >= (0, 12):
1217           nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1218           tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1219           kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1220         else:
1221           nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1222                                                          nic.mac, nic_model)
1223           tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1224           kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1225
1226     if incoming:
1227       target, port = incoming
1228       kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1229
1230     # Changing the vnc password doesn't bother the guest that much. At most it
1231     # will surprise people who connect to it. Whether positively or negatively
1232     # it's debatable.
1233     vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1234     vnc_pwd = None
1235     if vnc_pwd_file:
1236       try:
1237         vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1238       except EnvironmentError, err:
1239         raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1240                                      % (vnc_pwd_file, err))
1241
1242     if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1243       utils.EnsureDirs([(self._InstanceChrootDir(name),
1244                          constants.SECURE_DIR_MODE)])
1245
1246     # Automatically enable QMP if version is >= 0.14
1247     if (v_major, v_min) >= (0, 14):
1248       logging.debug("Enabling QMP")
1249       kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1250                     self._InstanceQmpMonitor(instance.name)])
1251
1252     # Configure the network now for starting instances and bridged interfaces,
1253     # during FinalizeMigration for incoming instances' routed interfaces
1254     for nic_seq, nic in enumerate(kvm_nics):
1255       if (incoming and
1256           nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1257         continue
1258       self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1259
1260     if security_model == constants.HT_SM_POOL:
1261       ss = ssconf.SimpleStore()
1262       uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1263       all_uids = set(uidpool.ExpandUidPool(uid_pool))
1264       uid = uidpool.RequestUnusedUid(all_uids)
1265       try:
1266         username = pwd.getpwuid(uid.GetUid()).pw_name
1267         kvm_cmd.extend(["-runas", username])
1268         self._RunKVMCmd(name, kvm_cmd, tapfds)
1269       except:
1270         uidpool.ReleaseUid(uid)
1271         raise
1272       else:
1273         uid.Unlock()
1274         utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1275     else:
1276       self._RunKVMCmd(name, kvm_cmd, tapfds)
1277
1278     utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1279                      constants.RUN_DIRS_MODE)])
1280     for nic_seq, tap in enumerate(taps):
1281       utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1282                       data=tap)
1283
1284     if vnc_pwd:
1285       change_cmd = "change vnc password %s" % vnc_pwd
1286       self._CallMonitorCommand(instance.name, change_cmd)
1287
1288     # Setting SPICE password. We are not vulnerable to malicious passwordless
1289     # connection attempts because SPICE by default does not allow connections
1290     # if neither a password nor the "disable_ticketing" options are specified.
1291     # As soon as we send the password via QMP, that password is a valid ticket
1292     # for connection.
1293     spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1294     if spice_password_file:
1295       try:
1296         spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1297         qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1298         qmp.connect()
1299         arguments = {
1300             "protocol": "spice",
1301             "password": spice_pwd,
1302         }
1303         qmp.Execute("set_password", arguments)
1304       except EnvironmentError, err:
1305         raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1306                                      % (spice_password_file, err))
1307
1308     for filename in temp_files:
1309       utils.RemoveFile(filename)
1310
1311   def StartInstance(self, instance, block_devices, startup_paused):
1312     """Start an instance.
1313
1314     """
1315     self._CheckDown(instance.name)
1316     kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1317                                            startup_paused)
1318     self._SaveKVMRuntime(instance, kvm_runtime)
1319     self._ExecuteKVMRuntime(instance, kvm_runtime)
1320
1321   def _CallMonitorCommand(self, instance_name, command):
1322     """Invoke a command on the instance monitor.
1323
1324     """
1325     socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1326              (utils.ShellQuote(command),
1327               constants.SOCAT_PATH,
1328               utils.ShellQuote(self._InstanceMonitor(instance_name))))
1329     result = utils.RunCmd(socat)
1330     if result.failed:
1331       msg = ("Failed to send command '%s' to instance %s."
1332              " output: %s, error: %s, fail_reason: %s" %
1333              (command, instance_name,
1334               result.stdout, result.stderr, result.fail_reason))
1335       raise errors.HypervisorError(msg)
1336
1337     return result
1338
1339   @classmethod
1340   def _GetKVMVersion(cls):
1341     """Return the installed KVM version.
1342
1343     @return: (version, v_maj, v_min, v_rev)
1344     @raise L{errors.HypervisorError}: when the KVM version cannot be retrieved
1345
1346     """
1347     result = utils.RunCmd([constants.KVM_PATH, "--help"])
1348     if result.failed:
1349       raise errors.HypervisorError("Unable to get KVM version")
1350     match = cls._VERSION_RE.search(result.output.splitlines()[0])
1351     if not match:
1352       raise errors.HypervisorError("Unable to get KVM version")
1353
1354     return (match.group(0), int(match.group(1)), int(match.group(2)),
1355             int(match.group(3)))
1356
1357   def StopInstance(self, instance, force=False, retry=False, name=None):
1358     """Stop an instance.
1359
1360     """
1361     if name is not None and not force:
1362       raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1363     if name is None:
1364       name = instance.name
1365       acpi = instance.hvparams[constants.HV_ACPI]
1366     else:
1367       acpi = False
1368     _, pid, alive = self._InstancePidAlive(name)
1369     if pid > 0 and alive:
1370       if force or not acpi:
1371         utils.KillProcess(pid)
1372       else:
1373         self._CallMonitorCommand(name, "system_powerdown")
1374
1375   def CleanupInstance(self, instance_name):
1376     """Cleanup after a stopped instance
1377
1378     """
1379     pidfile, pid, alive = self._InstancePidAlive(instance_name)
1380     if pid > 0 and alive:
1381       raise errors.HypervisorError("Cannot cleanup a live instance")
1382     self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1383
1384   def RebootInstance(self, instance):
1385     """Reboot an instance.
1386
1387     """
1388     # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1389     # socket the instance will stop, but now power up again. So we'll resort
1390     # to shutdown and restart.
1391     _, _, alive = self._InstancePidAlive(instance.name)
1392     if not alive:
1393       raise errors.HypervisorError("Failed to reboot instance %s:"
1394                                    " not running" % instance.name)
1395     # StopInstance will delete the saved KVM runtime so:
1396     # ...first load it...
1397     kvm_runtime = self._LoadKVMRuntime(instance)
1398     # ...now we can safely call StopInstance...
1399     if not self.StopInstance(instance):
1400       self.StopInstance(instance, force=True)
1401     # ...and finally we can save it again, and execute it...
1402     self._SaveKVMRuntime(instance, kvm_runtime)
1403     self._ExecuteKVMRuntime(instance, kvm_runtime)
1404
1405   def MigrationInfo(self, instance):
1406     """Get instance information to perform a migration.
1407
1408     @type instance: L{objects.Instance}
1409     @param instance: instance to be migrated
1410     @rtype: string
1411     @return: content of the KVM runtime file
1412
1413     """
1414     return self._ReadKVMRuntime(instance.name)
1415
1416   def AcceptInstance(self, instance, info, target):
1417     """Prepare to accept an instance.
1418
1419     @type instance: L{objects.Instance}
1420     @param instance: instance to be accepted
1421     @type info: string
1422     @param info: content of the KVM runtime file on the source node
1423     @type target: string
1424     @param target: target host (usually ip), on this node
1425
1426     """
1427     kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1428     incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1429     self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
1430
1431   def FinalizeMigration(self, instance, info, success):
1432     """Finalize an instance migration.
1433
1434     Stop the incoming mode KVM.
1435
1436     @type instance: L{objects.Instance}
1437     @param instance: instance whose migration is being finalized
1438
1439     """
1440     if success:
1441       kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1442       kvm_nics = kvm_runtime[1]
1443
1444       for nic_seq, nic in enumerate(kvm_nics):
1445         if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1446           # Bridged interfaces have already been configured
1447           continue
1448         try:
1449           tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1450         except EnvironmentError, err:
1451           logging.warning("Failed to find host interface for %s NIC #%d: %s",
1452                           instance.name, nic_seq, str(err))
1453           continue
1454         try:
1455           self._ConfigureNIC(instance, nic_seq, nic, tap)
1456         except errors.HypervisorError, err:
1457           logging.warning(str(err))
1458
1459       self._WriteKVMRuntime(instance.name, info)
1460     else:
1461       self.StopInstance(instance, force=True)
1462
1463   def MigrateInstance(self, instance, target, live):
1464     """Migrate an instance to a target node.
1465
1466     The migration will not be attempted if the instance is not
1467     currently running.
1468
1469     @type instance: L{objects.Instance}
1470     @param instance: the instance to be migrated
1471     @type target: string
1472     @param target: ip address of the target node
1473     @type live: boolean
1474     @param live: perform a live migration
1475
1476     """
1477     instance_name = instance.name
1478     port = instance.hvparams[constants.HV_MIGRATION_PORT]
1479     pidfile, pid, alive = self._InstancePidAlive(instance_name)
1480     if not alive:
1481       raise errors.HypervisorError("Instance not running, cannot migrate")
1482
1483     if not live:
1484       self._CallMonitorCommand(instance_name, "stop")
1485
1486     migrate_command = ("migrate_set_speed %dm" %
1487         instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1488     self._CallMonitorCommand(instance_name, migrate_command)
1489
1490     migrate_command = ("migrate_set_downtime %dms" %
1491         instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1492     self._CallMonitorCommand(instance_name, migrate_command)
1493
1494     migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1495     self._CallMonitorCommand(instance_name, migrate_command)
1496
1497     info_command = "info migrate"
1498     done = False
1499     broken_answers = 0
1500     while not done:
1501       result = self._CallMonitorCommand(instance_name, info_command)
1502       match = self._MIGRATION_STATUS_RE.search(result.stdout)
1503       if not match:
1504         broken_answers += 1
1505         if not result.stdout:
1506           logging.info("KVM: empty 'info migrate' result")
1507         else:
1508           logging.warning("KVM: unknown 'info migrate' result: %s",
1509                           result.stdout)
1510         time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1511       else:
1512         status = match.group(1)
1513         if status == "completed":
1514           done = True
1515         elif status == "active":
1516           # reset the broken answers count
1517           broken_answers = 0
1518           time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1519         elif status == "failed" or status == "cancelled":
1520           if not live:
1521             self._CallMonitorCommand(instance_name, 'cont')
1522           raise errors.HypervisorError("Migration %s at the kvm level" %
1523                                        status)
1524         else:
1525           logging.warning("KVM: unknown migration status '%s'", status)
1526           broken_answers += 1
1527           time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1528       if broken_answers >= self._MIGRATION_INFO_MAX_BAD_ANSWERS:
1529         raise errors.HypervisorError("Too many 'info migrate' broken answers")
1530
1531     utils.KillProcess(pid)
1532     self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1533
1534   def GetNodeInfo(self):
1535     """Return information about the node.
1536
1537     This is just a wrapper over the base GetLinuxNodeInfo method.
1538
1539     @return: a dict with the following keys (values in MiB):
1540           - memory_total: the total memory size on the node
1541           - memory_free: the available memory on the node for instances
1542           - memory_dom0: the memory used by the node itself, if available
1543
1544     """
1545     return self.GetLinuxNodeInfo()
1546
1547   @classmethod
1548   def GetInstanceConsole(cls, instance, hvparams, beparams):
1549     """Return a command for connecting to the console of an instance.
1550
1551     """
1552     if hvparams[constants.HV_SERIAL_CONSOLE]:
1553       cmd = [constants.KVM_CONSOLE_WRAPPER,
1554              constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1555              utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1556              "STDIO,%s" % cls._SocatUnixConsoleParams(),
1557              "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1558       return objects.InstanceConsole(instance=instance.name,
1559                                      kind=constants.CONS_SSH,
1560                                      host=instance.primary_node,
1561                                      user=constants.GANETI_RUNAS,
1562                                      command=cmd)
1563
1564     vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1565     if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1566       display = instance.network_port - constants.VNC_BASE_PORT
1567       return objects.InstanceConsole(instance=instance.name,
1568                                      kind=constants.CONS_VNC,
1569                                      host=vnc_bind_address,
1570                                      port=instance.network_port,
1571                                      display=display)
1572
1573     spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1574     if spice_bind:
1575       return objects.InstanceConsole(instance=instance.name,
1576                                      kind=constants.CONS_SPICE,
1577                                      host=spice_bind,
1578                                      port=instance.network_port)
1579
1580     return objects.InstanceConsole(instance=instance.name,
1581                                    kind=constants.CONS_MESSAGE,
1582                                    message=("No serial shell for instance %s" %
1583                                             instance.name))
1584
1585   def Verify(self):
1586     """Verify the hypervisor.
1587
1588     Check that the binary exists.
1589
1590     """
1591     if not os.path.exists(constants.KVM_PATH):
1592       return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
1593     if not os.path.exists(constants.SOCAT_PATH):
1594       return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
1595
1596   @classmethod
1597   def CheckParameterSyntax(cls, hvparams):
1598     """Check the given parameters for validity.
1599
1600     @type hvparams:  dict
1601     @param hvparams: dictionary with parameter names/value
1602     @raise errors.HypervisorError: when a parameter is not valid
1603
1604     """
1605     super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
1606
1607     kernel_path = hvparams[constants.HV_KERNEL_PATH]
1608     if kernel_path:
1609       if not hvparams[constants.HV_ROOT_PATH]:
1610         raise errors.HypervisorError("Need a root partition for the instance,"
1611                                      " if a kernel is defined")
1612
1613     if (hvparams[constants.HV_VNC_X509_VERIFY] and
1614         not hvparams[constants.HV_VNC_X509]):
1615       raise errors.HypervisorError("%s must be defined, if %s is" %
1616                                    (constants.HV_VNC_X509,
1617                                     constants.HV_VNC_X509_VERIFY))
1618
1619     boot_order = hvparams[constants.HV_BOOT_ORDER]
1620     if (boot_order == constants.HT_BO_CDROM and
1621         not hvparams[constants.HV_CDROM_IMAGE_PATH]):
1622       raise errors.HypervisorError("Cannot boot from cdrom without an"
1623                                    " ISO path")
1624
1625     security_model = hvparams[constants.HV_SECURITY_MODEL]
1626     if security_model == constants.HT_SM_USER:
1627       if not hvparams[constants.HV_SECURITY_DOMAIN]:
1628         raise errors.HypervisorError("A security domain (user to run kvm as)"
1629                                      " must be specified")
1630     elif (security_model == constants.HT_SM_NONE or
1631           security_model == constants.HT_SM_POOL):
1632       if hvparams[constants.HV_SECURITY_DOMAIN]:
1633         raise errors.HypervisorError("Cannot have a security domain when the"
1634                                      " security model is 'none' or 'pool'")
1635
1636     spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1637     spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
1638     if spice_bind:
1639       if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1640         # if an IP version is specified, the spice_bind parameter must be an
1641         # IP of that family
1642         if (netutils.IP4Address.IsValid(spice_bind) and
1643             spice_ip_version != constants.IP4_VERSION):
1644           raise errors.HypervisorError("spice: got an IPv4 address (%s), but"
1645                                        " the specified IP version is %s" %
1646                                        (spice_bind, spice_ip_version))
1647
1648         if (netutils.IP6Address.IsValid(spice_bind) and
1649             spice_ip_version != constants.IP6_VERSION):
1650           raise errors.HypervisorError("spice: got an IPv6 address (%s), but"
1651                                        " the specified IP version is %s" %
1652                                        (spice_bind, spice_ip_version))
1653     else:
1654       # All the other SPICE parameters depend on spice_bind being set. Raise an
1655       # error if any of them is set without it.
1656       spice_additional_params = frozenset([
1657         constants.HV_KVM_SPICE_IP_VERSION,
1658         constants.HV_KVM_SPICE_PASSWORD_FILE,
1659         constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR,
1660         constants.HV_KVM_SPICE_JPEG_IMG_COMPR,
1661         constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR,
1662         constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION,
1663         constants.HV_KVM_SPICE_USE_TLS,
1664         ])
1665       for param in spice_additional_params:
1666         if hvparams[param]:
1667           raise errors.HypervisorError("spice: %s requires %s to be set" %
1668                                        (param, constants.HV_KVM_SPICE_BIND))
1669
1670   @classmethod
1671   def ValidateParameters(cls, hvparams):
1672     """Check the given parameters for validity.
1673
1674     @type hvparams:  dict
1675     @param hvparams: dictionary with parameter names/value
1676     @raise errors.HypervisorError: when a parameter is not valid
1677
1678     """
1679     super(KVMHypervisor, cls).ValidateParameters(hvparams)
1680
1681     security_model = hvparams[constants.HV_SECURITY_MODEL]
1682     if security_model == constants.HT_SM_USER:
1683       username = hvparams[constants.HV_SECURITY_DOMAIN]
1684       try:
1685         pwd.getpwnam(username)
1686       except KeyError:
1687         raise errors.HypervisorError("Unknown security domain user %s"
1688                                      % username)
1689
1690     spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1691     if spice_bind:
1692       # only one of VNC and SPICE can be used currently.
1693       if hvparams[constants.HV_VNC_BIND_ADDRESS]:
1694         raise errors.HypervisorError("both SPICE and VNC are configured, but"
1695                                      " only one of them can be used at a"
1696                                      " given time.")
1697
1698       # KVM version should be >= 0.14.0
1699       _, v_major, v_min, _ = cls._GetKVMVersion()
1700       if (v_major, v_min) < (0, 14):
1701         raise errors.HypervisorError("spice is configured, but it is not"
1702                                      " available in versions of KVM < 0.14")
1703
1704       # if spice_bind is not an IP address, it must be a valid interface
1705       bound_to_addr = (netutils.IP4Address.IsValid(spice_bind)
1706                        or netutils.IP6Address.IsValid(spice_bind))
1707       if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
1708         raise errors.HypervisorError("spice: the %s parameter must be either"
1709                                      " a valid IP address or interface name" %
1710                                      constants.HV_KVM_SPICE_BIND)
1711
1712   @classmethod
1713   def PowercycleNode(cls):
1714     """KVM powercycle, just a wrapper over Linux powercycle.
1715
1716     """
1717     cls.LinuxPowercycle()