propellor spin
This commit is contained in:
parent
36469bc07d
commit
9172b79612
|
@ -70,15 +70,10 @@ 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"]
|
||||||
privdata <- gpgDecrypt (privDataFile host)
|
go url =<< gpgDecrypt (privDataFile host)
|
||||||
withBothHandles createProcessSuccess (proc "ssh" [user, bootstrapcmd url]) $ \(toh, fromh) -> do
|
where
|
||||||
status <- getstatus fromh `catchIO` error "protocol error"
|
go url privdata = withBothHandles createProcessSuccess (proc "ssh" [user, bootstrapcmd]) $ \(toh, fromh) -> do
|
||||||
case status of
|
let finish = do
|
||||||
NeedKeyRing -> do
|
|
||||||
d <- w82s . BL.unpack . B64.encode
|
|
||||||
<$> BL.readFile keyring
|
|
||||||
senddata toh keyring keyringMarker d
|
|
||||||
HaveKeyRing -> noop
|
|
||||||
senddata toh (privDataFile host) privDataMarker privdata
|
senddata toh (privDataFile host) privDataMarker privdata
|
||||||
hClose toh
|
hClose toh
|
||||||
|
|
||||||
|
@ -86,22 +81,36 @@ spin host = do
|
||||||
void $ tryIO $ forever $
|
void $ tryIO $ forever $
|
||||||
showremote =<< hGetLine fromh
|
showremote =<< hGetLine fromh
|
||||||
hClose 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
|
||||||
|
finish
|
||||||
|
NeedGitClone -> do
|
||||||
|
hClose toh
|
||||||
|
hClose fromh
|
||||||
|
sendGitClone host url
|
||||||
|
go url privdata
|
||||||
|
|
||||||
where
|
|
||||||
user = "root@"++host
|
user = "root@"++host
|
||||||
bootstrapcmd url = shellWrap $ intercalate " && "
|
|
||||||
|
bootstrapcmd = shellWrap $ intercalate " && "
|
||||||
[ intercalate " ; "
|
[ intercalate " ; "
|
||||||
[ "if [ ! -d " ++ localdir ++ " ]"
|
[ "if [ ! -d " ++ localdir ++ " ]"
|
||||||
, "then " ++ intercalate " && "
|
, "then " ++ intercalate " && "
|
||||||
[ "apt-get -y install git"
|
[ "apt-get -y install git"
|
||||||
, "git clone " ++ url ++ " " ++ localdir
|
, "echo " ++ toMarked statusMarker (show NeedGitClone)
|
||||||
]
|
]
|
||||||
, "fi"
|
, "fi"
|
||||||
]
|
]
|
||||||
, "cd " ++ localdir
|
, "cd " ++ localdir
|
||||||
, "make pull build"
|
, "make build"
|
||||||
, "./propellor --boot " ++ host
|
, "./propellor --boot " ++ host
|
||||||
]
|
]
|
||||||
|
|
||||||
getstatus :: Handle -> IO BootStrapStatus
|
getstatus :: Handle -> IO BootStrapStatus
|
||||||
getstatus h = do
|
getstatus h = do
|
||||||
l <- hGetLine h
|
l <- hGetLine h
|
||||||
|
@ -110,6 +119,7 @@ spin host = do
|
||||||
showremote l
|
showremote l
|
||||||
getstatus h
|
getstatus h
|
||||||
Just status -> return status
|
Just status -> return status
|
||||||
|
|
||||||
showremote s = putStrLn s
|
showremote s = putStrLn s
|
||||||
senddata toh f marker s = do
|
senddata toh f marker s = do
|
||||||
putStr $ "Sending " ++ f ++ " (" ++ show (length s) ++ " bytes) to " ++ host ++ "..."
|
putStr $ "Sending " ++ f ++ " (" ++ show (length s) ++ " bytes) to " ++ host ++ "..."
|
||||||
|
@ -118,7 +128,27 @@ spin host = do
|
||||||
hFlush toh
|
hFlush toh
|
||||||
putStrLn "done"
|
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)
|
deriving (Read, Show, Eq)
|
||||||
|
|
||||||
type Marker = String
|
type Marker = String
|
||||||
|
|
27
README
27
README
|
@ -6,10 +6,13 @@ properties, taking action as necessary when a property is not yet met.
|
||||||
|
|
||||||
The design is intentionally very minimal.
|
The design is intentionally very minimal.
|
||||||
|
|
||||||
Propellor lives in a git repository, and so to set it up it's cloned
|
Propellor lives in a git repository. You'll typically want to have
|
||||||
to a system, and "make" can be used to pull down any new changes,
|
the repository checked out on a laptop, in order to make changes and push
|
||||||
and compile and run propellor. This can be done by a cron job, or
|
them out to hosts. Each host will also have a clone of the repository,
|
||||||
a local propellor on your laptop can ssh in and run it.
|
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.
|
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
|
## bootstrapping and private data
|
||||||
|
|
||||||
To bootstrap propellor on a new host, use: propellor --spin $host
|
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
|
That clones the local git repository to the remote host (securely over ssh
|
||||||
done), and sets up and runs propellor in /usr/local/propellor
|
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
|
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
|
into a propellor git repository in the clear, unless you want to restrict
|
||||||
|
@ -43,8 +52,8 @@ for available fields.
|
||||||
|
|
||||||
## using git://... securely
|
## using git://... securely
|
||||||
|
|
||||||
It's often easiest to deploy propellor to a host by cloning a git:// or
|
It's often easiest for a remote host to use a git:// or http://
|
||||||
http:// repository rather than by cloning over ssh://. To avoid a MITM
|
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
|
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.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue