summaryrefslogtreecommitdiff
path: root/src/Propellor
diff options
context:
space:
mode:
authorJoey Hess2014-11-17 16:42:15 -0400
committerJoey Hess2014-11-17 16:42:15 -0400
commit46cd2ad0e067ba85d82ad75bb4d358e71d971ed3 (patch)
tree9b251d144eedfd3cd226c92efe8ae3dd901e93ee /src/Propellor
parent8d91b5de6b43333ba77974053cdcdfa87409fb62 (diff)
DigitalOcean.distroKernel property now reboots into the distribution kernel when necessary.
It might be better to do this check on boot to limit the time running the DO kernel (which is not well security supported), but that has the possibility of entering a bad reboot loop. Limiting this check to when propellor runs avoids that, while still fixing the problem pretty fast.
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