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') 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') 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 967a0d82dd84a2adfabe702d8ca030d30f8079b5 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sat, 12 Apr 2014 21:43:30 -0400 Subject: propellor spin --- Propellor/Property/Ssh.hs | 20 +++++++++++--------- Propellor/Types.hs | 3 ++- 2 files changed, 13 insertions(+), 10 deletions(-) (limited to 'Propellor') diff --git a/Propellor/Property/Ssh.hs b/Propellor/Property/Ssh.hs index 42809359..51649fd9 100644 --- a/Propellor/Property/Ssh.hs +++ b/Propellor/Property/Ssh.hs @@ -66,22 +66,24 @@ uniqueHostKeys = flagFile prop "/etc/ssh/.unique_host_keys" ["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 +keyImported keytype user = propertyList desc + [ Property desc (install (SshPubKey keytype user) ".pub") + , Property desc (install (SshPrivKey keytype user) "") + ] where desc = user ++ " has ssh key" - install = do - f <- liftIO keyfile + install p ext = do + f <- liftIO $ keyfile ext ifM (liftIO $ doesFileExist f) ( noChange - , withPrivData (SshKey keytype user) $ \key -> makeChange $ + , withPrivData p $ \key -> makeChange $ writeFileProtected f key ) - keyfile = do + keyfile ext = do home <- homeDirectory <$> getUserEntryForName user - return $ home ".ssh" "id_" ++ - case keytype of + return $ home ".ssh" "id_" + ++ case keytype of SshRsa -> "rsa" SshDsa -> "dsa" + ++ ext diff --git a/Propellor/Types.hs b/Propellor/Types.hs index a30b183c..86c56a28 100644 --- a/Propellor/Types.hs +++ b/Propellor/Types.hs @@ -164,7 +164,8 @@ data CmdLine -- It's fine to add new fields. data PrivDataField = DockerAuthentication - | SshKey SshKeyType UserName + | SshPubKey SshKeyType UserName + | SshPrivKey SshKeyType UserName | Password UserName | PrivFile FilePath | GpgKey GpgKeyId -- cgit v1.3-2-g0d8e From c7830f4e669735bf46945592b315e7e367129888 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sat, 12 Apr 2014 22:36:36 -0400 Subject: propellor spin --- Propellor/Property/Cron.hs | 9 +- Propellor/Property/Obnam.hs | 77 +++++++++++++++ config-joey.hs | 10 +- debian/changelog | 2 + privdata/diatom.kitenet.net.gpg | 211 ++++++++++++++++++++-------------------- propellor.cabal | 1 + 6 files changed, 202 insertions(+), 108 deletions(-) create mode 100644 Propellor/Property/Obnam.hs (limited to 'Propellor') diff --git a/Propellor/Property/Cron.hs b/Propellor/Property/Cron.hs index fa6019ea..2fa9c87e 100644 --- a/Propellor/Property/Cron.hs +++ b/Propellor/Property/Cron.hs @@ -4,13 +4,15 @@ import Propellor import qualified Propellor.Property.File as File import qualified Propellor.Property.Apt as Apt +import Data.Char + type CronTimes = String -- | Installs a cron job, run as a specificed user, in a particular --directory. Note that the Desc must be unique, as it is used for the --cron.d/ filename. job :: Desc -> CronTimes -> UserName -> FilePath -> String -> Property -job desc times user cddir command = ("/etc/cron.d/" ++ desc) `File.hasContent` +job desc times user cddir command = cronjobfile `File.hasContent` [ "# Generated by propellor" , "" , "SHELL=/bin/sh" @@ -20,6 +22,11 @@ job desc times user cddir command = ("/etc/cron.d/" ++ desc) `File.hasContent` ] `requires` Apt.serviceInstalledRunning "cron" `describe` ("cronned " ++ desc) + where + cronjobfile = "/etc/cron.d/" ++ map sanitize desc + sanitize c + | isAlphaNum c = c + | otherwise = '_' -- | Installs a cron job, and runs it niced and ioniced. niceJob :: Desc -> CronTimes -> UserName -> FilePath -> String -> Property diff --git a/Propellor/Property/Obnam.hs b/Propellor/Property/Obnam.hs new file mode 100644 index 00000000..ebdcb9dd --- /dev/null +++ b/Propellor/Property/Obnam.hs @@ -0,0 +1,77 @@ +module Propellor.Property.Obnam where + +import Propellor +import qualified Propellor.Property.Apt as Apt +import qualified Propellor.Property.Cron as Cron +import Utility.SafeCommand + +installed :: Property +installed = Apt.installed ["obnam"] + +type ObnamParam = String + +-- | Installs a cron job that causes a given directory to be backed +-- up, by running obnam with some parameters. +-- +-- If the directory does not exist, or exists but is completely empty, +-- this Property will immediately restore it from an existing backup. +-- +-- So, this property can be used to deploy a directory of content +-- to a host, while also ensuring any changes made to it get backed up. +-- And since Obnam encrypts, just make this property depend on a gpg +-- key, and tell obnam to use the key, and your data will be backed +-- up securely. For example: +-- +-- > & Obnam.backup "/srv/git" "33 3 * * *" +-- > [ "--repository=2318@usw-s002.rsync.net:mygitrepos.obnam" +-- > , "--encrypt-with=1B169BE1" +-- > ] +-- > `requires` Gpg.keyImported "1B169BE1" "root" +-- > `requires` Ssh.keyImported SshRsa "root" +-- +-- How awesome is that? +backup :: FilePath -> Cron.CronTimes -> [ObnamParam] -> Property +backup dir crontimes params = cronjob `describe` desc + `requires` restored dir params + `requires` installed + where + desc = dir ++ " backed up by obnam" + cronjob = Cron.niceJob ("obnam_backup" ++ dir) crontimes "root" "/" $ + unwords $ + [ "obnam" + , "backup" + , shellEscape dir + ] ++ map shellEscape params + +-- | Restores a directory from an obnam backup. +-- +-- Only does anything if the directory does not exist, or exists, +-- but is completely empty. +-- +-- The restore is performed atomically; restoring to a temp directory +-- and then moving it to the directory. +restored :: FilePath -> [ObnamParam] -> Property +restored dir params = Property (dir ++ " restored by obnam") go + `requires` installed + where + go = ifM (liftIO needsRestore) + ( liftIO restore + , noChange + ) + + needsRestore = null <$> catchDefaultIO [] (dirContents dir) + + restore = withTmpDirIn (takeDirectory dir) "obnam-restore" $ \tmpdir -> do + ok <- boolSystem "obnam" $ + [ Param "restore" + , Param "--to" + , Param tmpdir + ] ++ map Param params + let restoreddir = tmpdir ++ "/" ++ dir + ifM (pure ok <&&> doesDirectoryExist restoreddir) + ( do + void $ tryIO $ removeDirectory dir + renameDirectory restoreddir dir + return MadeChange + , return FailedChange + ) diff --git a/config-joey.hs b/config-joey.hs index 7403f873..a983e87b 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -18,6 +18,7 @@ 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.Obnam as Obnam import qualified Propellor.Property.SiteSpecific.GitHome as GitHome import qualified Propellor.Property.SiteSpecific.GitAnnexBuilder as GitAnnexBuilder import qualified Propellor.Property.SiteSpecific.JoeySites as JoeySites @@ -72,8 +73,13 @@ 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" + & Obnam.backup "/srv/git" "33 3 * * *" + [ "--repository=2318@usw-s002.rsync.net:git.kitenet.net" + , "--encrypt-with=1B169BE1" + ] + `requires` Gpg.keyImported "1B169BE1" "root" + `requires` Ssh.keyImported SshRsa "root" + -- git repos restore (how?) (also make backups!) -- family annex needs family members to have accounts, -- ssh host key etc.. finesse? diff --git a/debian/changelog b/debian/changelog index 29f1787e..6593c95d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,8 @@ propellor (0.3.1) UNRELEASED; urgency=medium * Merge scheduler bug fix from git-annex. + * Support for provisioning hosts with ssh and gpg keys. + * Obnam support. -- Joey Hess Fri, 11 Apr 2014 15:00:11 -0400 diff --git a/privdata/diatom.kitenet.net.gpg b/privdata/diatom.kitenet.net.gpg index 34d986c2..da97a08d 100644 --- a/privdata/diatom.kitenet.net.gpg +++ b/privdata/diatom.kitenet.net.gpg @@ -1,109 +1,110 @@ -----BEGIN PGP MESSAGE----- Version: GnuPG v1 -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 -UUFGrYcSqu0P -=w6i8 +hQILA7ODiaEXBlRZAQ/4hK79L/K03NtaiKU3whmLdty0JG1zPvGgXLjuMQ2XxL+J +Pr98VUjwtYjKvRRc6XQaHNwPojbT8uy825wBL+0iBr7O2Uyog8c5vDPkC+ksVvJ2 +PJJBkwiXTVh6e7lbHENJUa8yf0z3UQlz++W8qQOMRreVEI6wSJOlxz70WarXgNOB +p+zD1bgr+8yaOMAjnDqkUPr5ItFXL5EUy5xL5Kud9A+ukYMYMtLJbHFIe6bMH1fH +GajRWbyisaVgT3Rqvejg96oUSV9J83Am4XHUq8gJwOJlULI9mx9CCwQLIjmGbcql +WVKWq+h/ERLOHaMhogMvNSXcdljRFpYRcN5Dll3hJt9DXGtHqfSpfb0ZhK5y/C3s +afS4pEdCzsghgG2ZEELeRUSsiKKxt9ws524OSOAF1OqGktSUOD1muwm+8whhjr/0 +kZIqlX/mesyAtxquBCHT5t0uMN00/ksC5nAZmi7YFibf/tCjQfE2BdtE5Y6AYrqT +8Rth5Y6kNwGzUYFqIvmScHrsxH6Tjc1n1nKEWeeWOM0Pooq45RlSXLnybReGDRAW +xINqKXEjKqzy4EXsHIBKv87DZJoE+hs3Jk100mtgRNVQYcdzXtiXeBe1EWob/fEz +UU2VxjwojPH9MakVPFmDjVw2t60Bhc246ovB8jSyKqLn8yPUnhYqjObEGCuie9Ls +AYiU8Tl9s7hIV7XpSl/jYLYNo99Zzw/jz8Q8eV3wzndy/9+FbOU4UOxDy+XpBldO +LZzdzUbjyBLqDMKoNuRjMzqq24vSizMGxYV8MImJ2H0+VEUx3g4wMRKUpH9D3kVE +wVfzztZ1bxkpjqQVfHxIJrKwgqHS7pPcgPDrNvhTJn2pM1VGzPjaZ+U/E7mKreFM +mWyjcq4jQhpek1hQ0lGzZEPJTJKOZng1IsxJRatdL3+oeqFQ0hIqm9WvbKChLlMN +N4n8QX1/9gx2lt27Bi+7bmIxn6cQN822xXFiUWlz53aJ1ahx+xG9Gr452nCFQlaG +90ci94nsqnn4cKMkEyMNuY33ae85+WYWIo15FbFPv2ReW9R+0g0SABJduNQzr5rA +88MZTsiAS6rE0sB7adZZ8U133Wdl/rlJ7sMpAWCGT/P3+BJlBHq0Z31DDaH5oTOs +uaLeri98dmkEuiQ4cBI6uvFVtR2KnzE80yrCuqyfsNay8UpYK5oJB7WWZ7u0EhhW +8WisATSNLVuwtBmN6Z8qpzmwthmAvCNfDLCOKeSA7tdOyetMtBQeOJ6o2o+KZbuv +1F8gMQJDub4tQcT2Hd6yglCTQUAoYdc3sa09XV23GYRiu4LfL9Z9gXMVCUA+XfsT +SdlBZ7c/dwp9zZzwEUw0tieUok9uq0POEvnb6MYms6aB+cUsZJiOj3NQ5O3D719B +9XKH82ZPTtruiGj/9pwoGa8HV04RoLg2pHxdsbeQ8nf8EYCDo8V5VzhBSFdJ/twy +ocy6G029Gcm2Suiw8iSrhw77SJEqfxV139TxC8k8BeQOJXqwh0hNasGcpSQDdRxR +r0kE0HQt/U9cdOBrAuC8JrSG9UlxCxGRpJXPYn2EeMTv8Ljb+DS/Ovvkjrh2wvVR +Uyv0i1gAOGS+DoYxYJgxuc49yQGSqfk0jM1LCVTxxPWcAb4ykrsxuLFqNsWgeSq/ +CkkniYCcb9oA5lsnGjW2JOokNOT7Tf1jb47Lrv3J0dtmScn16ACeXSScNndjY8Zf ++3OuMEazut+LAAogCpxQQqzDgBQ1xoUlsHyj5nwzOINbCE55dJ6oCy/a3bLpmuBC +/i4i5+AW5shfPAvHOcOa8Wac6YCkOiOEGfgYQp5iqneXod8WBNs5dxpkRAEw7iIQ +Y+0Rh+y/FiV7h6cQ74ZjZSyI4txqNCUs1GMb9XnPyuFrnUao4jkLhYnbfqXEp/IP +ggKSJAQyeqvipKDNOVt0CM+d0DLsyogp61zDnDBLtb/h4k+154FFkNBZfLQosNjq +evBF87HPBzAShTWlyGd3AtTZS5nQZsVBrq2wQF8X9oJfu9k80GrMo9wgWj4NE25c +BQv22NdmHKY+/KgzrnxcBlrRXAxbTdgKLG3khFJw3lIfdgrIYG9CQkg5A/JsXUa0 +R/LCMg8qq5u9PEWJrWhDQGF7T2wbzLoGiU7ujXe220gayn5a59kfbBQaUTt6c5i4 +t2u5oyroMJSZUsou7BubhLEaTaLj5QOlipw3Vb6xtTKdlb8KB9AudA28+jVS/HlN +2b/LnbgoJ9s6F8syyWjyTihpAMRypgyPf4QQuwjQ0FWLdsZiCCjFesNyY7Y0ishx +VnMjRpQrGBL93zdLUoFmDcXKYhmO6oUvh0nOUyhwDiZg34gJMQkRoVVl4ysSnDNh +CbeSDiRBb1ewoTdvwEleGoogYCbO3YoNFDZCUfeTymNxVUrJRQdZ3PL6KmGvFJAA +fm6+7YDOc1I0D+pa0OqVJnLRV+ib04KmjGGdSdWEtbPdOMolhQjKR2BCEePhcjdr +Tm/jrDrfum66qBbcAf+EysG+P8FjXd4sCoj2rtv39cNHmsjFpqNWqOEnrVPhJQlu +MDmikc3i+F61L4LtNN/TX/rbLmWAHEKI6f/2yAmhrq9fJNP2wGnmr8CbAlRAXrmZ +pcvFtxPaXQavn6pNjDFGP1qXSMYr28FV5munVszi+O5EJGo/ntRSKDuYW8UARYq4 +Gp+ez8ey9PREiLu9GAKGCGhWSqPcbGX8OhbTO/W9AYsIw4//Wj7lhEelowcwaIQG +iIGj+Rnni6XR6ixi/fItCoJJSN9O1ZIOBaCCKsEotQhnA8mtmMrjdSp+guxMg5d6 +bGlFXoU8A3/bQPvdGMo0HGeqRhMLIYbrvU4u3iEwyTYD4dtpS9t6/xq8mt6QDpJF +UKcNQlgLscVUBQw+Sni72hLADEbFa86QFg2X6lU+EfHLXcDjpsosj+4odicf8IoH +Y+twu7J4p4q2BGvUc2B2s4Q01sviqax99wauDC6x0p/8gRbrjTMVY4Se39xGWsvc +gYJYNMD4U0GWh4qw4I8W10HP1Vs2Qa0oV7WvWSq9OaAcJ1SRsjdKmRIEFa7m7JkS +C9mxsDkepiN/BIs22V4kiEDCA6J78e3R+It2x/UtvoqIxx3UxoQlQMo4KBcNZ/OI +wg00B7lCftuR9RajbpqpcZCx5p+NRY+N+LMcvOgOBHK3CzC1WN3E40xFL9yn+fKo +99MW3mB6wEsw1l5ph7iE+SEYeSxScVzCLEQaqNUK+U/+B1RBwQanKEy3zT3tG3Nw +mF5IYiKgvcWWd0ISjGVWD6bQc6yFUWqMjTi23ZaGFrHoAwqMUcZSCPdGzJ4QETJ4 +2yxG1pMtAxpBQm85hdWloDYA3kmL/StmJH928UlGNIxYhiyd9si5QbONjbRFelfO +hSiOh/bU8AjMxuC2Js+B/24XhsZ8StmsxihUajcgKrHLPtGuKyOX5qF+onIONSzG +Jhnhn1VS6WBW0HXXuiErt/GZD9LPPsDpMTB3PyGYvNZwmPKxXywRj8XISJNSn/6/ +4kzlPjLmI+i8z+7yflSWLVtw0APxHNn9QHP+Wp8vUYYMycTw+n23787gVI/zvB6L +zp019sRM0lDuPQ89Ai0vDOteouggYIxzjxflfrjIMePw5+ZJNLDjxdWnwmXvB8oC +BQND9ciYAFtXNnc+1rUEAskXaKAipTlvwEPg9ei5+U63biI15AETBVwDZthwUYvC +1QL1G6NcXdUgCHEev7vEPM35d63OhtbYGjAYinMH42Y88scHbCgIcgvYl9SydkOy +4X7tK7MFHJ22G6aV4XM+XPzoOLSqaB5Iz9PBSXjU5AC3wzFtAJzyGMGJROnIEpXG +nUjo39JRDeVXhHlZSKYda2cthHeyd/EoJjBjR0vJRluKn0gBNy3I3XzE2S1B00xm +XMMTBsoJwScqpGSr0TdAHUVa3If+5QdIs4okbtXPiT9N0F2Fe183enUQJnb2l6zT +bvGY2PGHFfRhebfygXaxNbeEz6DkHXGxIj07gJl6X5eDh0/clpzBLA91xRSWorf6 +/w52wWTUryG/sseFqHjuczVx9HMlqqs6ZBFXSG8p3pUzzyyaRT0T0HlUk8JBYHXv +cdsrBnzTqj7ZkFMJim3ZeZU1CJ6/A+AuU1Gdwuu1mLNpvT63+RpLj9mDDoHnsUIe +1JNijHwdYlF8vucmnT9N5KXc1t/ttxnlbJWbNVMDCaacREi3IGIdF/QVxdBf76iZ +ORvS40RITFLenZTjfWE4HlZQR36xHb0DdiFdeM+DuLBLEhHuCQCV/txMx3TAlVEp +Oep4mJvP0Vkq5ZVqZiQdEm/UO3vo7O+eEBFfupmb6AZwXYu/Sdf3SqOzIkbAkiek +d7jGvH0+TrTsstdqt2sH5IsnNkB+vLUxKiDjAlcute0JJK23utUu8fSUjZSMG15Q +480UFSL3HPzObC7Lcm4pRm7w/JYwhk4UfiZWAh/an24qOuvLNJVNptH/78QfGv2K +dsihyRv8PabwCikTMqiKzLPSa2ESPYLHX1oIXmF7mxp8fYrc6gUgq071ZOe9T0Dm ++hWhufsFApgfi5U4xmdTGwFFYfyqqhGFjYdTPXicQq94t134pGcJB1JXSNXOmDFO +hL3mokPqJF47FJoJLIcKl8oUxfD1gj8Nei42zjOXDS1aFb9Zc1GsRnwy+1g31tD3 +yEoj9Io7z5Pk4OWsc1DBgSFlKwITi3x6VUiZYnQ4AT1cb439dfVcNZCNuoXcuI2o +KZBw9UK04fIKMSR9vc7yEESwpZGwAwIN0wIrwqjMjk9IriPSZ6LhnlZaKz3Dz6lp +PuEMLklXxXA8Z8owmGrgNiCLNZoN7E6ODpSJMQAGn7nFwVHaZXOCj7QKfTiSHNqT +2P04q5TbvhyT7gDkXntvb4SWBIeoLPBJInMFiIUFqSx8pOeIVMCFoNI0tV+AoXoL +zRNav7i9ooSM1QBqPk1stlbxjFP6AkfSzOCJ3a+qaPkQIY33iOqJya81UOePZZQy +6EM449DmHbBdOaJXnNu90Za+jHmhemVIHgangrwb8mlLZeRGYS8rsL6OmjJaBvHT +2KY8SNnB+6UzPqfWytdGG8RT1xC68VXW3WVzfTQ9BFN2FFFTuCY+s8rDKj07Z5El +7wdBRiQQGgiVGtRolakuBGD+pFpwVYRbtAi9LmT+2zz4fPpkjeLtyfoac9L6OOiE +DlOENN8HpVb/DK+nzzDX9INIjJJXXodiEEUTHjm2SGVemQT2aByW+CCyp71Y/KcP +RKwmIRpw1r1RijuedGShaG8xdQksdBik5pTnYlet91iR766R/tB2vfEr8PUXCZ7/ +cR8Jg0Zv3YrUQ/NiYWywD+zZy50RpmTjVIIzgFCerva80jyn2kEsf/7FMQImpTWh +ZgDlGfbZmUVwyd8gHXMkuD09Itk/aonIlCyfiuMpTX72ptHvzceQ8DPeuz4oZb1i +FtckUpsDhAgn+yfQ20HOk9MdDy2SjeI4lNJxCl01o/x30vYmaETzBo03+WXTgl5D +0JG+52OQS/7q8PxBTul20WSGgTb0ZvreH2QLpxHRD/gpOvaYXXsPUhpp4tvIyEqS +7DLi0UR1VZd70/7zh8dOQlEfMWNKzrayUduw1hgAvGXWe5yrHgph40roORn4yvIA +bLOaIvAygkcVpTGkKst8K7nQ1yE21hogBWqtxe0SJHPKxJtrePLZYSDBu+DnJtPp +zbElXfV+Oyhr2ehLTD46B6iBm2ssFLFOt2ViNj9bT9X3YfFl8sV5U20jdPwR4kZ2 +V6V2cfQ8kxYqeLE/v/uRZ0wHegTLVJxbZ2bwvNegguHOu3phwnHS21nfC6UFD1wU +tMvVENzBGkGrsVEc+xCukB8gPI6O7PebNTcPY5SOHicgS2zx1HMWcTZh72wM5KCT +mXqMxr8wR/thg2870MhigaCm0AIjbJC5JbXxvhMSmqfdZSTeeCqzV/59mXACO8he +D1LLQ1J1ahpE5tf+6TCjqbsbMHqSduXk1G2hxIhx900h9SkeAJqjOqXZSwg8i/hj +Wwvs25yBve3tuGNkr6M5z6PoayYopiIo705B0y0AVhRJftSczUOERs603BJsVIwr +6FcdCh6WU/V+rkwCWk9gDGXEGUS61lDwNfJewF1mXRacuP76/X3zheg6fjJ2K6Mc +KsvNo+ap1DU4koB80INqkMC+FUKElRGqgdiJ1BsWfBW9U4gIiV4N6BWVZN/6fU2M +Qa39w8UEj1iZ05TDQ0JrzJEY/WVjUWqYh4MTa0SSYF4b18gNTKYw5pJ7Ff6z6jlT +tpNnzRf+kwfhT041zRDeuB3FdjKpIaIvakPxLEdvz4BVEM3Xbsi7c8G4/DndhC6f +3SSq0QC8T77kWDjw6m7/ZGYplAsrbtqFTd2MllkH1KRj8wfk57ZuDOUsV7ShplXI +RaATN0DicTbbsMWTHBw+/6Z3tc6PET4VFDHvBVWBSo+yEBzruhKnbhtxVJced44b +Hpht1opiAhikvkhUJJUYZQ9+QfRQwFsyR6XlW07xArCWkjg6PJlgcX39WTxbnAYR +grKgB87pp3qThnOd97cCgppj0ETJOCxEKnpSuT234IqlZcBhdhFMsB92xYMzY9Jq +wNf5JwKp1rm6k4cQldFDlQ58GzeUjQpa20625j4jIWIuZeZ5Nf6FECyBXi4cbEaA +/kCJ1kYezrPgaFt3p6JHzQ== +=5opC -----END PGP MESSAGE----- diff --git a/propellor.cabal b/propellor.cabal index b28a26d0..cc616c17 100644 --- a/propellor.cabal +++ b/propellor.cabal @@ -78,6 +78,7 @@ Library Propellor.Property.Git Propellor.Property.Gpg Propellor.Property.Network + Propellor.Property.Obnam Propellor.Property.OpenId Propellor.Property.Reboot Propellor.Property.Scheduled -- cgit v1.3-2-g0d8e From c97285a21ea0e392e8c63c1898ee2deeb34e99a0 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 02:28:40 -0400 Subject: propellor spin --- Propellor/Attr.hs | 17 ++++++++++++++ Propellor/Property/Obnam.hs | 37 ++++++++++++++++++++++-------- Propellor/Property/SiteSpecific/GitHome.hs | 6 ++--- Propellor/Property/Ssh.hs | 35 ++++++++++++++++++++++++---- Propellor/Property/User.hs | 8 +++---- Propellor/Types/Attr.hs | 5 +++- config-joey.hs | 11 +++++---- 7 files changed, 91 insertions(+), 28 deletions(-) (limited to 'Propellor') diff --git a/Propellor/Attr.hs b/Propellor/Attr.hs index 4bc1c2c7..67ea8b8c 100644 --- a/Propellor/Attr.hs +++ b/Propellor/Attr.hs @@ -8,6 +8,7 @@ import Propellor.Types.Attr import "mtl" Control.Monad.Reader import qualified Data.Set as S import qualified Data.Map as M +import Control.Applicative pureAttrProperty :: Desc -> (Attr -> Attr) -> AttrProperty pureAttrProperty desc = AttrProperty $ Property ("has " ++ desc) @@ -31,6 +32,13 @@ cnameFor domain mkp = addCName :: HostName -> Attr -> Attr addCName domain d = d { _cnames = S.insert domain (_cnames d) } +sshPubKey :: String -> AttrProperty +sshPubKey k = pureAttrProperty ("ssh pubkey known") $ + \d -> d { _sshPubKey = Just k } + +getSshPubKey :: Propellor (Maybe String) +getSshPubKey = asks _sshPubKey + hostnameless :: Attr hostnameless = newAttr (error "hostname Attr not specified") @@ -45,3 +53,12 @@ hostMap l = M.fromList $ zip (map (_hostname . hostAttr) l) l findHost :: [Host] -> HostName -> Maybe Host findHost l hn = M.lookup hn (hostMap l) + +-- | Lifts an action into a different host. +-- +-- For example, `fromHost hosts "otherhost" getSshPubKey` +fromHost :: [Host] -> HostName -> Propellor a -> Propellor (Maybe a) +fromHost l hn getter = case findHost l hn of + Nothing -> return Nothing + Just h -> liftIO $ Just <$> + runReaderT (runWithAttr getter) (hostAttr h) diff --git a/Propellor/Property/Obnam.hs b/Propellor/Property/Obnam.hs index ebdcb9dd..b7d34223 100644 --- a/Propellor/Property/Obnam.hs +++ b/Propellor/Property/Obnam.hs @@ -5,11 +5,21 @@ import qualified Propellor.Property.Apt as Apt import qualified Propellor.Property.Cron as Cron import Utility.SafeCommand +import Data.List + installed :: Property installed = Apt.installed ["obnam"] type ObnamParam = String +-- | An obnam repository can be used by multiple clients. Obnam uses +-- locking to allow only one client to write at a time. Since stale lock +-- files can prevent backups from happening, it's more robust, if you know +-- a repository has only one client, to force the lock before starting a +-- backup. Using OnlyClient allows propellor to do so when running obnam. +data NumClients = OnlyClient | MultipleClients + deriving (Eq) + -- | Installs a cron job that causes a given directory to be backed -- up, by running obnam with some parameters. -- @@ -23,25 +33,32 @@ type ObnamParam = String -- up securely. For example: -- -- > & Obnam.backup "/srv/git" "33 3 * * *" --- > [ "--repository=2318@usw-s002.rsync.net:mygitrepos.obnam" +-- > [ "--repository=sftp://2318@usw-s002.rsync.net/~/mygitrepos.obnam" -- > , "--encrypt-with=1B169BE1" --- > ] +-- > ] Obnam.OnlyClient -- > `requires` Gpg.keyImported "1B169BE1" "root" -- > `requires` Ssh.keyImported SshRsa "root" -- -- How awesome is that? -backup :: FilePath -> Cron.CronTimes -> [ObnamParam] -> Property -backup dir crontimes params = cronjob `describe` desc +backup :: FilePath -> Cron.CronTimes -> [ObnamParam] -> NumClients -> Property +backup dir crontimes params numclients = cronjob `describe` desc `requires` restored dir params - `requires` installed where desc = dir ++ " backed up by obnam" cronjob = Cron.niceJob ("obnam_backup" ++ dir) crontimes "root" "/" $ - unwords $ - [ "obnam" - , "backup" - , shellEscape dir - ] ++ map shellEscape params + intercalate ";" $ catMaybes + [ if numclients == OnlyClient + then Just $ unwords $ + [ "obnam" + , "force-lock" + ] ++ map shellEscape params + else Nothing + , Just $ unwords $ + [ "obnam" + , "backup" + , shellEscape dir + ] ++ map shellEscape params + ] -- | Restores a directory from an obnam backup. -- diff --git a/Propellor/Property/SiteSpecific/GitHome.hs b/Propellor/Property/SiteSpecific/GitHome.hs index 1ba56b94..ee46a9e4 100644 --- a/Propellor/Property/SiteSpecific/GitHome.hs +++ b/Propellor/Property/SiteSpecific/GitHome.hs @@ -11,8 +11,7 @@ installedFor user = check (not <$> hasGitDir user) $ Property ("githome " ++ user) (go =<< liftIO (homedir user)) `requires` Apt.installed ["git"] where - go Nothing = noChange - go (Just home) = do + go home = do let tmpdir = home "githome" ensureProperty $ combineProperties "githome setup" [ userScriptProperty user ["git clone " ++ url ++ " " ++ tmpdir] @@ -32,5 +31,4 @@ url = "git://git.kitenet.net/joey/home" hasGitDir :: UserName -> IO Bool hasGitDir user = go =<< homedir user where - go Nothing = return False - go (Just home) = doesDirectoryExist (home ".git") + go home = doesDirectoryExist (home ".git") diff --git a/Propellor/Property/Ssh.hs b/Propellor/Property/Ssh.hs index 51649fd9..009511dd 100644 --- a/Propellor/Property/Ssh.hs +++ b/Propellor/Property/Ssh.hs @@ -5,7 +5,8 @@ module Propellor.Property.Ssh ( hasAuthorizedKeys, restartSshd, uniqueHostKeys, - keyImported + keyImported, + knownHost, ) where import Propellor @@ -39,12 +40,20 @@ permitRootLogin = setSshdConfig "PermitRootLogin" passwordAuthentication :: Bool -> Property passwordAuthentication = setSshdConfig "PasswordAuthentication" +dotDir :: UserName -> IO FilePath +dotDir user = do + h <- homedir user + return $ h ".ssh" + +dotFile :: FilePath -> UserName -> IO FilePath +dotFile f user = do + d <- dotDir user + return $ d f + hasAuthorizedKeys :: UserName -> IO Bool -hasAuthorizedKeys = go <=< homedir +hasAuthorizedKeys = go <=< dotFile "authorized_keys" where - go Nothing = return False - go (Just home) = not . null <$> catchDefaultIO "" - (readFile $ home ".ssh" "authorized_keys") + go f = not . null <$> catchDefaultIO "" (readFile f) restartSshd :: Property restartSshd = cmdProperty "service" ["ssh", "restart"] @@ -87,3 +96,19 @@ keyImported keytype user = propertyList desc SshRsa -> "rsa" SshDsa -> "dsa" ++ ext + +-- | Puts some host's ssh public key into the known_hosts file for a user. +knownHost :: [Host] -> HostName -> UserName -> Property +knownHost hosts hn user = Property desc $ + go =<< fromHost hosts hn getSshPubKey + where + desc = user ++ " knows ssh key for " ++ hn + go (Just (Just k)) = do + f <- liftIO $ dotFile "known_hosts" user + ensureProperty $ propertyList desc + [ File.dirExists (takeDirectory f) + , f `File.containsLine` (hn ++ " " ++ k) + ] + go _ = do + warningMessage $ "no configred sshPubKey for " ++ hn + return FailedChange diff --git a/Propellor/Property/User.hs b/Propellor/Property/User.hs index 9d948834..8e7afd81 100644 --- a/Propellor/Property/User.hs +++ b/Propellor/Property/User.hs @@ -7,7 +7,7 @@ import Propellor data Eep = YesReallyDeleteHome accountFor :: UserName -> Property -accountFor user = check (isNothing <$> homedir user) $ cmdProperty "adduser" +accountFor user = check (isNothing <$> catchMaybeIO (homedir user)) $ cmdProperty "adduser" [ "--disabled-password" , "--gecos", "" , user @@ -16,7 +16,7 @@ accountFor user = check (isNothing <$> homedir user) $ cmdProperty "adduser" -- | Removes user home directory!! Use with caution. nuked :: UserName -> Eep -> Property -nuked user _ = check (isJust <$> homedir user) $ cmdProperty "userdel" +nuked user _ = check (isJust <$> catchMaybeIO (homedir user)) $ cmdProperty "userdel" [ "-r" , user ] @@ -57,5 +57,5 @@ getPasswordStatus user = parse . words <$> readProcess "passwd" ["-S", user] isLockedPassword :: UserName -> IO Bool isLockedPassword user = (== LockedPassword) <$> getPasswordStatus user -homedir :: UserName -> IO (Maybe FilePath) -homedir user = catchMaybeIO $ homeDirectory <$> getUserEntryForName user +homedir :: UserName -> IO FilePath +homedir user = homeDirectory <$> getUserEntryForName user diff --git a/Propellor/Types/Attr.hs b/Propellor/Types/Attr.hs index c253e32b..cdbe9ca3 100644 --- a/Propellor/Types/Attr.hs +++ b/Propellor/Types/Attr.hs @@ -6,6 +6,7 @@ import qualified Data.Set as S data Attr = Attr { _hostname :: HostName , _cnames :: S.Set Domain + , _sshPubKey :: Maybe String , _dockerImage :: Maybe String , _dockerRunParams :: [HostName -> String] @@ -15,6 +16,7 @@ instance Eq Attr where x == y = and [ _hostname x == _hostname y , _cnames x == _cnames y + , _sshPubKey x == _sshPubKey y , _dockerImage x == _dockerImage y , let simpl v = map (\a -> a "") (_dockerRunParams v) @@ -25,12 +27,13 @@ instance Show Attr where show a = unlines [ "hostname " ++ _hostname a , "cnames " ++ show (_cnames a) + , "sshPubKey " ++ show (_sshPubKey a) , "docker image " ++ show (_dockerImage a) , "docker run params " ++ show (map (\mk -> mk "") (_dockerRunParams a)) ] newAttr :: HostName -> Attr -newAttr hn = Attr hn S.empty Nothing [] +newAttr hn = Attr hn S.empty Nothing Nothing [] type HostName = String type Domain = String diff --git a/config-joey.hs b/config-joey.hs index a983e87b..e66df10a 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -74,13 +74,12 @@ hosts = & Git.daemonRunning "/srv/git" & File.ownerGroup "/srv/git" "joey" "joey" & Obnam.backup "/srv/git" "33 3 * * *" - [ "--repository=2318@usw-s002.rsync.net:git.kitenet.net" + [ "--repository=sftp://2318@usw-s002.rsync.net/~/git.kitenet.net.obnam" , "--encrypt-with=1B169BE1" - ] + ] Obnam.OnlyClient `requires` Gpg.keyImported "1B169BE1" "root" `requires` Ssh.keyImported SshRsa "root" - - -- git repos restore (how?) (also make backups!) + `requires` Ssh.knownHost hosts "usw-s002.rsync.net" "root" -- family annex needs family members to have accounts, -- ssh host key etc.. finesse? -- (also should upgrade git-annex-shell for it..) @@ -89,6 +88,10 @@ hosts = -- gitweb -- downloads.kitenet.net setup (including ssh key to turtle) + -- I don't run this system, but tell propellor its public key. + , host "usw-s002.rsync.net" + & sshPubKey "ssh-dss AAAAB3NzaC1kc3MAAAEBAI6ZsoW8a+Zl6NqUf9a4xXSMcV1akJHDEKKBzlI2YZo9gb9YoCf5p9oby8THUSgfh4kse7LJeY7Nb64NR6Y/X7I2/QzbE1HGGl5mMwB6LeUcJ74T3TQAlNEZkGt/MOIVLolJHk049hC09zLpkUDtX8K0t1yaCirC9SxDGLTCLEhvU9+vVdVrdQlKZ9wpLUNbdAzvbra+O/IVvExxDZ9WCHrnfNA8ddVZIGEWMqsoNgiuCxiXpi8qL+noghsSQNFTXwo7W2Vp9zj1JkCt3GtSz5IzEpARQaXEAWNEM0n1nJ686YUOhou64iRM8bPC1lp3QXvvZNgj3m+QHhIempx+de8AAAAVAKB5vUDaZOg14gRn7Bp81ja/ik+RAAABACPH/bPbW912x1NxNiikzGR6clLh+bLpIp8Qie3J7DwOr8oC1QOKjNDK+UgQ7mDQEgr4nGjNKSvpDi4c1QCw4sbLqQgx1y2VhT0SmUPHf5NQFldRQyR/jcevSSwOBxszz3aq9AwHiv9OWaO3XY18suXPouiuPTpIcZwc2BLDNHFnDURQeGEtmgqj6gZLIkTY0iw7q9Tj5FOyl4AkvEJC5B4CSzaWgey93Wqn1Imt7KI8+H9lApMKziVL1q+K7xAuNkGmx5YOSNlE6rKAPtsIPHZGxR7dch0GURv2jhh0NQYvBRn3ukCjuIO5gx56HLgilq59/o50zZ4NcT7iASF76TcAAAEAC6YxX7rrs8pp13W4YGiJHwFvIO1yXLGOdqu66JM0plO4J1ItV1AQcazOXLiliny3p2/W+wXZZKd5HIRt52YafCA8YNyMk/sF7JcTR4d4z9CfKaAxh0UpzKiAk+0j/Wu3iPoTOsyt7N0j1+dIyrFodY2sKKuBMT4TQ0yqQpbC+IDQv2i1IlZAPneYGfd5MIGygs2QMfaMQ1jWAKJvEO0vstZ7GB6nDAcg4in3ZiBHtomx3PL5w+zg48S4Ed69BiFXLZ1f6MnjpUOP75pD4MP6toS0rgK9b93xCrEQLgm4oD/7TCHHBo2xR7wwcsN2OddtwWsEM2QgOkt/jdCAoVCqwQ==" + --' __|II| ,. ---- __|II|II|__ ( \_,/\ ------'\o/-'-.-'-.-'-.- __|II|II|II|II|___/ __/ -'-.-'-.-'-.-'-.-'- -- cgit v1.3-2-g0d8e From 00993a11fdfa06726a2e1711004a750bbd362227 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 03:09:00 -0400 Subject: propellor spin --- Propellor/Property/Ssh.hs | 54 +++++++++++++++++++++++++++++++++++------------ Propellor/Types.hs | 1 + config-joey.hs | 20 +++++++++++------- 3 files changed, 53 insertions(+), 22 deletions(-) (limited to 'Propellor') diff --git a/Propellor/Property/Ssh.hs b/Propellor/Property/Ssh.hs index 009511dd..51bb7c14 100644 --- a/Propellor/Property/Ssh.hs +++ b/Propellor/Property/Ssh.hs @@ -4,9 +4,11 @@ module Propellor.Property.Ssh ( passwordAuthentication, hasAuthorizedKeys, restartSshd, - uniqueHostKeys, + randomHostKeys, + hostKey, keyImported, knownHost, + authorizedKeys ) where import Propellor @@ -61,11 +63,11 @@ restartSshd = cmdProperty "service" ["ssh", "restart"] -- | Blows away existing host keys and make new ones. -- Useful for systems installed from an image that might reuse host keys. -- A flag file is used to only ever do this once. -uniqueHostKeys :: Property -uniqueHostKeys = flagFile prop "/etc/ssh/.unique_host_keys" +randomHostKeys :: Property +randomHostKeys = flagFile prop "/etc/ssh/.unique_host_keys" `onChange` restartSshd where - prop = Property "ssh unique host keys" $ do + prop = Property "ssh random host keys" $ do void $ liftIO $ boolSystem "sh" [ Param "-c" , Param "rm -f /etc/ssh/ssh_host_*" @@ -74,28 +76,44 @@ uniqueHostKeys = flagFile prop "/etc/ssh/.unique_host_keys" cmdProperty "/var/lib/dpkg/info/openssh-server.postinst" ["configure"] --- | Sets up a user with a ssh private key from the site's privdata. +-- | Sets ssh host keys from the site's PrivData. +-- +-- (Uses a null username for host keys.) +hostKey :: SshKeyType -> Property +hostKey keytype = propertyList desc + [ Property desc (install writeFile (SshPubKey keytype "") ".pub") + , Property desc (install writeFileProtected (SshPrivKey keytype "") "") + ] + where + desc = "known ssh host key" + install writer p ext = withPrivData p $ \key -> do + let f = "/etc/ssh/ssh_host_" ++ fromKeyType keytype ++ "key" ++ ext + void $ liftIO $ writer f key + noChange + +-- | Sets up a user with a ssh private key and public key pair +-- from the site's PrivData. keyImported :: SshKeyType -> UserName -> Property keyImported keytype user = propertyList desc - [ Property desc (install (SshPubKey keytype user) ".pub") - , Property desc (install (SshPrivKey keytype user) "") + [ Property desc (install writeFile (SshPubKey keytype user) ".pub") + , Property desc (install writeFileProtected (SshPrivKey keytype user) "") ] where desc = user ++ " has ssh key" - install p ext = do + install writer p ext = do f <- liftIO $ keyfile ext ifM (liftIO $ doesFileExist f) ( noChange , withPrivData p $ \key -> makeChange $ - writeFileProtected f key + writer f key ) keyfile ext = do home <- homeDirectory <$> getUserEntryForName user - return $ home ".ssh" "id_" - ++ case keytype of - SshRsa -> "rsa" - SshDsa -> "dsa" - ++ ext + return $ home ".ssh" "id_" ++ fromKeyType keytype ++ ext + +fromKeyType :: SshKeyType -> String +fromKeyType SshRsa = "rsa" +fromKeyType SshDsa = "dsa" -- | Puts some host's ssh public key into the known_hosts file for a user. knownHost :: [Host] -> HostName -> UserName -> Property @@ -112,3 +130,11 @@ knownHost hosts hn user = Property desc $ go _ = do warningMessage $ "no configred sshPubKey for " ++ hn return FailedChange + +-- | Makes a user have authorized_keys from the PrivData +authorizedKeys :: UserName -> Property +authorizedKeys user = Property (user ++ " has authorized_keys") $ + withPrivData (SshAuthorizedKeys user) $ \v -> liftIO $ do + f <- liftIO $ dotFile "authorized_keys" user + writeFileProtected f v + return NoChange diff --git a/Propellor/Types.hs b/Propellor/Types.hs index 86c56a28..dd66eb01 100644 --- a/Propellor/Types.hs +++ b/Propellor/Types.hs @@ -166,6 +166,7 @@ data PrivDataField = DockerAuthentication | SshPubKey SshKeyType UserName | SshPrivKey SshKeyType UserName + | SshAuthorizedKeys UserName | Password UserName | PrivFile FilePath | GpgKey GpgKeyId diff --git a/config-joey.hs b/config-joey.hs index e66df10a..ff8c1332 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -69,10 +69,10 @@ hosts = & Apt.serviceInstalledRunning "ntp" & Dns.zones myDnsSecondary & Apt.serviceInstalledRunning "apache2" - & Apt.installed ["git", "git-annex", "rsync"] - & Apt.buildDep ["git-annex"] `period` Daily - & Git.daemonRunning "/srv/git" - & File.ownerGroup "/srv/git" "joey" "joey" + + & cname "git.kitenet.net" + & Ssh.hostKey SshDsa + & Ssh.hostKey SshRsa & Obnam.backup "/srv/git" "33 3 * * *" [ "--repository=sftp://2318@usw-s002.rsync.net/~/git.kitenet.net.obnam" , "--encrypt-with=1B169BE1" @@ -80,13 +80,17 @@ hosts = `requires` Gpg.keyImported "1B169BE1" "root" `requires` Ssh.keyImported SshRsa "root" `requires` Ssh.knownHost hosts "usw-s002.rsync.net" "root" - -- family annex needs family members to have accounts, - -- ssh host key etc.. finesse? - -- (also should upgrade git-annex-shell for it..) + `requires` Ssh.authorizedKeys "family" + `requires` User.accountFor "family" + & Apt.installed ["git", "git-annex", "rsync"] + & Git.daemonRunning "/srv/git" + -- copy wren's ssh host key + -- TODO: upgrade to newer git-annex-shell for notification -- kgb installation and setup -- ssh keys for branchable and github repo hooks -- gitweb -- downloads.kitenet.net setup (including ssh key to turtle) + & Apt.buildDep ["git-annex"] `period` Daily -- I don't run this system, but tell propellor its public key. , host "usw-s002.rsync.net" @@ -184,7 +188,7 @@ image _ = "debian-stable-official" -- does not currently exist! cleanCloudAtCost :: Property cleanCloudAtCost = propertyList "cloudatcost cleanup" [ Hostname.sane - , Ssh.uniqueHostKeys + , Ssh.randomHostKeys , "worked around grub/lvm boot bug #743126" ==> "/etc/default/grub" `File.containsLine` "GRUB_DISABLE_LINUX_UUID=true" `onChange` cmdProperty "update-grub" [] -- cgit v1.3-2-g0d8e From 427246db6a6dc1d626297cf0af6f372a3c75486f Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 03:21:02 -0400 Subject: propellor spin --- Propellor/Property/Ssh.hs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'Propellor') diff --git a/Propellor/Property/Ssh.hs b/Propellor/Property/Ssh.hs index 51bb7c14..426e286e 100644 --- a/Propellor/Property/Ssh.hs +++ b/Propellor/Property/Ssh.hs @@ -85,7 +85,7 @@ hostKey keytype = propertyList desc , Property desc (install writeFileProtected (SshPrivKey keytype "") "") ] where - desc = "known ssh host key" + desc = "known ssh host key (" ++ fromKeyType keytype ++ ")" install writer p ext = withPrivData p $ \key -> do let f = "/etc/ssh/ssh_host_" ++ fromKeyType keytype ++ "key" ++ ext void $ liftIO $ writer f key @@ -99,7 +99,7 @@ keyImported keytype user = propertyList desc , Property desc (install writeFileProtected (SshPrivKey keytype user) "") ] where - desc = user ++ " has ssh key" + desc = user ++ " has ssh key (" ++ fromKeyType keytype ++ ")" install writer p ext = do f <- liftIO $ keyfile ext ifM (liftIO $ doesFileExist f) @@ -136,5 +136,6 @@ authorizedKeys :: UserName -> Property authorizedKeys user = Property (user ++ " has authorized_keys") $ withPrivData (SshAuthorizedKeys user) $ \v -> liftIO $ do f <- liftIO $ dotFile "authorized_keys" user + createDirectoryIfMissing True (takeDirectory f) writeFileProtected f v return NoChange -- cgit v1.3-2-g0d8e From 756d5754a9dd3d9e90bdbf03916820bd26f61db7 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 03:28:53 -0400 Subject: propellor spin --- Propellor/Property/Ssh.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Propellor') diff --git a/Propellor/Property/Ssh.hs b/Propellor/Property/Ssh.hs index 426e286e..ba23253d 100644 --- a/Propellor/Property/Ssh.hs +++ b/Propellor/Property/Ssh.hs @@ -87,7 +87,7 @@ hostKey keytype = propertyList desc where desc = "known ssh host key (" ++ fromKeyType keytype ++ ")" install writer p ext = withPrivData p $ \key -> do - let f = "/etc/ssh/ssh_host_" ++ fromKeyType keytype ++ "key" ++ ext + let f = "/etc/ssh/ssh_host_" ++ fromKeyType keytype ++ "_key" ++ ext void $ liftIO $ writer f key noChange @@ -123,7 +123,7 @@ knownHost hosts hn user = Property desc $ desc = user ++ " knows ssh key for " ++ hn go (Just (Just k)) = do f <- liftIO $ dotFile "known_hosts" user - ensureProperty $ propertyList desc + ensureProperty $ combineProperties desc [ File.dirExists (takeDirectory f) , f `File.containsLine` (hn ++ " " ++ k) ] -- cgit v1.3-2-g0d8e From 622a3d8a931979deec838f06f7fb0311adf40df6 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 03:49:24 -0400 Subject: propellor spin --- Propellor/Property/Ssh.hs | 7 +++++-- config-joey.hs | 5 +++-- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'Propellor') diff --git a/Propellor/Property/Ssh.hs b/Propellor/Property/Ssh.hs index ba23253d..2fc3c560 100644 --- a/Propellor/Property/Ssh.hs +++ b/Propellor/Property/Ssh.hs @@ -84,12 +84,15 @@ hostKey keytype = propertyList desc [ Property desc (install writeFile (SshPubKey keytype "") ".pub") , Property desc (install writeFileProtected (SshPrivKey keytype "") "") ] + `onChange` restartSshd where desc = "known ssh host key (" ++ fromKeyType keytype ++ ")" install writer p ext = withPrivData p $ \key -> do let f = "/etc/ssh/ssh_host_" ++ fromKeyType keytype ++ "_key" ++ ext - void $ liftIO $ writer f key - noChange + s <- liftIO $ readFileStrict f + if s == key + then noChange + else makeChange $ writer f key -- | Sets up a user with a ssh private key and public key pair -- from the site's PrivData. diff --git a/config-joey.hs b/config-joey.hs index dd454040..394881b4 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -74,7 +74,7 @@ hosts = & Ssh.hostKey SshDsa & Ssh.hostKey SshRsa & Obnam.backup "/srv/git" "33 3 * * *" - [ "--repository=sftp://2318@usw-s002.rsync.net/~/git.kitenet.net.obnam" + [ "--repository=sftp://2318@usw-s002.rsync.net/~/git.kitenet.net" , "--encrypt-with=1B169BE1" , "--client-name=wren" ] Obnam.OnlyClient @@ -93,7 +93,8 @@ hosts = -- downloads.kitenet.net setup (including ssh key to turtle) & Apt.buildDep ["git-annex"] `period` Daily - -- I don't run this system, but tell propellor its public key. + -- I don't run this system, so only relevant property is its + -- public key. , host "usw-s002.rsync.net" & sshPubKey "ssh-dss AAAAB3NzaC1kc3MAAAEBAI6ZsoW8a+Zl6NqUf9a4xXSMcV1akJHDEKKBzlI2YZo9gb9YoCf5p9oby8THUSgfh4kse7LJeY7Nb64NR6Y/X7I2/QzbE1HGGl5mMwB6LeUcJ74T3TQAlNEZkGt/MOIVLolJHk049hC09zLpkUDtX8K0t1yaCirC9SxDGLTCLEhvU9+vVdVrdQlKZ9wpLUNbdAzvbra+O/IVvExxDZ9WCHrnfNA8ddVZIGEWMqsoNgiuCxiXpi8qL+noghsSQNFTXwo7W2Vp9zj1JkCt3GtSz5IzEpARQaXEAWNEM0n1nJ686YUOhou64iRM8bPC1lp3QXvvZNgj3m+QHhIempx+de8AAAAVAKB5vUDaZOg14gRn7Bp81ja/ik+RAAABACPH/bPbW912x1NxNiikzGR6clLh+bLpIp8Qie3J7DwOr8oC1QOKjNDK+UgQ7mDQEgr4nGjNKSvpDi4c1QCw4sbLqQgx1y2VhT0SmUPHf5NQFldRQyR/jcevSSwOBxszz3aq9AwHiv9OWaO3XY18suXPouiuPTpIcZwc2BLDNHFnDURQeGEtmgqj6gZLIkTY0iw7q9Tj5FOyl4AkvEJC5B4CSzaWgey93Wqn1Imt7KI8+H9lApMKziVL1q+K7xAuNkGmx5YOSNlE6rKAPtsIPHZGxR7dch0GURv2jhh0NQYvBRn3ukCjuIO5gx56HLgilq59/o50zZ4NcT7iASF76TcAAAEAC6YxX7rrs8pp13W4YGiJHwFvIO1yXLGOdqu66JM0plO4J1ItV1AQcazOXLiliny3p2/W+wXZZKd5HIRt52YafCA8YNyMk/sF7JcTR4d4z9CfKaAxh0UpzKiAk+0j/Wu3iPoTOsyt7N0j1+dIyrFodY2sKKuBMT4TQ0yqQpbC+IDQv2i1IlZAPneYGfd5MIGygs2QMfaMQ1jWAKJvEO0vstZ7GB6nDAcg4in3ZiBHtomx3PL5w+zg48S4Ed69BiFXLZ1f6MnjpUOP75pD4MP6toS0rgK9b93xCrEQLgm4oD/7TCHHBo2xR7wwcsN2OddtwWsEM2QgOkt/jdCAoVCqwQ==" -- cgit v1.3-2-g0d8e From 6d1263043112d0c70ae8d76fcbc998e6d853fafa Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 11:14:43 -0400 Subject: propellor spin --- Propellor/Property/Obnam.hs | 4 +++- Propellor/Property/Ssh.hs | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'Propellor') diff --git a/Propellor/Property/Obnam.hs b/Propellor/Property/Obnam.hs index b7d34223..00e0bbef 100644 --- a/Propellor/Property/Obnam.hs +++ b/Propellor/Property/Obnam.hs @@ -72,7 +72,9 @@ restored dir params = Property (dir ++ " restored by obnam") go `requires` installed where go = ifM (liftIO needsRestore) - ( liftIO restore + ( do + warningMessage $ dir ++ " is empty/missing; restoring from backup ..." + liftIO restore , noChange ) diff --git a/Propellor/Property/Ssh.hs b/Propellor/Property/Ssh.hs index 2fc3c560..cb3b9231 100644 --- a/Propellor/Property/Ssh.hs +++ b/Propellor/Property/Ssh.hs @@ -80,7 +80,7 @@ randomHostKeys = flagFile prop "/etc/ssh/.unique_host_keys" -- -- (Uses a null username for host keys.) hostKey :: SshKeyType -> Property -hostKey keytype = propertyList desc +hostKey keytype = combineProperties desc [ Property desc (install writeFile (SshPubKey keytype "") ".pub") , Property desc (install writeFileProtected (SshPrivKey keytype "") "") ] @@ -97,7 +97,7 @@ hostKey keytype = propertyList desc -- | Sets up a user with a ssh private key and public key pair -- from the site's PrivData. keyImported :: SshKeyType -> UserName -> Property -keyImported keytype user = propertyList desc +keyImported keytype user = combineProperties desc [ Property desc (install writeFile (SshPubKey keytype user) ".pub") , Property desc (install writeFileProtected (SshPrivKey keytype user) "") ] -- cgit v1.3-2-g0d8e From 456dd534ce2984535a9fc36bad2aff9e6ee2863a Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 11:58:22 -0400 Subject: propellor spin --- Propellor/Property/File.hs | 34 ++-- Propellor/Property/OpenId.hs | 13 +- Propellor/Property/Ssh.hs | 1 + Propellor/Types.hs | 2 +- config-joey.hs | 16 +- privdata/diatom.kitenet.net.gpg | 335 ++++++++++++++++++++-------------------- 6 files changed, 219 insertions(+), 182 deletions(-) (limited to 'Propellor') diff --git a/Propellor/Property/File.hs b/Propellor/Property/File.hs index 10dee75e..d8caf366 100644 --- a/Propellor/Property/File.hs +++ b/Propellor/Property/File.hs @@ -1,8 +1,10 @@ module Propellor.Property.File where import Propellor +import Utility.FileMode import System.Posix.Files +import System.PosixCompat.Types type Line = String @@ -12,11 +14,15 @@ f `hasContent` newcontent = fileProperty ("replace " ++ f) (\_oldcontent -> newcontent) f -- | Ensures a file has contents that comes from PrivData. --- Note: Does not do anything with the permissions of the file to prevent --- it from being seen. +-- +-- The file's permissions are preserved if the file already existed. +-- Otherwise, they're set to 600. hasPrivContent :: FilePath -> Property -hasPrivContent f = Property ("privcontent " ++ f) $ - withPrivData (PrivFile f) (\v -> ensureProperty $ f `hasContent` lines v) +hasPrivContent f = Property desc $ withPrivData (PrivFile f) $ \privcontent -> + ensureProperty $ fileProperty' writeFileProtected desc + (\_oldcontent -> lines privcontent) f + where + desc = "privcontent " ++ f -- | Ensures that a line is present in a file, adding it to the end if not. containsLine :: FilePath -> Line -> Property @@ -38,7 +44,9 @@ notPresent f = check (doesFileExist f) $ Property (f ++ " not present") $ makeChange $ nukeFile f fileProperty :: Desc -> ([Line] -> [Line]) -> FilePath -> Property -fileProperty desc a f = Property desc $ go =<< liftIO (doesFileExist f) +fileProperty = fileProperty' writeFile +fileProperty' :: (FilePath -> String -> IO ()) -> Desc -> ([Line] -> [Line]) -> FilePath -> Property +fileProperty' writer desc a f = Property desc $ go =<< liftIO (doesFileExist f) where go True = do ls <- liftIO $ lines <$> readFile f @@ -46,13 +54,15 @@ fileProperty desc a f = Property desc $ go =<< liftIO (doesFileExist f) if ls' == ls then noChange else makeChange $ viaTmp updatefile f (unlines ls') - go False = makeChange $ writeFile f (unlines $ a []) + go False = makeChange $ writer f (unlines $ a []) -- viaTmp makes the temp file mode 600. - -- Replicate the original file mode before moving it into place. + -- Replicate the original file's owner and mode. updatefile f' content = do - writeFile f' content - getFileStatus f >>= setFileMode f' . fileMode + writer f' content + s <- getFileStatus f + setFileMode f' (fileMode s) + setOwnerAndGroup f' (fileOwner s) (fileGroup s) -- | Ensures a directory exists. dirExists :: FilePath -> Property @@ -68,3 +78,9 @@ ownerGroup f owner group = Property (f ++ " owner " ++ og) $ do else noChange where og = owner ++ ":" ++ group + +-- | Ensures that a file/dir has the specfied mode. +mode :: FilePath -> FileMode -> Property +mode f v = Property (f ++ " mode " ++ show v) $ do + liftIO $ modifyFileMode f (\_old -> v) + noChange diff --git a/Propellor/Property/OpenId.hs b/Propellor/Property/OpenId.hs index c397bdb8..b896180f 100644 --- a/Propellor/Property/OpenId.hs +++ b/Propellor/Property/OpenId.hs @@ -4,8 +4,10 @@ import Propellor import qualified Propellor.Property.File as File import qualified Propellor.Property.Apt as Apt import qualified Propellor.Property.Service as Service +import Utility.FileMode import Data.List +import System.Posix.Files providerFor :: [UserName] -> String -> Property providerFor users baseurl = propertyList desc $ @@ -16,11 +18,18 @@ providerFor users baseurl = propertyList desc $ (map setbaseurl) "/etc/simpleid/config.inc" ] ++ map identfile users where - identfile u = File.hasPrivContent $ concat - [ "/var/lib/simpleid/identities/", u, ".identity" ] url = "http://"++baseurl++"/simpleid" desc = "openid provider " ++ url setbaseurl l | "SIMPLEID_BASE_URL" `isInfixOf` l = "define('SIMPLEID_BASE_URL', '"++url++"');" | otherwise = l + + identfile u = combineProperties desc + [ File.hasPrivContent f + -- the identitites directory controls access, so open up + -- file mode + , File.mode f (combineModes (ownerWriteMode:readModes)) + ] + where + f = concat $ [ "/var/lib/simpleid/identities/", u, ".identity" ] diff --git a/Propellor/Property/Ssh.hs b/Propellor/Property/Ssh.hs index cb3b9231..6bfe1261 100644 --- a/Propellor/Property/Ssh.hs +++ b/Propellor/Property/Ssh.hs @@ -117,6 +117,7 @@ keyImported keytype user = combineProperties desc fromKeyType :: SshKeyType -> String fromKeyType SshRsa = "rsa" fromKeyType SshDsa = "dsa" +fromKeyType SshEcdsa = "ecdsa" -- | Puts some host's ssh public key into the known_hosts file for a user. knownHost :: [Host] -> HostName -> UserName -> Property diff --git a/Propellor/Types.hs b/Propellor/Types.hs index dd66eb01..b8f8f167 100644 --- a/Propellor/Types.hs +++ b/Propellor/Types.hs @@ -174,5 +174,5 @@ data PrivDataField type GpgKeyId = String -data SshKeyType = SshRsa | SshDsa +data SshKeyType = SshRsa | SshDsa | SshEcdsa deriving (Read, Show, Ord, Eq) diff --git a/config-joey.hs b/config-joey.hs index 394881b4..71048cf3 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -73,6 +73,7 @@ hosts = & cname "git.kitenet.net" & Ssh.hostKey SshDsa & Ssh.hostKey SshRsa + & Ssh.hostKey SshEcdsa & Obnam.backup "/srv/git" "33 3 * * *" [ "--repository=sftp://2318@usw-s002.rsync.net/~/git.kitenet.net" , "--encrypt-with=1B169BE1" @@ -83,15 +84,20 @@ hosts = `requires` Ssh.knownHost hosts "usw-s002.rsync.net" "root" `requires` Ssh.authorizedKeys "family" `requires` User.accountFor "family" - & Apt.installed ["git", "git-annex", "rsync"] + & Apt.installed ["git", "git-annex", "rsync", "kgb-client"] & Git.daemonRunning "/srv/git" - -- copy wren's ssh host key - -- TODO: upgrade to newer git-annex-shell for notification - -- kgb installation and setup -- ssh keys for branchable and github repo hooks + -- TODO: upgrade to newer git-annex-shell for notification -- gitweb - -- downloads.kitenet.net setup (including ssh key to turtle) + + & cname "kgb.kitenet.net" + & Apt.serviceInstalledRunning "kbg-bot" + & File.hasPrivContent "/etc/kgb-bot/kgb.conf" + & File.hasPrivContent "/etc/kgb-bot/kgb-client.conf" + + & cname "downloads.kitenet.net" & Apt.buildDep ["git-annex"] `period` Daily + -- downloads.kitenet.net setup (including ssh key to turtle) -- I don't run this system, so only relevant property is its -- public key. diff --git a/privdata/diatom.kitenet.net.gpg b/privdata/diatom.kitenet.net.gpg index cf3c4710..d5c1c563 100644 --- a/privdata/diatom.kitenet.net.gpg +++ b/privdata/diatom.kitenet.net.gpg @@ -1,169 +1,174 @@ -----BEGIN PGP MESSAGE----- Version: GnuPG v1 -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 -INladqAQRg== -=U5Y6 +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 +=ncya -----END PGP MESSAGE----- -- cgit v1.3-2-g0d8e From 479045277b29919797cee341b11d30bbd15ab3d7 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 12:21:43 -0400 Subject: propellor spin --- Propellor/Property/File.hs | 5 +++++ Propellor/Property/OpenId.hs | 13 ++++--------- config-joey.hs | 20 ++++++++++++++------ 3 files changed, 23 insertions(+), 15 deletions(-) (limited to 'Propellor') diff --git a/Propellor/Property/File.hs b/Propellor/Property/File.hs index d8caf366..bd33c9b8 100644 --- a/Propellor/Property/File.hs +++ b/Propellor/Property/File.hs @@ -24,6 +24,11 @@ hasPrivContent f = Property desc $ withPrivData (PrivFile f) $ \privcontent -> where desc = "privcontent " ++ f +-- | Leaves the file world-readable. +hasPrivContentExposed :: FilePath -> Property +hasPrivContentExposed f = hasPrivContent f `onChange` + mode f (combineModes (ownerWriteMode:readModes)) + -- | Ensures that a line is present in a file, adding it to the end if not. containsLine :: FilePath -> Line -> Property f `containsLine` l = fileProperty (f ++ " contains:" ++ l) go f diff --git a/Propellor/Property/OpenId.hs b/Propellor/Property/OpenId.hs index b896180f..d06bf88f 100644 --- a/Propellor/Property/OpenId.hs +++ b/Propellor/Property/OpenId.hs @@ -4,7 +4,6 @@ import Propellor import qualified Propellor.Property.File as File import qualified Propellor.Property.Apt as Apt import qualified Propellor.Property.Service as Service -import Utility.FileMode import Data.List import System.Posix.Files @@ -25,11 +24,7 @@ providerFor users baseurl = propertyList desc $ "define('SIMPLEID_BASE_URL', '"++url++"');" | otherwise = l - identfile u = combineProperties desc - [ File.hasPrivContent f - -- the identitites directory controls access, so open up - -- file mode - , File.mode f (combineModes (ownerWriteMode:readModes)) - ] - where - f = concat $ [ "/var/lib/simpleid/identities/", u, ".identity" ] + -- the identitites directory controls access, so open up + -- file mode + identfile u = File.hasPrivContentExposed $ + concat $ [ "/var/lib/simpleid/identities/", u, ".identity" ] diff --git a/config-joey.hs b/config-joey.hs index 7537b10a..2245f8dd 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -85,18 +85,15 @@ hosts = `requires` Ssh.knownHost hosts "usw-s002.rsync.net" "root" `requires` Ssh.authorizedKeys "family" `requires` User.accountFor "family" - & Apt.installed ["git", "git-annex", "rsync", "kgb-client"] + & Apt.installed ["git", "git-annex", "rsync", "kgb-client-git"] & Git.daemonRunning "/srv/git" -- ssh keys for branchable and github repo hooks -- TODO: upgrade to newer git-annex-shell for notification -- gitweb & cname "kgb.kitenet.net" - & Apt.serviceInstalledRunning "kgb-bot" - & File.hasPrivContent "/etc/kgb-bot/kgb.conf" - & File.hasPrivContent "/etc/kgb-bot/kgb-client.conf" - & "/etc/default/kgb-bot" `File.containsLine` "BOT_ENABLED=1" - `onChange` Service.running "kgb-bot" + & Docker.docked hosts "kgb-server" + & File.hasPrivContentExposed "/etc/kgb-bot/kgb-client.conf" & cname "downloads.kitenet.net" & Apt.buildDep ["git-annex"] `period` Daily @@ -127,7 +124,18 @@ hosts = & Docker.publish "8081:80" & OpenId.providerFor ["joey", "liw"] "openid.kitenet.net:8081" + + -- The kgb irc bot, in a container for security and because I need + -- features not in the stable version. + , standardContainer "kgb-server" Unstable "amd64" + & Docker.publish "9999:9999" + & Apt.serviceInstalledRunning "kgb-bot" + & File.hasPrivContent "/etc/kgb-bot/kgb.conf" + & "/etc/default/kgb-bot" `File.containsLine` "BOT_ENABLED=1" + `describe` "kgb bot enabled" + `onChange` Service.running "kgb-bot" + -- Exhibit: kite's 90's website. , standardContainer "ancient-kitenet" Stable "amd64" & Docker.publish "1994:80" & Apt.serviceInstalledRunning "apache2" -- cgit v1.3-2-g0d8e From 4bcd5816d156400282e160c1ae4d5ea4b2f78bed Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 12:24:14 -0400 Subject: propellor spin --- Propellor/Property/OpenId.hs | 1 - config-joey.hs | 10 ++++++---- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'Propellor') diff --git a/Propellor/Property/OpenId.hs b/Propellor/Property/OpenId.hs index d06bf88f..4c562175 100644 --- a/Propellor/Property/OpenId.hs +++ b/Propellor/Property/OpenId.hs @@ -6,7 +6,6 @@ import qualified Propellor.Property.Apt as Apt import qualified Propellor.Property.Service as Service import Data.List -import System.Posix.Files providerFor :: [UserName] -> String -> Property providerFor users baseurl = propertyList desc $ diff --git a/config-joey.hs b/config-joey.hs index 2245f8dd..ca7a0219 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -48,6 +48,11 @@ hosts = & cname "ancient.kitenet.net" & Docker.docked hosts "ancient-kitenet" + -- I'd rather this container were on diatom, but + -- docker.io is not available in stable. + & cname "kgb.kitenet.net" + & Docker.docked hosts "kgb-server" + & Docker.garbageCollected `period` Daily & Apt.installed ["git-annex", "mtr", "screen"] @@ -86,14 +91,11 @@ hosts = `requires` Ssh.authorizedKeys "family" `requires` User.accountFor "family" & Apt.installed ["git", "git-annex", "rsync", "kgb-client-git"] + & File.hasPrivContentExposed "/etc/kgb-bot/kgb-client.conf" & Git.daemonRunning "/srv/git" -- ssh keys for branchable and github repo hooks -- TODO: upgrade to newer git-annex-shell for notification -- gitweb - - & cname "kgb.kitenet.net" - & Docker.docked hosts "kgb-server" - & File.hasPrivContentExposed "/etc/kgb-bot/kgb-client.conf" & cname "downloads.kitenet.net" & Apt.buildDep ["git-annex"] `period` Daily -- cgit v1.3-2-g0d8e From b9d2fcc432da003e2c6054a0d6bcbd7eb8457cf0 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 12:57:35 -0400 Subject: propellor spin --- Propellor/PrivData.hs | 6 ++++- privdata/clam.kitenet.net.gpg | 50 ++++++++++++++++++++++++------------------ privdata/kgb-server.docker.gpg | 27 ----------------------- 3 files changed, 34 insertions(+), 49 deletions(-) delete mode 100644 privdata/kgb-server.docker.gpg (limited to 'Propellor') diff --git a/Propellor/PrivData.hs b/Propellor/PrivData.hs index c7af1aac..ad2c8d22 100644 --- a/Propellor/PrivData.hs +++ b/Propellor/PrivData.hs @@ -8,6 +8,7 @@ import System.FilePath import System.IO import System.Directory import Data.Maybe +import Data.List import Control.Monad import "mtl" Control.Monad.Reader @@ -30,9 +31,12 @@ 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 ++ "'" + putStrLn $ "Fix this by running: propellor --set "++host'++" '" ++ show field ++ "'" return FailedChange getPrivData :: PrivDataField -> IO (Maybe String) diff --git a/privdata/clam.kitenet.net.gpg b/privdata/clam.kitenet.net.gpg index 69d8f12f..601744c4 100644 --- a/privdata/clam.kitenet.net.gpg +++ b/privdata/clam.kitenet.net.gpg @@ -1,25 +1,33 @@ -----BEGIN PGP MESSAGE----- Version: GnuPG v1 -hQIMA7ODiaEXBlRZARAAuRttWmrr3tFgQnbnaQpWxiAQToL94e0SctFiYqiEGRNa -D63/ZaBhBkvKSx57+SyOloqfBaeWM63vd4Yacocypl2zOjC4aEN7/MKyQRl+xhmk -EwQ4kFfJ3dmYrgXt7NAdIarjHsK5/Bv7PGVIrcwD3zqV+FUyuxt2L2ETG61kYo+m -xNWl1NCvHDZ1QOfvw4ldBo7+LO2odzoZAxBF0ZgQFqo/r/6RZaqFNJRLdVTLERTq -E4igjtgfq6blrpyeupKpFu6oy8/7WeBXthnyoduftk+aBTkXWzb+i30zIzNNsc4+ -GE68a5tM0XE8nGwKp4yz0AZHhEYzv+BZXI7HQMAZ+m0srVn637SDHeAgOBU8NjrA -SbZt0ubQ28Qaux7C7awLJ5SjvlQyLT61jLaN6SMcpeLmgkjRVN+eiVOE/qmXzhHv -AobUwJgBOktiN6+WtRcxq7WduNf6Jtxw8UB5gVWiEeg6o+29ZBfIKVMT/Jly4rTO -M13HbmSVzwdGcUL1D7Gf3oY2R7eS4VR8ShCQmF8aB8TXdsw4mo71HnUa7u5N4hCP -jLtJG24+f39TWWRjMQjtFXi5hkep4OG5CBViWdCWOjlfn4Kmr5zCXaunkO9cgDAd -s8UZdmALu2MPoVdcVm+KLq2JQi1jBWEqRu5krx/nSi+eRRX2/y95CKPEPqZoU+rS -wM0BzlW+pEDc7aFlcYCrWTiwO0BWT2iBmbse9/r2NyJPpuFf7GOMI2v65jXQ+avy -1r69zPdAXNgJ19Gid/q1CXCYnYLLVHqigd8XNs12ANaVvkOnBi3gAf309SIPJtCa -uFVBxNasLTMQ3Ta7v7TLa0PopdBuFqfcy9d3BBiOKqokvhWFJobaG/WhF85ercRJ -F8lse9fgo5xfrDoCFk7u9rzhHl8xKLl24thKFTDzwm+yuzXOoLq8+Km/xYuzQXZK -JCjPvIUDaCCc1E/Yeoc3RafAiOuNwnjHW15TRdlohmgXzYlTCYF491WVKQfpL2Sd -VO8Uar094M1d52Rv8/1HCTBKJ0hnK259l4dguzw4sl2BcrFPBz9SJ0f6V/eAHE0h -la5QtLdwDDRI2giMXKfmzRiRA/5kBW01YaK7tt0om6L7Ri4Rs3JAhVgjcWDtH6fI -w807PpsIHaK8r3yDJoeqUnDYOsImuNgdctQkeroPsFYmV3fu5Hb5tYDkKzm5lE0z -C6mz09PD0M5hsnqmZXaw -=UFa1 +hQIMA7ODiaEXBlRZARAAl7WWTjAAI3dGASNptUEGmpWD46DAd/0M5uyw1oS+TUJz +cCTk23jvGeV+eWB+HdVKMsd8EbDYdEbrZxeFrWqlIFq8B+PM1FQ1NEfzigPzcEzR +0Jf+fQWOtki8RIEV7dkH6M4A9oiGQVA6hvR5ShrBEtLp0YR3xGMTFFZ1CZ2khZOi +dm47gWXfbyHnFzRsBnnBBHJ8RSez+McTqP8gHc86SzC2Ey/mJv0ShYaW8an5Aetw +yRhYa5OOGbEbiN+AphZOMyitEFrUGrp1M1kidsBZjgK6bR+9GrMRRZdXzYeyTwUy +1BTXI62SaTYmBroqa4Qt1U8mTxVF+BovOlIjcnK5kKSb2Nu2fu5jRkMHJ8RIh7kJ +eaYLi0adffZrBHBApoX4A+wrpuYdPsVkK6afZ1c7ING+GUuZ4rdUzO5lwjTB9VNV +uGkW+JmCZRA19glyKhGFIom4hkwnAObhxEsuJktOMwokFk4cnzCgb21QWsQZbwdw +Pbq/qosLDsR5Yym7sfo12B5NM4HTMt7Z4ztLpaHfJpfkzDft7bQHjT4zT1kwm/NT +NEA5T5bBKy9acT3Y2yOPE0VM87wr2gMFnHqbFiX+QUQWRAUi2q76w0K7dh5TInOs +hFjMtaz7Iq6vjvQhrHdclHiIuKDF18vndFJAHl8UYVW7XkqgGSSn8runqPcG/t3S +6QEkVzrFvLBroDnG15BuOtMnqcX72WOlX/hIRSNRuHMbUNiGpGrWGiYXKryWVA91 +BLCXY9a63FWKIhJEA/Si27OEA2kjP7h2lEK/jZt1S0gRVaWqpJu+VACBkZNdLcvc +kI6f6dz99ALKlqu4EbZcmWw3D+3Gb/AsWUUwdgKkk6ZWSFzglnXQJ72MXaO2dA4B +axd7peo5qa2Aw2IINrtyDTk9QcxwzuuEbKvl20H/KHT6gGSDey+lYRQac96Iqu9x +LADL9Z8Lv0pN41tFPpq2H9Fe8Lgo9R/sFlQHOMxYNwqbNMKblRXgsmhg3bpZtFbz +TLrqkiasqbnuAej3J1HLrOnYPNXx2WHZRPqZyWTBI2Al89AzYcVMwmLE2fHXF7Ko +cjTPkPv2cvCplbO4uoMVQPHQlQNyXjXR+CJvQ0M+T2jvX69+exx4doPmcp14SM8v +cZrxUILjim3Z9rAcIn7JVu2acslVpRlv1B0ebaWbUMQDxq+rb+mivzUil1ZpJu24 +1RTlF9Sk9xwUqDoaJBUUbWDHc1wrLFzI7/P5MAzBuuGwE5BKlq0cBjzMZpZqUB4x +WCkOrz0aOwXkLqEgbHFkHVu9VuLVrDeY59DIKqEK35t9XiY99FASIJstOAly+UpX +z53lhJKM9oJSrK6FpHu425FpbuJ+kjXWI2bPDRRB2UB8wEP64IzoRlXX34QMltdH +z5NpteD80V1zWKsTHibaJ3wBEpH3iHz7ujnwV4i63uR59YeHY9JWCZ06/t8QSvvh +kYZrBTSEyuxO4FBNb36Tee+0gQO+EhAKilFFf5J91Z3rmTL22T0k/2xwNCMfBeTh +Nvc2jpzM5s5dVDbNnfCVvrj3rvBCYRIBizkjhgJK/l7/FcEYqsUZH4bl1BggOwYY +pSDXzuunt+nsWZa+xfbmS5aKUgsOdnDlu3I7fv3KKHso//7oJJbg5HefAtmEvIvu +Us7SlPjMpx82RUQnJWgmzdML9HfnXFGy+9RRxnFZh4rw72SEzDUc4cOV1KKNeuvf +Q0vxgK8H +=mBZA -----END PGP MESSAGE----- diff --git a/privdata/kgb-server.docker.gpg b/privdata/kgb-server.docker.gpg deleted file mode 100644 index f0524854..00000000 --- a/privdata/kgb-server.docker.gpg +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN PGP MESSAGE----- -Version: GnuPG v1 - -hQIMA7ODiaEXBlRZAQ//ZDYso8hN4QDNWdv1dCyC38tEVYeuPtUu2/RuGOkzKInz -BlX/aTYtuBHWjpXFWaEVJsvihhvQnJc7nvzguM6wcXPPRBgGMO3/pO9X+81YCmVQ -smqiVyCPaWHxo0X2nmGCfAxRgap/ZpbVyHbS+V0Vh+vIsDYOjz9vXupXrknEocde -6BnxgxKbqIvJUntRlhYhsi0fYkvMSzamlB2Gy7k5iZhwmu95NmTiYSQVPeuwNyYJ -uLlfvSBAFFylg8q50svT0mI4IB2ta7/0V+F5zwSMzlwJ5Jlg7sveWVbHxL274CYk -/mGovgL0CEJ9G4+SayZcb9WwqgGBUWDfBEmYCgkRuAcHM0fmSEBW5OFGzCCdiQ1s -UOeLq/QrXS0hyyD+ug4gb2pKxxXSlm8dVr7hmgD6Lmr1WCdd02equUBnWnXMmZWR -7ewjyZiR36h9SxPtSTG5SP5kinQ/9OerNclJbn/ccgwZAMJyRES9O0wDJ9fum9gY -OzNhsGT6qSgTLRemDnknJjR9pCjCT9e7XdoBnF8IlvbhLYQFuro805+ri7uDxuoP -ELItTFmr+aW12afrQDV/y0fT4701Zs4oZPgqiVmqzRAeBNljdNw13TNTC/rM19Os -GiOsckyARxxolVNA632sb7+HoKXozXVQdxqDj4jlf53/FZpkwVYhXuJOHpklQoHS -wSMBHgPqgvkS40xjLgCuiSmqnahA9l/sH3zoSw8AkSByXbGtHXMXmkTehd0Pb2zY -XbMpXQ1R8Bw3EAykjNQbyZ+c1rMkFrr+KfTPtkTWHDOlKk1WIoN1ldHJvk5dDMoj -V7mGDD0Dbi7CgQHBH044kWCw4X63gClRrr4o+u9jKx/ZyS/gBGvxwz0CGcOM2/rz -t1FpEY01L/ytGBRtZ8S2mDu/M9n4b2SL9ed4ZoV14YPoh7nJBusR23mN+n2T1Fs8 -y+A/P9/Lin+IIKFlMTJK24Z59RrS2B7MC+a0YoSfI0DmBz2DwJHRuJU8q0rWCJLk -/r4EZx8h6Z0Ndrj4w3rmJhEbiWg0rjzcuKIfHIHsEmDBHVomsECnwmj1UKfAaL2A -M75aXTyLFCHKDOsFkdoMozykRX8ut39Hm57m0VFIkl9JRaTrYy3EeE7O6XFMnPbX -uVSS/SfEXIg/S9lR8AiIQMaLOOKnIUdAmEnO7gzZwkAOCEM8iaA0DrgCTkunRUKP -BO9wremAskdHXsT69jKspjvfJckOEJ2nPDdm9nzZFxwsXizUl5EMLcTq9DjI6CrQ -d26hCheOATEQiAr/AdATxQPeAhiK1Fc5b1AmNMDsqdC7tvqEeaFeBktIfxVNgFiI -rC1Ub6M= -=t6f6 ------END PGP MESSAGE----- -- cgit v1.3-2-g0d8e From 1495db6cd103bf5f9f4635dbbfe807c7c1f39b2e Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 14:01:30 -0400 Subject: propellor spin --- Propellor/Property/Apache.hs | 28 +++++++++ Propellor/Property/File.hs | 9 ++- Propellor/Property/SiteSpecific/JoeySites.hs | 92 ++++++++++++++++++++++++++++ config-joey.hs | 38 +++--------- debian/changelog | 1 + propellor.cabal | 1 + 6 files changed, 136 insertions(+), 33 deletions(-) create mode 100644 Propellor/Property/Apache.hs (limited to 'Propellor') diff --git a/Propellor/Property/Apache.hs b/Propellor/Property/Apache.hs new file mode 100644 index 00000000..5e32b0da --- /dev/null +++ b/Propellor/Property/Apache.hs @@ -0,0 +1,28 @@ +module Propellor.Property.Apache where + +import Propellor +import qualified Propellor.Property.File as File +import qualified Propellor.Property.Apt as Apt + +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"] + disable = File.notPresent (siteCfg hn) + `onChange` cmdProperty "a2dissite" ["--quiet", hn] + +siteAvailable :: HostName -> ConfigFile -> Property +siteAvailable hn cf = siteCfg hn `File.hasContent` (comment:cf) + `describe` ("apache site available " ++ hn) + where + comment = "# deployed with propellor, do not modify" + +siteCfg :: HostName -> FilePath +siteCfg hn = "/etc/apache2/sites-available/" ++ hn ++ ".conf" + +restart :: Property +restart = cmdProperty "service" ["apache2", "restart"] diff --git a/Propellor/Property/File.hs b/Propellor/Property/File.hs index bd33c9b8..8f23dab7 100644 --- a/Propellor/Property/File.hs +++ b/Propellor/Property/File.hs @@ -31,11 +31,14 @@ hasPrivContentExposed f = hasPrivContent f `onChange` -- | Ensures that a line is present in a file, adding it to the end if not. containsLine :: FilePath -> Line -> Property -f `containsLine` l = fileProperty (f ++ " contains:" ++ l) go f +f `containsLine` l = f `containsLines` [l] + +containsLines :: FilePath -> [Line] -> Property +f `containsLines` l = fileProperty (f ++ " contains:" ++ show l) go f where go ls - | l `elem` ls = ls - | otherwise = ls++[l] + | all (`elem` ls) l = ls + | otherwise = ls++l -- | Ensures that a line is not present in a file. -- Note that the file is ensured to exist, so if it doesn't, an empty diff --git a/Propellor/Property/SiteSpecific/JoeySites.hs b/Propellor/Property/SiteSpecific/JoeySites.hs index 46373170..81557b32 100644 --- a/Propellor/Property/SiteSpecific/JoeySites.hs +++ b/Propellor/Property/SiteSpecific/JoeySites.hs @@ -5,6 +5,14 @@ module Propellor.Property.SiteSpecific.JoeySites where import Propellor import qualified Propellor.Property.Apt as Apt +import qualified Propellor.Property.File as File +import qualified Propellor.Property.Gpg as Gpg +import qualified Propellor.Property.Ssh as Ssh +import qualified Propellor.Property.Git as Git +import qualified Propellor.Property.Service as Service +import qualified Propellor.Property.User as User +import qualified Propellor.Property.Obnam as Obnam +import qualified Propellor.Property.Apache as Apache oldUseNetShellBox :: Property oldUseNetShellBox = check (not <$> Apt.isInstalled "oldusenet") $ @@ -21,3 +29,87 @@ oldUseNetShellBox = check (not <$> Apt.isInstalled "oldusenet") $ , "rm -rf /root/tmp/oldusenet" ] `describe` "olduse.net built" ] + +-- git.kitenet.net and git.joeyh.name +gitServer :: [Host] -> Property +gitServer hosts = propertyList "git.kitenet.net setup" + [ Obnam.backup "/srv/git" "33 3 * * *" + [ "--repository=sftp://2318@usw-s002.rsync.net/~/git.kitenet.net" + , "--encrypt-with=1B169BE1" + , "--client-name=wren" + ] Obnam.OnlyClient + `requires` Gpg.keyImported "1B169BE1" "root" + `requires` Ssh.keyImported SshRsa "root" + `requires` Ssh.knownHost hosts "usw-s002.rsync.net" "root" + `requires` Ssh.authorizedKeys "family" + `requires` User.accountFor "family" + , Apt.installed ["git", "git-annex", "rsync", "kgb-client-git", "gitweb"] + , File.hasPrivContentExposed "/etc/kgb-bot/kgb-client.conf" + , toProp $ Git.daemonRunning "/srv/git" + , "/etc/gitweb.conf" `File.containsLines` + [ "$projectroot = 'srv/git';" + , "@git_base_url_list = ('git://git.kitenet.net', 'http://git.kitenet.net/git', 'ssh://git.kitenet.net/srv/git');" + , "# disable snapshot download; overloads server" + , "$feature{'snapshot'}{'default'} = [];" + ] + `describe` "gitweb configured" + , 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) + +gitapacheconf :: HostName -> Apache.ConfigFile +gitapacheconf hn = + [ "" + , " ServerAdmin joey@kitenet.net" + , "" + , " ServerName " ++ hn ++ ":80" + , "" + , " DocumentRoot /srv/web/git.kitenet.net/" + , " " + , " Options Indexes ExecCGI FollowSymlinks" + , " AllowOverride None" + , " DirectoryIndex index.cgi" + , " " + , "" + , " ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/" + , " " + , " SetHandler cgi-script" + , " Options ExecCGI" + , " " + , "" + , " ErrorLog /var/log/apache2/error.log" + , " LogLevel warn" + , " CustomLog /var/log/apache2/access.log combined" + , "" + , " # Possible values include: debug, info, notice, warn, error, crit," + , " # alert, emerg." + , " LogLevel warn" + , "" + , " CustomLog /var/log/apache2/access.log combined" + , " ServerSignature On" + , " " + , " " + , " Options Indexes MultiViews" + , " AllowOverride None" + , " Order allow,deny" + , " Allow from all" + , " " + , "" + ] + +-- Note: needs debian unstable for new kgb +kgbServer :: Property +kgbServer = propertyList "kgb.kitenet.net setup" + [ Apt.serviceInstalledRunning "kgb-bot" + , File.hasPrivContent "/etc/kgb-bot/kgb.conf" + `onChange` Service.restarted "kgb-bot" + , "/etc/default/kgb-bot" `File.containsLine` "BOT_ENABLED=1" + `describe` "kgb bot enabled" + `onChange` Service.running "kgb-bot" + ] + diff --git a/config-joey.hs b/config-joey.hs index 9976592e..aba648dc 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -5,7 +5,6 @@ import Propellor.CmdLine import Propellor.Property.Scheduled import qualified Propellor.Property.File as File import qualified Propellor.Property.Apt as Apt -import qualified Propellor.Property.Service as Service import qualified Propellor.Property.Network as Network import qualified Propellor.Property.Ssh as Ssh import qualified Propellor.Property.Cron as Cron @@ -18,8 +17,6 @@ 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.Obnam as Obnam import qualified Propellor.Property.SiteSpecific.GitHome as GitHome import qualified Propellor.Property.SiteSpecific.GitAnnexBuilder as GitAnnexBuilder import qualified Propellor.Property.SiteSpecific.JoeySites as JoeySites @@ -48,15 +45,10 @@ hosts = & cname "ancient.kitenet.net" & Docker.docked hosts "ancient-kitenet" - -- I'd rather this were on diatom, but I use features - -- not available in stable. + -- I'd rather this were on diatom, but it needs unstable. & cname "kgb.kitenet.net" - & Apt.serviceInstalledRunning "kgb-bot" - & File.hasPrivContent "/etc/kgb-bot/kgb.conf" - `onChange` Service.restarted "kgb-bot" - & "/etc/default/kgb-bot" `File.containsLine` "BOT_ENABLED=1" - `describe` "kgb bot enabled" - `onChange` Service.running "kgb-bot" + & JoeySites.kgbServer + & Docker.garbageCollected `period` Daily & Apt.installed ["git-annex", "mtr", "screen"] @@ -75,31 +67,17 @@ hosts = -- Important stuff that needs not too much memory or CPU. , standardSystem "diatom.kitenet.net" Stable & Hostname.sane + & Ssh.hostKey SshDsa + & Ssh.hostKey SshRsa + & Ssh.hostKey SshEcdsa & Apt.unattendedUpgrades & Apt.serviceInstalledRunning "ntp" & Dns.zones myDnsSecondary & Apt.serviceInstalledRunning "apache2" & cname "git.kitenet.net" - & Ssh.hostKey SshDsa - & Ssh.hostKey SshRsa - & Ssh.hostKey SshEcdsa - & Obnam.backup "/srv/git" "33 3 * * *" - [ "--repository=sftp://2318@usw-s002.rsync.net/~/git.kitenet.net" - , "--encrypt-with=1B169BE1" - , "--client-name=wren" - ] Obnam.OnlyClient - `requires` Gpg.keyImported "1B169BE1" "root" - `requires` Ssh.keyImported SshRsa "root" - `requires` Ssh.knownHost hosts "usw-s002.rsync.net" "root" - `requires` Ssh.authorizedKeys "family" - `requires` User.accountFor "family" - & Apt.installed ["git", "git-annex", "rsync", "kgb-client-git"] - & File.hasPrivContentExposed "/etc/kgb-bot/kgb-client.conf" - & Git.daemonRunning "/srv/git" - -- ssh keys for branchable and github repo hooks - -- TODO: upgrade to newer git-annex-shell for notification - -- gitweb + & cname "git.joeyh.name" + & JoeySites.gitServer hosts & cname "downloads.kitenet.net" & Apt.buildDep ["git-annex"] `period` Daily diff --git a/debian/changelog b/debian/changelog index 6593c95d..b3cc554a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -3,6 +3,7 @@ propellor (0.3.1) UNRELEASED; urgency=medium * Merge scheduler bug fix from git-annex. * Support for provisioning hosts with ssh and gpg keys. * Obnam support. + * Apache support. -- Joey Hess Fri, 11 Apr 2014 15:00:11 -0400 diff --git a/propellor.cabal b/propellor.cabal index cc616c17..a7b7fbca 100644 --- a/propellor.cabal +++ b/propellor.cabal @@ -68,6 +68,7 @@ Library Exposed-Modules: Propellor Propellor.Property + Propellor.Property.Apache Propellor.Property.Apt Propellor.Property.Cmd Propellor.Property.Hostname -- 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') 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 8fb347b694378a4445106dec400bde0584593b1b Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 14:13:26 -0400 Subject: propellor spin --- Propellor/Property/SiteSpecific/JoeySites.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Propellor') diff --git a/Propellor/Property/SiteSpecific/JoeySites.hs b/Propellor/Property/SiteSpecific/JoeySites.hs index fa444160..907233bd 100644 --- a/Propellor/Property/SiteSpecific/JoeySites.hs +++ b/Propellor/Property/SiteSpecific/JoeySites.hs @@ -54,7 +54,7 @@ gitServer hosts = propertyList "git.kitenet.net setup" ] `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 + , Git.cloned "root" "/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 -- 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') 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') 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 a829889e956890e29676de6addea9e53e704eb83 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 14:21:05 -0400 Subject: propellor spin --- Propellor/CmdLine.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Propellor') diff --git a/Propellor/CmdLine.hs b/Propellor/CmdLine.hs index 5be91c4f..b58179f2 100644 --- a/Propellor/CmdLine.hs +++ b/Propellor/CmdLine.hs @@ -174,7 +174,7 @@ spin hn = do cacheparams <- toCommand <$> sshCachingParams hn go cacheparams url =<< gpgDecrypt (privDataFile hn) where - go cacheparams url privdata = withBothHandles createProcessSuccess (proc "ssh" $ cacheparams ++ [user, bootstrapcmd]) $ \(toh, fromh) -> do + go cacheparams url privdata = withBothHandles createProcessSuccess (proc "ssh" $ cacheparams ++ ["-t", user, bootstrapcmd]) $ \(toh, fromh) -> do let finish = do senddata toh (privDataFile hn) privDataMarker privdata hClose toh -- 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') 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') 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 From 0b9879942fa5d00b8329fc3ebc14563de3d9fbf8 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 14:45:18 -0400 Subject: propellor spin --- Propellor/Property/SiteSpecific/JoeySites.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Propellor') diff --git a/Propellor/Property/SiteSpecific/JoeySites.hs b/Propellor/Property/SiteSpecific/JoeySites.hs index 4b98fe0b..0594fe54 100644 --- a/Propellor/Property/SiteSpecific/JoeySites.hs +++ b/Propellor/Property/SiteSpecific/JoeySites.hs @@ -47,7 +47,7 @@ gitServer hosts = propertyList "git.kitenet.net setup" , File.hasPrivContentExposed "/etc/kgb-bot/kgb-client.conf" , toProp $ Git.daemonRunning "/srv/git" , "/etc/gitweb.conf" `File.containsLines` - [ "$projectroot = 'srv/git';" + [ "$projectroot = '/srv/git';" , "@git_base_url_list = ('git://git.kitenet.net', 'http://git.kitenet.net/git', 'ssh://git.kitenet.net/srv/git');" , "# disable snapshot download; overloads server" , "$feature{'snapshot'}{'default'} = [];" @@ -75,6 +75,7 @@ gitapacheconf hn = , " " , " Options Indexes ExecCGI FollowSymlinks" , " AllowOverride None" + , " AddHandler cgi-script .cgi" , " DirectoryIndex index.cgi" , " " , "" -- cgit v1.3-2-g0d8e From 576acfed33abfae2065354431100701713e83a23 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 14:58:56 -0400 Subject: propellor spin --- Propellor/Property/SiteSpecific/JoeySites.hs | 1 - 1 file changed, 1 deletion(-) (limited to 'Propellor') diff --git a/Propellor/Property/SiteSpecific/JoeySites.hs b/Propellor/Property/SiteSpecific/JoeySites.hs index 0594fe54..9192786c 100644 --- a/Propellor/Property/SiteSpecific/JoeySites.hs +++ b/Propellor/Property/SiteSpecific/JoeySites.hs @@ -58,7 +58,6 @@ gitServer hosts = propertyList "git.kitenet.net setup" , 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 ] where -- cgit v1.3-2-g0d8e From 95ac5163da904780ae166c2bf3a0addcb8d8870e Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 15:34:01 -0400 Subject: Properties can now be satisfied differently on different operating systems. --- Propellor/Attr.hs | 7 +++++++ Propellor/Message.hs | 4 ++-- Propellor/Property.hs | 8 ++++++++ Propellor/Types.hs | 28 ++-------------------------- Propellor/Types/Attr.hs | 7 ++++++- Propellor/Types/OS.hs | 19 +++++++++++++++++++ config-joey.hs | 12 +++++++----- debian/changelog | 2 ++ propellor.cabal | 1 + 9 files changed, 54 insertions(+), 34 deletions(-) create mode 100644 Propellor/Types/OS.hs (limited to 'Propellor') diff --git a/Propellor/Attr.hs b/Propellor/Attr.hs index 67ea8b8c..9a9d8446 100644 --- a/Propellor/Attr.hs +++ b/Propellor/Attr.hs @@ -21,6 +21,13 @@ hostname name = pureAttrProperty ("hostname " ++ name) $ getHostName :: Propellor HostName getHostName = asks _hostname +os :: System -> AttrProperty +os system = pureAttrProperty ("OS " ++ show system) $ + \d -> d { _os = Just system } + +getOS :: Propellor (Maybe System) +getOS = asks _os + cname :: Domain -> AttrProperty cname domain = pureAttrProperty ("cname " ++ domain) (addCName domain) diff --git a/Propellor/Message.hs b/Propellor/Message.hs index 2e63061e..780471c3 100644 --- a/Propellor/Message.hs +++ b/Propellor/Message.hs @@ -29,7 +29,7 @@ actionMessage desc a = do return r warningMessage :: MonadIO m => String -> m () -warningMessage s = liftIO $ colorLine Vivid Red $ "** warning: " ++ s +warningMessage s = liftIO $ colorLine Vivid Magenta $ "** warning: " ++ s colorLine :: ColorIntensity -> Color -> String -> IO () colorLine intensity color msg = do @@ -43,7 +43,7 @@ colorLine intensity color msg = do errorMessage :: String -> IO a errorMessage s = do - warningMessage s + liftIO $ colorLine Vivid Red $ "** error: " ++ s error "Cannot continue!" -- | Causes a debug message to be displayed when PROPELLOR_DEBUG=1 diff --git a/Propellor/Property.hs b/Propellor/Property.hs index 3e41fbcb..95d17c05 100644 --- a/Propellor/Property.hs +++ b/Propellor/Property.hs @@ -10,6 +10,7 @@ import "mtl" Control.Monad.Reader import Propellor.Types import Propellor.Types.Attr +import Propellor.Attr import Propellor.Engine import Utility.Monad import System.FilePath @@ -91,6 +92,13 @@ check c property = Property (propertyDesc property) $ ifM (liftIO c) , return NoChange ) +-- | Makes a property that is satisfied differently depending on the host's +-- operating system. +-- +-- Note that the operating system may not be declared for some hosts. +withOS :: Desc -> (Maybe System -> Propellor Result) -> Property +withOS desc a = Property desc $ a =<< getOS + boolProperty :: Desc -> IO Bool -> Property boolProperty desc a = Property desc $ ifM (liftIO a) ( return MadeChange diff --git a/Propellor/Types.hs b/Propellor/Types.hs index b8f8f167..5f575daf 100644 --- a/Propellor/Types.hs +++ b/Propellor/Types.hs @@ -6,8 +6,6 @@ module Propellor.Types ( Host(..) , Attr , HostName - , UserName - , GroupName , Propellor(..) , Property(..) , RevertableProperty(..) @@ -19,16 +17,12 @@ module Propellor.Types , requires , Desc , Result(..) - , System(..) - , Distribution(..) - , DebianSuite(..) - , Release - , Architecture , ActionResult(..) , CmdLine(..) , PrivDataField(..) , GpgKeyId , SshKeyType(..) + , module Propellor.Types.OS ) where import Data.Monoid @@ -38,12 +32,10 @@ import "mtl" Control.Monad.Reader import "MonadCatchIO-transformers" Control.Monad.CatchIO import Propellor.Types.Attr +import Propellor.Types.OS data Host = Host [Property] (Attr -> Attr) -type UserName = String -type GroupName = String - -- | Propellor's monad provides read-only access to attributes of the -- system. newtype Propellor p = Propellor { runWithAttr :: ReaderT Attr IO p } @@ -119,22 +111,6 @@ instance Monoid Result where mappend _ MadeChange = MadeChange mappend NoChange NoChange = NoChange --- | High level descritption of a operating system. -data System = System Distribution Architecture - deriving (Show) - -data Distribution - = Debian DebianSuite - | Ubuntu Release - deriving (Show) - -data DebianSuite = Experimental | Unstable | Testing | Stable | DebianRelease Release - deriving (Show, Eq) - -type Release = String - -type Architecture = String - -- | Results of actions, with color. class ActionResult a where getActionResult :: a -> (String, ColorIntensity, Color) diff --git a/Propellor/Types/Attr.hs b/Propellor/Types/Attr.hs index cdbe9ca3..1ff58148 100644 --- a/Propellor/Types/Attr.hs +++ b/Propellor/Types/Attr.hs @@ -1,11 +1,14 @@ module Propellor.Types.Attr where +import Propellor.Types.OS + import qualified Data.Set as S -- | The attributes of a host. For example, its hostname. data Attr = Attr { _hostname :: HostName , _cnames :: S.Set Domain + , _os :: Maybe System , _sshPubKey :: Maybe String , _dockerImage :: Maybe String @@ -16,6 +19,7 @@ instance Eq Attr where x == y = and [ _hostname x == _hostname y , _cnames x == _cnames y + , _os x == _os y , _sshPubKey x == _sshPubKey y , _dockerImage x == _dockerImage y @@ -27,13 +31,14 @@ instance Show Attr where show a = unlines [ "hostname " ++ _hostname a , "cnames " ++ show (_cnames a) + , "OS " ++ show (_os a) , "sshPubKey " ++ show (_sshPubKey a) , "docker image " ++ show (_dockerImage a) , "docker run params " ++ show (map (\mk -> mk "") (_dockerRunParams a)) ] newAttr :: HostName -> Attr -newAttr hn = Attr hn S.empty Nothing Nothing [] +newAttr hn = Attr hn S.empty Nothing Nothing Nothing [] type HostName = String type Domain = String diff --git a/Propellor/Types/OS.hs b/Propellor/Types/OS.hs new file mode 100644 index 00000000..5b0e376d --- /dev/null +++ b/Propellor/Types/OS.hs @@ -0,0 +1,19 @@ +module Propellor.Types.OS where + +type UserName = String +type GroupName = String + +-- | High level descritption of a operating system. +data System = System Distribution Architecture + deriving (Show, Eq) + +data Distribution + = Debian DebianSuite + | Ubuntu Release + deriving (Show, Eq) + +data DebianSuite = Experimental | Unstable | Testing | Stable | DebianRelease Release + deriving (Show, Eq) + +type Release = String +type Architecture = String diff --git a/config-joey.hs b/config-joey.hs index aba648dc..ed214e82 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -29,7 +29,7 @@ hosts = & Apt.buildDep ["git-annex"] `period` Daily -- Nothing super-important lives here. - , standardSystem "clam.kitenet.net" Unstable + , standardSystem "clam.kitenet.net" Unstable "amd64" & cleanCloudAtCost & Apt.unattendedUpgrades & Network.ipv6to4 @@ -53,7 +53,7 @@ hosts = & Apt.installed ["git-annex", "mtr", "screen"] -- Orca is the main git-annex build box. - , standardSystem "orca.kitenet.net" Unstable + , standardSystem "orca.kitenet.net" Unstable "amd64" & Hostname.sane & Apt.unattendedUpgrades & Docker.configured @@ -65,7 +65,7 @@ hosts = & Apt.buildDep ["git-annex"] `period` Daily -- Important stuff that needs not too much memory or CPU. - , standardSystem "diatom.kitenet.net" Stable + , standardSystem "diatom.kitenet.net" Stable "amd64" & Hostname.sane & Ssh.hostKey SshDsa & Ssh.hostKey SshRsa @@ -142,8 +142,9 @@ gitAnnexBuilder arch buildminute = Docker.container (arch ++ "-git-annex-builder & Apt.unattendedUpgrades -- This is my standard system setup. -standardSystem :: HostName -> DebianSuite -> Host -standardSystem hn suite = host hn +standardSystem :: HostName -> DebianSuite -> Architecture -> Host +standardSystem hn suite arch = host hn + & os (System (Debian suite) arch) & Apt.stdSourcesList suite `onChange` Apt.upgrade & Apt.installed ["etckeeper"] & Apt.installed ["ssh"] @@ -166,6 +167,7 @@ standardSystem hn suite = host hn -- This is my standard container setup, featuring automatic upgrades. standardContainer :: Docker.ContainerName -> DebianSuite -> Architecture -> Host standardContainer name suite arch = Docker.container name (image system) + & os (System (Debian suite) arch) & Apt.stdSourcesList suite & Apt.unattendedUpgrades where diff --git a/debian/changelog b/debian/changelog index b3cc554a..4c18df20 100644 --- a/debian/changelog +++ b/debian/changelog @@ -4,6 +4,8 @@ propellor (0.3.1) UNRELEASED; urgency=medium * Support for provisioning hosts with ssh and gpg keys. * Obnam support. * Apache support. + * Properties can now be satisfied differently on different operating + systems. -- Joey Hess Fri, 11 Apr 2014 15:00:11 -0400 diff --git a/propellor.cabal b/propellor.cabal index a7b7fbca..1d625381 100644 --- a/propellor.cabal +++ b/propellor.cabal @@ -97,6 +97,7 @@ Library Propellor.Engine Propellor.Exception Propellor.Types + Propellor.Types.OS Other-Modules: Propellor.Types.Attr Propellor.CmdLine -- cgit v1.3-2-g0d8e From f806a55649a5d06b479123e35fef4d592e6efe0d Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 15:37:43 -0400 Subject: propellor spin --- Propellor/Property/SiteSpecific/JoeySites.hs | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'Propellor') diff --git a/Propellor/Property/SiteSpecific/JoeySites.hs b/Propellor/Property/SiteSpecific/JoeySites.hs index 9192786c..3115d4b7 100644 --- a/Propellor/Property/SiteSpecific/JoeySites.hs +++ b/Propellor/Property/SiteSpecific/JoeySites.hs @@ -104,14 +104,17 @@ gitapacheconf hn = , "" ] --- Note: needs debian unstable for new kgb kgbServer :: Property -kgbServer = propertyList "kgb.kitenet.net setup" - [ Apt.serviceInstalledRunning "kgb-bot" - , File.hasPrivContent "/etc/kgb-bot/kgb.conf" - `onChange` Service.restarted "kgb-bot" - , "/etc/default/kgb-bot" `File.containsLine` "BOT_ENABLED=1" - `describe` "kgb bot enabled" - `onChange` Service.running "kgb-bot" - ] - +kgbServer = withOS desc $ \o -> case o of + (Just (System (Debian Unstable) _)) -> + ensureProperty $ propertyList desc + [ Apt.serviceInstalledRunning "kgb-bot" + , File.hasPrivContent "/etc/kgb-bot/kgb.conf" + `onChange` Service.restarted "kgb-bot" + , "/etc/default/kgb-bot" `File.containsLine` "BOT_ENABLED=1" + `describe` "kgb bot enabled" + `onChange` Service.running "kgb-bot" + ] + _ -> error "kgb server needs Debian unstable (for kgb-bot 1.31+)" + where + desc = "kgb.kitenet.net setup" -- cgit v1.3-2-g0d8e From 2c1397c5b09f2bbc8339c9763c60fcca601bc212 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 15:54:25 -0400 Subject: Standard apt configuration for stable now includes backports. --- Propellor/Attr.hs | 2 +- Propellor/Property/Apt.hs | 25 ++++++++++++++++++++----- Propellor/Property/OpenId.hs | 2 +- debian/changelog | 1 + 4 files changed, 23 insertions(+), 7 deletions(-) (limited to 'Propellor') diff --git a/Propellor/Attr.hs b/Propellor/Attr.hs index 9a9d8446..94376b0d 100644 --- a/Propellor/Attr.hs +++ b/Propellor/Attr.hs @@ -22,7 +22,7 @@ getHostName :: Propellor HostName getHostName = asks _hostname os :: System -> AttrProperty -os system = pureAttrProperty ("OS " ++ show system) $ +os system = pureAttrProperty ("Operating " ++ show system) $ \d -> d { _os = Just system } getOS :: Propellor (Maybe System) diff --git a/Propellor/Property/Apt.hs b/Propellor/Property/Apt.hs index 4da13a2f..b7c281ce 100644 --- a/Propellor/Property/Apt.hs +++ b/Propellor/Property/Apt.hs @@ -24,9 +24,12 @@ showSuite Unstable = "unstable" showSuite Experimental = "experimental" showSuite (DebianRelease r) = r -debLine :: DebianSuite -> Url -> [Section] -> Line +backportSuite :: DebianSuite -> String +backportSuite suite = showSuite suite ++ "-backports" + +debLine :: String -> Url -> [Section] -> Line debLine suite mirror sections = unwords $ - ["deb", mirror, showSuite suite] ++ sections + ["deb", mirror, suite] ++ sections srcLine :: Line -> Line srcLine l = case words l of @@ -37,9 +40,12 @@ stdSections :: [Section] stdSections = ["main", "contrib", "non-free"] binandsrc :: String -> DebianSuite -> [Line] -binandsrc url suite = [l, srcLine l] +binandsrc url suite + | suite == Stable = [l, srcLine l, bl, srcLine bl] + | otherwise = [l, srcLine l] where - l = debLine suite url stdSections + l = debLine (showSuite suite) url stdSections + bl = debLine (backportSuite suite) url stdSections debCdn :: DebianSuite -> [Line] debCdn = binandsrc "http://cdn.debian.net/debian" @@ -62,7 +68,7 @@ securityUpdates suite -- kernel.org. stdSourcesList :: DebianSuite -> Property stdSourcesList suite = setSourcesList - (debCdn suite ++ kernelOrg suite ++ securityUpdates suite) + (concatMap (\gen -> gen suite) [debCdn, kernelOrg, securityUpdates]) `describe` ("standard sources.list for " ++ show suite) setSourcesList :: [Line] -> Property @@ -96,6 +102,15 @@ installed' params ps = robustly $ check (isInstallable ps) go where go = runApt $ params ++ ["install"] ++ ps +installedBackport :: [Package] -> Property +installedBackport ps = withOS desc $ \o -> case o of + (Just (System (Debian suite) _)) -> + ensureProperty $ installed' ["-t", backportSuite suite, "-y"] ps + Nothing -> error "cannot install backports; os not declared" + _ -> error $ "backports not supported on " ++ show o + where + desc = (unwords $ "apt installed backport":ps) + -- | Minimal install of package, without recommends. installedMin :: [Package] -> Property installedMin = installed' ["--no-install-recommends", "-y"] diff --git a/Propellor/Property/OpenId.hs b/Propellor/Property/OpenId.hs index 4c562175..051d6425 100644 --- a/Propellor/Property/OpenId.hs +++ b/Propellor/Property/OpenId.hs @@ -12,7 +12,7 @@ providerFor users baseurl = propertyList desc $ [ Apt.serviceInstalledRunning "apache2" , Apt.installed ["simpleid"] `onChange` Service.restarted "apache2" - , File.fileProperty desc + , File.fileProperty (desc ++ " configured") (map setbaseurl) "/etc/simpleid/config.inc" ] ++ map identfile users where diff --git a/debian/changelog b/debian/changelog index 4c18df20..18436b29 100644 --- a/debian/changelog +++ b/debian/changelog @@ -6,6 +6,7 @@ propellor (0.3.1) UNRELEASED; urgency=medium * Apache support. * Properties can now be satisfied differently on different operating systems. + * Standard apt configuration for stable now includes backports. -- Joey Hess Fri, 11 Apr 2014 15:00:11 -0400 -- cgit v1.3-2-g0d8e From f8e350e4c88c0b535e5ceba33a5ab226a9acd33a Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 16:06:23 -0400 Subject: propellor spin --- Propellor/Property/SiteSpecific/JoeySites.hs | 4 ++-- TODO | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'Propellor') diff --git a/Propellor/Property/SiteSpecific/JoeySites.hs b/Propellor/Property/SiteSpecific/JoeySites.hs index 3115d4b7..635d99ba 100644 --- a/Propellor/Property/SiteSpecific/JoeySites.hs +++ b/Propellor/Property/SiteSpecific/JoeySites.hs @@ -43,7 +43,8 @@ gitServer hosts = propertyList "git.kitenet.net setup" `requires` Ssh.knownHost hosts "usw-s002.rsync.net" "root" `requires` Ssh.authorizedKeys "family" `requires` User.accountFor "family" - , Apt.installed ["git", "git-annex", "rsync", "kgb-client-git", "gitweb"] + , Apt.installed ["git", "rsync", "kgb-client-git", "gitweb"] + , Apt.installedBackport ["git-annex"] , File.hasPrivContentExposed "/etc/kgb-bot/kgb-client.conf" , toProp $ Git.daemonRunning "/srv/git" , "/etc/gitweb.conf" `File.containsLines` @@ -58,7 +59,6 @@ gitServer hosts = propertyList "git.kitenet.net setup" , website "git.kitenet.net" , website "git.joeyh.name" , toProp $ Apache.modEnabled "cgi" - -- TODO: upgrade to newer git-annex-shell for notification ] where website hn = toProp $ Apache.siteEnabled hn (gitapacheconf hn) diff --git a/TODO b/TODO index a203169c..93dcf0d4 100644 --- a/TODO +++ b/TODO @@ -2,9 +2,6 @@ run it once for the whole. For example, may want to restart apache, but only once despite many config changes being made to satisfy properties. onChange is a poor substitute. -* Currently only Debian and derivatives are supported by most Properties. - This could be improved by making the Distribution of the system part - of its HostAttr. * Display of docker container properties is a bit wonky. It always says they are unchanged even when they changed and triggered a reprovision. @@ -18,3 +15,7 @@ * There is no way for a property of a docker container to require some property be met outside the container. For example, some servers need ntp installed for a good date source. +* Attributes can only be set in the top level property list for a Host. + If an attribute is set inside a propertyList, it won't propigate out. + Fix this. Probably the fix involves combining AttrProperty into Property. + Then propertyList can gather the attributes from its list. -- cgit v1.3-2-g0d8e From feeec9d3819d39cbb0c0ece3b5c6628881f2d5a1 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 16:38:58 -0400 Subject: propellor spin --- Propellor/Property/SiteSpecific/JoeySites.hs | 94 +++++++++++++++++++++++----- config-joey.hs | 14 ++++- 2 files changed, 92 insertions(+), 16 deletions(-) (limited to 'Propellor') diff --git a/Propellor/Property/SiteSpecific/JoeySites.hs b/Propellor/Property/SiteSpecific/JoeySites.hs index 635d99ba..e1119469 100644 --- a/Propellor/Property/SiteSpecific/JoeySites.hs +++ b/Propellor/Property/SiteSpecific/JoeySites.hs @@ -13,6 +13,7 @@ import qualified Propellor.Property.Service as Service import qualified Propellor.Property.User as User import qualified Propellor.Property.Obnam as Obnam import qualified Propellor.Property.Apache as Apache +import Utility.SafeCommand oldUseNetShellBox :: Property oldUseNetShellBox = check (not <$> Apt.isInstalled "oldusenet") $ @@ -30,6 +31,21 @@ oldUseNetShellBox = check (not <$> Apt.isInstalled "oldusenet") $ ] `describe` "olduse.net built" ] +kgbServer :: Property +kgbServer = withOS desc $ \o -> case o of + (Just (System (Debian Unstable) _)) -> + ensureProperty $ propertyList desc + [ Apt.serviceInstalledRunning "kgb-bot" + , File.hasPrivContent "/etc/kgb-bot/kgb.conf" + `onChange` Service.restarted "kgb-bot" + , "/etc/default/kgb-bot" `File.containsLine` "BOT_ENABLED=1" + `describe` "kgb bot enabled" + `onChange` Service.running "kgb-bot" + ] + _ -> error "kgb server needs Debian unstable (for kgb-bot 1.31+)" + where + desc = "kgb.kitenet.net setup" + -- git.kitenet.net and git.joeyh.name gitServer :: [Host] -> Property gitServer hosts = propertyList "git.kitenet.net setup" @@ -63,6 +79,69 @@ gitServer hosts = propertyList "git.kitenet.net setup" where website hn = toProp $ Apache.siteEnabled hn (gitapacheconf hn) +type AnnexUUID = String + +-- | A website, with files coming from a git-annex repository. +annexWebSite :: Git.RepoUrl -> HostName -> AnnexUUID -> [(String, Git.RepoUrl)] -> Property +annexWebSite origin hn uuid remotes = Git.cloned "joey" origin dir Nothing + `onChange` setup + `onChange` toProp (Apache.siteEnabled hn $ annexwebsiteconf hn) + where + dir = "/srv/web/" ++ hn + setup = userScriptProperty "joey" $ + [ "cd " ++ shellEscape dir + , "git config annex.uuid " ++ shellEscape uuid + ] ++ map addremote remotes ++ + [ "git annex get" + ] + addremote (name, url) = "git remote add " ++ shellEscape name ++ " " ++ shellEscape url + +annexwebsiteconf :: HostName -> Apache.ConfigFile +annexwebsiteconf hn = stanza 80 False ++ stanza 443 True + where + stanza :: Int -> Bool -> Apache.ConfigFile + stanza port withssl = catMaybes + [ Just $ "" + , Just $ " ServerAdmin joey@kitenet.net" + , Just $ "" + , Just $ " ServerName "++hn++":"++show port + , Just $ " ServerAlias www."++hn + , Just $ "" + , ssl $ " SSLEngine on" + , ssl $ " SSLCertificateFile /etc/ssl/certs/web.pem" + , ssl $ " SSLCertificateKeyFile /etc/ssl/private/web.pem" + , ssl $ " SSLCertificateChainFile /etc/ssl/certs/startssl.pem" + , Just $ "" + , Just $ " DocumentRoot /srv/web/"++hn + , Just $ " " + , Just $ " Options FollowSymLinks" + , Just $ " AllowOverride None" + , Just $ " " + , Just $ " " + , Just $ " Options Indexes FollowSymLinks ExecCGI" + , Just $ " AllowOverride None" + , Just $ " Order allow,deny" + , Just $ " allow from all" + , Just $ " " + , Just $ "" + , Just $ " ErrorLog /var/log/apache2/error.log" + , Just $ " LogLevel warn" + , Just $ " CustomLog /var/log/apache2/access.log combined" + , Just $ " ServerSignature On" + , Just $ " " + , Just $ " " + , Just $ " Options Indexes MultiViews" + , Just $ " AllowOverride None" + , Just $ " Order allow,deny" + , Just $ " Allow from all" + , Just $ " " + , Just $ "" + ] + where + ssl l + | withssl = Just l + | otherwise = Nothing + gitapacheconf :: HostName -> Apache.ConfigFile gitapacheconf hn = [ "" @@ -103,18 +182,3 @@ gitapacheconf hn = , " " , "" ] - -kgbServer :: Property -kgbServer = withOS desc $ \o -> case o of - (Just (System (Debian Unstable) _)) -> - ensureProperty $ propertyList desc - [ Apt.serviceInstalledRunning "kgb-bot" - , File.hasPrivContent "/etc/kgb-bot/kgb.conf" - `onChange` Service.restarted "kgb-bot" - , "/etc/default/kgb-bot" `File.containsLine` "BOT_ENABLED=1" - `describe` "kgb bot enabled" - `onChange` Service.running "kgb-bot" - ] - _ -> error "kgb server needs Debian unstable (for kgb-bot 1.31+)" - where - desc = "kgb.kitenet.net setup" diff --git a/config-joey.hs b/config-joey.hs index ed214e82..f1484031 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -74,14 +74,26 @@ hosts = & Apt.serviceInstalledRunning "ntp" & Dns.zones myDnsSecondary & Apt.serviceInstalledRunning "apache2" + & File.ownerGroup "/srv" "joey" "joey" & cname "git.kitenet.net" & cname "git.joeyh.name" & JoeySites.gitServer hosts & cname "downloads.kitenet.net" + & JoeySites.annexWebSite "/srv/git/download.git" + "downloads.kitenet.net" + "840760dc-08f0-11e2-8c61-576b7e66acfd" + [("turtle", "ssh://turtle.kitenet.net/~/lib/downloads/")] & Apt.buildDep ["git-annex"] `period` Daily - -- downloads.kitenet.net setup (including ssh key to turtle) + + & cname "tmp.kitenet.net" + & JoeySites.annexWebSite "/srv/git/joey/tmp.git" + "tmp.kitenet.net" + "274ce1ca-1226-11e2-bcbd-eb57078e31b1" + [] + + & Apt.installed ["ntop"] -- I don't run this system, so only relevant property is its -- public key. -- cgit v1.3-2-g0d8e From 32ffe1797271a269708ca06060bbe18f1b6f880a Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 16:49:49 -0400 Subject: propellor spin --- Propellor/Property/SiteSpecific/JoeySites.hs | 2 ++ config-joey.hs | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'Propellor') diff --git a/Propellor/Property/SiteSpecific/JoeySites.hs b/Propellor/Property/SiteSpecific/JoeySites.hs index e1119469..ba77eaca 100644 --- a/Propellor/Property/SiteSpecific/JoeySites.hs +++ b/Propellor/Property/SiteSpecific/JoeySites.hs @@ -70,6 +70,8 @@ gitServer hosts = propertyList "git.kitenet.net setup" , "$feature{'snapshot'}{'default'} = [];" ] `describe` "gitweb configured" + -- Repos push on to github. + , Ssh.knownHost hosts "github.com" "joey" -- I keep the website used for gitweb checked into git.. , Git.cloned "root" "/srv/git/joey/git.kitenet.net.git" "/srv/web/git.kitenet.net" Nothing , website "git.kitenet.net" diff --git a/config-joey.hs b/config-joey.hs index f1484031..f0f2f293 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -95,10 +95,11 @@ hosts = & Apt.installed ["ntop"] - -- I don't run this system, so only relevant property is its - -- public key. + -- Systems I don't run, but do want to track their public keys. , host "usw-s002.rsync.net" & sshPubKey "ssh-dss AAAAB3NzaC1kc3MAAAEBAI6ZsoW8a+Zl6NqUf9a4xXSMcV1akJHDEKKBzlI2YZo9gb9YoCf5p9oby8THUSgfh4kse7LJeY7Nb64NR6Y/X7I2/QzbE1HGGl5mMwB6LeUcJ74T3TQAlNEZkGt/MOIVLolJHk049hC09zLpkUDtX8K0t1yaCirC9SxDGLTCLEhvU9+vVdVrdQlKZ9wpLUNbdAzvbra+O/IVvExxDZ9WCHrnfNA8ddVZIGEWMqsoNgiuCxiXpi8qL+noghsSQNFTXwo7W2Vp9zj1JkCt3GtSz5IzEpARQaXEAWNEM0n1nJ686YUOhou64iRM8bPC1lp3QXvvZNgj3m+QHhIempx+de8AAAAVAKB5vUDaZOg14gRn7Bp81ja/ik+RAAABACPH/bPbW912x1NxNiikzGR6clLh+bLpIp8Qie3J7DwOr8oC1QOKjNDK+UgQ7mDQEgr4nGjNKSvpDi4c1QCw4sbLqQgx1y2VhT0SmUPHf5NQFldRQyR/jcevSSwOBxszz3aq9AwHiv9OWaO3XY18suXPouiuPTpIcZwc2BLDNHFnDURQeGEtmgqj6gZLIkTY0iw7q9Tj5FOyl4AkvEJC5B4CSzaWgey93Wqn1Imt7KI8+H9lApMKziVL1q+K7xAuNkGmx5YOSNlE6rKAPtsIPHZGxR7dch0GURv2jhh0NQYvBRn3ukCjuIO5gx56HLgilq59/o50zZ4NcT7iASF76TcAAAEAC6YxX7rrs8pp13W4YGiJHwFvIO1yXLGOdqu66JM0plO4J1ItV1AQcazOXLiliny3p2/W+wXZZKd5HIRt52YafCA8YNyMk/sF7JcTR4d4z9CfKaAxh0UpzKiAk+0j/Wu3iPoTOsyt7N0j1+dIyrFodY2sKKuBMT4TQ0yqQpbC+IDQv2i1IlZAPneYGfd5MIGygs2QMfaMQ1jWAKJvEO0vstZ7GB6nDAcg4in3ZiBHtomx3PL5w+zg48S4Ed69BiFXLZ1f6MnjpUOP75pD4MP6toS0rgK9b93xCrEQLgm4oD/7TCHHBo2xR7wwcsN2OddtwWsEM2QgOkt/jdCAoVCqwQ==" + , host "github.com" + & sshPubKey "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==" --' __|II| ,. ---- __|II|II|__ ( \_,/\ -- cgit v1.3-2-g0d8e From 414b0dffec57d259d761965b5b5da3bfb57b1a80 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 16:54:24 -0400 Subject: propellor spin --- Propellor/CmdLine.hs | 2 +- config-joey.hs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'Propellor') diff --git a/Propellor/CmdLine.hs b/Propellor/CmdLine.hs index b58179f2..5be91c4f 100644 --- a/Propellor/CmdLine.hs +++ b/Propellor/CmdLine.hs @@ -174,7 +174,7 @@ spin hn = do cacheparams <- toCommand <$> sshCachingParams hn go cacheparams url =<< gpgDecrypt (privDataFile hn) where - go cacheparams url privdata = withBothHandles createProcessSuccess (proc "ssh" $ cacheparams ++ ["-t", user, bootstrapcmd]) $ \(toh, fromh) -> do + go cacheparams url privdata = withBothHandles createProcessSuccess (proc "ssh" $ cacheparams ++ [user, bootstrapcmd]) $ \(toh, fromh) -> do let finish = do senddata toh (privDataFile hn) privDataMarker privdata hClose toh diff --git a/config-joey.hs b/config-joey.hs index 67296bcb..ab878fb2 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -81,7 +81,7 @@ hosts = & JoeySites.gitServer hosts & cname "downloads.kitenet.net" - & JoeySites.annexWebSite "/srv/git/download.git" + & JoeySites.annexWebSite "/srv/git/downloads.git" "downloads.kitenet.net" "840760dc-08f0-11e2-8c61-576b7e66acfd" [("turtle", "ssh://turtle.kitenet.net/~/lib/downloads/")] -- cgit v1.3-2-g0d8e From a79e33944d14a3ee050ce6663e3813e0c2f52b26 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 17:03:21 -0400 Subject: propellor spin --- Propellor/Property/SiteSpecific/JoeySites.hs | 9 ++++++--- config-joey.hs | 11 +++++++---- 2 files changed, 13 insertions(+), 7 deletions(-) (limited to 'Propellor') diff --git a/Propellor/Property/SiteSpecific/JoeySites.hs b/Propellor/Property/SiteSpecific/JoeySites.hs index ba77eaca..6b149598 100644 --- a/Propellor/Property/SiteSpecific/JoeySites.hs +++ b/Propellor/Property/SiteSpecific/JoeySites.hs @@ -84,13 +84,16 @@ gitServer hosts = propertyList "git.kitenet.net setup" type AnnexUUID = String -- | A website, with files coming from a git-annex repository. -annexWebSite :: Git.RepoUrl -> HostName -> AnnexUUID -> [(String, Git.RepoUrl)] -> Property -annexWebSite origin hn uuid remotes = Git.cloned "joey" origin dir Nothing +annexWebSite :: [Host] -> Git.RepoUrl -> HostName -> AnnexUUID -> [(String, Git.RepoUrl)] -> Property +annexWebSite hosts origin hn uuid remotes = Git.cloned "joey" origin dir Nothing `onChange` setup `onChange` toProp (Apache.siteEnabled hn $ annexwebsiteconf hn) where dir = "/srv/web/" ++ hn - setup = userScriptProperty "joey" $ + setup = userScriptProperty "joey" setupscript + `requires` Ssh.keyImported SshRsa "joey" + `requires` Ssh.knownHost hosts "turtle.kitenet.net" "joey" + setupscript = [ "cd " ++ shellEscape dir , "git config annex.uuid " ++ shellEscape uuid ] ++ map addremote remotes ++ diff --git a/config-joey.hs b/config-joey.hs index ab878fb2..055c1a65 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -81,21 +81,24 @@ hosts = & JoeySites.gitServer hosts & cname "downloads.kitenet.net" - & JoeySites.annexWebSite "/srv/git/downloads.git" + & JoeySites.annexWebSite hosts "/srv/git/downloads.git" "downloads.kitenet.net" "840760dc-08f0-11e2-8c61-576b7e66acfd" [("turtle", "ssh://turtle.kitenet.net/~/lib/downloads/")] & Apt.buildDep ["git-annex"] `period` Daily & cname "tmp.kitenet.net" - & JoeySites.annexWebSite "/srv/git/joey/tmp.git" + & JoeySites.annexWebSite hosts "/srv/git/joey/tmp.git" "tmp.kitenet.net" - "274ce1ca-1226-11e2-bcbd-eb57078e31b1" + "26fd6e38-1226-11e2-a75f-ff007033bdba" [] & Apt.installed ["ntop"] - -- Systems I don't run, but do want to track their public keys. + -- Systems I don't manage with propellor, + -- but do want to track their public keys. + , host "turtle.kitenet.net" + & sshPubKey "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAokMXQiX/NZjA1UbhMdgAscnS5dsmy+Q7bWrQ6tsTZ/o+6N/T5cbjoBHOdpypXJI3y/PiJTDJaQtXIhLa8gFg/EvxMnMz/KG9skADW1361JmfCc4BxicQIO2IOOe6eilPr+YsnOwiHwL0vpUnuty39cppuMWVD25GzxXlS6KQsLCvXLzxLLuNnGC43UAM0q4UwQxDtAZEK1dH2o3HMWhgMP2qEQupc24dbhpO3ecxh2C9678a3oGDuDuNf7mLp3s7ptj5qF3onitpJ82U5o7VajaHoygMaSRFeWxP2c13eM57j3bLdLwxVXFhePcKXARu1iuFTLS5uUf3hN6MkQcOGw==" , host "usw-s002.rsync.net" & sshPubKey "ssh-dss AAAAB3NzaC1kc3MAAAEBAI6ZsoW8a+Zl6NqUf9a4xXSMcV1akJHDEKKBzlI2YZo9gb9YoCf5p9oby8THUSgfh4kse7LJeY7Nb64NR6Y/X7I2/QzbE1HGGl5mMwB6LeUcJ74T3TQAlNEZkGt/MOIVLolJHk049hC09zLpkUDtX8K0t1yaCirC9SxDGLTCLEhvU9+vVdVrdQlKZ9wpLUNbdAzvbra+O/IVvExxDZ9WCHrnfNA8ddVZIGEWMqsoNgiuCxiXpi8qL+noghsSQNFTXwo7W2Vp9zj1JkCt3GtSz5IzEpARQaXEAWNEM0n1nJ686YUOhou64iRM8bPC1lp3QXvvZNgj3m+QHhIempx+de8AAAAVAKB5vUDaZOg14gRn7Bp81ja/ik+RAAABACPH/bPbW912x1NxNiikzGR6clLh+bLpIp8Qie3J7DwOr8oC1QOKjNDK+UgQ7mDQEgr4nGjNKSvpDi4c1QCw4sbLqQgx1y2VhT0SmUPHf5NQFldRQyR/jcevSSwOBxszz3aq9AwHiv9OWaO3XY18suXPouiuPTpIcZwc2BLDNHFnDURQeGEtmgqj6gZLIkTY0iw7q9Tj5FOyl4AkvEJC5B4CSzaWgey93Wqn1Imt7KI8+H9lApMKziVL1q+K7xAuNkGmx5YOSNlE6rKAPtsIPHZGxR7dch0GURv2jhh0NQYvBRn3ukCjuIO5gx56HLgilq59/o50zZ4NcT7iASF76TcAAAEAC6YxX7rrs8pp13W4YGiJHwFvIO1yXLGOdqu66JM0plO4J1ItV1AQcazOXLiliny3p2/W+wXZZKd5HIRt52YafCA8YNyMk/sF7JcTR4d4z9CfKaAxh0UpzKiAk+0j/Wu3iPoTOsyt7N0j1+dIyrFodY2sKKuBMT4TQ0yqQpbC+IDQv2i1IlZAPneYGfd5MIGygs2QMfaMQ1jWAKJvEO0vstZ7GB6nDAcg4in3ZiBHtomx3PL5w+zg48S4Ed69BiFXLZ1f6MnjpUOP75pD4MP6toS0rgK9b93xCrEQLgm4oD/7TCHHBo2xR7wwcsN2OddtwWsEM2QgOkt/jdCAoVCqwQ==" , host "github.com" -- cgit v1.3-2-g0d8e From 56dd4ff4d8c77293e8e703f91fc8ac5ef96d55e9 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 17:16:31 -0400 Subject: propellor spin --- Propellor/Property/Ssh.hs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'Propellor') diff --git a/Propellor/Property/Ssh.hs b/Propellor/Property/Ssh.hs index 6bfe1261..b13a12bf 100644 --- a/Propellor/Property/Ssh.hs +++ b/Propellor/Property/Ssh.hs @@ -107,8 +107,12 @@ keyImported keytype user = combineProperties desc f <- liftIO $ keyfile ext ifM (liftIO $ doesFileExist f) ( noChange - , withPrivData p $ \key -> makeChange $ - writer f key + , ensureProperty $ combineProperties desc + [ Property desc $ + withPrivData p $ \key -> makeChange $ + writer f key + , File.ownerGroup f user user + ] ) keyfile ext = do home <- homeDirectory <$> getUserEntryForName user @@ -130,6 +134,7 @@ knownHost hosts hn user = Property desc $ ensureProperty $ combineProperties desc [ File.dirExists (takeDirectory f) , f `File.containsLine` (hn ++ " " ++ k) + , File.ownerGroup f user user ] go _ = do warningMessage $ "no configred sshPubKey for " ++ hn @@ -138,8 +143,9 @@ knownHost hosts hn user = Property desc $ -- | Makes a user have authorized_keys from the PrivData authorizedKeys :: UserName -> Property authorizedKeys user = Property (user ++ " has authorized_keys") $ - withPrivData (SshAuthorizedKeys user) $ \v -> liftIO $ do + withPrivData (SshAuthorizedKeys user) $ \v -> do f <- liftIO $ dotFile "authorized_keys" user - createDirectoryIfMissing True (takeDirectory f) - writeFileProtected f v - return NoChange + liftIO $ do + createDirectoryIfMissing True (takeDirectory f) + writeFileProtected f v + ensureProperty $ File.ownerGroup f user user -- cgit v1.3-2-g0d8e From 90370dc57576ec6d4701acd4b5672eeba269a386 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 17:50:44 -0400 Subject: stable-backports can't be used :( --- Propellor/Property/Apache.hs | 4 ++++ Propellor/Property/Apt.hs | 15 ++++++++------- Propellor/Types/OS.hs | 7 +++++++ config-joey.hs | 6 ++++++ 4 files changed, 25 insertions(+), 7 deletions(-) (limited to 'Propellor') diff --git a/Propellor/Property/Apache.hs b/Propellor/Property/Apache.hs index 81daf9e7..eab87862 100644 --- a/Propellor/Property/Apache.hs +++ b/Propellor/Property/Apache.hs @@ -11,10 +11,12 @@ siteEnabled :: HostName -> ConfigFile -> RevertableProperty siteEnabled hn cf = RevertableProperty enable disable where enable = cmdProperty "a2ensite" ["--quiet", hn] + `describe` ("apache site enabled " ++ hn) `requires` siteAvailable hn cf `requires` installed `onChange` reloaded disable = File.notPresent (siteCfg hn) + `describe` ("apache site disabled " ++ hn) `onChange` cmdProperty "a2dissite" ["--quiet", hn] `requires` installed `onChange` reloaded @@ -29,9 +31,11 @@ modEnabled :: String -> RevertableProperty modEnabled modname = RevertableProperty enable disable where enable = cmdProperty "a2enmod" ["--quiet", modname] + `describe` ("apache module enabled " ++ modname) `requires` installed `onChange` reloaded disable = cmdProperty "a2dismod" ["--quiet", modname] + `describe` ("apache module disabled " ++ modname) `requires` installed `onChange` reloaded diff --git a/Propellor/Property/Apt.hs b/Propellor/Property/Apt.hs index b7c281ce..5c095d64 100644 --- a/Propellor/Property/Apt.hs +++ b/Propellor/Property/Apt.hs @@ -24,8 +24,8 @@ showSuite Unstable = "unstable" showSuite Experimental = "experimental" showSuite (DebianRelease r) = r -backportSuite :: DebianSuite -> String -backportSuite suite = showSuite suite ++ "-backports" +backportSuite :: String +backportSuite = showSuite stableRelease ++ "-backports" debLine :: String -> Url -> [Section] -> Line debLine suite mirror sections = unwords $ @@ -41,11 +41,11 @@ stdSections = ["main", "contrib", "non-free"] binandsrc :: String -> DebianSuite -> [Line] binandsrc url suite - | suite == Stable = [l, srcLine l, bl, srcLine bl] + | isStable suite = [l, srcLine l, bl, srcLine bl] | otherwise = [l, srcLine l] where l = debLine (showSuite suite) url stdSections - bl = debLine (backportSuite suite) url stdSections + bl = debLine backportSuite url stdSections debCdn :: DebianSuite -> [Line] debCdn = binandsrc "http://cdn.debian.net/debian" @@ -56,7 +56,7 @@ kernelOrg = binandsrc "http://mirrors.kernel.org/debian" -- | Only available for Stable and Testing securityUpdates :: DebianSuite -> [Line] securityUpdates suite - | suite == Stable || suite == Testing = + | isStable suite || suite == Testing = let l = "deb http://security.debian.org/ " ++ showSuite suite ++ "/updates " ++ unwords stdSections in [l, srcLine l] | otherwise = [] @@ -104,9 +104,10 @@ installed' params ps = robustly $ check (isInstallable ps) go installedBackport :: [Package] -> Property installedBackport ps = withOS desc $ \o -> case o of - (Just (System (Debian suite) _)) -> - ensureProperty $ installed' ["-t", backportSuite suite, "-y"] ps Nothing -> error "cannot install backports; os not declared" + (Just (System (Debian suite) _)) + | isStable suite -> + ensureProperty $ installed' ["-t", backportSuite, "-y"] ps _ -> error $ "backports not supported on " ++ show o where desc = (unwords $ "apt installed backport":ps) diff --git a/Propellor/Types/OS.hs b/Propellor/Types/OS.hs index 5b0e376d..0635b271 100644 --- a/Propellor/Types/OS.hs +++ b/Propellor/Types/OS.hs @@ -15,5 +15,12 @@ data Distribution data DebianSuite = Experimental | Unstable | Testing | Stable | DebianRelease Release deriving (Show, Eq) +-- | The release that currently corresponds to stable. +stableRelease :: DebianSuite +stableRelease = DebianRelease "wheezy" + +isStable :: DebianSuite -> Bool +isStable s = s == Stable || s == stableRelease + type Release = String type Architecture = String diff --git a/config-joey.hs b/config-joey.hs index 055c1a65..031b493f 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -86,6 +86,12 @@ hosts = "840760dc-08f0-11e2-8c61-576b7e66acfd" [("turtle", "ssh://turtle.kitenet.net/~/lib/downloads/")] & Apt.buildDep ["git-annex"] `period` Daily + -- rsync server for git-annex autobuilders + & Apt.installed ["rsync"] + & hasPrivContent "/etc/rsyncd.conf" + & hasPrivContent "/etc/rsyncd.secrets" + & "/etc/default/rsync" `File.containsLine` "" + `describe` "rsync server enabled" & cname "tmp.kitenet.net" & JoeySites.annexWebSite hosts "/srv/git/joey/tmp.git" -- cgit v1.3-2-g0d8e From b345271f0b231ac5dd10143298d2d5cf655686be Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 18:29:57 -0400 Subject: propellor spin --- Propellor/Property/Apt.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Propellor') diff --git a/Propellor/Property/Apt.hs b/Propellor/Property/Apt.hs index 5c095d64..f45bc2e6 100644 --- a/Propellor/Property/Apt.hs +++ b/Propellor/Property/Apt.hs @@ -107,7 +107,8 @@ installedBackport ps = withOS desc $ \o -> case o of Nothing -> error "cannot install backports; os not declared" (Just (System (Debian suite) _)) | isStable suite -> - ensureProperty $ installed' ["-t", backportSuite, "-y"] ps + ensureProperty $ runApt $ + ["install", "-t", backportSuite, "-y"] ++ ps _ -> error $ "backports not supported on " ++ show o where desc = (unwords $ "apt installed backport":ps) -- cgit v1.3-2-g0d8e From b143b5af13272f162e3144a52d8dc97bea824648 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 18:41:02 -0400 Subject: propellor spin --- Propellor/Property/SiteSpecific/JoeySites.hs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'Propellor') diff --git a/Propellor/Property/SiteSpecific/JoeySites.hs b/Propellor/Property/SiteSpecific/JoeySites.hs index 6b149598..f7c432c0 100644 --- a/Propellor/Property/SiteSpecific/JoeySites.hs +++ b/Propellor/Property/SiteSpecific/JoeySites.hs @@ -87,7 +87,11 @@ type AnnexUUID = String annexWebSite :: [Host] -> Git.RepoUrl -> HostName -> AnnexUUID -> [(String, Git.RepoUrl)] -> Property annexWebSite hosts origin hn uuid remotes = Git.cloned "joey" origin dir Nothing `onChange` setup - `onChange` toProp (Apache.siteEnabled hn $ annexwebsiteconf hn) + `onChange` setupapache + `requires` File.hasPrivContent "/etc/ssl/certs/web.pem" + `requires` File.hasPrivContent "/etc/ssl/private/web.pem" + `requires` File.hasPrivContent "/etc/ssl/certs/startssl.pem" + `requires` toProp (Apache.modEnabled "ssl") where dir = "/srv/web/" ++ hn setup = userScriptProperty "joey" setupscript @@ -100,6 +104,7 @@ annexWebSite hosts origin hn uuid remotes = Git.cloned "joey" origin dir Nothing [ "git annex get" ] addremote (name, url) = "git remote add " ++ shellEscape name ++ " " ++ shellEscape url + setupapache = toProp (Apache.siteEnabled hn $ annexwebsiteconf hn) annexwebsiteconf :: HostName -> Apache.ConfigFile annexwebsiteconf hn = stanza 80 False ++ stanza 443 True -- cgit v1.3-2-g0d8e From fb1d65125b543b38151974e12a3ad3b672cc9aa6 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 20:22:35 -0400 Subject: propellor spin --- Propellor/Property/SiteSpecific/JoeySites.hs | 149 +++++++++++---------------- config-joey.hs | 6 ++ 2 files changed, 68 insertions(+), 87 deletions(-) (limited to 'Propellor') diff --git a/Propellor/Property/SiteSpecific/JoeySites.hs b/Propellor/Property/SiteSpecific/JoeySites.hs index f7c432c0..bd6e93f3 100644 --- a/Propellor/Property/SiteSpecific/JoeySites.hs +++ b/Propellor/Property/SiteSpecific/JoeySites.hs @@ -79,7 +79,21 @@ gitServer hosts = propertyList "git.kitenet.net setup" , toProp $ Apache.modEnabled "cgi" ] where - website hn = toProp $ Apache.siteEnabled hn (gitapacheconf hn) + website hn = toProp $ Apache.siteEnabled hn $ apachecfg hn True + [ " DocumentRoot /srv/web/git.kitenet.net/" + , " " + , " Options Indexes ExecCGI FollowSymlinks" + , " AllowOverride None" + , " AddHandler cgi-script .cgi" + , " DirectoryIndex index.cgi" + , " " + , "" + , " ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/" + , " " + , " SetHandler cgi-script" + , " Options ExecCGI" + , " " + ] type AnnexUUID = String @@ -88,10 +102,6 @@ annexWebSite :: [Host] -> Git.RepoUrl -> HostName -> AnnexUUID -> [(String, Git. annexWebSite hosts origin hn uuid remotes = Git.cloned "joey" origin dir Nothing `onChange` setup `onChange` setupapache - `requires` File.hasPrivContent "/etc/ssl/certs/web.pem" - `requires` File.hasPrivContent "/etc/ssl/private/web.pem" - `requires` File.hasPrivContent "/etc/ssl/certs/startssl.pem" - `requires` toProp (Apache.modEnabled "ssl") where dir = "/srv/web/" ++ hn setup = userScriptProperty "joey" setupscript @@ -104,91 +114,56 @@ annexWebSite hosts origin hn uuid remotes = Git.cloned "joey" origin dir Nothing [ "git annex get" ] addremote (name, url) = "git remote add " ++ shellEscape name ++ " " ++ shellEscape url - setupapache = toProp (Apache.siteEnabled hn $ annexwebsiteconf hn) + setupapache = toProp $ Apache.siteEnabled hn $ apachecfg hn True $ + [ " ServerAlias www."++hn + , "" + , " DocumentRoot /srv/web/"++hn + , " " + , " Options FollowSymLinks" + , " AllowOverride None" + , " " + , " " + , " Options Indexes FollowSymLinks ExecCGI" + , " AllowOverride None" + , " Order allow,deny" + , " allow from all" + , " " + ] -annexwebsiteconf :: HostName -> Apache.ConfigFile -annexwebsiteconf hn = stanza 80 False ++ stanza 443 True +apachecfg :: HostName -> Bool -> Apache.ConfigFile -> Apache.ConfigFile +apachecfg hn withssl middle + | withssl = vhost False ++ vhost True + | otherwise = vhost False where - stanza :: Int -> Bool -> Apache.ConfigFile - stanza port withssl = catMaybes - [ Just $ "" - , Just $ " ServerAdmin joey@kitenet.net" - , Just $ "" - , Just $ " ServerName "++hn++":"++show port - , Just $ " ServerAlias www."++hn - , Just $ "" - , ssl $ " SSLEngine on" - , ssl $ " SSLCertificateFile /etc/ssl/certs/web.pem" - , ssl $ " SSLCertificateKeyFile /etc/ssl/private/web.pem" - , ssl $ " SSLCertificateChainFile /etc/ssl/certs/startssl.pem" - , Just $ "" - , Just $ " DocumentRoot /srv/web/"++hn - , Just $ " " - , Just $ " Options FollowSymLinks" - , Just $ " AllowOverride None" - , Just $ " " - , Just $ " " - , Just $ " Options Indexes FollowSymLinks ExecCGI" - , Just $ " AllowOverride None" - , Just $ " Order allow,deny" - , Just $ " allow from all" - , Just $ " " - , Just $ "" - , Just $ " ErrorLog /var/log/apache2/error.log" - , Just $ " LogLevel warn" - , Just $ " CustomLog /var/log/apache2/access.log combined" - , Just $ " ServerSignature On" - , Just $ " " - , Just $ " " - , Just $ " Options Indexes MultiViews" - , Just $ " AllowOverride None" - , Just $ " Order allow,deny" - , Just $ " Allow from all" - , Just $ " " - , Just $ "" + vhost ssl = + [ "" + , " ServerAdmin grue@joeyh.name" + , " ServerName "++hn++":"++show port + ] + ++ mainhttpscert ssl + ++ middle ++ + [ "" + , " ErrorLog /var/log/apache2/error.log" + , " LogLevel warn" + , " CustomLog /var/log/apache2/access.log combined" + , " ServerSignature On" + , " " + , " " + , " Options Indexes MultiViews" + , " AllowOverride None" + , " Order allow,deny" + , " Allow from all" + , " " + , "" ] where - ssl l - | withssl = Just l - | otherwise = Nothing + port = if ssl then 443 else 80 :: Int -gitapacheconf :: HostName -> Apache.ConfigFile -gitapacheconf hn = - [ "" - , " ServerAdmin joey@kitenet.net" - , "" - , " ServerName " ++ hn ++ ":80" - , "" - , " DocumentRoot /srv/web/git.kitenet.net/" - , " " - , " Options Indexes ExecCGI FollowSymlinks" - , " AllowOverride None" - , " AddHandler cgi-script .cgi" - , " DirectoryIndex index.cgi" - , " " - , "" - , " ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/" - , " " - , " SetHandler cgi-script" - , " Options ExecCGI" - , " " - , "" - , " ErrorLog /var/log/apache2/error.log" - , " LogLevel warn" - , " CustomLog /var/log/apache2/access.log combined" - , "" - , " # Possible values include: debug, info, notice, warn, error, crit," - , " # alert, emerg." - , " LogLevel warn" - , "" - , " CustomLog /var/log/apache2/access.log combined" - , " ServerSignature On" - , " " - , " " - , " Options Indexes MultiViews" - , " AllowOverride None" - , " Order allow,deny" - , " Allow from all" - , " " - , "" +mainhttpscert :: Bool -> Apache.ConfigFile +mainhttpscert False = [] +mainhttpscert True = + [ " SSLEngine on" + , " SSLCertificateFile /etc/ssl/certs/web.pem" + , " SSLCertificateKeyFile /etc/ssl/private/web.pem" + , " SSLCertificateChainFile /etc/ssl/certs/startssl.pem" ] diff --git a/config-joey.hs b/config-joey.hs index ca1c2205..08093043 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.Apache as Apache import qualified Propellor.Property.Service as Service import qualified Propellor.Property.SiteSpecific.GitHome as GitHome import qualified Propellor.Property.SiteSpecific.GitAnnexBuilder as GitAnnexBuilder @@ -74,7 +75,12 @@ hosts = & Apt.unattendedUpgrades & Apt.serviceInstalledRunning "ntp" & Dns.zones myDnsSecondary + & Apt.serviceInstalledRunning "apache2" + & File.hasPrivContent "/etc/ssl/certs/web.pem" + & File.hasPrivContent "/etc/ssl/private/web.pem" + & File.hasPrivContent "/etc/ssl/certs/startssl.pem" + & Apache.modEnabled "ssl" & File.ownerGroup "/srv/web" "joey" "joey" & cname "git.kitenet.net" -- cgit v1.3-2-g0d8e From 56dd63916925627773cb2cf590f1c8191470dccc Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 13 Apr 2014 21:04:34 -0400 Subject: propellor spin --- Propellor/Property/Apache.hs | 10 ++++++++++ Propellor/Property/SiteSpecific/JoeySites.hs | 10 ++++++---- config-joey.hs | 1 + 3 files changed, 17 insertions(+), 4 deletions(-) (limited to 'Propellor') diff --git a/Propellor/Property/Apache.hs b/Propellor/Property/Apache.hs index eab87862..f45ef9df 100644 --- a/Propellor/Property/Apache.hs +++ b/Propellor/Property/Apache.hs @@ -50,3 +50,13 @@ restarted = cmdProperty "service" ["apache2", "restart"] reloaded :: Property reloaded = Service.reloaded "apache2" + +-- | Configure apache to use SNI to differentiate between +-- https hosts. +multiSSL :: Property +multiSSL = "/etc/apache2/conf.d/ssl" `File.hasContent` + [ "NameVirtualHost *:443" + , "SSLStrictSNIVHostCheck off" + ] + `describe` "apache SNI enabled" + `onChange` reloaded diff --git a/Propellor/Property/SiteSpecific/JoeySites.hs b/Propellor/Property/SiteSpecific/JoeySites.hs index bd6e93f3..73a8f71f 100644 --- a/Propellor/Property/SiteSpecific/JoeySites.hs +++ b/Propellor/Property/SiteSpecific/JoeySites.hs @@ -65,7 +65,7 @@ gitServer hosts = propertyList "git.kitenet.net setup" , toProp $ Git.daemonRunning "/srv/git" , "/etc/gitweb.conf" `File.containsLines` [ "$projectroot = '/srv/git';" - , "@git_base_url_list = ('git://git.kitenet.net', 'http://git.kitenet.net/git', 'ssh://git.kitenet.net/srv/git');" + , "@git_base_url_list = ('git://git.kitenet.net', 'http://git.kitenet.net/git', 'https://git.kitenet.net/git', 'ssh://git.kitenet.net/srv/git');" , "# disable snapshot download; overloads server" , "$feature{'snapshot'}{'default'} = [];" ] @@ -99,9 +99,11 @@ type AnnexUUID = String -- | A website, with files coming from a git-annex repository. annexWebSite :: [Host] -> Git.RepoUrl -> HostName -> AnnexUUID -> [(String, Git.RepoUrl)] -> Property -annexWebSite hosts origin hn uuid remotes = Git.cloned "joey" origin dir Nothing - `onChange` setup - `onChange` setupapache +annexWebSite hosts origin hn uuid remotes = propertyList (hn ++" website using git-annex") + [ Git.cloned "joey" origin dir Nothing + `onChange` setup + , setupapache + ] where dir = "/srv/web/" ++ hn setup = userScriptProperty "joey" setupscript diff --git a/config-joey.hs b/config-joey.hs index 08093043..235a749b 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -81,6 +81,7 @@ hosts = & File.hasPrivContent "/etc/ssl/private/web.pem" & File.hasPrivContent "/etc/ssl/certs/startssl.pem" & Apache.modEnabled "ssl" + & Apache.multiSSL & File.ownerGroup "/srv/web" "joey" "joey" & cname "git.kitenet.net" -- cgit v1.3-2-g0d8e