2014-11-20 18:06:55 +00:00
|
|
|
module Propellor.Property.Chroot (
|
2014-11-20 21:18:26 +00:00
|
|
|
Chroot(..),
|
2014-11-21 19:55:27 +00:00
|
|
|
debootstrapped,
|
2014-11-20 18:06:55 +00:00
|
|
|
provisioned,
|
2014-11-21 16:17:03 +00:00
|
|
|
-- * Internal use
|
2014-11-21 18:11:02 +00:00
|
|
|
provisioned',
|
|
|
|
propigateChrootInfo,
|
2014-11-21 16:17:03 +00:00
|
|
|
propellChroot,
|
2014-11-20 19:15:28 +00:00
|
|
|
chain,
|
2014-11-20 18:06:55 +00:00
|
|
|
) where
|
|
|
|
|
|
|
|
import Propellor
|
2014-11-21 22:55:33 +00:00
|
|
|
import Propellor.Types.Chroot
|
2014-11-23 02:37:25 +00:00
|
|
|
import Propellor.Property.Chroot.Util
|
2014-11-20 18:06:55 +00:00
|
|
|
import qualified Propellor.Property.Debootstrap as Debootstrap
|
2014-11-21 21:11:26 +00:00
|
|
|
import qualified Propellor.Property.Systemd.Core as Systemd
|
2014-11-20 19:15:28 +00:00
|
|
|
import qualified Propellor.Shim as Shim
|
|
|
|
import Utility.SafeCommand
|
2014-11-20 18:06:55 +00:00
|
|
|
|
|
|
|
import qualified Data.Map as M
|
2014-11-20 19:15:28 +00:00
|
|
|
import Data.List.Utils
|
|
|
|
import System.Posix.Directory
|
2014-11-20 18:06:55 +00:00
|
|
|
|
2014-11-21 19:55:27 +00:00
|
|
|
data Chroot = Chroot FilePath System BuilderConf Host
|
|
|
|
deriving (Show)
|
|
|
|
|
|
|
|
data BuilderConf
|
|
|
|
= UsingDeboostrap Debootstrap.DebootstrapConfig
|
2014-11-21 18:31:13 +00:00
|
|
|
deriving (Show)
|
2014-11-20 18:06:55 +00:00
|
|
|
|
|
|
|
instance Hostlike Chroot where
|
2014-11-21 19:55:27 +00:00
|
|
|
(Chroot l s c h) & p = Chroot l s c (h & p)
|
|
|
|
(Chroot l s c h) &^ p = Chroot l s c (h &^ p)
|
|
|
|
getHost (Chroot _ _ _ h) = h
|
2014-11-20 18:06:55 +00:00
|
|
|
|
2014-11-21 19:55:27 +00:00
|
|
|
-- | Defines a Chroot at the given location, built with debootstrap.
|
2014-11-20 18:06:55 +00:00
|
|
|
--
|
2014-11-21 19:55:27 +00:00
|
|
|
-- Properties can be added to configure the Chroot.
|
|
|
|
--
|
|
|
|
-- > debootstrapped (System (Debian Unstable) "amd64") Debootstrap.BuildD "/srv/chroot/ghc-dev"
|
|
|
|
-- > & Apt.installed ["ghc", "haskell-platform"]
|
2014-11-20 18:06:55 +00:00
|
|
|
-- > & ...
|
2014-11-21 19:55:27 +00:00
|
|
|
debootstrapped :: System -> Debootstrap.DebootstrapConfig -> FilePath -> Chroot
|
|
|
|
debootstrapped system conf location = case system of
|
|
|
|
(System (Debian _) _) -> mk
|
|
|
|
(System (Ubuntu _) _) -> mk
|
|
|
|
where
|
|
|
|
h = Host location [] mempty
|
|
|
|
mk = Chroot location system (UsingDeboostrap conf) h
|
|
|
|
& os system
|
2014-11-20 18:06:55 +00:00
|
|
|
|
|
|
|
-- | Ensures that the chroot exists and is provisioned according to its
|
|
|
|
-- properties.
|
|
|
|
--
|
|
|
|
-- Reverting this property removes the chroot. Note that it does not ensure
|
|
|
|
-- that any processes that might be running inside the chroot are stopped.
|
|
|
|
provisioned :: Chroot -> RevertableProperty
|
2014-11-21 21:11:26 +00:00
|
|
|
provisioned c = provisioned' (propigateChrootInfo c) c False
|
2014-11-21 18:11:02 +00:00
|
|
|
|
2014-11-21 21:11:26 +00:00
|
|
|
provisioned' :: (Property -> Property) -> Chroot -> Bool -> RevertableProperty
|
|
|
|
provisioned' propigator c@(Chroot loc system builderconf _) systemdonly = RevertableProperty
|
2014-11-21 18:11:02 +00:00
|
|
|
(propigator $ go "exists" setup)
|
2014-11-20 18:06:55 +00:00
|
|
|
(go "removed" teardown)
|
|
|
|
where
|
2014-11-20 19:15:28 +00:00
|
|
|
go desc a = property (chrootDesc c desc) $ ensureProperties [a]
|
2014-11-20 18:06:55 +00:00
|
|
|
|
2014-11-21 21:11:26 +00:00
|
|
|
setup = propellChroot c (inChrootProcess c) systemdonly
|
|
|
|
`requires` toProp built
|
2014-11-20 18:06:55 +00:00
|
|
|
|
2014-11-21 19:55:27 +00:00
|
|
|
built = case (system, builderconf) of
|
|
|
|
((System (Debian _) _), UsingDeboostrap cf) -> debootstrap cf
|
|
|
|
((System (Ubuntu _) _), UsingDeboostrap cf) -> debootstrap cf
|
2014-11-20 18:06:55 +00:00
|
|
|
|
2014-11-21 19:55:27 +00:00
|
|
|
debootstrap = Debootstrap.built loc system
|
2014-11-20 18:06:55 +00:00
|
|
|
|
2014-11-21 05:09:15 +00:00
|
|
|
teardown = toProp (revert built)
|
2014-11-20 18:06:55 +00:00
|
|
|
|
|
|
|
propigateChrootInfo :: Chroot -> Property -> Property
|
2014-11-20 20:04:48 +00:00
|
|
|
propigateChrootInfo c p = propigateInfo c p (<> chrootInfo c)
|
|
|
|
|
|
|
|
chrootInfo :: Chroot -> Info
|
2014-11-21 19:55:27 +00:00
|
|
|
chrootInfo (Chroot loc _ _ h) =
|
2014-11-20 20:04:48 +00:00
|
|
|
mempty { _chrootinfo = mempty { _chroots = M.singleton loc h } }
|
2014-11-20 18:06:55 +00:00
|
|
|
|
2014-11-20 19:15:28 +00:00
|
|
|
-- | Propellor is run inside the chroot to provision it.
|
2014-11-21 21:11:26 +00:00
|
|
|
propellChroot :: Chroot -> ([String] -> CreateProcess) -> Bool -> Property
|
|
|
|
propellChroot c@(Chroot loc _ _ _) mkproc systemdonly = property (chrootDesc c "provisioned") $ do
|
2014-11-20 19:15:28 +00:00
|
|
|
let d = localdir </> shimdir c
|
|
|
|
let me = localdir </> "propellor"
|
|
|
|
shim <- liftIO $ ifM (doesDirectoryExist d)
|
|
|
|
( pure (Shim.file me d)
|
2014-11-23 02:10:53 +00:00
|
|
|
, Shim.setup me Nothing d
|
2014-11-20 19:15:28 +00:00
|
|
|
)
|
|
|
|
ifM (liftIO $ bindmount shim)
|
|
|
|
( chainprovision shim
|
|
|
|
, return FailedChange
|
|
|
|
)
|
|
|
|
where
|
|
|
|
bindmount shim = ifM (doesFileExist (loc ++ shim))
|
|
|
|
( return True
|
|
|
|
, do
|
|
|
|
let mntpnt = loc ++ localdir
|
|
|
|
createDirectoryIfMissing True mntpnt
|
|
|
|
boolSystem "mount"
|
|
|
|
[ Param "--bind"
|
|
|
|
, File localdir, File mntpnt
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|
|
|
|
chainprovision shim = do
|
|
|
|
parenthost <- asks hostName
|
2014-11-21 21:11:26 +00:00
|
|
|
cmd <- liftIO $ toChain parenthost c systemdonly
|
2014-11-23 02:37:25 +00:00
|
|
|
pe <- liftIO standardPathEnv
|
2014-11-21 16:17:03 +00:00
|
|
|
let p = mkproc
|
2014-11-20 19:15:28 +00:00
|
|
|
[ shim
|
|
|
|
, "--continue"
|
2014-11-21 05:05:51 +00:00
|
|
|
, show cmd
|
2014-11-20 19:15:28 +00:00
|
|
|
]
|
2014-11-23 02:37:25 +00:00
|
|
|
let p' = p { env = Just pe }
|
|
|
|
liftIO $ withHandle StdoutHandle createProcessSuccess p'
|
2014-11-20 19:15:28 +00:00
|
|
|
processChainOutput
|
|
|
|
|
2014-11-21 21:11:26 +00:00
|
|
|
toChain :: HostName -> Chroot -> Bool -> IO CmdLine
|
|
|
|
toChain parenthost (Chroot loc _ _ _) systemdonly = do
|
2014-11-21 05:05:51 +00:00
|
|
|
onconsole <- isConsole <$> mkMessageHandle
|
2014-11-21 21:11:26 +00:00
|
|
|
return $ ChrootChain parenthost loc systemdonly onconsole
|
|
|
|
|
|
|
|
chain :: [Host] -> CmdLine -> IO ()
|
|
|
|
chain hostlist (ChrootChain hn loc systemdonly onconsole) =
|
|
|
|
case findHostNoAlias hostlist hn of
|
|
|
|
Nothing -> errorMessage ("cannot find host " ++ hn)
|
|
|
|
Just parenthost -> case M.lookup loc (_chroots $ _chrootinfo $ hostInfo parenthost) of
|
|
|
|
Nothing -> errorMessage ("cannot find chroot " ++ loc ++ " on host " ++ hn)
|
|
|
|
Just h -> go h
|
2014-11-20 19:15:28 +00:00
|
|
|
where
|
|
|
|
go h = do
|
|
|
|
changeWorkingDirectory localdir
|
2014-11-21 05:05:51 +00:00
|
|
|
when onconsole forceConsole
|
2014-11-20 19:15:28 +00:00
|
|
|
onlyProcess (provisioningLock loc) $ do
|
2014-11-21 21:11:26 +00:00
|
|
|
r <- runPropellor h $ ensureProperties $
|
|
|
|
if systemdonly
|
|
|
|
then [Systemd.installed]
|
|
|
|
else hostProperties h
|
2014-11-20 19:15:28 +00:00
|
|
|
putStrLn $ "\n" ++ show r
|
2014-11-21 21:11:26 +00:00
|
|
|
chain _ _ = errorMessage "bad chain command"
|
2014-11-20 19:15:28 +00:00
|
|
|
|
|
|
|
inChrootProcess :: Chroot -> [String] -> CreateProcess
|
2014-11-21 19:55:27 +00:00
|
|
|
inChrootProcess (Chroot loc _ _ _) cmd = proc "chroot" (loc:cmd)
|
2014-11-20 19:15:28 +00:00
|
|
|
|
|
|
|
provisioningLock :: FilePath -> FilePath
|
|
|
|
provisioningLock containerloc = "chroot" </> mungeloc containerloc ++ ".lock"
|
|
|
|
|
|
|
|
shimdir :: Chroot -> FilePath
|
2014-11-21 19:55:27 +00:00
|
|
|
shimdir (Chroot loc _ _ _) = "chroot" </> mungeloc loc ++ ".shim"
|
2014-11-20 19:15:28 +00:00
|
|
|
|
|
|
|
mungeloc :: FilePath -> String
|
|
|
|
mungeloc = replace "/" "_"
|
|
|
|
|
|
|
|
chrootDesc :: Chroot -> String -> String
|
2014-11-21 19:55:27 +00:00
|
|
|
chrootDesc (Chroot loc _ _ _) desc = "chroot " ++ loc ++ " " ++ desc
|