summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--debian/changelog5
-rw-r--r--doc/README.mdwn19
-rw-r--r--doc/components.mdwn8
-rw-r--r--doc/todo/commandline_to_setup_minimal_repo.mdwn2
-rw-r--r--src/Propellor/Gpg.hs17
-rw-r--r--src/wrapper.hs88
6 files changed, 104 insertions, 35 deletions
diff --git a/debian/changelog b/debian/changelog
index 14d3f1a9..21c53bf8 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -65,8 +65,9 @@ propellor (3.0.0) UNRELEASED; urgency=medium
* Added dependency on concurrent-output; removed embedded copy.
* Apt.PPA: New module, contributed by Evan Cofsky.
* Improved propellor's first run experience; the wrapper program will
- now walk the user through setting up ~/.propellor with a choice between
- a clone of propellor's git repository, or a minimal config.
+ now walk the user through setting up ~/.propellor, with a choice between
+ a clone of propellor's git repository, or a minimal config, and will
+ configure propellor to use a gpg key.
-- Joey Hess <id@joeyh.name> Wed, 30 Mar 2016 15:45:08 -0400
diff --git a/doc/README.mdwn b/doc/README.mdwn
index b17f8575..fc3c3fd1 100644
--- a/doc/README.mdwn
+++ b/doc/README.mdwn
@@ -44,18 +44,13 @@ see [configuration for the Haskell newbie](https://propellor.branchable.com/hask
`apt-get install propellor`
2. Run `propellor` for the first time. It will set up a `~/.propellor/` git
repository for you.
-3. If you don't have a gpg private key already, generate one: `gpg --gen-key`
-4. Run: `propellor --add-key $KEYID`, which will make propellor trust
- your gpg key, and will sign your `~/.propellor` repository using it.
-5. Edit `~/.propellor/config.hs`, and add a host you want to manage.
+3. Edit `~/.propellor/config.hs`, and add a host you want to manage.
You can start by not adding any properties, or only a few.
-6. Run: `propellor --spin $HOST`
-7. Now you have a simple propellor deployment, but it doesn't do
- much to the host yet, besides installing propellor.
- So, edit `~/.propellor/config.hs` to configure the host, add some
- properties to it, and re-run step 6.
- Repeat until happy and move on to the next host. :)
-8. Once you have a lot of hosts, and running `propellor --spin HOST` for
+4. Run: `propellor --spin $HOST`
+5. Now you have a simple propellor deployment to a host. Continue editing
+ `~/.propellor/config.hs` to further configure the host, add more hosts
+ etc, and re-run `propellor --spin $HOST` after each change.
+6. Once you have a lot of hosts, and running `propellor --spin HOST` for
each host becomes tiresome, you can
[automate that](http://propellor.branchable.com/automated_spins/).
-9. Write some neat new properties and send patches!
+7. Write some neat new properties and send patches!
diff --git a/doc/components.mdwn b/doc/components.mdwn
index 801bb6bf..5b47e106 100644
--- a/doc/components.mdwn
+++ b/doc/components.mdwn
@@ -28,12 +28,8 @@ then copy in `~/.propellor/src/Propellor/` and it will be used. See
## minimal .propellor repository
All that really needs to be in `~/.propellor/` though, is a `config.hs`
-file, and a cabal file. To use propellor this way, you can first
-install propellor, and then copy the two files from the
-[mininalconfig branch](http://source.propellor.branchable.com/?p=source.git;a=tree;h=refs/heads/minimalconfig;hb=refs/heads/minimalconfig),
-or clone it:
-
- git clone git://propellor.branchable.com/ .propellor --branch minimalconfig --single-branch
+file, and a cabal file. Running propellor when `~/.propellor/` doesn't exist
+will ask you if you want a minimal config, and create those files.
In this configuration, when propellor is deploying itself to a new host,
it will automatically install the version of the propellor library
diff --git a/doc/todo/commandline_to_setup_minimal_repo.mdwn b/doc/todo/commandline_to_setup_minimal_repo.mdwn
index 5e82ed0f..2b41d370 100644
--- a/doc/todo/commandline_to_setup_minimal_repo.mdwn
+++ b/doc/todo/commandline_to_setup_minimal_repo.mdwn
@@ -3,3 +3,5 @@ parameters, like --minimal to clone the minimal config repo instead of the
full one, or --stack to set up ~/.propellor to use stack. --[[Joey]]
> Or, it could be an interactive setup process. --[[Joey]]
+
+>> Made it interactive. [[done]] --[[Joey]]
diff --git a/src/Propellor/Gpg.hs b/src/Propellor/Gpg.hs
index 55d89d29..4e6ceb79 100644
--- a/src/Propellor/Gpg.hs
+++ b/src/Propellor/Gpg.hs
@@ -32,14 +32,21 @@ getGpgBin = do
-- Lists the keys in propellor's keyring.
listPubKeys :: IO [KeyId]
listPubKeys = do
- gpgbin <- getGpgBin
keyring <- privDataKeyring
- parse . lines <$> readProcess gpgbin (listopts keyring)
+ map fst <$> listKeys ("--list-public-keys" : useKeyringOpts keyring)
+
+listSecretKeys :: IO [(KeyId, String)]
+listSecretKeys = listKeys ["--list-secret-keys"]
+
+listKeys :: [String] -> IO [(KeyId, String)]
+listKeys ps = do
+ gpgbin <- getGpgBin
+ parse . lines <$> readProcess gpgbin listopts
where
- listopts keyring = useKeyringOpts keyring ++
- ["--with-colons", "--list-public-keys"]
+ listopts = ps ++ ["--with-colons"]
parse = mapMaybe (keyIdField . split ":")
- keyIdField ("pub":_:_:_:f:_) = Just f
+ keyIdField (t:_:_:_:f:_:_:_:_:n:_)
+ | t == "pub" || t == "sec" = Just (f, n)
keyIdField _ = Nothing
useKeyringOpts :: FilePath -> [String]
diff --git a/src/wrapper.hs b/src/wrapper.hs
index 82251dc9..32e036da 100644
--- a/src/wrapper.hs
+++ b/src/wrapper.hs
@@ -3,8 +3,7 @@
-- Distributions should install this program into PATH.
-- (Cabal builds it as dist/build/propellor/propellor).
--
--- This is not the propellor main program (that's config.hs)
---
+-- This is not the propellor main program (that's config.hs).
-- This bootstraps ~/.propellor/config.hs, builds it if
-- it's not already built, and runs it.
@@ -13,13 +12,16 @@ module Main where
import Propellor.Message
import Propellor.Bootstrap
import Propellor.Git
+import Propellor.Gpg
import Utility.UserInfo
import Utility.Monad
import Utility.Process
import Utility.SafeCommand
import Utility.Exception
+import Utility.Path
import Data.Char
+import Data.List
import Control.Monad
import Control.Monad.IfElse
import System.Directory
@@ -97,14 +99,14 @@ welcomeBanner = putStr $ unlines $ map prettify
| c == x = y
| otherwise = c
-prompt :: String -> [(Char, IO ())] -> IO ()
+prompt :: String -> [(String, IO ())] -> IO ()
prompt p cs = do
- putStr (p ++ " [" ++ map fst cs ++ "] ")
+ putStr (p ++ " [" ++ intercalate "|" (map fst cs) ++ "] ")
hFlush stdout
r <- map toLower <$> getLine
- if r == "\n"
+ if null r
then snd (head cs) -- default to first choice on return
- else case filter (\(c, a) -> [toLower c] == r) cs of
+ else case filter (\(s, _) -> map toLower s == r) cs of
[(_, a)] -> a
_ -> do
putStrLn "Not a valid choice, try again.. (Or ctrl-c to quit)"
@@ -125,23 +127,89 @@ setup dotpropellor = do
putStrLn " A: A clone of propellor's git repository (most flexible)"
putStrLn " B: The bare minimum files to use propellor (most simple)"
prompt "Which would you prefer?"
- [ ('A', fullClone dotpropellor),
- ('B', minimalConfig dotpropellor)
+ [ ("A", fullClone dotpropellor)
+ , ("B", minimalConfig dotpropellor)
]
putStrLn "Ok, ~/.propellor/config.hs is set up!"
-
+ changeWorkingDirectory dotpropellor
+
section
putStrLn "Let's try building the propellor configuration, to make sure it will work..."
buildPropellor Nothing
- putStrLn "Great! Propellor is set up and ready to use."
+ putStrLn "Great! Propellor is bootstrapped."
+
+ section
+ putStrLn "Propellor uses gpg to encrypt private data about the systems it manages,"
+ putStrLn "and to sign git commits."
+ gpg <- getGpgBin
+ ifM (inPath gpg)
+ ( setupGpgKey dotpropellor
+ , do
+ putStrLn "You don't seem to have gpg installed, so skipping setting it up."
+ explainManualSetupGpgKey
+ )
section
+ putStrLn "Everything is set up ..."
putStrLn "Your next step is to edit ~/.propellor/config.hs,"
putStrLn "and run propellor again to try it out."
putStrLn ""
putStrLn "For docs, see https://propellor.branchable.com/"
putStrLn "Enjoy propellor!"
+explainManualSetupGpgKey :: IO ()
+explainManualSetupGpgKey = do
+ putStrLn "Propellor can still be used without gpg, but it won't be able to"
+ putStrLn "manage private data. You can set this up later:"
+ putStrLn " 1. gpg --gen-key"
+ putStrLn " 2. propellor --add-key (pass it the key ID generated in step 1)"
+
+setupGpgKey :: FilePath -> IO ()
+setupGpgKey dotpropellor = do
+ ks <- listSecretKeys
+ putStrLn ""
+ case ks of
+ [] -> makeGpgKey dotpropellor
+ [(k, _)] -> propellorAddKey dotpropellor k
+ _ -> do
+ let nks = zip ks (map show ([1..] :: [Integer]))
+ putStrLn "I see you have several gpg keys:"
+ forM_ nks $ \((k, d), n) ->
+ putStrLn $ " " ++ n ++ " " ++ d ++ " (keyid " ++ k ++ ")"
+ prompt "Which of your gpg keys should propellor use?"
+ (map (\((k, _), n) -> (n, propellorAddKey dotpropellor k)) nks)
+
+makeGpgKey :: FilePath -> IO ()
+makeGpgKey dotpropellor = do
+ putStrLn "You seem to not have any gpg secret keys."
+ prompt "Would you like to create one now?"
+ [("Y", rungpg), ("N", nope)]
+ where
+ nope = do
+ putStrLn "No problem."
+ explainManualSetupGpgKey
+ rungpg = do
+ putStrLn "Running gpg --gen-key ..."
+ gpg <- getGpgBin
+ void $ boolSystem gpg [Param "--gen-key"]
+ ks <- listSecretKeys
+ case ks of
+ [] -> do
+ putStrLn "Hmm, gpg seemed to not set up a secret key."
+ prompt "Want to try running gpg again?"
+ [("Y", rungpg), ("N", nope)]
+ ((k, _):_) -> propellorAddKey dotpropellor k
+
+propellorAddKey :: FilePath -> String -> IO ()
+propellorAddKey dotpropellor keyid = do
+ putStrLn ""
+ putStrLn $ "Telling propellor to use your gpg key by running: propellor --add-key " ++ keyid
+ unlessM (boolSystem propellorbin [Param "--add-key", Param keyid]) $ do
+ putStrLn "Oops, that didn't work! You can retry the same command later."
+ putStrLn "Continuing onward ..."
+ where
+ propellorbin = dotpropellor </> "propellor"
+
minimalConfig :: FilePath -> IO ()
minimalConfig dotpropellor = do
createDirectoryIfMissing True dotpropellor