improved remote and local provisioning

This commit is contained in:
Joey Hess 2014-04-03 13:49:26 -04:00
parent b9f32f4c1d
commit c764993cb3
3 changed files with 36 additions and 18 deletions

View File

@ -7,6 +7,7 @@ import System.Log.Logger
import System.Log.Formatter import System.Log.Formatter
import System.Log.Handler (setFormatter, LogHandler) import System.Log.Handler (setFormatter, LogHandler)
import System.Log.Handler.Simple import System.Log.Handler.Simple
import System.PosixCompat
import Propellor import Propellor
import qualified Propellor.Property.Docker as Docker import qualified Propellor.Property.Docker as Docker
@ -67,12 +68,24 @@ defaultMain getprops = do
go True cmdline@(Spin _) = buildFirst cmdline $ go False cmdline go True cmdline@(Spin _) = buildFirst cmdline $ go False cmdline
go True cmdline = updateFirst cmdline $ go False cmdline go True cmdline = updateFirst cmdline $ go False cmdline
go False (Spin host) = withprops host $ const $ spin host go False (Spin host) = withprops host $ const $ spin host
go False (Run host) = withprops host $ ensureProperties go False cmdline@(Run host) = withprops host $
asRoot cmdline . ensureProperties
go False (Boot host) = withprops host $ boot go False (Boot host) = withprops host $ boot
withprops host a = maybe (unknownhost host) a $ withprops host a = maybe (unknownhost host) a $
headMaybe $ catMaybes $ map (\get -> get host) getprops headMaybe $ catMaybes $ map (\get -> get host) getprops
asRoot :: CmdLine -> IO a -> IO a
asRoot cmdline a = ifM ((==) 0 <$> getRealUserID)
( a
, do
hPutStrLn stderr "Need to be root to provision the local host! Running sudo propellor..."
hFlush stderr
(_, _, _, pid) <- createProcess $
proc "sudo" ["./propellor", show (Continue cmdline)]
exitWith =<< waitForProcess pid
)
unknownhost :: HostName -> IO a unknownhost :: HostName -> IO a
unknownhost h = errorMessage $ unlines unknownhost h = errorMessage $ unlines
[ "Unknown host: " ++ h [ "Unknown host: " ++ h
@ -106,7 +119,7 @@ updateFirst cmdline next = do
void $ actionMessage "Git fetch" $ boolSystem "git" [Param "fetch"] void $ actionMessage "Git fetch" $ boolSystem "git" [Param "fetch"]
whenM (doesFileExist keyring) $ do whenM (doesFileExist keyring) $ do
{- To verify origin/master commit's signature, have to {- To verify origin branch commit's signature, have to
- convince gpg to use our keyring. While running git log. - convince gpg to use our keyring. While running git log.
- Which has no way to pass options to gpg. - Which has no way to pass options to gpg.
- Argh! -} - Argh! -}
@ -147,10 +160,9 @@ spin host = do
url <- getUrl url <- getUrl
void $ gitCommit [Param "--allow-empty", Param "-a", Param "-m", Param "propellor spin"] void $ gitCommit [Param "--allow-empty", Param "-a", Param "-m", Param "propellor spin"]
void $ boolSystem "git" [Param "push"] void $ boolSystem "git" [Param "push"]
branch <- getCurrentBranch go url =<< gpgDecrypt (privDataFile host)
go url branch =<< gpgDecrypt (privDataFile host)
where where
go url branch privdata = withBothHandles createProcessSuccess (proc "ssh" [user, bootstrapcmd branch]) $ \(toh, fromh) -> do go url privdata = withBothHandles createProcessSuccess (proc "ssh" [user, bootstrapcmd]) $ \(toh, fromh) -> do
let finish = do let finish = do
senddata toh (privDataFile host) privDataMarker privdata senddata toh (privDataFile host) privDataMarker privdata
hClose toh hClose toh
@ -166,11 +178,11 @@ spin host = do
hClose toh hClose toh
hClose fromh hClose fromh
sendGitClone host url sendGitClone host url
go url branch privdata go url privdata
user = "root@"++host user = "root@"++host
bootstrapcmd branch = shellWrap $ intercalate " ; " bootstrapcmd = shellWrap $ intercalate " ; "
[ "if [ ! -d " ++ localdir ++ " ]" [ "if [ ! -d " ++ localdir ++ " ]"
, "then " ++ intercalate " && " , "then " ++ intercalate " && "
[ "apt-get -y install git" [ "apt-get -y install git"
@ -178,8 +190,6 @@ spin host = do
] ]
, "else " ++ intercalate " && " , "else " ++ intercalate " && "
[ "cd " ++ localdir [ "cd " ++ localdir
, "git checkout -b " ++ branch
, "git branch --set-upstream-to=origin/" ++ branch ++ " " ++ branch
, "if ! test -x ./propellor; then make build; fi" , "if ! test -x ./propellor; then make build; fi"
, "./propellor --boot " ++ host , "./propellor --boot " ++ host
] ]
@ -202,23 +212,28 @@ spin host = do
return True return True
sendGitClone :: HostName -> String -> IO () sendGitClone :: HostName -> String -> IO ()
sendGitClone host url = void $ actionMessage ("Pushing git repository to " ++ host) $ sendGitClone host url = void $ actionMessage ("Pushing git repository to " ++ host) $ do
branch <- getCurrentBranch
withTmpFile "propellor.git" $ \tmp _ -> allM id withTmpFile "propellor.git" $ \tmp _ -> allM id
-- TODO: ssh connection caching, or better push method -- TODO: ssh connection caching, or better push method
-- with less connections. -- with less connections.
[ boolSystem "git" [Param "bundle", Param "create", File tmp, Param "HEAD"] [ boolSystem "git" [Param "bundle", Param "create", File tmp, Param "HEAD"]
, boolSystem "scp" [File tmp, Param ("root@"++host++":"++remotebundle)] , boolSystem "scp" [File tmp, Param ("root@"++host++":"++remotebundle)]
, boolSystem "ssh" [Param ("root@"++host), Param unpackcmd] , boolSystem "ssh" [Param ("root@"++host), Param $ unpackcmd branch]
] ]
where where
remotebundle = "/usr/local/propellor.git" remotebundle = "/usr/local/propellor.git"
unpackcmd = shellWrap $ intercalate " && " unpackcmd branch = shellWrap $ intercalate " && "
[ "git clone " ++ remotebundle ++ " " ++ localdir [ "git clone " ++ remotebundle ++ " " ++ localdir
, "cd " ++ localdir , "cd " ++ localdir
, "git checkout -b master" , "git checkout -b " ++ branch
, "git remote rm origin" , "git remote rm origin"
, "git remote add origin " ++ url
, "rm -f " ++ remotebundle , "rm -f " ++ remotebundle
, "git remote add origin " ++ url
-- same as --set-upstream-to, except origin branch
-- has not been pulled yet
, "git config branch."++branch++".remote origin"
, "git config branch."++branch++".merge refs/heads/"++branch
] ]
data BootStrapStatus = Ready | NeedGitClone data BootStrapStatus = Ready | NeedGitClone

View File

@ -35,7 +35,7 @@ warningMessage s = do
errorMessage :: String -> IO a errorMessage :: String -> IO a
errorMessage s = do errorMessage s = do
warningMessage s warningMessage s
error "Propellor failed!" error "Cannot continue!"
-- | Causes a debug message to be displayed when PROPELLOR_DEBUG=1 -- | Causes a debug message to be displayed when PROPELLOR_DEBUG=1
debug :: [String] -> IO () debug :: [String] -> IO ()

View File

@ -27,9 +27,8 @@ main = defaultMain [host, Docker.containerProperties container]
-- --
-- Edit this to configure propellor! -- Edit this to configure propellor!
host :: HostName -> Maybe [Property] host :: HostName -> Maybe [Property]
-- Clam is a tor bridge, and an olduse.net shellbox and other fun stuff.
host hostname@"clam.kitenet.net" = standardSystem Unstable $ props host hostname@"clam.kitenet.net" = standardSystem Unstable $ props
-- Clam is a tor bridge, and an olduse.net shellbox and other
-- fun stuff.
& cleanCloudAtCost hostname & cleanCloudAtCost hostname
& Apt.unattendedUpgrades & Apt.unattendedUpgrades
& Network.ipv6to4 & Network.ipv6to4
@ -41,8 +40,8 @@ host hostname@"clam.kitenet.net" = standardSystem Unstable $ props
! Docker.docked container hostname "webserver" ! Docker.docked container hostname "webserver"
! Docker.docked container hostname "amd64-git-annex-builder" ! Docker.docked container hostname "amd64-git-annex-builder"
& Docker.garbageCollected & Docker.garbageCollected
host hostname@"orca.kitenet.net" = standardSystem Unstable $ props
-- Orca is the main git-annex build box. -- Orca is the main git-annex build box.
host hostname@"orca.kitenet.net" = standardSystem Unstable $ props
& Hostname.set hostname & Hostname.set hostname
& Apt.unattendedUpgrades & Apt.unattendedUpgrades
& Docker.configured & Docker.configured
@ -50,6 +49,10 @@ host hostname@"orca.kitenet.net" = standardSystem Unstable $ props
& Docker.docked container hostname "amd64-git-annex-builder" & Docker.docked container hostname "amd64-git-annex-builder"
! Docker.docked container hostname "i386-git-annex-builder" ! Docker.docked container hostname "i386-git-annex-builder"
& Docker.garbageCollected & Docker.garbageCollected
-- My laptop
host _hostname@"darkstar.kitenet.net" = Just $ props
& Docker.configured
-- add more hosts here... -- add more hosts here...
--host "foo.example.com" = --host "foo.example.com" =
host _ = Nothing host _ = Nothing