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