summaryrefslogtreecommitdiff
path: root/src/Propellor/PrivData.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Propellor/PrivData.hs')
-rw-r--r--src/Propellor/PrivData.hs91
1 files changed, 91 insertions, 0 deletions
diff --git a/src/Propellor/PrivData.hs b/src/Propellor/PrivData.hs
new file mode 100644
index 00000000..ad2c8d22
--- /dev/null
+++ b/src/Propellor/PrivData.hs
@@ -0,0 +1,91 @@
+{-# LANGUAGE PackageImports #-}
+
+module Propellor.PrivData where
+
+import qualified Data.Map as M
+import Control.Applicative
+import System.FilePath
+import System.IO
+import System.Directory
+import Data.Maybe
+import Data.List
+import Control.Monad
+import "mtl" Control.Monad.Reader
+
+import Propellor.Types
+import Propellor.Attr
+import Propellor.Message
+import Utility.Monad
+import Utility.PartialPrelude
+import Utility.Exception
+import Utility.Process
+import Utility.Tmp
+import Utility.SafeCommand
+import Utility.Misc
+
+-- | When the specified PrivDataField is available on the host Propellor
+-- is provisioning, it provies the data to the action. Otherwise, it prints
+-- a message to help the user make the necessary private data available.
+withPrivData :: PrivDataField -> (String -> Propellor Result) -> Propellor Result
+withPrivData field a = maybe missing a =<< liftIO (getPrivData field)
+ where
+ missing = do
+ host <- getHostName
+ let host' = if ".docker" `isSuffixOf` host
+ then "$parent_host"
+ else host
+ liftIO $ do
+ warningMessage $ "Missing privdata " ++ show field
+ putStrLn $ "Fix this by running: propellor --set "++host'++" '" ++ show field ++ "'"
+ return FailedChange
+
+getPrivData :: PrivDataField -> IO (Maybe String)
+getPrivData field = do
+ m <- catchDefaultIO Nothing $ readish <$> readFile privDataLocal
+ return $ maybe Nothing (M.lookup field) m
+
+setPrivData :: HostName -> PrivDataField -> IO ()
+setPrivData host field = do
+ putStrLn "Enter private data on stdin; ctrl-D when done:"
+ value <- chomp <$> hGetContentsStrict stdin
+ makePrivDataDir
+ let f = privDataFile host
+ m <- fromMaybe M.empty . readish <$> gpgDecrypt f
+ let m' = M.insert field value m
+ gpgEncrypt f (show m')
+ putStrLn "Private data set."
+ void $ boolSystem "git" [Param "add", File f]
+ where
+ chomp s
+ | end s == "\n" = chomp (beginning s)
+ | otherwise = s
+
+makePrivDataDir :: IO ()
+makePrivDataDir = createDirectoryIfMissing False privDataDir
+
+privDataDir :: FilePath
+privDataDir = "privdata"
+
+privDataFile :: HostName -> FilePath
+privDataFile host = privDataDir </> host ++ ".gpg"
+
+privDataLocal :: FilePath
+privDataLocal = privDataDir </> "local"
+
+gpgDecrypt :: FilePath -> IO String
+gpgDecrypt f = ifM (doesFileExist f)
+ ( readProcess "gpg" ["--decrypt", f]
+ , return ""
+ )
+
+gpgEncrypt :: FilePath -> String -> IO ()
+gpgEncrypt f s = do
+ encrypted <- writeReadProcessEnv "gpg"
+ [ "--default-recipient-self"
+ , "--armor"
+ , "--encrypt"
+ ]
+ Nothing
+ (Just $ flip hPutStr s)
+ Nothing
+ viaTmp writeFile f encrypted