2014-04-10 21:22:32 +00:00
|
|
|
{-# LANGUAGE PackageImports #-}
|
2015-01-24 17:59:29 +00:00
|
|
|
{-# LANGUAGE GADTs #-}
|
2014-04-10 21:22:32 +00:00
|
|
|
|
2014-12-07 21:09:55 +00:00
|
|
|
module Propellor.Engine (
|
|
|
|
mainProperties,
|
|
|
|
runPropellor,
|
|
|
|
ensureProperty,
|
|
|
|
ensureProperties,
|
|
|
|
fromHost,
|
|
|
|
onlyProcess,
|
|
|
|
processChainOutput,
|
|
|
|
) where
|
2014-03-31 05:06:44 +00:00
|
|
|
|
|
|
|
import System.Exit
|
|
|
|
import System.IO
|
2014-03-31 14:36:45 +00:00
|
|
|
import Data.Monoid
|
2014-05-31 22:02:56 +00:00
|
|
|
import Control.Applicative
|
2014-03-31 22:31:08 +00:00
|
|
|
import System.Console.ANSI
|
2014-12-06 10:34:32 +00:00
|
|
|
import "mtl" Control.Monad.RWS.Strict
|
2014-11-19 05:28:38 +00:00
|
|
|
import System.PosixCompat
|
|
|
|
import System.Posix.IO
|
2014-11-23 02:24:09 +00:00
|
|
|
import System.FilePath
|
|
|
|
import System.Directory
|
2014-03-31 05:06:44 +00:00
|
|
|
|
|
|
|
import Propellor.Types
|
2014-03-31 22:31:08 +00:00
|
|
|
import Propellor.Message
|
2014-04-10 21:22:32 +00:00
|
|
|
import Propellor.Exception
|
2014-06-09 05:45:58 +00:00
|
|
|
import Propellor.Info
|
2014-11-19 05:28:38 +00:00
|
|
|
import Utility.Exception
|
2014-11-20 19:15:28 +00:00
|
|
|
import Utility.PartialPrelude
|
|
|
|
import Utility.Monad
|
2014-03-31 05:06:44 +00:00
|
|
|
|
2014-12-06 10:34:32 +00:00
|
|
|
-- | Gets the Properties of a Host, and ensures them all,
|
|
|
|
-- with nice display of what's being done.
|
2014-05-31 22:02:56 +00:00
|
|
|
mainProperties :: Host -> IO ()
|
|
|
|
mainProperties host = do
|
2014-12-06 10:34:32 +00:00
|
|
|
ret <- runPropellor host $
|
2015-01-25 02:38:10 +00:00
|
|
|
ensureProperties [ignoreInfo $ infoProperty "overall" (ensureProperties ps) mempty mempty]
|
2014-11-22 03:33:39 +00:00
|
|
|
h <- mkMessageHandle
|
|
|
|
whenConsole h $
|
|
|
|
setTitle "propellor: done"
|
2014-03-31 05:19:40 +00:00
|
|
|
hFlush stdout
|
2014-12-06 10:34:32 +00:00
|
|
|
case ret of
|
2014-03-31 05:06:44 +00:00
|
|
|
FailedChange -> exitWith (ExitFailure 1)
|
|
|
|
_ -> exitWith ExitSuccess
|
2015-01-24 17:59:29 +00:00
|
|
|
where
|
2015-01-24 20:54:49 +00:00
|
|
|
ps = map ignoreInfo $ hostProperties host
|
2014-03-31 05:06:44 +00:00
|
|
|
|
2014-12-06 10:34:32 +00:00
|
|
|
-- | Runs a Propellor action with the specified host.
|
|
|
|
--
|
|
|
|
-- If the Result is not FailedChange, any EndActions
|
|
|
|
-- that were accumulated while running the action
|
|
|
|
-- are then also run.
|
|
|
|
runPropellor :: Host -> Propellor Result -> IO Result
|
|
|
|
runPropellor host a = do
|
2014-12-06 17:21:19 +00:00
|
|
|
(res, _s, endactions) <- runRWST (runWithHost a) host ()
|
|
|
|
endres <- mapM (runEndAction host res) endactions
|
|
|
|
return $ mconcat (res:endres)
|
2014-12-06 10:34:32 +00:00
|
|
|
|
2014-12-06 17:21:19 +00:00
|
|
|
runEndAction :: Host -> Result -> EndAction -> IO Result
|
|
|
|
runEndAction host res (EndAction desc a) = actionMessageOn (hostName host) desc $ do
|
|
|
|
(ret, _s, _) <- runRWST (runWithHost (catchPropellor (a res))) host ()
|
2014-12-06 10:34:32 +00:00
|
|
|
return ret
|
|
|
|
|
2014-12-07 20:37:02 +00:00
|
|
|
-- | For when code running in the Propellor monad needs to ensure a
|
|
|
|
-- Property.
|
2015-01-19 20:14:01 +00:00
|
|
|
--
|
2015-01-24 20:54:49 +00:00
|
|
|
-- This can only be used on a Property that has NoInfo.
|
|
|
|
ensureProperty :: Property NoInfo -> Propellor Result
|
2014-12-22 01:33:03 +00:00
|
|
|
ensureProperty = catchPropellor . propertySatisfy
|
2014-12-07 20:37:02 +00:00
|
|
|
|
2014-12-06 10:34:32 +00:00
|
|
|
-- | Ensures a list of Properties, with a display of each as it runs.
|
2015-01-24 20:54:49 +00:00
|
|
|
ensureProperties :: [Property NoInfo] -> Propellor Result
|
2014-12-22 01:33:03 +00:00
|
|
|
ensureProperties ps = ensure ps NoChange
|
2014-03-31 05:06:44 +00:00
|
|
|
where
|
|
|
|
ensure [] rs = return rs
|
2014-12-07 21:09:55 +00:00
|
|
|
ensure (p:ls) rs = do
|
2014-06-01 00:48:23 +00:00
|
|
|
hn <- asks hostName
|
2014-12-22 01:33:03 +00:00
|
|
|
r <- actionMessageOn hn (propertyDesc p) (ensureProperty p)
|
2014-03-31 14:36:45 +00:00
|
|
|
ensure ls (r <> rs)
|
2014-04-10 21:22:32 +00:00
|
|
|
|
2014-05-31 22:02:56 +00:00
|
|
|
-- | Lifts an action into a different host.
|
|
|
|
--
|
2015-01-19 19:09:03 +00:00
|
|
|
-- > fromHost hosts "otherhost" getPubKey
|
2014-05-31 22:02:56 +00:00
|
|
|
fromHost :: [Host] -> HostName -> Propellor a -> Propellor (Maybe a)
|
|
|
|
fromHost l hn getter = case findHost l hn of
|
2014-07-23 16:27:38 +00:00
|
|
|
Nothing -> return Nothing
|
2014-12-06 10:34:32 +00:00
|
|
|
Just h -> do
|
|
|
|
(ret, _s, runlog) <- liftIO $
|
|
|
|
runRWST (runWithHost getter) h ()
|
|
|
|
tell runlog
|
|
|
|
return (Just ret)
|
2014-11-19 05:28:38 +00:00
|
|
|
|
|
|
|
onlyProcess :: FilePath -> IO a -> IO a
|
|
|
|
onlyProcess lockfile a = bracket lock unlock (const a)
|
|
|
|
where
|
|
|
|
lock = do
|
2014-11-23 02:24:09 +00:00
|
|
|
createDirectoryIfMissing True (takeDirectory lockfile)
|
2014-11-19 05:28:38 +00:00
|
|
|
l <- createFile lockfile stdFileMode
|
|
|
|
setLock l (WriteLock, AbsoluteSeek, 0, 0)
|
|
|
|
`catchIO` const alreadyrunning
|
|
|
|
return l
|
|
|
|
unlock = closeFd
|
|
|
|
alreadyrunning = error "Propellor is already running on this host!"
|
2014-11-20 19:15:28 +00:00
|
|
|
|
|
|
|
-- | Reads and displays each line from the Handle, except for the last line
|
|
|
|
-- which is a Result.
|
|
|
|
processChainOutput :: Handle -> IO Result
|
|
|
|
processChainOutput h = go Nothing
|
|
|
|
where
|
|
|
|
go lastline = do
|
|
|
|
v <- catchMaybeIO (hGetLine h)
|
2014-11-27 21:51:41 +00:00
|
|
|
debug ["read from chained propellor: ", show v]
|
2014-11-20 19:15:28 +00:00
|
|
|
case v of
|
2014-11-22 03:30:01 +00:00
|
|
|
Nothing -> case lastline of
|
2014-11-27 21:55:56 +00:00
|
|
|
Nothing -> do
|
|
|
|
debug ["chained propellor output nothing; assuming it failed"]
|
|
|
|
return FailedChange
|
2014-11-22 03:30:01 +00:00
|
|
|
Just l -> case readish l of
|
|
|
|
Just r -> pure r
|
|
|
|
Nothing -> do
|
2014-11-27 21:55:56 +00:00
|
|
|
debug ["chained propellor output did not end with a Result; assuming it failed"]
|
2014-11-22 03:30:01 +00:00
|
|
|
putStrLn l
|
|
|
|
hFlush stdout
|
|
|
|
return FailedChange
|
2014-11-20 19:15:28 +00:00
|
|
|
Just s -> do
|
2014-11-20 20:07:57 +00:00
|
|
|
maybe noop (\l -> unless (null l) (putStrLn l)) lastline
|
2014-11-20 19:15:28 +00:00
|
|
|
hFlush stdout
|
|
|
|
go (Just s)
|