propellor spin

This commit is contained in:
Joey Hess 2014-11-19 01:02:13 -04:00
parent 9a779939c4
commit 05086b3abe
Failed to extract signature
2 changed files with 29 additions and 29 deletions

View File

@ -37,13 +37,13 @@ module Propellor.Property.Docker (
) where ) where
import Propellor import Propellor
import Propellor.SimpleSh
import Propellor.Types.Info import Propellor.Types.Info
import qualified Propellor.Property.File as File import qualified Propellor.Property.File as File
import qualified Propellor.Property.Apt as Apt import qualified Propellor.Property.Apt as Apt
import qualified Propellor.Property.Docker.Shim as Shim import qualified Propellor.Property.Docker.Shim as Shim
import Utility.SafeCommand import Utility.SafeCommand
import Utility.Path import Utility.Path
import Utility.ThreadScheduler
import Control.Concurrent.Async hiding (link) import Control.Concurrent.Async hiding (link)
import System.Posix.Directory import System.Posix.Directory
@ -339,7 +339,7 @@ runningContainer :: ContainerId -> Image -> [RunParam] -> Property
runningContainer cid@(ContainerId hn cn) image runps = containerDesc cid $ property "running" $ do runningContainer cid@(ContainerId hn cn) image runps = containerDesc cid $ property "running" $ do
l <- liftIO $ listContainers RunningContainers l <- liftIO $ listContainers RunningContainers
if cid `elem` l if cid `elem` l
then checkident =<< liftIO (getrunningident simpleShClient) then checkident =<< liftIO getrunningident
else ifM (liftIO $ elem cid <$> listContainers AllContainers) else ifM (liftIO $ elem cid <$> listContainers AllContainers)
( do ( do
-- The container exists, but is not -- The container exists, but is not
@ -348,9 +348,9 @@ runningContainer cid@(ContainerId hn cn) image runps = containerDesc cid $ prope
-- starting it up first. -- starting it up first.
void $ liftIO $ startContainer cid void $ liftIO $ startContainer cid
-- It can take a while for the container to -- It can take a while for the container to
-- start up enough to get its ident, so -- start up enough for its ident file to be
-- retry for up to 60 seconds. -- written, so retry for up to 60 seconds.
checkident =<< liftIO (getrunningident (simpleShClientRetry 60)) checkident =<< liftIO (retry 60 $ getrunningident)
, go image , go image
) )
where where
@ -370,12 +370,18 @@ runningContainer cid@(ContainerId hn cn) image runps = containerDesc cid $ prope
void $ liftIO $ removeContainer cid void $ liftIO $ removeContainer cid
go oldimage go oldimage
getrunningident shclient = shclient (namedPipe cid) "cat" [propellorIdent] $ \rs -> do getrunningident = readish
let !v = extractident rs <$> readProcess' (inContainerProcess cid [] ["cat", propellorIdent])
return v
extractident :: [Resp] -> Maybe ContainerIdent retry :: Int -> IO (Maybe a) -> IO (Maybe a)
extractident = headMaybe . catMaybes . map readish . catMaybes . map getStdout retry 0 _ = return Nothing
retry n a = do
v <- a
case v of
Just _ -> return v
Nothing -> do
threadDelaySeconds (Seconds 1)
retry (n-1) a
go img = do go img = do
liftIO $ do liftIO $ do
@ -393,7 +399,6 @@ runningContainer cid@(ContainerId hn cn) image runps = containerDesc cid $ prope
-- This process is effectively init inside the container. -- This process is effectively init inside the container.
-- It even needs to wait on zombie processes! -- It even needs to wait on zombie processes!
-- --
-- Fork a thread to run the SimpleSh server in the background.
-- In the foreground, run an interactive bash (or sh) shell, -- In the foreground, run an interactive bash (or sh) shell,
-- so that the user can interact with it when attached to the container. -- so that the user can interact with it when attached to the container.
-- --
@ -412,14 +417,11 @@ chain s = case toContainerId s of
Just cid -> do Just cid -> do
changeWorkingDirectory localdir changeWorkingDirectory localdir
writeFile propellorIdent . show =<< readIdentFile cid writeFile propellorIdent . show =<< readIdentFile cid
-- Run boot provisioning before starting simpleSh,
-- to avoid ever provisioning twice at the same time.
whenM (checkProvisionedFlag cid) $ do whenM (checkProvisionedFlag cid) $ do
let shim = Shim.file (localdir </> "propellor") (localdir </> shimdir cid) let shim = Shim.file (localdir </> "propellor") (localdir </> shimdir cid)
unlessM (boolSystem shim [Param "--continue", Param $ show $ Chain (containerHostName cid)]) $ unlessM (boolSystem shim [Param "--continue", Param $ show $ Chain (containerHostName cid)]) $
warningMessage "Boot provision failed!" warningMessage "Boot provision failed!"
void $ async $ job reapzombies void $ async $ job reapzombies
void $ async $ job $ simpleSh $ namedPipe cid
job $ do job $ do
void $ tryIO $ ifM (inPath "bash") void $ tryIO $ ifM (inPath "bash")
( boolSystem "bash" [Param "-l"] ( boolSystem "bash" [Param "-l"]
@ -437,10 +439,11 @@ provisionContainer cid = containerDesc cid $ property "provisioned" $ liftIO $ d
let shim = Shim.file (localdir </> "propellor") (localdir </> shimdir cid) let shim = Shim.file (localdir </> "propellor") (localdir </> shimdir cid)
let params = ["--continue", show $ Chain (containerHostName cid)] let params = ["--continue", show $ Chain (containerHostName cid)]
msgh <- mkMessageHandle msgh <- mkMessageHandle
r <- inContainer cid let p = inContainerProcess cid
[ if isConsole msgh then "-it" else "-i" ] [ if isConsole msgh then "-it" else "-i" ]
(shim : params) (shim : params)
(processoutput Nothing) r <- withHandle StdoutHandle createProcessSuccess p $
processoutput Nothing
when (r /= FailedChange) $ when (r /= FailedChange) $
setProvisionedFlag cid setProvisionedFlag cid
return r return r
@ -471,7 +474,6 @@ stoppedContainer cid = containerDesc cid $ property desc $
where where
desc = "stopped" desc = "stopped"
cleanup = do cleanup = do
nukeFile $ namedPipe cid
nukeFile $ identFile cid nukeFile $ identFile cid
removeDirectoryRecursive $ shimdir cid removeDirectoryRecursive $ shimdir cid
clearProvisionedFlag cid clearProvisionedFlag cid
@ -488,9 +490,8 @@ runContainer :: Image -> [RunParam] -> [String] -> IO Bool
runContainer image ps cmd = boolSystem dockercmd $ map Param $ runContainer image ps cmd = boolSystem dockercmd $ map Param $
"run" : (ps ++ image : cmd) "run" : (ps ++ image : cmd)
inContainer :: ContainerId -> [String] -> [String] -> (Handle -> IO a) -> IO a inContainerProcess :: ContainerId -> [String] -> [String] -> CreateProcess
inContainer cid ps cmd = withHandle StdoutHandle createProcessSuccess inContainerProcess cid ps cmd = proc dockercmd ("exec" : ps ++ [fromContainerId cid] ++ cmd)
(proc dockercmd ("exec" : ps ++ [fromContainerId cid] ++ cmd))
commitContainer :: ContainerId -> IO (Maybe Image) commitContainer :: ContainerId -> IO (Maybe Image)
commitContainer cid = catchMaybeIO $ commitContainer cid = catchMaybeIO $
@ -534,10 +535,6 @@ dockerInfo i = mempty { _dockerinfo = i }
propellorIdent :: FilePath propellorIdent :: FilePath
propellorIdent = "/.propellor-ident" propellorIdent = "/.propellor-ident"
-- | Named pipe used for communication with the container.
namedPipe :: ContainerId -> FilePath
namedPipe cid = "docker" </> fromContainerId cid
provisionedFlag :: ContainerId -> FilePath provisionedFlag :: ContainerId -> FilePath
provisionedFlag cid = "docker" </> fromContainerId cid ++ ".provisioned" provisionedFlag cid = "docker" </> fromContainerId cid ++ ".provisioned"

View File

@ -13,6 +13,7 @@ module Utility.Process (
CreateProcess(..), CreateProcess(..),
StdHandle(..), StdHandle(..),
readProcess, readProcess,
readProcess',
readProcessEnv, readProcessEnv,
writeReadProcessEnv, writeReadProcessEnv,
forceSuccessProcess, forceSuccessProcess,
@ -66,17 +67,19 @@ readProcess :: FilePath -> [String] -> IO String
readProcess cmd args = readProcessEnv cmd args Nothing readProcess cmd args = readProcessEnv cmd args Nothing
readProcessEnv :: FilePath -> [String] -> Maybe [(String, String)] -> IO String readProcessEnv :: FilePath -> [String] -> Maybe [(String, String)] -> IO String
readProcessEnv cmd args environ = readProcessEnv cmd args environ = readProcess' p
withHandle StdoutHandle createProcessSuccess p $ \h -> do
output <- hGetContentsStrict h
hClose h
return output
where where
p = (proc cmd args) p = (proc cmd args)
{ std_out = CreatePipe { std_out = CreatePipe
, env = environ , env = environ
} }
readProcess' :: CreateProcess -> IO String
readProcess' p = withHandle StdoutHandle createProcessSuccess p $ \h -> do
output <- hGetContentsStrict h
hClose h
return output
{- Runs an action to write to a process on its stdin, {- Runs an action to write to a process on its stdin,
- returns its output, and also allows specifying the environment. - returns its output, and also allows specifying the environment.
-} -}