diff --git a/debian/changelog b/debian/changelog index a44d72a..4d264f4 100644 --- a/debian/changelog +++ b/debian/changelog @@ -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 Sat, 22 Nov 2014 00:12:35 -0400 diff --git a/doc/usage.mdwn b/doc/usage.mdwn index 4279704..7baba50 100644 --- a/doc/usage.mdwn +++ b/doc/usage.mdwn @@ -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 diff --git a/src/Propellor/CmdLine.hs b/src/Propellor/CmdLine.hs index ec2ca7e..c681a08 100644 --- a/src/Propellor/CmdLine.hs +++ b/src/Propellor/CmdLine.hs @@ -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 + diff --git a/src/Propellor/PrivData/Paths.hs b/src/Propellor/PrivData/Paths.hs index 1922a31..9f791b7 100644 --- a/src/Propellor/PrivData/Paths.hs +++ b/src/Propellor/PrivData/Paths.hs @@ -10,3 +10,6 @@ privDataFile = privDataDir "privdata.gpg" privDataLocal :: FilePath privDataLocal = privDataDir "local" + +privDataRelay :: String -> FilePath +privDataRelay host = privDataDir "relay" host diff --git a/src/Propellor/Server.hs b/src/Propellor/Server.hs index 19a2c90..e2d6552 100644 --- a/src/Propellor/Server.hs +++ b/src/Propellor/Server.hs @@ -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 () diff --git a/src/Propellor/Types.hs b/src/Propellor/Types.hs index e7d6354..e4cbf98 100644 --- a/src/Propellor/Types.hs +++ b/src/Propellor/Types.hs @@ -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