module Propellor.Property.Reboot (
now,
atEnd,
toDistroKernel,
toKernelNewerThan,
KernelVersion,
) where
import Propellor.Base
import Data.List
import Data.Version
import Text.ParserCombinators.ReadP
type KernelVersion = String
now :: Property Linux
now = tightenTargets $ cmdProperty "reboot" []
`assume` MadeChange
`describe` "reboot now"
type Force = Bool
atEnd :: Force -> (Result -> Bool) -> Property Linux
atEnd force resultok = property "scheduled reboot at end of propellor run" $ do
endAction "rebooting" atend
return NoChange
where
atend r
| resultok r = liftIO $ toResult
<$> boolSystem "reboot" rebootparams
| otherwise = do
warningMessage "Not rebooting, due to status of propellor run."
return FailedChange
rebootparams
| force = [Param "--force"]
| otherwise = []
toDistroKernel :: Property DebianLike
toDistroKernel = tightenTargets $ check (not <$> runningInstalledKernel) now
`describe` "running installed kernel"
toKernelNewerThan :: KernelVersion -> Property DebianLike
toKernelNewerThan ver =
property' ("reboot to kernel newer than " ++ ver) $ \w -> do
wantV <- tryReadVersion ver
runningV <- tryReadVersion =<< liftIO runningKernelVersion
installedV <- maximum <$>
(mapM tryReadVersion =<< liftIO installedKernelVersions)
if runningV >= wantV then noChange
else if installedV >= wantV
then ensureProperty w now
else errorMessage $
"kernel newer than "
++ ver
++ " not installed"
runningInstalledKernel :: IO Bool
runningInstalledKernel = do
kernelver <- runningKernelVersion
when (null kernelver) $
error "failed to read uname -r"
kernelimages <- installedKernelImages
when (null kernelimages) $
error "failed to find any installed kernel images"
findVersion kernelver <$>
readProcess "file" ("-L" : kernelimages)
runningKernelVersion :: IO KernelVersion
runningKernelVersion = takeWhile (/= '\n') <$> readProcess "uname" ["-r"]
installedKernelImages :: IO [String]
installedKernelImages = concat <$> mapM kernelsIn ["/", "/boot/"]
findVersion :: KernelVersion -> String -> Bool
findVersion ver s = (" version " ++ ver ++ " ") `isInfixOf` s
installedKernelVersions :: IO [KernelVersion]
installedKernelVersions = do
kernelimages <- installedKernelImages
when (null kernelimages) $
error "failed to find any installed kernel images"
imageLines <- lines <$> readProcess "file" ("-L" : kernelimages)
return $ extractKernelVersion <$> imageLines
kernelsIn :: FilePath -> IO [FilePath]
kernelsIn d = filter ("vmlinu" `isInfixOf`) <$> dirContents d
extractKernelVersion :: String -> KernelVersion
extractKernelVersion =
unwords . take 1 . drop 1 . dropWhile (/= "version") . words
readVersionMaybe :: KernelVersion -> Maybe Version
readVersionMaybe ver = case map fst $ readP_to_S parseVersion ver of
[] -> Nothing
l -> Just $ maximum l
tryReadVersion :: KernelVersion -> Propellor Version
tryReadVersion ver = case readVersionMaybe ver of
Just x -> return x
Nothing -> errorMessage ("couldn't parse version " ++ ver)