From 29600a2c67a586849b232b0173ff019e4b601083 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sat, 12 Apr 2014 20:21:33 -0400 Subject: propellor spin --- Propellor/Property/Git.hs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'Propellor/Property/Git.hs') diff --git a/Propellor/Property/Git.hs b/Propellor/Property/Git.hs index c0494160..6f3c0364 100644 --- a/Propellor/Property/Git.hs +++ b/Propellor/Property/Git.hs @@ -4,6 +4,7 @@ import Propellor import Propellor.Property.File import qualified Propellor.Property.Apt as Apt import qualified Propellor.Property.Service as Service +import Utility.SafeCommand import Data.List @@ -46,3 +47,38 @@ daemonRunning exportdir = RevertableProperty setup unsetup , "--base-path=" ++ exportdir , exportdir ] + +installed :: Property +installed = Apt.installed ["git"] + +type RepoUrl = String + +type Branch = String + +-- | Specified git repository is cloned to the specified directory. +-- +-- If the firectory exists with some other content, it will be recursively +-- deleted. +-- +-- A branch can be specified, to check out. +cloned :: UserName -> RepoUrl -> FilePath -> Maybe Branch -> Property +cloned owner url dir mbranch = check originurl (Property desc checkout) + `requires` installed + where + desc = "git cloned " ++ url ++ " " ++ dir + gitconfig = dir ".git/config" + originurl = ifM (doesFileExist gitconfig) + ( do + v <- catchDefaultIO Nothing $ headMaybe . lines <$> + readProcess "git" ["config", "--file", gitconfig, "remote.origin.url"] + return (v /= Just url) + , return True + ) + checkout = do + liftIO $ whenM (doesDirectoryExist dir) $ + removeDirectoryRecursive dir + ensureProperty $ userScriptProperty owner $ catMaybes + [ Just $ "git clone " ++ shellEscape url ++ " " ++ shellEscape dir + , Just $ "cd " ++ shellEscape dir + , ("git checkout " ++) <$> mbranch + ] -- cgit v1.3-2-g0d8e From 6075fc636dfd9d8c946ed11a58ffa7059dd560d0 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sat, 12 Apr 2014 21:34:25 -0400 Subject: propellor spin --- Propellor/Property.hs | 16 +++++++++++----- Propellor/Property/Git.hs | 2 +- Propellor/Property/Gpg.hs | 41 +++++++++++++++++++++++++++++++++++++++++ Propellor/Property/Ssh.hs | 27 ++++++++++++++++++++++++++- Propellor/Types.hs | 8 +++++++- config-joey.hs | 17 ++++++++++------- propellor.cabal | 1 + 7 files changed, 97 insertions(+), 15 deletions(-) create mode 100644 Propellor/Property/Gpg.hs (limited to 'Propellor/Property/Git.hs') diff --git a/Propellor/Property.hs b/Propellor/Property.hs index 83e19a73..3e41fbcb 100644 --- a/Propellor/Property.hs +++ b/Propellor/Property.hs @@ -12,6 +12,7 @@ import Propellor.Types import Propellor.Types.Attr import Propellor.Engine import Utility.Monad +import System.FilePath makeChange :: IO () -> Propellor Result makeChange a = liftIO a >> return MadeChange @@ -52,14 +53,19 @@ p1 `before` p2 = Property (propertyDesc p1) $ do -- file to indicate whether it has run before. -- Use with caution. flagFile :: Property -> FilePath -> Property -flagFile property flagfile = Property (propertyDesc property) $ - go =<< liftIO (doesFileExist flagfile) +flagFile property = flagFile' property . return + +flagFile' :: Property -> IO FilePath -> Property +flagFile' property getflagfile = Property (propertyDesc property) $ do + flagfile <- liftIO getflagfile + go flagfile =<< liftIO (doesFileExist flagfile) where - go True = return NoChange - go False = do + go _ True = return NoChange + go flagfile False = do r <- ensureProperty property when (r == MadeChange) $ liftIO $ - unlessM (doesFileExist flagfile) $ + unlessM (doesFileExist flagfile) $ do + createDirectoryIfMissing True (takeDirectory flagfile) writeFile flagfile "" return r diff --git a/Propellor/Property/Git.hs b/Propellor/Property/Git.hs index 6f3c0364..6541dc74 100644 --- a/Propellor/Property/Git.hs +++ b/Propellor/Property/Git.hs @@ -65,7 +65,7 @@ cloned :: UserName -> RepoUrl -> FilePath -> Maybe Branch -> Property cloned owner url dir mbranch = check originurl (Property desc checkout) `requires` installed where - desc = "git cloned " ++ url ++ " " ++ dir + desc = "git cloned " ++ url ++ " to " ++ dir gitconfig = dir ".git/config" originurl = ifM (doesFileExist gitconfig) ( do diff --git a/Propellor/Property/Gpg.hs b/Propellor/Property/Gpg.hs new file mode 100644 index 00000000..e23111bb --- /dev/null +++ b/Propellor/Property/Gpg.hs @@ -0,0 +1,41 @@ +module Propellor.Property.Gpg where + +import Propellor +import qualified Propellor.Property.Apt as Apt +import Utility.FileSystemEncoding + +import System.PosixCompat + +installed :: Property +installed = Apt.installed ["gnupg"] + +-- | Sets up a user with a gpg key from the privdata. +-- +-- Note that if a secret key is exported using gpg -a --export-secret-key, +-- the public key is also included. Or just a public key could be +-- exported, and this would set it up just as well. +-- +-- Recommend only using this for low-value dedicated role keys. +-- No attempt has been made to scrub the key out of memory once it's used. +-- +-- The GpgKeyId does not have to be a numeric id; it can just as easily +-- be a description of the key. +keyImported :: GpgKeyId -> UserName -> Property +keyImported keyid user = flagFile' (Property desc go) genflag + `requires` installed + where + desc = user ++ " has gpg key " ++ show keyid + genflag = do + d <- dotDir user + return $ d ".propellor-imported-keyid-" ++ keyid + go = withPrivData (GpgKey keyid) $ \key -> makeChange $ + withHandle StdinHandle createProcessSuccess + (proc "su" ["-c", "gpg --import", user]) $ \h -> do + fileEncoding h + hPutStr h key + hClose h + +dotDir :: UserName -> IO FilePath +dotDir user = do + home <- homeDirectory <$> getUserEntryForName user + return $ home ".gnupg" diff --git a/Propellor/Property/Ssh.hs b/Propellor/Property/Ssh.hs index 59845f8f..42809359 100644 --- a/Propellor/Property/Ssh.hs +++ b/Propellor/Property/Ssh.hs @@ -4,13 +4,17 @@ module Propellor.Property.Ssh ( passwordAuthentication, hasAuthorizedKeys, restartSshd, - uniqueHostKeys + uniqueHostKeys, + keyImported ) where import Propellor import qualified Propellor.Property.File as File import Propellor.Property.User import Utility.SafeCommand +import Utility.FileMode + +import System.PosixCompat sshBool :: Bool -> String sshBool True = "yes" @@ -60,3 +64,24 @@ uniqueHostKeys = flagFile prop "/etc/ssh/.unique_host_keys" ensureProperty $ cmdProperty "/var/lib/dpkg/info/openssh-server.postinst" ["configure"] + +-- | Sets up a user with a ssh private key from the site's privdata. +-- +-- The ssh public key (.pub) is not installed. Ssh does not use it. +keyImported :: SshKeyType -> UserName -> Property +keyImported keytype user = Property desc install + where + desc = user ++ " has ssh key" + install = do + f <- liftIO keyfile + ifM (liftIO $ doesFileExist f) + ( noChange + , withPrivData (SshKey keytype user) $ \key -> makeChange $ + writeFileProtected f key + ) + keyfile = do + home <- homeDirectory <$> getUserEntryForName user + return $ home ".ssh" "id_" ++ + case keytype of + SshRsa -> "rsa" + SshDsa -> "dsa" diff --git a/Propellor/Types.hs b/Propellor/Types.hs index e6e02126..a30b183c 100644 --- a/Propellor/Types.hs +++ b/Propellor/Types.hs @@ -27,6 +27,8 @@ module Propellor.Types , ActionResult(..) , CmdLine(..) , PrivDataField(..) + , GpgKeyId + , SshKeyType(..) ) where import Data.Monoid @@ -162,9 +164,13 @@ data CmdLine -- It's fine to add new fields. data PrivDataField = DockerAuthentication - | SshPrivKey UserName + | SshKey SshKeyType UserName | Password UserName | PrivFile FilePath + | GpgKey GpgKeyId deriving (Read, Show, Ord, Eq) +type GpgKeyId = String +data SshKeyType = SshRsa | SshDsa + deriving (Read, Show, Ord, Eq) diff --git a/config-joey.hs b/config-joey.hs index 2efb81c6..7403f873 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -17,6 +17,7 @@ import qualified Propellor.Property.Dns as Dns import qualified Propellor.Property.OpenId as OpenId import qualified Propellor.Property.Docker as Docker import qualified Propellor.Property.Git as Git +import qualified Propellor.Property.Gpg as Gpg import qualified Propellor.Property.SiteSpecific.GitHome as GitHome import qualified Propellor.Property.SiteSpecific.GitAnnexBuilder as GitAnnexBuilder import qualified Propellor.Property.SiteSpecific.JoeySites as JoeySites @@ -71,6 +72,8 @@ hosts = & Apt.buildDep ["git-annex"] `period` Daily & Git.daemonRunning "/srv/git" & File.ownerGroup "/srv/git" "joey" "joey" + & Gpg.keyImported "git.kitenet.net obnam backup key" "root" + & Ssh.keyImported SshRsa "root" -- git repos restore (how?) (also make backups!) -- family annex needs family members to have accounts, -- ssh host key etc.. finesse? @@ -80,13 +83,13 @@ hosts = -- gitweb -- downloads.kitenet.net setup (including ssh key to turtle) - --' __|II| ,. ----- __|II|II|__ ( \_,/\ ------'\o/-'-.-'-.-'-.- __|II|II|II|II|___/ __/ -'-.-'-.-'-.-'-.-'- ---------------------- | [Docker] / ---------------------- ---------------------- : / ----------------------- ----------------------- \____, o ,' ------------------------ ------------------------ '--,___________,' ------------------------- + --' __|II| ,. + ---- __|II|II|__ ( \_,/\ + ------'\o/-'-.-'-.-'-.- __|II|II|II|II|___/ __/ -'-.-'-.-'-.-'-.-'- + ----------------------- | [Docker] / ---------------------- + ----------------------- : / ----------------------- + ------------------------ \____, o ,' ------------------------ + ------------------------- '--,___________,' ------------------------- -- Simple web server, publishing the outside host's /var/www , standardContainer "webserver" Stable "amd64" diff --git a/propellor.cabal b/propellor.cabal index 5497cc6b..b28a26d0 100644 --- a/propellor.cabal +++ b/propellor.cabal @@ -76,6 +76,7 @@ Library Propellor.Property.Docker Propellor.Property.File Propellor.Property.Git + Propellor.Property.Gpg Propellor.Property.Network Propellor.Property.OpenId Propellor.Property.Reboot -- cgit v1.3-2-g0d8e From 2e128c8fe25fb92ecfbd0bbe79ea777d53fa11ca Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 14:12:11 -0400 Subject: propellor spin --- Propellor/Property/Git.hs | 6 ++++-- Propellor/Property/SiteSpecific/JoeySites.hs | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'Propellor/Property/Git.hs') diff --git a/Propellor/Property/Git.hs b/Propellor/Property/Git.hs index 6541dc74..431f4134 100644 --- a/Propellor/Property/Git.hs +++ b/Propellor/Property/Git.hs @@ -75,8 +75,10 @@ cloned owner url dir mbranch = check originurl (Property desc checkout) , return True ) checkout = do - liftIO $ whenM (doesDirectoryExist dir) $ - removeDirectoryRecursive dir + liftIO $ do + whenM (doesDirectoryExist dir) $ + removeDirectoryRecursive dir + createDirectoryIfMissing True (takeDirectory dir) ensureProperty $ userScriptProperty owner $ catMaybes [ Just $ "git clone " ++ shellEscape url ++ " " ++ shellEscape dir , Just $ "cd " ++ shellEscape dir diff --git a/Propellor/Property/SiteSpecific/JoeySites.hs b/Propellor/Property/SiteSpecific/JoeySites.hs index 81557b32..fa444160 100644 --- a/Propellor/Property/SiteSpecific/JoeySites.hs +++ b/Propellor/Property/SiteSpecific/JoeySites.hs @@ -53,11 +53,12 @@ gitServer hosts = propertyList "git.kitenet.net setup" , "$feature{'snapshot'}{'default'} = [];" ] `describe` "gitweb configured" + -- I keep the website used for gitweb checked into git.. + , Git.cloned "joey" "/srv/git/joey/git.kitenet.net.git" "/srv/web/git.kitenet.net" Nothing , website "git.kitenet.net" , website "git.joeyh.name" -- ssh keys for branchable and github repo hooks -- TODO: upgrade to newer git-annex-shell for notification - -- gitweb ] where website hn = toProp $ Apache.siteEnabled hn (gitapacheconf hn) -- cgit v1.3-2-g0d8e From 70a5e9fe7b441440e1634e93aebbfb4c85c230aa Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 14:15:49 -0400 Subject: propellor spin --- Propellor/Property/Git.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Propellor/Property/Git.hs') diff --git a/Propellor/Property/Git.hs b/Propellor/Property/Git.hs index 431f4134..24feabd8 100644 --- a/Propellor/Property/Git.hs +++ b/Propellor/Property/Git.hs @@ -80,7 +80,8 @@ cloned owner url dir mbranch = check originurl (Property desc checkout) removeDirectoryRecursive dir createDirectoryIfMissing True (takeDirectory dir) ensureProperty $ userScriptProperty owner $ catMaybes - [ Just $ "git clone " ++ shellEscape url ++ " " ++ shellEscape dir + [ Just "set -x" + , Just $ "git clone " ++ shellEscape url ++ " " ++ shellEscape dir , Just $ "cd " ++ shellEscape dir , ("git checkout " ++) <$> mbranch ] -- cgit v1.3-2-g0d8e From 3835e6b1c7cdb7ba2ed14bf872331bf44f95cb17 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 14:18:31 -0400 Subject: propellor spin --- Propellor/Property/Git.hs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'Propellor/Property/Git.hs') diff --git a/Propellor/Property/Git.hs b/Propellor/Property/Git.hs index 24feabd8..431f4134 100644 --- a/Propellor/Property/Git.hs +++ b/Propellor/Property/Git.hs @@ -80,8 +80,7 @@ cloned owner url dir mbranch = check originurl (Property desc checkout) removeDirectoryRecursive dir createDirectoryIfMissing True (takeDirectory dir) ensureProperty $ userScriptProperty owner $ catMaybes - [ Just "set -x" - , Just $ "git clone " ++ shellEscape url ++ " " ++ shellEscape dir + [ Just $ "git clone " ++ shellEscape url ++ " " ++ shellEscape dir , Just $ "cd " ++ shellEscape dir , ("git checkout " ++) <$> mbranch ] -- cgit v1.3-2-g0d8e From c1307f5dc26b96e61743f590df5797999ca82d92 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 14:23:17 -0400 Subject: propellor spin --- Propellor/Property/Git.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Propellor/Property/Git.hs') diff --git a/Propellor/Property/Git.hs b/Propellor/Property/Git.hs index 431f4134..b2a53800 100644 --- a/Propellor/Property/Git.hs +++ b/Propellor/Property/Git.hs @@ -80,7 +80,7 @@ cloned owner url dir mbranch = check originurl (Property desc checkout) removeDirectoryRecursive dir createDirectoryIfMissing True (takeDirectory dir) ensureProperty $ userScriptProperty owner $ catMaybes - [ Just $ "git clone " ++ shellEscape url ++ " " ++ shellEscape dir + [ Just $ "git clone " ++ shellEscape url ++ " " ++ shellEscape dir ++ " < /dev/null" , Just $ "cd " ++ shellEscape dir , ("git checkout " ++) <$> mbranch ] -- cgit v1.3-2-g0d8e From 96f07ef513f6447baec8f66d52d4490ef627a588 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 14:36:19 -0400 Subject: propellor spin --- Propellor/Property/Apache.hs | 32 ++++++++++++++++++++++------ Propellor/Property/Git.hs | 3 +++ Propellor/Property/SiteSpecific/JoeySites.hs | 1 + 3 files changed, 30 insertions(+), 6 deletions(-) (limited to 'Propellor/Property/Git.hs') diff --git a/Propellor/Property/Apache.hs b/Propellor/Property/Apache.hs index 5e32b0da..81daf9e7 100644 --- a/Propellor/Property/Apache.hs +++ b/Propellor/Property/Apache.hs @@ -3,17 +3,21 @@ module Propellor.Property.Apache where import Propellor import qualified Propellor.Property.File as File import qualified Propellor.Property.Apt as Apt +import qualified Propellor.Property.Service as Service type ConfigFile = [String] siteEnabled :: HostName -> ConfigFile -> RevertableProperty siteEnabled hn cf = RevertableProperty enable disable where - enable = siteAvailable hn cf - `onChange` cmdProperty "a2ensite" ["--quiet", hn] - `requires` Apt.installed ["apache2"] + enable = cmdProperty "a2ensite" ["--quiet", hn] + `requires` siteAvailable hn cf + `requires` installed + `onChange` reloaded disable = File.notPresent (siteCfg hn) `onChange` cmdProperty "a2dissite" ["--quiet", hn] + `requires` installed + `onChange` reloaded siteAvailable :: HostName -> ConfigFile -> Property siteAvailable hn cf = siteCfg hn `File.hasContent` (comment:cf) @@ -21,8 +25,24 @@ siteAvailable hn cf = siteCfg hn `File.hasContent` (comment:cf) where comment = "# deployed with propellor, do not modify" +modEnabled :: String -> RevertableProperty +modEnabled modname = RevertableProperty enable disable + where + enable = cmdProperty "a2enmod" ["--quiet", modname] + `requires` installed + `onChange` reloaded + disable = cmdProperty "a2dismod" ["--quiet", modname] + `requires` installed + `onChange` reloaded + siteCfg :: HostName -> FilePath -siteCfg hn = "/etc/apache2/sites-available/" ++ hn ++ ".conf" +siteCfg hn = "/etc/apache2/sites-available/" ++ hn + +installed :: Property +installed = Apt.installed ["apache2"] + +restarted :: Property +restarted = cmdProperty "service" ["apache2", "restart"] -restart :: Property -restart = cmdProperty "service" ["apache2", "restart"] +reloaded :: Property +reloaded = Service.reloaded "apache2" diff --git a/Propellor/Property/Git.hs b/Propellor/Property/Git.hs index b2a53800..1dae94bf 100644 --- a/Propellor/Property/Git.hs +++ b/Propellor/Property/Git.hs @@ -80,6 +80,9 @@ cloned owner url dir mbranch = check originurl (Property desc checkout) removeDirectoryRecursive dir createDirectoryIfMissing True (takeDirectory dir) ensureProperty $ userScriptProperty owner $ catMaybes + -- The mbranch diff --git a/Propellor/Property/SiteSpecific/JoeySites.hs b/Propellor/Property/SiteSpecific/JoeySites.hs index 907233bd..4b98fe0b 100644 --- a/Propellor/Property/SiteSpecific/JoeySites.hs +++ b/Propellor/Property/SiteSpecific/JoeySites.hs @@ -57,6 +57,7 @@ gitServer hosts = propertyList "git.kitenet.net setup" , Git.cloned "root" "/srv/git/joey/git.kitenet.net.git" "/srv/web/git.kitenet.net" Nothing , website "git.kitenet.net" , website "git.joeyh.name" + , toProp $ Apache.modEnabled "cgi" -- ssh keys for branchable and github repo hooks -- TODO: upgrade to newer git-annex-shell for notification ] -- cgit v1.3-2-g0d8e