KVM: don't add -nographic using spice
[ganeti-local] / lib / hypervisor / hv_kvm.py
1 #
2 #
3
4 # Copyright (C) 2008, 2009, 2010, 2011 Google Inc.
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 # General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 # 02110-1301, USA.
20
21
22 """KVM hypervisor
23
24 """
25
26 import errno
27 import os
28 import os.path
29 import re
30 import tempfile
31 import time
32 import logging
33 import pwd
34 import struct
35 import fcntl
36 import shutil
37
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]
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     """
527     _, v_major, v_min, _ = self._GetKVMVersion()
528
529     pidfile = self._InstancePidFile(instance.name)
530     kvm = constants.KVM_PATH
531     kvm_cmd = [kvm]
532     # used just by the vnc server, if enabled
533     kvm_cmd.extend(["-name", instance.name])
534     kvm_cmd.extend(["-m", instance.beparams[constants.BE_MEMORY]])
535     kvm_cmd.extend(["-smp", instance.beparams[constants.BE_VCPUS]])
536     kvm_cmd.extend(["-pidfile", pidfile])
537     kvm_cmd.extend(["-daemonize"])
538     if not instance.hvparams[constants.HV_ACPI]:
539       kvm_cmd.extend(["-no-acpi"])
540     if startup_paused:
541       kvm_cmd.extend(["-S"])
542     if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
543         constants.INSTANCE_REBOOT_EXIT:
544       kvm_cmd.extend(["-no-reboot"])
545
546     hvp = instance.hvparams
547     boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
548     boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
549     boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
550     boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
551
552     self.ValidateParameters(hvp)
553
554     if hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED:
555       kvm_cmd.extend(["-enable-kvm"])
556     elif hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED:
557       kvm_cmd.extend(["-disable-kvm"])
558
559     if boot_network:
560       kvm_cmd.extend(["-boot", "n"])
561
562     disk_type = hvp[constants.HV_DISK_TYPE]
563     if disk_type == constants.HT_DISK_PARAVIRTUAL:
564       if_val = ",if=virtio"
565     else:
566       if_val = ",if=%s" % disk_type
567     # Cache mode
568     disk_cache = hvp[constants.HV_DISK_CACHE]
569     if instance.disk_template in constants.DTS_EXT_MIRROR:
570       if disk_cache != "none":
571         # TODO: make this a hard error, instead of a silent overwrite
572         logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
573                         " to prevent shared storage corruption on migration",
574                         disk_cache)
575       cache_val = ",cache=none"
576     elif disk_cache != constants.HT_CACHE_DEFAULT:
577       cache_val = ",cache=%s" % disk_cache
578     else:
579       cache_val = ""
580     for cfdev, dev_path in block_devices:
581       if cfdev.mode != constants.DISK_RDWR:
582         raise errors.HypervisorError("Instance has read-only disks which"
583                                      " are not supported by KVM")
584       # TODO: handle FD_LOOP and FD_BLKTAP (?)
585       boot_val = ""
586       if boot_disk:
587         kvm_cmd.extend(["-boot", "c"])
588         boot_disk = False
589         if (v_major, v_min) < (0, 14) and disk_type != constants.HT_DISK_IDE:
590           boot_val = ",boot=on"
591
592       drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
593                                                 cache_val)
594       kvm_cmd.extend(["-drive", drive_val])
595
596     #Now we can specify a different device type for CDROM devices.
597     cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
598     if not cdrom_disk_type:
599       cdrom_disk_type = disk_type
600
601     iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
602     if iso_image:
603       options = ",format=raw,media=cdrom"
604       if boot_cdrom:
605         kvm_cmd.extend(["-boot", "d"])
606         if cdrom_disk_type != constants.HT_DISK_IDE:
607           options = "%s,boot=on,if=%s" % (options, constants.HT_DISK_IDE)
608         else:
609           options = "%s,boot=on" % options
610       else:
611         if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
612           if_val = ",if=virtio"
613         else:
614           if_val = ",if=%s" % cdrom_disk_type
615         options = "%s%s" % (options, if_val)
616       drive_val = "file=%s%s" % (iso_image, options)
617       kvm_cmd.extend(["-drive", drive_val])
618
619     iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
620     if iso_image2:
621       options = ",format=raw,media=cdrom"
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_image2, options)
628       kvm_cmd.extend(["-drive", drive_val])
629
630     floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
631     if floppy_image:
632       options = ",format=raw,media=disk"
633       if boot_floppy:
634         kvm_cmd.extend(["-boot", "a"])
635         options = "%s,boot=on" % options
636       if_val = ",if=floppy"
637       options = "%s%s" % (options, if_val)
638       drive_val = "file=%s%s" % (floppy_image, options)
639       kvm_cmd.extend(["-drive", drive_val])
640
641     kernel_path = hvp[constants.HV_KERNEL_PATH]
642     if kernel_path:
643       kvm_cmd.extend(["-kernel", kernel_path])
644       initrd_path = hvp[constants.HV_INITRD_PATH]
645       if initrd_path:
646         kvm_cmd.extend(["-initrd", initrd_path])
647       root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
648                      hvp[constants.HV_KERNEL_ARGS]]
649       if hvp[constants.HV_SERIAL_CONSOLE]:
650         root_append.append("console=ttyS0,38400")
651       kvm_cmd.extend(["-append", " ".join(root_append)])
652
653     mem_path = hvp[constants.HV_MEM_PATH]
654     if mem_path:
655       kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
656
657     monitor_dev = ("unix:%s,server,nowait" %
658                    self._InstanceMonitor(instance.name))
659     kvm_cmd.extend(["-monitor", monitor_dev])
660     if hvp[constants.HV_SERIAL_CONSOLE]:
661       serial_dev = ("unix:%s,server,nowait" %
662                     self._InstanceSerial(instance.name))
663       kvm_cmd.extend(["-serial", serial_dev])
664     else:
665       kvm_cmd.extend(["-serial", "none"])
666
667     mouse_type = hvp[constants.HV_USB_MOUSE]
668     vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
669     spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
670     spice_ip_version = None
671
672     if mouse_type:
673       kvm_cmd.extend(["-usb"])
674       kvm_cmd.extend(["-usbdevice", mouse_type])
675     elif vnc_bind_address:
676       kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
677
678     keymap = hvp[constants.HV_KEYMAP]
679     if keymap:
680       keymap_path = self._InstanceKeymapFile(instance.name)
681       # If a keymap file is specified, KVM won't use its internal defaults. By
682       # first including the "en-us" layout, an error on loading the actual
683       # layout (e.g. because it can't be found) won't lead to a non-functional
684       # keyboard. A keyboard with incorrect keys is still better than none.
685       utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
686       kvm_cmd.extend(["-k", keymap_path])
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       if netutils.IsValidInterface(spice_bind):
724         # The user specified a network interface, we have to figure out the IP
725         # address.
726         addresses = netutils.GetInterfaceIpAddresses(spice_bind)
727         spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
728
729         # if the user specified an IP version and the interface does not
730         # have that kind of IP addresses, throw an exception
731         if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
732           if not addresses[spice_ip_version]:
733             raise errors.HypervisorError("spice: unable to get an IPv%s address"
734                                          " for %s" % (spice_ip_version,
735                                                       spice_bind))
736
737         # the user did not specify an IP version, we have to figure it out
738         elif (addresses[constants.IP4_VERSION] and
739               addresses[constants.IP6_VERSION]):
740           # we have both ipv4 and ipv6, let's use the cluster default IP
741           # version
742           cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
743           spice_ip_version = netutils.IPAddress.GetVersionFromAddressFamily(
744               cluster_family)
745         elif addresses[constants.IP4_VERSION]:
746           spice_ip_version = constants.IP4_VERSION
747         elif addresses[constants.IP6_VERSION]:
748           spice_ip_version = constants.IP6_VERSION
749         else:
750           raise errors.HypervisorError("spice: unable to get an IP address"
751                                        " for %s" % (spice_bind))
752
753         spice_address = addresses[spice_ip_version][0]
754
755       else:
756         # spice_bind is known to be a valid IP address, because
757         # ValidateParameters checked it.
758         spice_address = spice_bind
759
760       spice_arg = "addr=%s,port=%s,disable-ticketing" % (spice_address,
761                                                          instance.network_port)
762       if spice_ip_version:
763         spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
764
765       logging.info("KVM: SPICE will listen on port %s", instance.network_port)
766       kvm_cmd.extend(["-spice", spice_arg])
767
768     else:
769       kvm_cmd.extend(["-nographic"])
770
771     if hvp[constants.HV_USE_LOCALTIME]:
772       kvm_cmd.extend(["-localtime"])
773
774     if hvp[constants.HV_KVM_USE_CHROOT]:
775       kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
776
777     # Save the current instance nics, but defer their expansion as parameters,
778     # as we'll need to generate executable temp files for them.
779     kvm_nics = instance.nics
780     hvparams = hvp
781
782     return (kvm_cmd, kvm_nics, hvparams)
783
784   def _WriteKVMRuntime(self, instance_name, data):
785     """Write an instance's KVM runtime
786
787     """
788     try:
789       utils.WriteFile(self._InstanceKVMRuntime(instance_name),
790                       data=data)
791     except EnvironmentError, err:
792       raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
793
794   def _ReadKVMRuntime(self, instance_name):
795     """Read an instance's KVM runtime
796
797     """
798     try:
799       file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
800     except EnvironmentError, err:
801       raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
802     return file_content
803
804   def _SaveKVMRuntime(self, instance, kvm_runtime):
805     """Save an instance's KVM runtime
806
807     """
808     kvm_cmd, kvm_nics, hvparams = kvm_runtime
809     serialized_nics = [nic.ToDict() for nic in kvm_nics]
810     serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
811     self._WriteKVMRuntime(instance.name, serialized_form)
812
813   def _LoadKVMRuntime(self, instance, serialized_runtime=None):
814     """Load an instance's KVM runtime
815
816     """
817     if not serialized_runtime:
818       serialized_runtime = self._ReadKVMRuntime(instance.name)
819     loaded_runtime = serializer.Load(serialized_runtime)
820     kvm_cmd, serialized_nics, hvparams = loaded_runtime
821     kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
822     return (kvm_cmd, kvm_nics, hvparams)
823
824   def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
825     """Run the KVM cmd and check for errors
826
827     @type name: string
828     @param name: instance name
829     @type kvm_cmd: list of strings
830     @param kvm_cmd: runcmd input for kvm
831     @type tap_fds: list of int
832     @param tap_fds: fds of tap devices opened by Ganeti
833
834     """
835     try:
836       result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
837     finally:
838       for fd in tap_fds:
839         utils_wrapper.CloseFdNoError(fd)
840
841     if result.failed:
842       raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
843                                    (name, result.fail_reason, result.output))
844     if not self._InstancePidAlive(name)[2]:
845       raise errors.HypervisorError("Failed to start instance %s" % name)
846
847   def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
848     """Execute a KVM cmd, after completing it with some last minute data
849
850     @type incoming: tuple of strings
851     @param incoming: (target_host_ip, port)
852
853     """
854     # Small _ExecuteKVMRuntime hv parameters programming howto:
855     #  - conf_hvp contains the parameters as configured on ganeti. they might
856     #    have changed since the instance started; only use them if the change
857     #    won't affect the inside of the instance (which hasn't been rebooted).
858     #  - up_hvp contains the parameters as they were when the instance was
859     #    started, plus any new parameter which has been added between ganeti
860     #    versions: it is paramount that those default to a value which won't
861     #    affect the inside of the instance as well.
862     conf_hvp = instance.hvparams
863     name = instance.name
864     self._CheckDown(name)
865
866     temp_files = []
867
868     kvm_cmd, kvm_nics, up_hvp = kvm_runtime
869     up_hvp = objects.FillDict(conf_hvp, up_hvp)
870
871     _, v_major, v_min, _ = self._GetKVMVersion()
872
873     # We know it's safe to run as a different user upon migration, so we'll use
874     # the latest conf, from conf_hvp.
875     security_model = conf_hvp[constants.HV_SECURITY_MODEL]
876     if security_model == constants.HT_SM_USER:
877       kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
878
879     # We have reasons to believe changing something like the nic driver/type
880     # upon migration won't exactly fly with the instance kernel, so for nic
881     # related parameters we'll use up_hvp
882     tapfds = []
883     taps = []
884     if not kvm_nics:
885       kvm_cmd.extend(["-net", "none"])
886     else:
887       vnet_hdr = False
888       tap_extra = ""
889       nic_type = up_hvp[constants.HV_NIC_TYPE]
890       if nic_type == constants.HT_NIC_PARAVIRTUAL:
891         # From version 0.12.0, kvm uses a new sintax for network configuration.
892         if (v_major, v_min) >= (0, 12):
893           nic_model = "virtio-net-pci"
894           vnet_hdr = True
895         else:
896           nic_model = "virtio"
897
898         if up_hvp[constants.HV_VHOST_NET]:
899           # vhost_net is only available from version 0.13.0 or newer
900           if (v_major, v_min) >= (0, 13):
901             tap_extra = ",vhost=on"
902           else:
903             raise errors.HypervisorError("vhost_net is configured"
904                                         " but it is not available")
905       else:
906         nic_model = nic_type
907
908       for nic_seq, nic in enumerate(kvm_nics):
909         tapname, tapfd = _OpenTap(vnet_hdr)
910         tapfds.append(tapfd)
911         taps.append(tapname)
912         if (v_major, v_min) >= (0, 12):
913           nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
914           tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
915           kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
916         else:
917           nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
918                                                          nic.mac, nic_model)
919           tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
920           kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
921
922     if incoming:
923       target, port = incoming
924       kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
925
926     # Changing the vnc password doesn't bother the guest that much. At most it
927     # will surprise people who connect to it. Whether positively or negatively
928     # it's debatable.
929     vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
930     vnc_pwd = None
931     if vnc_pwd_file:
932       try:
933         vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
934       except EnvironmentError, err:
935         raise errors.HypervisorError("Failed to open VNC password file %s: %s"
936                                      % (vnc_pwd_file, err))
937
938     if conf_hvp[constants.HV_KVM_USE_CHROOT]:
939       utils.EnsureDirs([(self._InstanceChrootDir(name),
940                          constants.SECURE_DIR_MODE)])
941
942     # Configure the network now for starting instances and bridged interfaces,
943     # during FinalizeMigration for incoming instances' routed interfaces
944     for nic_seq, nic in enumerate(kvm_nics):
945       if (incoming and
946           nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
947         continue
948       self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
949
950     if security_model == constants.HT_SM_POOL:
951       ss = ssconf.SimpleStore()
952       uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
953       all_uids = set(uidpool.ExpandUidPool(uid_pool))
954       uid = uidpool.RequestUnusedUid(all_uids)
955       try:
956         username = pwd.getpwuid(uid.GetUid()).pw_name
957         kvm_cmd.extend(["-runas", username])
958         self._RunKVMCmd(name, kvm_cmd, tapfds)
959       except:
960         uidpool.ReleaseUid(uid)
961         raise
962       else:
963         uid.Unlock()
964         utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
965     else:
966       self._RunKVMCmd(name, kvm_cmd, tapfds)
967
968     utils.EnsureDirs([(self._InstanceNICDir(instance.name),
969                      constants.RUN_DIRS_MODE)])
970     for nic_seq, tap in enumerate(taps):
971       utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
972                       data=tap)
973
974     if vnc_pwd:
975       change_cmd = "change vnc password %s" % vnc_pwd
976       self._CallMonitorCommand(instance.name, change_cmd)
977
978     for filename in temp_files:
979       utils.RemoveFile(filename)
980
981   def StartInstance(self, instance, block_devices, startup_paused):
982     """Start an instance.
983
984     """
985     self._CheckDown(instance.name)
986     kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
987                                            startup_paused)
988     self._SaveKVMRuntime(instance, kvm_runtime)
989     self._ExecuteKVMRuntime(instance, kvm_runtime)
990
991   def _CallMonitorCommand(self, instance_name, command):
992     """Invoke a command on the instance monitor.
993
994     """
995     socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
996              (utils.ShellQuote(command),
997               constants.SOCAT_PATH,
998               utils.ShellQuote(self._InstanceMonitor(instance_name))))
999     result = utils.RunCmd(socat)
1000     if result.failed:
1001       msg = ("Failed to send command '%s' to instance %s."
1002              " output: %s, error: %s, fail_reason: %s" %
1003              (command, instance_name,
1004               result.stdout, result.stderr, result.fail_reason))
1005       raise errors.HypervisorError(msg)
1006
1007     return result
1008
1009   @classmethod
1010   def _ParseKVMVersion(cls, text):
1011     """Parse the KVM version from the --help output.
1012
1013     @type text: string
1014     @param text: output of kvm --help
1015     @return: (version, v_maj, v_min, v_rev)
1016     @raise L{errors.HypervisorError}: when the KVM version cannot be retrieved
1017
1018     """
1019     match = cls._VERSION_RE.search(text.splitlines()[0])
1020     if not match:
1021       raise errors.HypervisorError("Unable to get KVM version")
1022
1023     v_all = match.group(0)
1024     v_maj = int(match.group(1))
1025     v_min = int(match.group(2))
1026     if match.group(4):
1027       v_rev = int(match.group(4))
1028     else:
1029       v_rev = 0
1030     return (v_all, v_maj, v_min, v_rev)
1031
1032   @classmethod
1033   def _GetKVMVersion(cls):
1034     """Return the installed KVM version.
1035
1036     @return: (version, v_maj, v_min, v_rev)
1037     @raise L{errors.HypervisorError}: when the KVM version cannot be retrieved
1038
1039     """
1040     result = utils.RunCmd([constants.KVM_PATH, "--help"])
1041     if result.failed:
1042       raise errors.HypervisorError("Unable to get KVM version")
1043     return cls._ParseKVMVersion(result.output)
1044
1045   def StopInstance(self, instance, force=False, retry=False, name=None):
1046     """Stop an instance.
1047
1048     """
1049     if name is not None and not force:
1050       raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1051     if name is None:
1052       name = instance.name
1053       acpi = instance.hvparams[constants.HV_ACPI]
1054     else:
1055       acpi = False
1056     _, pid, alive = self._InstancePidAlive(name)
1057     if pid > 0 and alive:
1058       if force or not acpi:
1059         utils.KillProcess(pid)
1060       else:
1061         self._CallMonitorCommand(name, "system_powerdown")
1062
1063   def CleanupInstance(self, instance_name):
1064     """Cleanup after a stopped instance
1065
1066     """
1067     pidfile, pid, alive = self._InstancePidAlive(instance_name)
1068     if pid > 0 and alive:
1069       raise errors.HypervisorError("Cannot cleanup a live instance")
1070     self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1071
1072   def RebootInstance(self, instance):
1073     """Reboot an instance.
1074
1075     """
1076     # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1077     # socket the instance will stop, but now power up again. So we'll resort
1078     # to shutdown and restart.
1079     _, _, alive = self._InstancePidAlive(instance.name)
1080     if not alive:
1081       raise errors.HypervisorError("Failed to reboot instance %s:"
1082                                    " not running" % instance.name)
1083     # StopInstance will delete the saved KVM runtime so:
1084     # ...first load it...
1085     kvm_runtime = self._LoadKVMRuntime(instance)
1086     # ...now we can safely call StopInstance...
1087     if not self.StopInstance(instance):
1088       self.StopInstance(instance, force=True)
1089     # ...and finally we can save it again, and execute it...
1090     self._SaveKVMRuntime(instance, kvm_runtime)
1091     self._ExecuteKVMRuntime(instance, kvm_runtime)
1092
1093   def MigrationInfo(self, instance):
1094     """Get instance information to perform a migration.
1095
1096     @type instance: L{objects.Instance}
1097     @param instance: instance to be migrated
1098     @rtype: string
1099     @return: content of the KVM runtime file
1100
1101     """
1102     return self._ReadKVMRuntime(instance.name)
1103
1104   def AcceptInstance(self, instance, info, target):
1105     """Prepare to accept an instance.
1106
1107     @type instance: L{objects.Instance}
1108     @param instance: instance to be accepted
1109     @type info: string
1110     @param info: content of the KVM runtime file on the source node
1111     @type target: string
1112     @param target: target host (usually ip), on this node
1113
1114     """
1115     kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1116     incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1117     self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
1118
1119   def FinalizeMigration(self, instance, info, success):
1120     """Finalize an instance migration.
1121
1122     Stop the incoming mode KVM.
1123
1124     @type instance: L{objects.Instance}
1125     @param instance: instance whose migration is being finalized
1126
1127     """
1128     if success:
1129       kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1130       kvm_nics = kvm_runtime[1]
1131
1132       for nic_seq, nic in enumerate(kvm_nics):
1133         if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1134           # Bridged interfaces have already been configured
1135           continue
1136         try:
1137           tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1138         except EnvironmentError, err:
1139           logging.warning("Failed to find host interface for %s NIC #%d: %s",
1140                           instance.name, nic_seq, str(err))
1141           continue
1142         try:
1143           self._ConfigureNIC(instance, nic_seq, nic, tap)
1144         except errors.HypervisorError, err:
1145           logging.warning(str(err))
1146
1147       self._WriteKVMRuntime(instance.name, info)
1148     else:
1149       self.StopInstance(instance, force=True)
1150
1151   def MigrateInstance(self, instance, target, live):
1152     """Migrate an instance to a target node.
1153
1154     The migration will not be attempted if the instance is not
1155     currently running.
1156
1157     @type instance: L{objects.Instance}
1158     @param instance: the instance to be migrated
1159     @type target: string
1160     @param target: ip address of the target node
1161     @type live: boolean
1162     @param live: perform a live migration
1163
1164     """
1165     instance_name = instance.name
1166     port = instance.hvparams[constants.HV_MIGRATION_PORT]
1167     pidfile, pid, alive = self._InstancePidAlive(instance_name)
1168     if not alive:
1169       raise errors.HypervisorError("Instance not running, cannot migrate")
1170
1171     if not live:
1172       self._CallMonitorCommand(instance_name, "stop")
1173
1174     migrate_command = ("migrate_set_speed %dm" %
1175         instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1176     self._CallMonitorCommand(instance_name, migrate_command)
1177
1178     migrate_command = ("migrate_set_downtime %dms" %
1179         instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1180     self._CallMonitorCommand(instance_name, migrate_command)
1181
1182     migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1183     self._CallMonitorCommand(instance_name, migrate_command)
1184
1185     info_command = "info migrate"
1186     done = False
1187     broken_answers = 0
1188     while not done:
1189       result = self._CallMonitorCommand(instance_name, info_command)
1190       match = self._MIGRATION_STATUS_RE.search(result.stdout)
1191       if not match:
1192         broken_answers += 1
1193         if not result.stdout:
1194           logging.info("KVM: empty 'info migrate' result")
1195         else:
1196           logging.warning("KVM: unknown 'info migrate' result: %s",
1197                           result.stdout)
1198         time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1199       else:
1200         status = match.group(1)
1201         if status == "completed":
1202           done = True
1203         elif status == "active":
1204           # reset the broken answers count
1205           broken_answers = 0
1206           time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1207         elif status == "failed" or status == "cancelled":
1208           if not live:
1209             self._CallMonitorCommand(instance_name, 'cont')
1210           raise errors.HypervisorError("Migration %s at the kvm level" %
1211                                        status)
1212         else:
1213           logging.warning("KVM: unknown migration status '%s'", status)
1214           broken_answers += 1
1215           time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1216       if broken_answers >= self._MIGRATION_INFO_MAX_BAD_ANSWERS:
1217         raise errors.HypervisorError("Too many 'info migrate' broken answers")
1218
1219     utils.KillProcess(pid)
1220     self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1221
1222   def GetNodeInfo(self):
1223     """Return information about the node.
1224
1225     This is just a wrapper over the base GetLinuxNodeInfo method.
1226
1227     @return: a dict with the following keys (values in MiB):
1228           - memory_total: the total memory size on the node
1229           - memory_free: the available memory on the node for instances
1230           - memory_dom0: the memory used by the node itself, if available
1231
1232     """
1233     return self.GetLinuxNodeInfo()
1234
1235   @classmethod
1236   def GetInstanceConsole(cls, instance, hvparams, beparams):
1237     """Return a command for connecting to the console of an instance.
1238
1239     """
1240     if hvparams[constants.HV_SERIAL_CONSOLE]:
1241       cmd = [constants.KVM_CONSOLE_WRAPPER,
1242              constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1243              utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1244              "STDIO,%s" % cls._SocatUnixConsoleParams(),
1245              "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1246       return objects.InstanceConsole(instance=instance.name,
1247                                      kind=constants.CONS_SSH,
1248                                      host=instance.primary_node,
1249                                      user=constants.GANETI_RUNAS,
1250                                      command=cmd)
1251
1252     vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1253     if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1254       display = instance.network_port - constants.VNC_BASE_PORT
1255       return objects.InstanceConsole(instance=instance.name,
1256                                      kind=constants.CONS_VNC,
1257                                      host=vnc_bind_address,
1258                                      port=instance.network_port,
1259                                      display=display)
1260
1261     return objects.InstanceConsole(instance=instance.name,
1262                                    kind=constants.CONS_MESSAGE,
1263                                    message=("No serial shell for instance %s" %
1264                                             instance.name))
1265
1266   def Verify(self):
1267     """Verify the hypervisor.
1268
1269     Check that the binary exists.
1270
1271     """
1272     if not os.path.exists(constants.KVM_PATH):
1273       return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
1274     if not os.path.exists(constants.SOCAT_PATH):
1275       return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
1276
1277   @classmethod
1278   def CheckParameterSyntax(cls, hvparams):
1279     """Check the given parameters for validity.
1280
1281     @type hvparams:  dict
1282     @param hvparams: dictionary with parameter names/value
1283     @raise errors.HypervisorError: when a parameter is not valid
1284
1285     """
1286     super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
1287
1288     kernel_path = hvparams[constants.HV_KERNEL_PATH]
1289     if kernel_path:
1290       if not hvparams[constants.HV_ROOT_PATH]:
1291         raise errors.HypervisorError("Need a root partition for the instance,"
1292                                      " if a kernel is defined")
1293
1294     if (hvparams[constants.HV_VNC_X509_VERIFY] and
1295         not hvparams[constants.HV_VNC_X509]):
1296       raise errors.HypervisorError("%s must be defined, if %s is" %
1297                                    (constants.HV_VNC_X509,
1298                                     constants.HV_VNC_X509_VERIFY))
1299
1300     boot_order = hvparams[constants.HV_BOOT_ORDER]
1301     if (boot_order == constants.HT_BO_CDROM and
1302         not hvparams[constants.HV_CDROM_IMAGE_PATH]):
1303       raise errors.HypervisorError("Cannot boot from cdrom without an"
1304                                    " ISO path")
1305
1306     security_model = hvparams[constants.HV_SECURITY_MODEL]
1307     if security_model == constants.HT_SM_USER:
1308       if not hvparams[constants.HV_SECURITY_DOMAIN]:
1309         raise errors.HypervisorError("A security domain (user to run kvm as)"
1310                                      " must be specified")
1311     elif (security_model == constants.HT_SM_NONE or
1312           security_model == constants.HT_SM_POOL):
1313       if hvparams[constants.HV_SECURITY_DOMAIN]:
1314         raise errors.HypervisorError("Cannot have a security domain when the"
1315                                      " security model is 'none' or 'pool'")
1316
1317     spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1318     if spice_bind:
1319       spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
1320       if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1321         # if an IP version is specified, the spice_bind parameter must be an
1322         # IP of that family
1323         if (netutils.IP4Address.IsValid(spice_bind) and
1324             spice_ip_version != constants.IP4_VERSION):
1325           raise errors.HypervisorError("spice: got an IPv4 address (%s), but"
1326                                        " the specified IP version is %s" %
1327                                        (spice_bind, spice_ip_version))
1328
1329         if (netutils.IP6Address.IsValid(spice_bind) and
1330             spice_ip_version != constants.IP6_VERSION):
1331           raise errors.HypervisorError("spice: got an IPv6 address (%s), but"
1332                                        " the specified IP version is %s" %
1333                                        (spice_bind, spice_ip_version))
1334
1335   @classmethod
1336   def ValidateParameters(cls, hvparams):
1337     """Check the given parameters for validity.
1338
1339     @type hvparams:  dict
1340     @param hvparams: dictionary with parameter names/value
1341     @raise errors.HypervisorError: when a parameter is not valid
1342
1343     """
1344     super(KVMHypervisor, cls).ValidateParameters(hvparams)
1345
1346     security_model = hvparams[constants.HV_SECURITY_MODEL]
1347     if security_model == constants.HT_SM_USER:
1348       username = hvparams[constants.HV_SECURITY_DOMAIN]
1349       try:
1350         pwd.getpwnam(username)
1351       except KeyError:
1352         raise errors.HypervisorError("Unknown security domain user %s"
1353                                      % username)
1354
1355     spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1356     if spice_bind:
1357       # only one of VNC and SPICE can be used currently.
1358       if hvparams[constants.HV_VNC_BIND_ADDRESS]:
1359         raise errors.HypervisorError("both SPICE and VNC are configured, but"
1360                                      " only one of them can be used at a"
1361                                      " given time.")
1362
1363       # KVM version should be >= 0.14.0
1364       _, v_major, v_min, _ = cls._GetKVMVersion()
1365       if (v_major, v_min) < (0, 14):
1366         raise errors.HypervisorError("spice is configured, but it is not"
1367                                      " available in versions of KVM < 0.14")
1368
1369       # if spice_bind is not an IP address, it must be a valid interface
1370       bound_to_addr = (netutils.IP4Address.IsValid(spice_bind)
1371                        or netutils.IP6Address.IsValid(spice_bind))
1372       if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
1373         raise errors.HypervisorError("spice: the %s parameter must be either"
1374                                      " a valid IP address or interface name" %
1375                                      constants.HV_KVM_SPICE_BIND)
1376
1377   @classmethod
1378   def PowercycleNode(cls):
1379     """KVM powercycle, just a wrapper over Linux powercycle.
1380
1381     """
1382     cls.LinuxPowercycle()