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