Merge branch 'devel-2.5'
[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_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
436     constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
437     constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
438     constants.HV_BOOT_ORDER:
439       hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
440     constants.HV_NIC_TYPE:
441       hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
442     constants.HV_DISK_TYPE:
443       hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
444     constants.HV_KVM_CDROM_DISK_TYPE:
445       hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
446     constants.HV_USB_MOUSE:
447       hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
448     constants.HV_KEYMAP: hv_base.NO_CHECK,
449     constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
450     constants.HV_MIGRATION_BANDWIDTH: hv_base.NO_CHECK,
451     constants.HV_MIGRATION_DOWNTIME: hv_base.NO_CHECK,
452     constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
453     constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
454     constants.HV_DISK_CACHE:
455       hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
456     constants.HV_SECURITY_MODEL:
457       hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
458     constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
459     constants.HV_KVM_FLAG:
460       hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
461     constants.HV_VHOST_NET: hv_base.NO_CHECK,
462     constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
463     constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
464     constants.HV_REBOOT_BEHAVIOR:
465       hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
466     constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
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
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,port=%s" % (spice_address, instance.network_port)
1035       if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1036         spice_arg = "%s,disable-ticketing" % spice_arg
1037
1038       if spice_ip_version:
1039         spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1040
1041       # Image compression options
1042       img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1043       img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1044       img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1045       if img_lossless:
1046         spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1047       if img_jpeg:
1048         spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1049       if img_zlib_glz:
1050         spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1051
1052       # Video stream detection
1053       video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1054       if video_streaming:
1055         spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1056
1057       # Audio compression, by default in qemu-kvm it is on
1058       if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1059         spice_arg = "%s,playback-compression=off" % spice_arg
1060
1061       logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1062       kvm_cmd.extend(["-spice", spice_arg])
1063
1064       # Tell kvm to use the paravirtualized graphic card, optimized for SPICE
1065       kvm_cmd.extend(["-vga", "qxl"])
1066
1067     if hvp[constants.HV_USE_LOCALTIME]:
1068       kvm_cmd.extend(["-localtime"])
1069
1070     if hvp[constants.HV_KVM_USE_CHROOT]:
1071       kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1072
1073     # Save the current instance nics, but defer their expansion as parameters,
1074     # as we'll need to generate executable temp files for them.
1075     kvm_nics = instance.nics
1076     hvparams = hvp
1077
1078     return (kvm_cmd, kvm_nics, hvparams)
1079
1080   def _WriteKVMRuntime(self, instance_name, data):
1081     """Write an instance's KVM runtime
1082
1083     """
1084     try:
1085       utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1086                       data=data)
1087     except EnvironmentError, err:
1088       raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1089
1090   def _ReadKVMRuntime(self, instance_name):
1091     """Read an instance's KVM runtime
1092
1093     """
1094     try:
1095       file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1096     except EnvironmentError, err:
1097       raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1098     return file_content
1099
1100   def _SaveKVMRuntime(self, instance, kvm_runtime):
1101     """Save an instance's KVM runtime
1102
1103     """
1104     kvm_cmd, kvm_nics, hvparams = kvm_runtime
1105     serialized_nics = [nic.ToDict() for nic in kvm_nics]
1106     serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1107     self._WriteKVMRuntime(instance.name, serialized_form)
1108
1109   def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1110     """Load an instance's KVM runtime
1111
1112     """
1113     if not serialized_runtime:
1114       serialized_runtime = self._ReadKVMRuntime(instance.name)
1115     loaded_runtime = serializer.Load(serialized_runtime)
1116     kvm_cmd, serialized_nics, hvparams = loaded_runtime
1117     kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1118     return (kvm_cmd, kvm_nics, hvparams)
1119
1120   def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1121     """Run the KVM cmd and check for errors
1122
1123     @type name: string
1124     @param name: instance name
1125     @type kvm_cmd: list of strings
1126     @param kvm_cmd: runcmd input for kvm
1127     @type tap_fds: list of int
1128     @param tap_fds: fds of tap devices opened by Ganeti
1129
1130     """
1131     try:
1132       result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1133     finally:
1134       for fd in tap_fds:
1135         utils_wrapper.CloseFdNoError(fd)
1136
1137     if result.failed:
1138       raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1139                                    (name, result.fail_reason, result.output))
1140     if not self._InstancePidAlive(name)[2]:
1141       raise errors.HypervisorError("Failed to start instance %s" % name)
1142
1143   def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
1144     """Execute a KVM cmd, after completing it with some last minute data
1145
1146     @type incoming: tuple of strings
1147     @param incoming: (target_host_ip, port)
1148
1149     """
1150     # Small _ExecuteKVMRuntime hv parameters programming howto:
1151     #  - conf_hvp contains the parameters as configured on ganeti. they might
1152     #    have changed since the instance started; only use them if the change
1153     #    won't affect the inside of the instance (which hasn't been rebooted).
1154     #  - up_hvp contains the parameters as they were when the instance was
1155     #    started, plus any new parameter which has been added between ganeti
1156     #    versions: it is paramount that those default to a value which won't
1157     #    affect the inside of the instance as well.
1158     conf_hvp = instance.hvparams
1159     name = instance.name
1160     self._CheckDown(name)
1161
1162     temp_files = []
1163
1164     kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1165     up_hvp = objects.FillDict(conf_hvp, up_hvp)
1166
1167     _, v_major, v_min, _ = self._GetKVMVersion()
1168
1169     # We know it's safe to run as a different user upon migration, so we'll use
1170     # the latest conf, from conf_hvp.
1171     security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1172     if security_model == constants.HT_SM_USER:
1173       kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1174
1175     # We have reasons to believe changing something like the nic driver/type
1176     # upon migration won't exactly fly with the instance kernel, so for nic
1177     # related parameters we'll use up_hvp
1178     tapfds = []
1179     taps = []
1180     if not kvm_nics:
1181       kvm_cmd.extend(["-net", "none"])
1182     else:
1183       vnet_hdr = False
1184       tap_extra = ""
1185       nic_type = up_hvp[constants.HV_NIC_TYPE]
1186       if nic_type == constants.HT_NIC_PARAVIRTUAL:
1187         # From version 0.12.0, kvm uses a new sintax for network configuration.
1188         if (v_major, v_min) >= (0, 12):
1189           nic_model = "virtio-net-pci"
1190           vnet_hdr = True
1191         else:
1192           nic_model = "virtio"
1193
1194         if up_hvp[constants.HV_VHOST_NET]:
1195           # vhost_net is only available from version 0.13.0 or newer
1196           if (v_major, v_min) >= (0, 13):
1197             tap_extra = ",vhost=on"
1198           else:
1199             raise errors.HypervisorError("vhost_net is configured"
1200                                         " but it is not available")
1201       else:
1202         nic_model = nic_type
1203
1204       for nic_seq, nic in enumerate(kvm_nics):
1205         tapname, tapfd = _OpenTap(vnet_hdr)
1206         tapfds.append(tapfd)
1207         taps.append(tapname)
1208         if (v_major, v_min) >= (0, 12):
1209           nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1210           tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1211           kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1212         else:
1213           nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1214                                                          nic.mac, nic_model)
1215           tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1216           kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1217
1218     if incoming:
1219       target, port = incoming
1220       kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1221
1222     # Changing the vnc password doesn't bother the guest that much. At most it
1223     # will surprise people who connect to it. Whether positively or negatively
1224     # it's debatable.
1225     vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1226     vnc_pwd = None
1227     if vnc_pwd_file:
1228       try:
1229         vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1230       except EnvironmentError, err:
1231         raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1232                                      % (vnc_pwd_file, err))
1233
1234     if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1235       utils.EnsureDirs([(self._InstanceChrootDir(name),
1236                          constants.SECURE_DIR_MODE)])
1237
1238     # Automatically enable QMP if version is >= 0.14
1239     if (v_major, v_min) >= (0, 14):
1240       logging.debug("Enabling QMP")
1241       kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1242                     self._InstanceQmpMonitor(instance.name)])
1243
1244     # Configure the network now for starting instances and bridged interfaces,
1245     # during FinalizeMigration for incoming instances' routed interfaces
1246     for nic_seq, nic in enumerate(kvm_nics):
1247       if (incoming and
1248           nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1249         continue
1250       self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1251
1252     if security_model == constants.HT_SM_POOL:
1253       ss = ssconf.SimpleStore()
1254       uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1255       all_uids = set(uidpool.ExpandUidPool(uid_pool))
1256       uid = uidpool.RequestUnusedUid(all_uids)
1257       try:
1258         username = pwd.getpwuid(uid.GetUid()).pw_name
1259         kvm_cmd.extend(["-runas", username])
1260         self._RunKVMCmd(name, kvm_cmd, tapfds)
1261       except:
1262         uidpool.ReleaseUid(uid)
1263         raise
1264       else:
1265         uid.Unlock()
1266         utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1267     else:
1268       self._RunKVMCmd(name, kvm_cmd, tapfds)
1269
1270     utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1271                      constants.RUN_DIRS_MODE)])
1272     for nic_seq, tap in enumerate(taps):
1273       utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1274                       data=tap)
1275
1276     if vnc_pwd:
1277       change_cmd = "change vnc password %s" % vnc_pwd
1278       self._CallMonitorCommand(instance.name, change_cmd)
1279
1280     # Setting SPICE password. We are not vulnerable to malicious passwordless
1281     # connection attempts because SPICE by default does not allow connections
1282     # if neither a password nor the "disable_ticketing" options are specified.
1283     # As soon as we send the password via QMP, that password is a valid ticket
1284     # for connection.
1285     spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1286     if spice_password_file:
1287       try:
1288         spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1289         qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1290         qmp.connect()
1291         arguments = {
1292             "protocol": "spice",
1293             "password": spice_pwd,
1294         }
1295         qmp.Execute("set_password", arguments)
1296       except EnvironmentError, err:
1297         raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1298                                      % (spice_password_file, err))
1299
1300     for filename in temp_files:
1301       utils.RemoveFile(filename)
1302
1303   def StartInstance(self, instance, block_devices, startup_paused):
1304     """Start an instance.
1305
1306     """
1307     self._CheckDown(instance.name)
1308     kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1309                                            startup_paused)
1310     self._SaveKVMRuntime(instance, kvm_runtime)
1311     self._ExecuteKVMRuntime(instance, kvm_runtime)
1312
1313   def _CallMonitorCommand(self, instance_name, command):
1314     """Invoke a command on the instance monitor.
1315
1316     """
1317     socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1318              (utils.ShellQuote(command),
1319               constants.SOCAT_PATH,
1320               utils.ShellQuote(self._InstanceMonitor(instance_name))))
1321     result = utils.RunCmd(socat)
1322     if result.failed:
1323       msg = ("Failed to send command '%s' to instance %s."
1324              " output: %s, error: %s, fail_reason: %s" %
1325              (command, instance_name,
1326               result.stdout, result.stderr, result.fail_reason))
1327       raise errors.HypervisorError(msg)
1328
1329     return result
1330
1331   @classmethod
1332   def _GetKVMVersion(cls):
1333     """Return the installed KVM version.
1334
1335     @return: (version, v_maj, v_min, v_rev)
1336     @raise L{errors.HypervisorError}: when the KVM version cannot be retrieved
1337
1338     """
1339     result = utils.RunCmd([constants.KVM_PATH, "--help"])
1340     if result.failed:
1341       raise errors.HypervisorError("Unable to get KVM version")
1342     match = cls._VERSION_RE.search(result.output.splitlines()[0])
1343     if not match:
1344       raise errors.HypervisorError("Unable to get KVM version")
1345
1346     return (match.group(0), int(match.group(1)), int(match.group(2)),
1347             int(match.group(3)))
1348
1349   def StopInstance(self, instance, force=False, retry=False, name=None):
1350     """Stop an instance.
1351
1352     """
1353     if name is not None and not force:
1354       raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1355     if name is None:
1356       name = instance.name
1357       acpi = instance.hvparams[constants.HV_ACPI]
1358     else:
1359       acpi = False
1360     _, pid, alive = self._InstancePidAlive(name)
1361     if pid > 0 and alive:
1362       if force or not acpi:
1363         utils.KillProcess(pid)
1364       else:
1365         self._CallMonitorCommand(name, "system_powerdown")
1366
1367   def CleanupInstance(self, instance_name):
1368     """Cleanup after a stopped instance
1369
1370     """
1371     pidfile, pid, alive = self._InstancePidAlive(instance_name)
1372     if pid > 0 and alive:
1373       raise errors.HypervisorError("Cannot cleanup a live instance")
1374     self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1375
1376   def RebootInstance(self, instance):
1377     """Reboot an instance.
1378
1379     """
1380     # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1381     # socket the instance will stop, but now power up again. So we'll resort
1382     # to shutdown and restart.
1383     _, _, alive = self._InstancePidAlive(instance.name)
1384     if not alive:
1385       raise errors.HypervisorError("Failed to reboot instance %s:"
1386                                    " not running" % instance.name)
1387     # StopInstance will delete the saved KVM runtime so:
1388     # ...first load it...
1389     kvm_runtime = self._LoadKVMRuntime(instance)
1390     # ...now we can safely call StopInstance...
1391     if not self.StopInstance(instance):
1392       self.StopInstance(instance, force=True)
1393     # ...and finally we can save it again, and execute it...
1394     self._SaveKVMRuntime(instance, kvm_runtime)
1395     self._ExecuteKVMRuntime(instance, kvm_runtime)
1396
1397   def MigrationInfo(self, instance):
1398     """Get instance information to perform a migration.
1399
1400     @type instance: L{objects.Instance}
1401     @param instance: instance to be migrated
1402     @rtype: string
1403     @return: content of the KVM runtime file
1404
1405     """
1406     return self._ReadKVMRuntime(instance.name)
1407
1408   def AcceptInstance(self, instance, info, target):
1409     """Prepare to accept an instance.
1410
1411     @type instance: L{objects.Instance}
1412     @param instance: instance to be accepted
1413     @type info: string
1414     @param info: content of the KVM runtime file on the source node
1415     @type target: string
1416     @param target: target host (usually ip), on this node
1417
1418     """
1419     kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1420     incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1421     self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
1422
1423   def FinalizeMigration(self, instance, info, success):
1424     """Finalize an instance migration.
1425
1426     Stop the incoming mode KVM.
1427
1428     @type instance: L{objects.Instance}
1429     @param instance: instance whose migration is being finalized
1430
1431     """
1432     if success:
1433       kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1434       kvm_nics = kvm_runtime[1]
1435
1436       for nic_seq, nic in enumerate(kvm_nics):
1437         if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1438           # Bridged interfaces have already been configured
1439           continue
1440         try:
1441           tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1442         except EnvironmentError, err:
1443           logging.warning("Failed to find host interface for %s NIC #%d: %s",
1444                           instance.name, nic_seq, str(err))
1445           continue
1446         try:
1447           self._ConfigureNIC(instance, nic_seq, nic, tap)
1448         except errors.HypervisorError, err:
1449           logging.warning(str(err))
1450
1451       self._WriteKVMRuntime(instance.name, info)
1452     else:
1453       self.StopInstance(instance, force=True)
1454
1455   def MigrateInstance(self, instance, target, live):
1456     """Migrate an instance to a target node.
1457
1458     The migration will not be attempted if the instance is not
1459     currently running.
1460
1461     @type instance: L{objects.Instance}
1462     @param instance: the instance to be migrated
1463     @type target: string
1464     @param target: ip address of the target node
1465     @type live: boolean
1466     @param live: perform a live migration
1467
1468     """
1469     instance_name = instance.name
1470     port = instance.hvparams[constants.HV_MIGRATION_PORT]
1471     pidfile, pid, alive = self._InstancePidAlive(instance_name)
1472     if not alive:
1473       raise errors.HypervisorError("Instance not running, cannot migrate")
1474
1475     if not live:
1476       self._CallMonitorCommand(instance_name, "stop")
1477
1478     migrate_command = ("migrate_set_speed %dm" %
1479         instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1480     self._CallMonitorCommand(instance_name, migrate_command)
1481
1482     migrate_command = ("migrate_set_downtime %dms" %
1483         instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1484     self._CallMonitorCommand(instance_name, migrate_command)
1485
1486     migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1487     self._CallMonitorCommand(instance_name, migrate_command)
1488
1489     info_command = "info migrate"
1490     done = False
1491     broken_answers = 0
1492     while not done:
1493       result = self._CallMonitorCommand(instance_name, info_command)
1494       match = self._MIGRATION_STATUS_RE.search(result.stdout)
1495       if not match:
1496         broken_answers += 1
1497         if not result.stdout:
1498           logging.info("KVM: empty 'info migrate' result")
1499         else:
1500           logging.warning("KVM: unknown 'info migrate' result: %s",
1501                           result.stdout)
1502         time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1503       else:
1504         status = match.group(1)
1505         if status == "completed":
1506           done = True
1507         elif status == "active":
1508           # reset the broken answers count
1509           broken_answers = 0
1510           time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1511         elif status == "failed" or status == "cancelled":
1512           if not live:
1513             self._CallMonitorCommand(instance_name, 'cont')
1514           raise errors.HypervisorError("Migration %s at the kvm level" %
1515                                        status)
1516         else:
1517           logging.warning("KVM: unknown migration status '%s'", status)
1518           broken_answers += 1
1519           time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1520       if broken_answers >= self._MIGRATION_INFO_MAX_BAD_ANSWERS:
1521         raise errors.HypervisorError("Too many 'info migrate' broken answers")
1522
1523     utils.KillProcess(pid)
1524     self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1525
1526   def GetNodeInfo(self):
1527     """Return information about the node.
1528
1529     This is just a wrapper over the base GetLinuxNodeInfo method.
1530
1531     @return: a dict with the following keys (values in MiB):
1532           - memory_total: the total memory size on the node
1533           - memory_free: the available memory on the node for instances
1534           - memory_dom0: the memory used by the node itself, if available
1535
1536     """
1537     return self.GetLinuxNodeInfo()
1538
1539   @classmethod
1540   def GetInstanceConsole(cls, instance, hvparams, beparams):
1541     """Return a command for connecting to the console of an instance.
1542
1543     """
1544     if hvparams[constants.HV_SERIAL_CONSOLE]:
1545       cmd = [constants.KVM_CONSOLE_WRAPPER,
1546              constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1547              utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1548              "STDIO,%s" % cls._SocatUnixConsoleParams(),
1549              "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1550       return objects.InstanceConsole(instance=instance.name,
1551                                      kind=constants.CONS_SSH,
1552                                      host=instance.primary_node,
1553                                      user=constants.GANETI_RUNAS,
1554                                      command=cmd)
1555
1556     vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1557     if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1558       display = instance.network_port - constants.VNC_BASE_PORT
1559       return objects.InstanceConsole(instance=instance.name,
1560                                      kind=constants.CONS_VNC,
1561                                      host=vnc_bind_address,
1562                                      port=instance.network_port,
1563                                      display=display)
1564
1565     spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1566     if spice_bind:
1567       return objects.InstanceConsole(instance=instance.name,
1568                                      kind=constants.CONS_SPICE,
1569                                      host=spice_bind,
1570                                      port=instance.network_port)
1571
1572     return objects.InstanceConsole(instance=instance.name,
1573                                    kind=constants.CONS_MESSAGE,
1574                                    message=("No serial shell for instance %s" %
1575                                             instance.name))
1576
1577   def Verify(self):
1578     """Verify the hypervisor.
1579
1580     Check that the binary exists.
1581
1582     """
1583     if not os.path.exists(constants.KVM_PATH):
1584       return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
1585     if not os.path.exists(constants.SOCAT_PATH):
1586       return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
1587
1588   @classmethod
1589   def CheckParameterSyntax(cls, hvparams):
1590     """Check the given parameters for validity.
1591
1592     @type hvparams:  dict
1593     @param hvparams: dictionary with parameter names/value
1594     @raise errors.HypervisorError: when a parameter is not valid
1595
1596     """
1597     super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
1598
1599     kernel_path = hvparams[constants.HV_KERNEL_PATH]
1600     if kernel_path:
1601       if not hvparams[constants.HV_ROOT_PATH]:
1602         raise errors.HypervisorError("Need a root partition for the instance,"
1603                                      " if a kernel is defined")
1604
1605     if (hvparams[constants.HV_VNC_X509_VERIFY] and
1606         not hvparams[constants.HV_VNC_X509]):
1607       raise errors.HypervisorError("%s must be defined, if %s is" %
1608                                    (constants.HV_VNC_X509,
1609                                     constants.HV_VNC_X509_VERIFY))
1610
1611     boot_order = hvparams[constants.HV_BOOT_ORDER]
1612     if (boot_order == constants.HT_BO_CDROM and
1613         not hvparams[constants.HV_CDROM_IMAGE_PATH]):
1614       raise errors.HypervisorError("Cannot boot from cdrom without an"
1615                                    " ISO path")
1616
1617     security_model = hvparams[constants.HV_SECURITY_MODEL]
1618     if security_model == constants.HT_SM_USER:
1619       if not hvparams[constants.HV_SECURITY_DOMAIN]:
1620         raise errors.HypervisorError("A security domain (user to run kvm as)"
1621                                      " must be specified")
1622     elif (security_model == constants.HT_SM_NONE or
1623           security_model == constants.HT_SM_POOL):
1624       if hvparams[constants.HV_SECURITY_DOMAIN]:
1625         raise errors.HypervisorError("Cannot have a security domain when the"
1626                                      " security model is 'none' or 'pool'")
1627
1628     spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1629     spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
1630     if spice_bind:
1631       if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1632         # if an IP version is specified, the spice_bind parameter must be an
1633         # IP of that family
1634         if (netutils.IP4Address.IsValid(spice_bind) and
1635             spice_ip_version != constants.IP4_VERSION):
1636           raise errors.HypervisorError("spice: got an IPv4 address (%s), but"
1637                                        " the specified IP version is %s" %
1638                                        (spice_bind, spice_ip_version))
1639
1640         if (netutils.IP6Address.IsValid(spice_bind) and
1641             spice_ip_version != constants.IP6_VERSION):
1642           raise errors.HypervisorError("spice: got an IPv6 address (%s), but"
1643                                        " the specified IP version is %s" %
1644                                        (spice_bind, spice_ip_version))
1645     else:
1646       # All the other SPICE parameters depend on spice_bind being set. Raise an
1647       # error if any of them is set without it.
1648       spice_additional_params = frozenset([
1649         constants.HV_KVM_SPICE_IP_VERSION,
1650         constants.HV_KVM_SPICE_PASSWORD_FILE,
1651         constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR,
1652         constants.HV_KVM_SPICE_JPEG_IMG_COMPR,
1653         constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR,
1654         constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION,
1655         ])
1656       for param in spice_additional_params:
1657         if hvparams[param]:
1658           raise errors.HypervisorError("spice: %s requires %s to be set" %
1659                                        (param, constants.HV_KVM_SPICE_BIND))
1660
1661   @classmethod
1662   def ValidateParameters(cls, hvparams):
1663     """Check the given parameters for validity.
1664
1665     @type hvparams:  dict
1666     @param hvparams: dictionary with parameter names/value
1667     @raise errors.HypervisorError: when a parameter is not valid
1668
1669     """
1670     super(KVMHypervisor, cls).ValidateParameters(hvparams)
1671
1672     security_model = hvparams[constants.HV_SECURITY_MODEL]
1673     if security_model == constants.HT_SM_USER:
1674       username = hvparams[constants.HV_SECURITY_DOMAIN]
1675       try:
1676         pwd.getpwnam(username)
1677       except KeyError:
1678         raise errors.HypervisorError("Unknown security domain user %s"
1679                                      % username)
1680
1681     spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1682     if spice_bind:
1683       # only one of VNC and SPICE can be used currently.
1684       if hvparams[constants.HV_VNC_BIND_ADDRESS]:
1685         raise errors.HypervisorError("both SPICE and VNC are configured, but"
1686                                      " only one of them can be used at a"
1687                                      " given time.")
1688
1689       # KVM version should be >= 0.14.0
1690       _, v_major, v_min, _ = cls._GetKVMVersion()
1691       if (v_major, v_min) < (0, 14):
1692         raise errors.HypervisorError("spice is configured, but it is not"
1693                                      " available in versions of KVM < 0.14")
1694
1695       # if spice_bind is not an IP address, it must be a valid interface
1696       bound_to_addr = (netutils.IP4Address.IsValid(spice_bind)
1697                        or netutils.IP6Address.IsValid(spice_bind))
1698       if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
1699         raise errors.HypervisorError("spice: the %s parameter must be either"
1700                                      " a valid IP address or interface name" %
1701                                      constants.HV_KVM_SPICE_BIND)
1702
1703   @classmethod
1704   def PowercycleNode(cls):
1705     """KVM powercycle, just a wrapper over Linux powercycle.
1706
1707     """
1708     cls.LinuxPowercycle()