From 17d46c67fa020b79ce6d31557136a66f66d673af Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 4 Apr 2014 18:21:54 -0400 Subject: [PATCH] docker: When running as effective init inside container, wait on zombies. --- Propellor/Property/Docker.hs | 12 ++++++++++-- Propellor/SimpleSh.hs | 9 +++++---- debian/changelog | 1 + 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/Propellor/Property/Docker.hs b/Propellor/Property/Docker.hs index 6be8c4e..0d07f82 100644 --- a/Propellor/Property/Docker.hs +++ b/Propellor/Property/Docker.hs @@ -17,6 +17,7 @@ import Utility.Path import Control.Concurrent.Async import System.Posix.Directory +import System.Posix.Process import Data.List -- | Configures docker with an authentication file, so that images can be @@ -272,6 +273,9 @@ runningContainer cid@(ContainerId hn cn) image containerprops = containerDesc ci -- | Called when propellor is running inside a docker container. -- The string should be the container's ContainerId. -- +-- This process is effectively init inside the container. +-- 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, -- so that the user can interact with it when attached to the container. @@ -291,19 +295,23 @@ chain s = case toContainerId s of Just cid -> do changeWorkingDirectory localdir writeFile propellorIdent . show =<< readIdentFile cid + gogo reapzombies -- Run boot provisioning before starting simpleSh, -- to avoid ever provisioning twice at the same time. whenM (checkProvisionedFlag cid) $ do let shim = Shim.file (localdir "propellor") (localdir shimdir cid) unlessM (boolSystem shim [Param "--continue", Param $ show $ Chain $ fromContainerId cid]) $ warningMessage "Boot provision failed!" - void $ async $ simpleSh $ namedPipe cid + gogo $ simpleSh $ namedPipe cid forever $ do void $ ifM (inPath "bash") ( boolSystem "bash" [Param "-l"] , boolSystem "/bin/sh" [] ) putStrLn "Container is still running. Press ^P^Q to detach." + where + gogo = void . async . forever . void . tryIO + reapzombies = void $ getAnyProcessStatus True False -- | Once a container is running, propellor can be run inside -- it to provision it. @@ -335,7 +343,7 @@ provisionContainer cid = containerDesc cid $ Property "provision" $ do hPutStrLn stderr s hFlush stderr go Nothing rest - Done _ -> ret lastline + Done -> ret lastline go lastline [] = ret lastline ret lastline = return $ fromMaybe FailedChange $ diff --git a/Propellor/SimpleSh.hs b/Propellor/SimpleSh.hs index 0999be9..99a6fc2 100644 --- a/Propellor/SimpleSh.hs +++ b/Propellor/SimpleSh.hs @@ -9,7 +9,6 @@ import Network.Socket import Control.Concurrent.Chan import Control.Concurrent.Async import System.Process (std_in, std_out, std_err) -import System.Exit import Propellor import Utility.FileMode @@ -18,7 +17,7 @@ import Utility.ThreadScheduler data Cmd = Cmd String [String] deriving (Read, Show) -data Resp = StdoutLine String | StderrLine String | Done ExitCode +data Resp = StdoutLine String | StderrLine String | Done deriving (Read, Show) simpleSh :: FilePath -> IO () @@ -49,7 +48,7 @@ simpleSh namedpipe = do v <- readChan chan hPutStrLn h (show v) case v of - Done _ -> noop + Done -> noop _ -> runwriter writer <- async runwriter @@ -58,8 +57,10 @@ simpleSh namedpipe = do void $ concurrently (mkreader StdoutLine outh) (mkreader StderrLine errh) + + void $ tryIO $ waitForProcess pid - writeChan chan . Done =<< waitForProcess pid + writeChan chan Done wait writer diff --git a/debian/changelog b/debian/changelog index a02c27d..e2f955b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -3,6 +3,7 @@ propellor (0.2.3) UNRELEASED; urgency=medium * docker: Fix laziness bug that caused running containers to be unnecessarily stopped and committed. * Add locking so only one propellor can run at a time on a host. + * docker: When running as effective init inside container, wait on zombies. -- Joey Hess Fri, 04 Apr 2014 15:58:03 -0400