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