summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoey Hess2014-03-31 15:40:16 -0400
committerJoey Hess2014-03-31 15:40:16 -0400
commit9172b796122bf9558873ad4a2356d4f9d817d3e2 (patch)
tree9d280eb9d00673f6fc7269efd59345be0a654222
parent36469bc07dc3021b4737a87175d662a0ddb8c878 (diff)
propellor spin
-rw-r--r--Propellor/CmdLine.hs62
-rw-r--r--README29
2 files changed, 65 insertions, 26 deletions
diff --git a/Propellor/CmdLine.hs b/Propellor/CmdLine.hs
index ef825d92..7b82d281 100644
--- a/Propellor/CmdLine.hs
+++ b/Propellor/CmdLine.hs
@@ -70,38 +70,47 @@ spin host = do
url <- getUrl
void $ gitCommit [Param "--allow-empty", Param "-a", Param "-m", Param "propellor spin"]
void $ boolSystem "git" [Param "push"]
- privdata <- gpgDecrypt (privDataFile host)
- withBothHandles createProcessSuccess (proc "ssh" [user, bootstrapcmd url]) $ \(toh, fromh) -> do
+ go url =<< gpgDecrypt (privDataFile host)
+ where
+ go url privdata = withBothHandles createProcessSuccess (proc "ssh" [user, bootstrapcmd]) $ \(toh, fromh) -> do
+ let finish = do
+ senddata toh (privDataFile host) privDataMarker privdata
+ hClose toh
+
+ -- Display remaining output.
+ void $ tryIO $ forever $
+ showremote =<< hGetLine fromh
+ hClose fromh
status <- getstatus fromh `catchIO` error "protocol error"
case status of
+ HaveKeyRing -> finish
NeedKeyRing -> do
d <- w82s . BL.unpack . B64.encode
<$> BL.readFile keyring
senddata toh keyring keyringMarker d
- HaveKeyRing -> noop
- senddata toh (privDataFile host) privDataMarker privdata
- hClose toh
-
- -- Display remaining output.
- void $ tryIO $ forever $
- showremote =<< hGetLine fromh
- hClose fromh
-
- where
+ finish
+ NeedGitClone -> do
+ hClose toh
+ hClose fromh
+ sendGitClone host url
+ go url privdata
+
user = "root@"++host
- bootstrapcmd url = shellWrap $ intercalate " && "
+
+ bootstrapcmd = shellWrap $ intercalate " && "
[ intercalate " ; "
[ "if [ ! -d " ++ localdir ++ " ]"
, "then " ++ intercalate " && "
[ "apt-get -y install git"
- , "git clone " ++ url ++ " " ++ localdir
+ , "echo " ++ toMarked statusMarker (show NeedGitClone)
]
, "fi"
]
, "cd " ++ localdir
- , "make pull build"
+ , "make build"
, "./propellor --boot " ++ host
]
+
getstatus :: Handle -> IO BootStrapStatus
getstatus h = do
l <- hGetLine h
@@ -110,6 +119,7 @@ spin host = do
showremote l
getstatus h
Just status -> return status
+
showremote s = putStrLn s
senddata toh f marker s = do
putStr $ "Sending " ++ f ++ " (" ++ show (length s) ++ " bytes) to " ++ host ++ "..."
@@ -118,7 +128,27 @@ spin host = do
hFlush toh
putStrLn "done"
-data BootStrapStatus = HaveKeyRing | NeedKeyRing
+sendGitClone :: HostName -> String -> IO ()
+sendGitClone host url = do
+ putStrLn $ "Pushing git repository to " ++ host
+ withTmpFile "gitbundle" $ \tmp _ -> do
+ -- TODO: ssh connection caching, or better push method
+ -- with less connections.
+ void $ boolSystem "git" [Param "bundle", Param "create", File tmp, Param "HEAD"]
+ void $ boolSystem "scp" [File tmp, Param ("root@"++host++":"++remotebundle)]
+ void $ boolSystem "ssh" [Param ("root@"++host), Param unpackcmd]
+ where
+ remotebundle = "/usr/local/propellor.git"
+ unpackcmd = shellWrap $ intercalate " && "
+ [ "git clone " ++ remotebundle ++ " " ++ localdir
+ , "cd " ++ localdir
+ , "git checkout -b master"
+ , "git remote rm origin"
+ , "git remote add origin " ++ url
+ , "rm -f " ++ remotebundle
+ ]
+
+data BootStrapStatus = HaveKeyRing | NeedKeyRing | NeedGitClone
deriving (Read, Show, Eq)
type Marker = String
diff --git a/README b/README
index c46131b8..ce9769c0 100644
--- a/README
+++ b/README
@@ -6,10 +6,13 @@ properties, taking action as necessary when a property is not yet met.
The design is intentionally very minimal.
-Propellor lives in a git repository, and so to set it up it's cloned
-to a system, and "make" can be used to pull down any new changes,
-and compile and run propellor. This can be done by a cron job, or
-a local propellor on your laptop can ssh in and run it.
+Propellor lives in a git repository. You'll typically want to have
+the repository checked out on a laptop, in order to make changes and push
+them out to hosts. Each host will also have a clone of the repository,
+and in that clone "make" can be used to build and run propellor.
+This can be done by a cron job (which propellor can set up),
+or a remote host can be triggered to update by running propellor
+on your laptop: propellor --spin $host
Properties are defined using Haskell. Edit config.hs to get started.
@@ -26,9 +29,15 @@ and so it's easy to factor out things like classes of hosts as desired.
## bootstrapping and private data
To bootstrap propellor on a new host, use: propellor --spin $host
-This looks up the git repository's remote.origin.url (or remote.deploy.url
-if available) and logs into the host, clones the url (if not already
-done), and sets up and runs propellor in /usr/local/propellor
+
+That clones the local git repository to the remote host (securely over ssh
+and without needing any central server!), if it doesn't already have
+a clone.
+
+The repository on the remote host will have its origin set to the local git
+repository's remote.origin.url (or remote.deploy.url if available).
+This way, when propellor is run on the remote host, it can contact
+whatever central git repository you're using.
Private data such as passwords, ssh private keys, etc should not be checked
into a propellor git repository in the clear, unless you want to restrict
@@ -43,10 +52,10 @@ for available fields.
## using git://... securely
-It's often easiest to deploy propellor to a host by cloning a git:// or
-http:// repository rather than by cloning over ssh://. To avoid a MITM
+It's often easiest for a remote host to use a git:// or http://
+url to its origin repository, rather than ssh://. So, to avoid a MITM
attack, propellor checks that the top commit in the git repository is gpg
-signed by a trusted gpg key, and refuses to deploy it otherwise.
+signed by a trusted gpg key, and refuses to deploy it otherwise.
This is only done when privdata/keyring.gpg exists. To set it up: