diff --git a/debian/changelog b/debian/changelog index b3a8a20..3858ac2 100644 --- a/debian/changelog +++ b/debian/changelog @@ -5,6 +5,8 @@ propellor (0.9.3) UNRELEASED; urgency=medium * When multiple gpg keys are added, ensure that the privdata file can be decrypted by all of them. * Convert GpgKeyId to newtype. + * DigitalOcean.distroKernel property now reboots into the distribution + kernel when necessary. -- Joey Hess Mon, 10 Nov 2014 11:15:27 -0400 diff --git a/src/Propellor/Property/HostingProvider/DigitalOcean.hs b/src/Propellor/Property/HostingProvider/DigitalOcean.hs index 4565935..32165d4 100644 --- a/src/Propellor/Property/HostingProvider/DigitalOcean.hs +++ b/src/Propellor/Property/HostingProvider/DigitalOcean.hs @@ -1,21 +1,50 @@ -module Propellor.Property.HostingProvider.DigitalOcean where +module Propellor.Property.HostingProvider.DigitalOcean ( + distroKernel +) where import Propellor import qualified Propellor.Property.Apt as Apt import qualified Propellor.Property.File as File +import Data.List + -- Digital Ocean does not provide any way to boot -- the kernel provided by the distribution, except using kexec. -- Without this, some old, and perhaps insecure kernel will be used. -- --- Note that this only causes the new kernel to be loaded on reboot. --- If the power is cycled, the old kernel still boots up. --- TODO: detect this and reboot immediately? +-- This property causes the distro kernel to be loaded on reboot, using kexec. +-- +-- If the power is cycled, the non-distro kernel still boots up. +-- So, this property also checks if the running kernel is present in /boot, +-- and if not, reboots immediately into a distro kernel. distroKernel :: Property distroKernel = propertyList "digital ocean distro kernel hack" - [ Apt.installed ["grub-pc", "kexec-tools"] + [ Apt.installed ["grub-pc", "kexec-tools", "file"] , "/etc/default/kexec" `File.containsLines` [ "LOAD_KEXEC=true" , "USE_GRUB_CONFIG=true" ] `describe` "kexec configured" + , check (not <$> runningInstalledKernel) + (cmdProperty "reboot" []) + `describe` "running installed kernel" ] + +runningInstalledKernel :: IO Bool +runningInstalledKernel = do + kernelver <- takeWhile (/= '\n') <$> readProcess "uname" ["-r"] + when (null kernelver) $ + error "failed to read uname -r" + kernelimages <- concat <$> mapM kernelsIn ["/", "/boot/"] + when (null kernelimages) $ + error "failed to find any installed kernel images" + findVersion kernelver <$> + readProcess "file" ("-L" : kernelimages) + +-- File output looks something like this, we want to unambiguously +-- match the running kernel version: +-- Linux kernel x86 boot executable bzImage, version 3.16-3-amd64 (debian-kernel@lists.debian.org) #1 SMP Debian 3.1, RO-rootFS, swap_dev 0x2, Normal VGA +findVersion :: String -> String -> Bool +findVersion ver s = (" version " ++ ver ++ " ") `isInfixOf` s + +kernelsIn :: FilePath -> IO [FilePath] +kernelsIn d = filter ("vmlinu" `isInfixOf`) <$> dirContents d