summaryrefslogtreecommitdiff
path: root/src/Propellor
diff options
context:
space:
mode:
Diffstat (limited to 'src/Propellor')
-rw-r--r--src/Propellor/Property/HostingProvider/DigitalOcean.hs39
1 files changed, 34 insertions, 5 deletions
diff --git a/src/Propellor/Property/HostingProvider/DigitalOcean.hs b/src/Propellor/Property/HostingProvider/DigitalOcean.hs
index 4565935f..32165d48 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