KVM: Add function to check the hypervisor version
[ganeti-local] / lib / hypervisor / hv_kvm.py
1 #
2 #
3
4 # Copyright (C) 2008, 2009, 2010 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 from cStringIO import StringIO
35
36 from ganeti import utils
37 from ganeti import constants
38 from ganeti import errors
39 from ganeti import serializer
40 from ganeti import objects
41 from ganeti import uidpool
42 from ganeti import ssconf
43 from ganeti.hypervisor import hv_base
44 from ganeti import netutils
45
46
47 _KVM_NETWORK_SCRIPT = constants.SYSCONFDIR + "/ganeti/kvm-vif-bridge"
48
49
50 def _WriteNetScript(instance, nic, index):
51   """Write a script to connect a net interface to the proper bridge.
52
53   This can be used by any qemu-type hypervisor.
54
55   @type instance: L{objects.Instance}
56   @param instance: Instance object
57   @type nic: L{objects.NIC}
58   @param nic: NIC object
59   @type index: int
60   @param index: NIC index
61   @return: Script
62   @rtype: string
63
64   """
65   if instance.tags:
66     tags = " ".join(instance.tags)
67   else:
68     tags = ""
69
70   buf = StringIO()
71   sw = utils.ShellWriter(buf)
72   sw.Write("#!/bin/sh")
73   sw.Write("# this is autogenerated by Ganeti, please do not edit")
74   sw.Write("export PATH=$PATH:/sbin:/usr/sbin")
75   sw.Write("export INSTANCE=%s", utils.ShellQuote(instance.name))
76   sw.Write("export MAC=%s", utils.ShellQuote(nic.mac))
77   sw.Write("export MODE=%s",
78            utils.ShellQuote(nic.nicparams[constants.NIC_MODE]))
79   sw.Write("export INTERFACE=\"$1\"")
80   sw.Write("export TAGS=%s", utils.ShellQuote(tags))
81
82   if nic.ip:
83     sw.Write("export IP=%s", utils.ShellQuote(nic.ip))
84
85   if nic.nicparams[constants.NIC_LINK]:
86     sw.Write("export LINK=%s",
87              utils.ShellQuote(nic.nicparams[constants.NIC_LINK]))
88
89   if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
90     sw.Write("export BRIDGE=%s",
91              utils.ShellQuote(nic.nicparams[constants.NIC_LINK]))
92
93   # TODO: make this configurable at ./configure time
94   sw.Write("if [ -x %s ]; then", utils.ShellQuote(_KVM_NETWORK_SCRIPT))
95   sw.IncIndent()
96   try:
97     sw.Write("# Execute the user-specific vif file")
98     sw.Write(_KVM_NETWORK_SCRIPT)
99   finally:
100     sw.DecIndent()
101   sw.Write("else")
102   sw.IncIndent()
103   try:
104     sw.Write("ifconfig $INTERFACE 0.0.0.0 up")
105
106     if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
107       sw.Write("# Connect the interface to the bridge")
108       sw.Write("brctl addif $BRIDGE $INTERFACE")
109
110     elif nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_ROUTED:
111       if not nic.ip:
112         raise errors.HypervisorError("nic/%d is routed, but has no IP"
113                                      " address" % index)
114
115       sw.Write("# Route traffic targeted at the IP to the interface")
116       if nic.nicparams[constants.NIC_LINK]:
117         sw.Write("while ip rule del dev $INTERFACE; do :; done")
118         sw.Write("ip rule add dev $INTERFACE table $LINK")
119         sw.Write("ip route replace $IP table $LINK proto static"
120                  " dev $INTERFACE")
121       else:
122         sw.Write("ip route replace $IP proto static dev $INTERFACE")
123
124       interface_v4_conf = "/proc/sys/net/ipv4/conf/$INTERFACE"
125       sw.Write(" if [ -d %s ]; then", interface_v4_conf)
126       sw.IncIndent()
127       try:
128         sw.Write("echo 1 > %s/proxy_arp", interface_v4_conf)
129         sw.Write("echo 1 > %s/forwarding", interface_v4_conf)
130       finally:
131         sw.DecIndent()
132       sw.Write("fi")
133
134       interface_v6_conf = "/proc/sys/net/ipv6/conf/$INTERFACE"
135       sw.Write("if [ -d %s ]; then", interface_v6_conf)
136       sw.IncIndent()
137       try:
138         sw.Write("echo 1 > %s/proxy_ndp", interface_v6_conf)
139         sw.Write("echo 1 > %s/forwarding", interface_v6_conf)
140       finally:
141         sw.DecIndent()
142       sw.Write("fi")
143   finally:
144     sw.DecIndent()
145   sw.Write("fi")
146
147   return buf.getvalue()
148
149
150 class KVMHypervisor(hv_base.BaseHypervisor):
151   """KVM hypervisor interface"""
152   CAN_MIGRATE = True
153
154   _ROOT_DIR = constants.RUN_GANETI_DIR + "/kvm-hypervisor"
155   _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
156   _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
157   _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
158   _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
159   # KVM instances with chroot enabled are started in empty chroot directories.
160   _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
161   # After an instance is stopped, its chroot directory is removed.
162   # If the chroot directory is not empty, it can't be removed.
163   # A non-empty chroot directory indicates a possible security incident.
164   # To support forensics, the non-empty chroot directory is quarantined in
165   # a separate directory, called 'chroot-quarantine'.
166   _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
167   _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR,
168            _CHROOT_DIR, _CHROOT_QUARANTINE_DIR]
169
170   PARAMETERS = {
171     constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
172     constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
173     constants.HV_ROOT_PATH: hv_base.NO_CHECK,
174     constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
175     constants.HV_ACPI: hv_base.NO_CHECK,
176     constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
177     constants.HV_VNC_BIND_ADDRESS:
178       (False, lambda x: (netutils.IsValidIP4(x) or utils.IsNormAbsPath(x)),
179        "the VNC bind address must be either a valid IP address or an absolute"
180        " pathname", None, None),
181     constants.HV_VNC_TLS: hv_base.NO_CHECK,
182     constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
183     constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
184     constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
185     constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
186     constants.HV_BOOT_ORDER:
187       hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
188     constants.HV_NIC_TYPE:
189       hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
190     constants.HV_DISK_TYPE:
191       hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
192     constants.HV_USB_MOUSE:
193       hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
194     constants.HV_MIGRATION_PORT: hv_base.NET_PORT_CHECK,
195     constants.HV_MIGRATION_BANDWIDTH: hv_base.NO_CHECK,
196     constants.HV_MIGRATION_DOWNTIME: hv_base.NO_CHECK,
197     constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
198     constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
199     constants.HV_DISK_CACHE:
200       hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
201     constants.HV_SECURITY_MODEL:
202       hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
203     constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
204     constants.HV_KVM_FLAG:
205       hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
206     constants.HV_VHOST_NET: hv_base.NO_CHECK,
207     constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
208     }
209
210   _MIGRATION_STATUS_RE = re.compile('Migration\s+status:\s+(\w+)',
211                                     re.M | re.I)
212   _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
213   _MIGRATION_INFO_RETRY_DELAY = 2
214
215   _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)\.(\d+)\b")
216
217   ANCILLARY_FILES = [
218     _KVM_NETWORK_SCRIPT,
219     ]
220
221   def __init__(self):
222     hv_base.BaseHypervisor.__init__(self)
223     # Let's make sure the directories we need exist, even if the RUN_DIR lives
224     # in a tmpfs filesystem or has been otherwise wiped out.
225     dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
226     utils.EnsureDirs(dirs)
227
228   @classmethod
229   def _InstancePidFile(cls, instance_name):
230     """Returns the instance pidfile.
231
232     """
233     return utils.PathJoin(cls._PIDS_DIR, instance_name)
234
235   @classmethod
236   def _InstanceUidFile(cls, instance_name):
237     """Returns the instance uidfile.
238
239     """
240     return utils.PathJoin(cls._UIDS_DIR, instance_name)
241
242   @classmethod
243   def _InstancePidInfo(cls, pid):
244     """Check pid file for instance information.
245
246     Check that a pid file is associated with an instance, and retrieve
247     information from its command line.
248
249     @type pid: string or int
250     @param pid: process id of the instance to check
251     @rtype: tuple
252     @return: (instance_name, memory, vcpus)
253     @raise errors.HypervisorError: when an instance cannot be found
254
255     """
256     alive = utils.IsProcessAlive(pid)
257     if not alive:
258       raise errors.HypervisorError("Cannot get info for pid %s" % pid)
259
260     cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
261     try:
262       cmdline = utils.ReadFile(cmdline_file)
263     except EnvironmentError, err:
264       raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
265                                    (pid, err))
266
267     instance = None
268     memory = 0
269     vcpus = 0
270
271     arg_list = cmdline.split('\x00')
272     while arg_list:
273       arg =  arg_list.pop(0)
274       if arg == "-name":
275         instance = arg_list.pop(0)
276       elif arg == "-m":
277         memory = int(arg_list.pop(0))
278       elif arg == "-smp":
279         vcpus = int(arg_list.pop(0))
280
281     if instance is None:
282       raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
283                                    " instance" % pid)
284
285     return (instance, memory, vcpus)
286
287   def _InstancePidAlive(self, instance_name):
288     """Returns the instance pidfile, pid, and liveness.
289
290     @type instance_name: string
291     @param instance_name: instance name
292     @rtype: tuple
293     @return: (pid file name, pid, liveness)
294
295     """
296     pidfile = self._InstancePidFile(instance_name)
297     pid = utils.ReadPidFile(pidfile)
298
299     alive = False
300     try:
301       cmd_instance = self._InstancePidInfo(pid)[0]
302       alive = (cmd_instance == instance_name)
303     except errors.HypervisorError:
304       pass
305
306     return (pidfile, pid, alive)
307
308   def _CheckDown(self, instance_name):
309     """Raises an error unless the given instance is down.
310
311     """
312     alive = self._InstancePidAlive(instance_name)[2]
313     if alive:
314       raise errors.HypervisorError("Failed to start instance %s: %s" %
315                                    (instance_name, "already running"))
316
317   @classmethod
318   def _InstanceMonitor(cls, instance_name):
319     """Returns the instance monitor socket name
320
321     """
322     return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
323
324   @classmethod
325   def _InstanceSerial(cls, instance_name):
326     """Returns the instance serial socket name
327
328     """
329     return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
330
331   @staticmethod
332   def _SocatUnixConsoleParams():
333     """Returns the correct parameters for socat
334
335     If we have a new-enough socat we can use raw mode with an escape character.
336
337     """
338     if constants.SOCAT_USE_ESCAPE:
339       return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
340     else:
341       return "echo=0,icanon=0"
342
343   @classmethod
344   def _InstanceKVMRuntime(cls, instance_name):
345     """Returns the instance KVM runtime filename
346
347     """
348     return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
349
350   @classmethod
351   def _InstanceChrootDir(cls, instance_name):
352     """Returns the name of the KVM chroot dir of the instance
353
354     """
355     return utils.PathJoin(cls._CHROOT_DIR, instance_name)
356
357   @classmethod
358   def _TryReadUidFile(cls, uid_file):
359     """Try to read a uid file
360
361     """
362     if os.path.exists(uid_file):
363       try:
364         uid = int(utils.ReadOneLineFile(uid_file))
365         return uid
366       except EnvironmentError:
367         logging.warning("Can't read uid file", exc_info=True)
368       except (TypeError, ValueError):
369         logging.warning("Can't parse uid file contents", exc_info=True)
370     return None
371
372   @classmethod
373   def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
374     """Removes an instance's rutime sockets/files/dirs.
375
376     """
377     utils.RemoveFile(pidfile)
378     utils.RemoveFile(cls._InstanceMonitor(instance_name))
379     utils.RemoveFile(cls._InstanceSerial(instance_name))
380     utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
381     uid_file = cls._InstanceUidFile(instance_name)
382     uid = cls._TryReadUidFile(uid_file)
383     utils.RemoveFile(uid_file)
384     if uid is not None:
385       uidpool.ReleaseUid(uid)
386     try:
387       chroot_dir = cls._InstanceChrootDir(instance_name)
388       utils.RemoveDir(chroot_dir)
389     except OSError, err:
390       if err.errno == errno.ENOTEMPTY:
391         # The chroot directory is expected to be empty, but it isn't.
392         new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
393                                           prefix="%s-%s-" %
394                                           (instance_name,
395                                            utils.TimestampForFilename()))
396         logging.warning("The chroot directory of instance %s can not be"
397                         " removed as it is not empty. Moving it to the"
398                         " quarantine instead. Please investigate the"
399                         " contents (%s) and clean up manually",
400                         instance_name, new_chroot_dir)
401         utils.RenameFile(chroot_dir, new_chroot_dir)
402       else:
403         raise
404
405   @staticmethod
406   def _WriteNetScriptFile(instance, seq, nic):
407     """Write a script to connect a net interface to the proper bridge.
408
409     This can be used by any qemu-type hypervisor.
410
411     @param instance: instance we're acting on
412     @type instance: instance object
413     @param seq: nic sequence number
414     @type seq: int
415     @param nic: nic we're acting on
416     @type nic: nic object
417     @return: netscript file name
418     @rtype: string
419
420     """
421     script = _WriteNetScript(instance, nic, seq)
422
423     # As much as we'd like to put this in our _ROOT_DIR, that will happen to be
424     # mounted noexec sometimes, so we'll have to find another place.
425     (tmpfd, tmpfile_name) = tempfile.mkstemp()
426     tmpfile = os.fdopen(tmpfd, 'w')
427     try:
428       tmpfile.write(script)
429     finally:
430       tmpfile.close()
431     os.chmod(tmpfile_name, 0755)
432     return tmpfile_name
433
434   def ListInstances(self):
435     """Get the list of running instances.
436
437     We can do this by listing our live instances directory and
438     checking whether the associated kvm process is still alive.
439
440     """
441     result = []
442     for name in os.listdir(self._PIDS_DIR):
443       if self._InstancePidAlive(name)[2]:
444         result.append(name)
445     return result
446
447   def GetInstanceInfo(self, instance_name):
448     """Get instance properties.
449
450     @type instance_name: string
451     @param instance_name: the instance name
452     @rtype: tuple of strings
453     @return: (name, id, memory, vcpus, stat, times)
454
455     """
456     _, pid, alive = self._InstancePidAlive(instance_name)
457     if not alive:
458       return None
459
460     _, memory, vcpus = self._InstancePidInfo(pid)
461     stat = "---b-"
462     times = "0"
463
464     return (instance_name, pid, memory, vcpus, stat, times)
465
466   def GetAllInstancesInfo(self):
467     """Get properties of all instances.
468
469     @return: list of tuples (name, id, memory, vcpus, stat, times)
470
471     """
472     data = []
473     for name in os.listdir(self._PIDS_DIR):
474       try:
475         info = self.GetInstanceInfo(name)
476       except errors.HypervisorError:
477         continue
478       if info:
479         data.append(info)
480     return data
481
482   def _GenerateKVMRuntime(self, instance, block_devices):
483     """Generate KVM information to start an instance.
484
485     """
486     pidfile  = self._InstancePidFile(instance.name)
487     kvm = constants.KVM_PATH
488     kvm_cmd = [kvm]
489     # used just by the vnc server, if enabled
490     kvm_cmd.extend(['-name', instance.name])
491     kvm_cmd.extend(['-m', instance.beparams[constants.BE_MEMORY]])
492     kvm_cmd.extend(['-smp', instance.beparams[constants.BE_VCPUS]])
493     kvm_cmd.extend(['-pidfile', pidfile])
494     kvm_cmd.extend(['-daemonize'])
495     if not instance.hvparams[constants.HV_ACPI]:
496       kvm_cmd.extend(['-no-acpi'])
497
498     hvp = instance.hvparams
499     boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
500     boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
501     boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
502
503     if hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED:
504       kvm_cmd.extend(["-enable-kvm"])
505     elif hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED:
506       kvm_cmd.extend(["-disable-kvm"])
507
508     if boot_network:
509       kvm_cmd.extend(['-boot', 'n'])
510
511     disk_type = hvp[constants.HV_DISK_TYPE]
512     if disk_type == constants.HT_DISK_PARAVIRTUAL:
513       if_val = ',if=virtio'
514     else:
515       if_val = ',if=%s' % disk_type
516     # Cache mode
517     disk_cache = hvp[constants.HV_DISK_CACHE]
518     if disk_cache != constants.HT_CACHE_DEFAULT:
519       cache_val = ",cache=%s" % disk_cache
520     else:
521       cache_val = ""
522     for cfdev, dev_path in block_devices:
523       if cfdev.mode != constants.DISK_RDWR:
524         raise errors.HypervisorError("Instance has read-only disks which"
525                                      " are not supported by KVM")
526       # TODO: handle FD_LOOP and FD_BLKTAP (?)
527       if boot_disk:
528         kvm_cmd.extend(['-boot', 'c'])
529         if disk_type != constants.HT_DISK_IDE:
530           boot_val = ',boot=on'
531         else:
532           boot_val = ''
533         # We only boot from the first disk
534         boot_disk = False
535       else:
536         boot_val = ''
537
538       drive_val = 'file=%s,format=raw%s%s%s' % (dev_path, if_val, boot_val,
539                                                 cache_val)
540       kvm_cmd.extend(['-drive', drive_val])
541
542     iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
543     if iso_image:
544       options = ',format=raw,media=cdrom'
545       if boot_cdrom:
546         kvm_cmd.extend(['-boot', 'd'])
547         if disk_type != constants.HT_DISK_IDE:
548           options = '%s,boot=on' % options
549       else:
550         if disk_type == constants.HT_DISK_PARAVIRTUAL:
551           if_val = ',if=virtio'
552         else:
553           if_val = ',if=%s' % disk_type
554         options = '%s%s' % (options, if_val)
555       drive_val = 'file=%s%s' % (iso_image, options)
556       kvm_cmd.extend(['-drive', drive_val])
557
558     kernel_path = hvp[constants.HV_KERNEL_PATH]
559     if kernel_path:
560       kvm_cmd.extend(['-kernel', kernel_path])
561       initrd_path = hvp[constants.HV_INITRD_PATH]
562       if initrd_path:
563         kvm_cmd.extend(['-initrd', initrd_path])
564       root_append = ['root=%s' % hvp[constants.HV_ROOT_PATH],
565                      hvp[constants.HV_KERNEL_ARGS]]
566       if hvp[constants.HV_SERIAL_CONSOLE]:
567         root_append.append('console=ttyS0,38400')
568       kvm_cmd.extend(['-append', ' '.join(root_append)])
569
570     mouse_type = hvp[constants.HV_USB_MOUSE]
571     vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
572
573     if mouse_type:
574       kvm_cmd.extend(['-usb'])
575       kvm_cmd.extend(['-usbdevice', mouse_type])
576     elif vnc_bind_address:
577       kvm_cmd.extend(['-usbdevice', constants.HT_MOUSE_TABLET])
578
579     if vnc_bind_address:
580       if netutils.IsValidIP4(vnc_bind_address):
581         if instance.network_port > constants.VNC_BASE_PORT:
582           display = instance.network_port - constants.VNC_BASE_PORT
583           if vnc_bind_address == constants.IP4_ADDRESS_ANY:
584             vnc_arg = ':%d' % (display)
585           else:
586             vnc_arg = '%s:%d' % (vnc_bind_address, display)
587         else:
588           logging.error("Network port is not a valid VNC display (%d < %d)."
589                         " Not starting VNC", instance.network_port,
590                         constants.VNC_BASE_PORT)
591           vnc_arg = 'none'
592
593         # Only allow tls and other option when not binding to a file, for now.
594         # kvm/qemu gets confused otherwise about the filename to use.
595         vnc_append = ''
596         if hvp[constants.HV_VNC_TLS]:
597           vnc_append = '%s,tls' % vnc_append
598           if hvp[constants.HV_VNC_X509_VERIFY]:
599             vnc_append = '%s,x509verify=%s' % (vnc_append,
600                                                hvp[constants.HV_VNC_X509])
601           elif hvp[constants.HV_VNC_X509]:
602             vnc_append = '%s,x509=%s' % (vnc_append,
603                                          hvp[constants.HV_VNC_X509])
604         if hvp[constants.HV_VNC_PASSWORD_FILE]:
605           vnc_append = '%s,password' % vnc_append
606
607         vnc_arg = '%s%s' % (vnc_arg, vnc_append)
608
609       else:
610         vnc_arg = 'unix:%s/%s.vnc' % (vnc_bind_address, instance.name)
611
612       kvm_cmd.extend(['-vnc', vnc_arg])
613     else:
614       kvm_cmd.extend(['-nographic'])
615
616     monitor_dev = ("unix:%s,server,nowait" %
617                    self._InstanceMonitor(instance.name))
618     kvm_cmd.extend(['-monitor', monitor_dev])
619     if hvp[constants.HV_SERIAL_CONSOLE]:
620       serial_dev = ('unix:%s,server,nowait' %
621                     self._InstanceSerial(instance.name))
622       kvm_cmd.extend(['-serial', serial_dev])
623     else:
624       kvm_cmd.extend(['-serial', 'none'])
625
626     if hvp[constants.HV_USE_LOCALTIME]:
627       kvm_cmd.extend(['-localtime'])
628
629     if hvp[constants.HV_KVM_USE_CHROOT]:
630       kvm_cmd.extend(['-chroot', self._InstanceChrootDir(instance.name)])
631
632     # Save the current instance nics, but defer their expansion as parameters,
633     # as we'll need to generate executable temp files for them.
634     kvm_nics = instance.nics
635     hvparams = hvp
636
637     return (kvm_cmd, kvm_nics, hvparams)
638
639   def _WriteKVMRuntime(self, instance_name, data):
640     """Write an instance's KVM runtime
641
642     """
643     try:
644       utils.WriteFile(self._InstanceKVMRuntime(instance_name),
645                       data=data)
646     except EnvironmentError, err:
647       raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
648
649   def _ReadKVMRuntime(self, instance_name):
650     """Read an instance's KVM runtime
651
652     """
653     try:
654       file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
655     except EnvironmentError, err:
656       raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
657     return file_content
658
659   def _SaveKVMRuntime(self, instance, kvm_runtime):
660     """Save an instance's KVM runtime
661
662     """
663     kvm_cmd, kvm_nics, hvparams = kvm_runtime
664     serialized_nics = [nic.ToDict() for nic in kvm_nics]
665     serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
666     self._WriteKVMRuntime(instance.name, serialized_form)
667
668   def _LoadKVMRuntime(self, instance, serialized_runtime=None):
669     """Load an instance's KVM runtime
670
671     """
672     if not serialized_runtime:
673       serialized_runtime = self._ReadKVMRuntime(instance.name)
674     loaded_runtime = serializer.Load(serialized_runtime)
675     kvm_cmd, serialized_nics, hvparams = loaded_runtime
676     kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
677     return (kvm_cmd, kvm_nics, hvparams)
678
679   def _RunKVMCmd(self, name, kvm_cmd):
680     """Run the KVM cmd and check for errors
681
682     @type name: string
683     @param name: instance name
684     @type kvm_cmd: list of strings
685     @param kvm_cmd: runcmd input for kvm
686
687     """
688     result = utils.RunCmd(kvm_cmd)
689     if result.failed:
690       raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
691                                    (name, result.fail_reason, result.output))
692     if not self._InstancePidAlive(name)[2]:
693       raise errors.HypervisorError("Failed to start instance %s" % name)
694
695   def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
696     """Execute a KVM cmd, after completing it with some last minute data
697
698     @type incoming: tuple of strings
699     @param incoming: (target_host_ip, port)
700
701     """
702     # Small _ExecuteKVMRuntime hv parameters programming howto:
703     #  - conf_hvp contains the parameters as configured on ganeti. they might
704     #    have changed since the instance started; only use them if the change
705     #    won't affect the inside of the instance (which hasn't been rebooted).
706     #  - up_hvp contains the parameters as they were when the instance was
707     #    started, plus any new parameter which has been added between ganeti
708     #    versions: it is paramount that those default to a value which won't
709     #    affect the inside of the instance as well.
710     conf_hvp = instance.hvparams
711     name = instance.name
712     self._CheckDown(name)
713
714     temp_files = []
715
716     kvm_cmd, kvm_nics, up_hvp = kvm_runtime
717     up_hvp = objects.FillDict(conf_hvp, up_hvp)
718
719     # We know it's safe to run as a different user upon migration, so we'll use
720     # the latest conf, from conf_hvp.
721     security_model = conf_hvp[constants.HV_SECURITY_MODEL]
722     if security_model == constants.HT_SM_USER:
723       kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
724
725     # We have reasons to believe changing something like the nic driver/type
726     # upon migration won't exactly fly with the instance kernel, so for nic
727     # related parameters we'll use up_hvp
728     if not kvm_nics:
729       kvm_cmd.extend(["-net", "none"])
730     else:
731       tap_extra = ""
732       nic_type = up_hvp[constants.HV_NIC_TYPE]
733       if nic_type == constants.HT_NIC_PARAVIRTUAL:
734         nic_model = "model=virtio"
735         if up_hvp[constants.HV_VHOST_NET]:
736           tap_extra = ",vhost=on"
737       else:
738         nic_model = "model=%s" % nic_type
739
740       for nic_seq, nic in enumerate(kvm_nics):
741         nic_val = "nic,vlan=%s,macaddr=%s,%s" % (nic_seq, nic.mac, nic_model)
742         script = self._WriteNetScriptFile(instance, nic_seq, nic)
743         tap_val = "tap,vlan=%s,script=%s%s" % (nic_seq, script, tap_extra)
744         kvm_cmd.extend(["-net", nic_val])
745         kvm_cmd.extend(["-net", tap_val])
746         temp_files.append(script)
747
748     if incoming:
749       target, port = incoming
750       kvm_cmd.extend(['-incoming', 'tcp:%s:%s' % (target, port)])
751
752     # Changing the vnc password doesn't bother the guest that much. At most it
753     # will surprise people who connect to it. Whether positively or negatively
754     # it's debatable.
755     vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
756     vnc_pwd = None
757     if vnc_pwd_file:
758       try:
759         vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
760       except EnvironmentError, err:
761         raise errors.HypervisorError("Failed to open VNC password file %s: %s"
762                                      % (vnc_pwd_file, err))
763
764     if conf_hvp[constants.HV_KVM_USE_CHROOT]:
765       utils.EnsureDirs([(self._InstanceChrootDir(name),
766                          constants.SECURE_DIR_MODE)])
767
768     if security_model == constants.HT_SM_POOL:
769       ss = ssconf.SimpleStore()
770       uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
771       all_uids = set(uidpool.ExpandUidPool(uid_pool))
772       uid = uidpool.RequestUnusedUid(all_uids)
773       try:
774         username = pwd.getpwuid(uid.GetUid()).pw_name
775         kvm_cmd.extend(["-runas", username])
776         self._RunKVMCmd(name, kvm_cmd)
777       except:
778         uidpool.ReleaseUid(uid)
779         raise
780       else:
781         uid.Unlock()
782         utils.WriteFile(self._InstanceUidFile(name), data=str(uid))
783     else:
784       self._RunKVMCmd(name, kvm_cmd)
785
786     if vnc_pwd:
787       change_cmd = 'change vnc password %s' % vnc_pwd
788       self._CallMonitorCommand(instance.name, change_cmd)
789
790     for filename in temp_files:
791       utils.RemoveFile(filename)
792
793   def StartInstance(self, instance, block_devices):
794     """Start an instance.
795
796     """
797     self._CheckDown(instance.name)
798     kvm_runtime = self._GenerateKVMRuntime(instance, block_devices)
799     self._SaveKVMRuntime(instance, kvm_runtime)
800     self._ExecuteKVMRuntime(instance, kvm_runtime)
801
802   def _CallMonitorCommand(self, instance_name, command):
803     """Invoke a command on the instance monitor.
804
805     """
806     socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
807              (utils.ShellQuote(command),
808               constants.SOCAT_PATH,
809               utils.ShellQuote(self._InstanceMonitor(instance_name))))
810     result = utils.RunCmd(socat)
811     if result.failed:
812       msg = ("Failed to send command '%s' to instance %s."
813              " output: %s, error: %s, fail_reason: %s" %
814              (command, instance_name,
815               result.stdout, result.stderr, result.fail_reason))
816       raise errors.HypervisorError(msg)
817
818     return result
819
820   @classmethod
821   def _GetKVMVersion(cls):
822     """Return the installed KVM version
823
824     @return: (version, v_maj, v_min, v_rev), or None
825
826     """
827     result = utils.RunCmd([constants.KVM_PATH, "--help"])
828     if result.failed:
829       return None
830     match = cls._VERSION_RE.search(result.output.splitlines()[0])
831     if not match:
832       return None
833     return (match.group(0), match.group(1), match.group(2), match.group(3))
834
835   def StopInstance(self, instance, force=False, retry=False, name=None):
836     """Stop an instance.
837
838     """
839     if name is not None and not force:
840       raise errors.HypervisorError("Cannot shutdown cleanly by name only")
841     if name is None:
842       name = instance.name
843       acpi = instance.hvparams[constants.HV_ACPI]
844     else:
845       acpi = False
846     _, pid, alive = self._InstancePidAlive(name)
847     if pid > 0 and alive:
848       if force or not acpi:
849         utils.KillProcess(pid)
850       else:
851         self._CallMonitorCommand(name, 'system_powerdown')
852
853   def CleanupInstance(self, instance_name):
854     """Cleanup after a stopped instance
855
856     """
857     pidfile, pid, alive = self._InstancePidAlive(instance_name)
858     if pid > 0 and alive:
859       raise errors.HypervisorError("Cannot cleanup a live instance")
860     self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
861
862   def RebootInstance(self, instance):
863     """Reboot an instance.
864
865     """
866     # For some reason if we do a 'send-key ctrl-alt-delete' to the control
867     # socket the instance will stop, but now power up again. So we'll resort
868     # to shutdown and restart.
869     _, _, alive = self._InstancePidAlive(instance.name)
870     if not alive:
871       raise errors.HypervisorError("Failed to reboot instance %s:"
872                                    " not running" % instance.name)
873     # StopInstance will delete the saved KVM runtime so:
874     # ...first load it...
875     kvm_runtime = self._LoadKVMRuntime(instance)
876     # ...now we can safely call StopInstance...
877     if not self.StopInstance(instance):
878       self.StopInstance(instance, force=True)
879     # ...and finally we can save it again, and execute it...
880     self._SaveKVMRuntime(instance, kvm_runtime)
881     self._ExecuteKVMRuntime(instance, kvm_runtime)
882
883   def MigrationInfo(self, instance):
884     """Get instance information to perform a migration.
885
886     @type instance: L{objects.Instance}
887     @param instance: instance to be migrated
888     @rtype: string
889     @return: content of the KVM runtime file
890
891     """
892     return self._ReadKVMRuntime(instance.name)
893
894   def AcceptInstance(self, instance, info, target):
895     """Prepare to accept an instance.
896
897     @type instance: L{objects.Instance}
898     @param instance: instance to be accepted
899     @type info: string
900     @param info: content of the KVM runtime file on the source node
901     @type target: string
902     @param target: target host (usually ip), on this node
903
904     """
905     kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
906     incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
907     self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
908
909   def FinalizeMigration(self, instance, info, success):
910     """Finalize an instance migration.
911
912     Stop the incoming mode KVM.
913
914     @type instance: L{objects.Instance}
915     @param instance: instance whose migration is being finalized
916
917     """
918     if success:
919       self._WriteKVMRuntime(instance.name, info)
920     else:
921       self.StopInstance(instance, force=True)
922
923   def MigrateInstance(self, instance, target, live):
924     """Migrate an instance to a target node.
925
926     The migration will not be attempted if the instance is not
927     currently running.
928
929     @type instance: L{objects.Instance}
930     @param instance: the instance to be migrated
931     @type target: string
932     @param target: ip address of the target node
933     @type live: boolean
934     @param live: perform a live migration
935
936     """
937     instance_name = instance.name
938     port = instance.hvparams[constants.HV_MIGRATION_PORT]
939     pidfile, pid, alive = self._InstancePidAlive(instance_name)
940     if not alive:
941       raise errors.HypervisorError("Instance not running, cannot migrate")
942
943     if not live:
944       self._CallMonitorCommand(instance_name, 'stop')
945
946     migrate_command = ('migrate_set_speed %dm' %
947         instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
948     self._CallMonitorCommand(instance_name, migrate_command)
949
950     migrate_command = ('migrate_set_downtime %dms' %
951         instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
952     self._CallMonitorCommand(instance_name, migrate_command)
953
954     migrate_command = 'migrate -d tcp:%s:%s' % (target, port)
955     self._CallMonitorCommand(instance_name, migrate_command)
956
957     info_command = 'info migrate'
958     done = False
959     broken_answers = 0
960     while not done:
961       result = self._CallMonitorCommand(instance_name, info_command)
962       match = self._MIGRATION_STATUS_RE.search(result.stdout)
963       if not match:
964         broken_answers += 1
965         if not result.stdout:
966           logging.info("KVM: empty 'info migrate' result")
967         else:
968           logging.warning("KVM: unknown 'info migrate' result: %s",
969                           result.stdout)
970         time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
971       else:
972         status = match.group(1)
973         if status == 'completed':
974           done = True
975         elif status == 'active':
976           # reset the broken answers count
977           broken_answers = 0
978           time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
979         elif status == 'failed' or status == 'cancelled':
980           if not live:
981             self._CallMonitorCommand(instance_name, 'cont')
982           raise errors.HypervisorError("Migration %s at the kvm level" %
983                                        status)
984         else:
985           logging.warning("KVM: unknown migration status '%s'", status)
986           broken_answers += 1
987           time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
988       if broken_answers >= self._MIGRATION_INFO_MAX_BAD_ANSWERS:
989         raise errors.HypervisorError("Too many 'info migrate' broken answers")
990
991     utils.KillProcess(pid)
992     self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
993
994   def GetNodeInfo(self):
995     """Return information about the node.
996
997     This is just a wrapper over the base GetLinuxNodeInfo method.
998
999     @return: a dict with the following keys (values in MiB):
1000           - memory_total: the total memory size on the node
1001           - memory_free: the available memory on the node for instances
1002           - memory_dom0: the memory used by the node itself, if available
1003
1004     """
1005     return self.GetLinuxNodeInfo()
1006
1007   @classmethod
1008   def GetShellCommandForConsole(cls, instance, hvparams, beparams):
1009     """Return a command for connecting to the console of an instance.
1010
1011     """
1012     if hvparams[constants.HV_SERIAL_CONSOLE]:
1013       shell_command = ("%s STDIO,%s UNIX-CONNECT:%s" %
1014                        (constants.SOCAT_PATH, cls._SocatUnixConsoleParams(),
1015                         utils.ShellQuote(cls._InstanceSerial(instance.name))))
1016     else:
1017       shell_command = "echo 'No serial shell for instance %s'" % instance.name
1018
1019     vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1020     if vnc_bind_address:
1021       if instance.network_port > constants.VNC_BASE_PORT:
1022         display = instance.network_port - constants.VNC_BASE_PORT
1023         vnc_command = ("echo 'Instance has VNC listening on %s:%d"
1024                        " (display: %d)'" % (vnc_bind_address,
1025                                             instance.network_port,
1026                                             display))
1027         shell_command = "%s; %s" % (vnc_command, shell_command)
1028
1029     return shell_command
1030
1031   def Verify(self):
1032     """Verify the hypervisor.
1033
1034     Check that the binary exists.
1035
1036     """
1037     if not os.path.exists(constants.KVM_PATH):
1038       return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
1039     if not os.path.exists(constants.SOCAT_PATH):
1040       return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
1041
1042
1043   @classmethod
1044   def CheckParameterSyntax(cls, hvparams):
1045     """Check the given parameters for validity.
1046
1047     @type hvparams:  dict
1048     @param hvparams: dictionary with parameter names/value
1049     @raise errors.HypervisorError: when a parameter is not valid
1050
1051     """
1052     super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
1053
1054     kernel_path = hvparams[constants.HV_KERNEL_PATH]
1055     if kernel_path:
1056       if not hvparams[constants.HV_ROOT_PATH]:
1057         raise errors.HypervisorError("Need a root partition for the instance,"
1058                                      " if a kernel is defined")
1059
1060     if (hvparams[constants.HV_VNC_X509_VERIFY] and
1061         not hvparams[constants.HV_VNC_X509]):
1062       raise errors.HypervisorError("%s must be defined, if %s is" %
1063                                    (constants.HV_VNC_X509,
1064                                     constants.HV_VNC_X509_VERIFY))
1065
1066     boot_order = hvparams[constants.HV_BOOT_ORDER]
1067     if (boot_order == constants.HT_BO_CDROM and
1068         not hvparams[constants.HV_CDROM_IMAGE_PATH]):
1069       raise errors.HypervisorError("Cannot boot from cdrom without an"
1070                                    " ISO path")
1071
1072     security_model = hvparams[constants.HV_SECURITY_MODEL]
1073     if security_model == constants.HT_SM_USER:
1074       if not hvparams[constants.HV_SECURITY_DOMAIN]:
1075         raise errors.HypervisorError("A security domain (user to run kvm as)"
1076                                      " must be specified")
1077     elif (security_model == constants.HT_SM_NONE or
1078           security_model == constants.HT_SM_POOL):
1079       if hvparams[constants.HV_SECURITY_DOMAIN]:
1080         raise errors.HypervisorError("Cannot have a security domain when the"
1081                                      " security model is 'none' or 'pool'")
1082
1083   @classmethod
1084   def ValidateParameters(cls, hvparams):
1085     """Check the given parameters for validity.
1086
1087     @type hvparams:  dict
1088     @param hvparams: dictionary with parameter names/value
1089     @raise errors.HypervisorError: when a parameter is not valid
1090
1091     """
1092     super(KVMHypervisor, cls).ValidateParameters(hvparams)
1093
1094     security_model = hvparams[constants.HV_SECURITY_MODEL]
1095     if security_model == constants.HT_SM_USER:
1096       username = hvparams[constants.HV_SECURITY_DOMAIN]
1097       try:
1098         pwd.getpwnam(username)
1099       except KeyError:
1100         raise errors.HypervisorError("Unknown security domain user %s"
1101                                      % username)
1102
1103   @classmethod
1104   def PowercycleNode(cls):
1105     """KVM powercycle, just a wrapper over Linux powercycle.
1106
1107     """
1108     cls.LinuxPowercycle()