--via implemented

This commit is contained in:
Joey Hess 2014-11-22 12:57:07 -04:00
parent 61945b4ff3
commit fd3335e40e
6 changed files with 60 additions and 29 deletions

5
debian/changelog vendored
View File

@ -3,8 +3,9 @@ propellor (1.0.1) UNRELEASED; urgency=medium
* propellor --spin can now deploy propellor to hosts that do not have
git, ghc, or apt-get. This is accomplished by uploading a fairly
portable precompiled tarball of propellor.
* --spin host --via host causes propellor to bounce through an intermediate
host, which handles any necessary provisioning of the host being spun.
* --spin target --via relay causes propellor to bounce through an
intermediate relay host, which handles any necessary provisioning
of the target host.
-- Joey Hess <joeyh@debian.org> Sat, 22 Nov 2014 00:12:35 -0400

View File

@ -20,11 +20,18 @@ action as needed to satisfy the configured properties of the local host.
# OPTIONS
* --spin hostname
* --spin targethost [--via relayhost]
Causes propellor to automatically install itself on the specified host,
or if it's already installed there, push any updates. Propellor is then
run on the host, to satisfy its configured properties.
Causes propellor to automatically install itself on the specified target
host, or if it's already installed there, push any updates. Propellor is
then run on the target host, to satisfy its configured properties.
When run with --via, propellor sshes to the relay host and runs
`propellor --spin hostname` from there. This can be useful when
propellor is installing itself, since most of the data transfer
is done between relay host and target host. Note that propellor
uses ssh agent forwarding to make this work, and the relay host
sees any privdata belonging to the target host.
* --add-key keyid

View File

@ -24,7 +24,7 @@ usage h = hPutStrLn h $ unlines
[ "Usage:"
, " propellor"
, " propellor hostname"
, " propellor --spin hostname"
, " propellor --spin targethost [--via relayhost]"
, " propellor --add-key keyid"
, " propellor --set field context"
, " propellor --dump field context"
@ -41,7 +41,8 @@ processCmdLine :: IO CmdLine
processCmdLine = go =<< getArgs
where
go ("--run":h:[]) = return $ Run h
go ("--spin":h:[]) = return $ Spin h
go ("--spin":h:[]) = return $ Spin h Nothing
go ("--spin":h:"--via":r:[]) = return $ Spin h (Just r)
go ("--add-key":k:[]) = return $ AddKey k
go ("--set":f:c:[]) = withprivfield f c Set
go ("--dump":f:c:[]) = withprivfield f c Dump
@ -50,8 +51,8 @@ processCmdLine = go =<< getArgs
go ("--help":_) = do
usage stdout
exitFailure
go ("--update":h:[]) = return $ Update h
go ("--boot":h:[]) = return $ Update h -- for back-compat
go ("--update":_:[]) = return $ Update Nothing
go ("--boot":_:[]) = return $ Update Nothing -- for back-compat
go ("--continue":s:[]) = case readish s of
Just cmdline -> return $ Continue cmdline
Nothing -> errorMessage $ "--continue serialization failure (" ++ s ++ ")"
@ -89,15 +90,16 @@ defaultMain hostlist = do
go _ (DockerChain hn cid) = Docker.chain hostlist hn cid
go _ (DockerInit hn) = Docker.init hn
go _ (GitPush fin fout) = gitPushHelper fin fout
go _ (Update _) = forceConsole >> fetchFirst (onlyprocess update)
go True cmdline@(Spin _) = buildFirst cmdline $ go False cmdline
go _ (Update Nothing) = forceConsole >> fetchFirst (onlyprocess (update Nothing))
go _ (Update (Just h)) = forceConsole >> fetchFirst (update (Just h))
go True cmdline@(Spin _ _) = buildFirst cmdline $ go False cmdline
go True cmdline = updateFirst cmdline $ go False cmdline
go False (Spin hn) = withhost hn $ spin hn
go False (Spin hn r) = withhost hn $ spin hn r
go False cmdline@(SimpleRun hn) = buildFirst cmdline $
go False (Run hn)
go False (Run hn) = ifM ((==) 0 <$> getRealUserID)
( onlyprocess $ withhost hn mainProperties
, go True (Spin hn)
, go True (Spin hn Nothing)
)
withhost :: HostName -> (Host -> IO ()) -> IO ()
@ -148,8 +150,8 @@ updateFirst' cmdline next = ifM fetchOrigin
, next
)
spin :: HostName -> Host -> IO ()
spin hn hst = do
spin :: HostName -> Maybe HostName -> Host -> IO ()
spin target relay hst = do
void $ actionMessage "Git commit" $
gitCommit [Param "--allow-empty", Param "-a", Param "-m", Param "propellor spin"]
-- Push to central origin repo first, if possible.
@ -160,15 +162,18 @@ spin hn hst = do
boolSystem "git" [Param "push"]
cacheparams <- toCommand <$> sshCachingParams hn
when (isJust relay) $
void $ boolSystem "ssh-add" []
-- Install, or update the remote propellor.
updateServer hn hst $ withBothHandles createProcessSuccess
updateServer target relay hst $ withBothHandles createProcessSuccess
(proc "ssh" $ cacheparams ++ [user, updatecmd])
-- And now we can run it.
unlessM (boolSystem "ssh" (map Param $ cacheparams ++ ["-t", user, runcmd])) $
error $ "remote propellor failed"
where
hn = fromMaybe target relay
user = "root@"++hn
mkcmd = shellWrap . intercalate " ; "
@ -183,10 +188,17 @@ spin hn hst = do
, "else " ++ intercalate " && "
[ "cd " ++ localdir
, "if ! test -x ./propellor; then make deps build; fi"
, "./propellor --boot " ++ hn
, if isNothing relay
-- Still using --boot for back-compat...
then "./propellor --boot " ++ target
else "./propellor --continue " ++
shellEscape (show (Update (Just target)))
]
, "fi"
]
runcmd = mkcmd
[ "cd " ++ localdir ++ " && ./propellor --continue " ++ shellEscape (show (SimpleRun hn)) ]
runcmd = mkcmd [ "cd " ++ localdir ++ " && ./propellor " ++ cmd ]
cmd = if isNothing relay
then "--continue " ++ shellEscape (show (SimpleRun target))
else "--spin " ++ shellEscape target

View File

@ -10,3 +10,6 @@ privDataFile = privDataDir </> "privdata.gpg"
privDataLocal :: FilePath
privDataLocal = privDataDir </> "local"
privDataRelay :: String -> FilePath
privDataRelay host = privDataDir </> "relay" </> host

View File

@ -29,13 +29,16 @@ import Utility.SafeCommand
-- Update the privdata, repo url, and git repo over the ssh
-- connection, talking to the user's local propellor instance which is
-- running the updateServer
update :: IO ()
update = do
update :: Maybe HostName -> IO ()
update forhost = do
whenM hasOrigin $
req NeedRepoUrl repoUrlMarker setRepoUrl
makePrivDataDir
createDirectoryIfMissing True (takeDirectory privfile)
req NeedPrivData privDataMarker $
writeFileProtected privDataLocal
writeFileProtected privfile
whenM hasOrigin $
req NeedGitPush gitPushMarker $ \_ -> do
hin <- dup stdInput
@ -52,12 +55,17 @@ update = do
, Param $ "./propellor --gitpush " ++ show hin ++ " " ++ show hout
, Param "."
]
-- When --spin --relay is run, get a privdata file
-- to be relayed to the target host.
privfile = maybe privDataLocal privDataRelay forhost
-- The connect action should ssh to the remote host and run the provided
-- calback action.
updateServer :: HostName -> Host -> (((Handle, Handle) -> IO ()) -> IO ()) -> IO ()
updateServer hn hst connect = connect go
updateServer :: HostName -> Maybe HostName -> Host -> (((Handle, Handle) -> IO ()) -> IO ()) -> IO ()
updateServer target relay hst connect = connect go
where
hn = fromMaybe target relay
go (toh, fromh) = do
let loop = go (toh, fromh)
v <- (maybe Nothing readish <$> getMarked fromh statusMarker)
@ -77,12 +85,12 @@ updateServer hn hst connect = connect go
hClose toh
hClose fromh
sendGitClone hn
updateServer hn hst connect
updateServer hn relay hst connect
(Just NeedPrecompiled) -> do
hClose toh
hClose fromh
sendPrecompiled hn
updateServer hn hst connect
updateServer hn relay hst connect
Nothing -> return ()
sendRepoUrl :: Handle -> IO ()

View File

@ -142,7 +142,7 @@ instance ActionResult Result where
data CmdLine
= Run HostName
| Spin HostName
| Spin HostName (Maybe HostName)
| SimpleRun HostName
| Set PrivDataField Context
| Dump PrivDataField Context
@ -150,7 +150,7 @@ data CmdLine
| ListFields
| AddKey String
| Continue CmdLine
| Update HostName
| Update (Maybe HostName)
| DockerInit HostName
| DockerChain HostName String
| ChrootChain HostName FilePath Bool Bool