propellor spin

This commit is contained in:
Joey Hess 2014-04-12 22:36:36 -04:00
parent 596c6590e8
commit c7830f4e66
Failed to extract signature
6 changed files with 202 additions and 108 deletions

View File

@ -4,13 +4,15 @@ import Propellor
import qualified Propellor.Property.File as File import qualified Propellor.Property.File as File
import qualified Propellor.Property.Apt as Apt import qualified Propellor.Property.Apt as Apt
import Data.Char
type CronTimes = String type CronTimes = String
-- | Installs a cron job, run as a specificed user, in a particular -- | 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 --directory. Note that the Desc must be unique, as it is used for the
--cron.d/ filename. --cron.d/ filename.
job :: Desc -> CronTimes -> UserName -> FilePath -> String -> Property 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" [ "# Generated by propellor"
, "" , ""
, "SHELL=/bin/sh" , "SHELL=/bin/sh"
@ -20,6 +22,11 @@ job desc times user cddir command = ("/etc/cron.d/" ++ desc) `File.hasContent`
] ]
`requires` Apt.serviceInstalledRunning "cron" `requires` Apt.serviceInstalledRunning "cron"
`describe` ("cronned " ++ desc) `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. -- | Installs a cron job, and runs it niced and ioniced.
niceJob :: Desc -> CronTimes -> UserName -> FilePath -> String -> Property niceJob :: Desc -> CronTimes -> UserName -> FilePath -> String -> Property

View File

@ -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
)

View File

@ -18,6 +18,7 @@ import qualified Propellor.Property.OpenId as OpenId
import qualified Propellor.Property.Docker as Docker import qualified Propellor.Property.Docker as Docker
import qualified Propellor.Property.Git as Git import qualified Propellor.Property.Git as Git
import qualified Propellor.Property.Gpg as Gpg 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.GitHome as GitHome
import qualified Propellor.Property.SiteSpecific.GitAnnexBuilder as GitAnnexBuilder import qualified Propellor.Property.SiteSpecific.GitAnnexBuilder as GitAnnexBuilder
import qualified Propellor.Property.SiteSpecific.JoeySites as JoeySites import qualified Propellor.Property.SiteSpecific.JoeySites as JoeySites
@ -72,8 +73,13 @@ hosts =
& Apt.buildDep ["git-annex"] `period` Daily & Apt.buildDep ["git-annex"] `period` Daily
& Git.daemonRunning "/srv/git" & Git.daemonRunning "/srv/git"
& File.ownerGroup "/srv/git" "joey" "joey" & File.ownerGroup "/srv/git" "joey" "joey"
& Gpg.keyImported "git.kitenet.net obnam backup key" "root" & Obnam.backup "/srv/git" "33 3 * * *"
& Ssh.keyImported SshRsa "root" [ "--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!) -- git repos restore (how?) (also make backups!)
-- family annex needs family members to have accounts, -- family annex needs family members to have accounts,
-- ssh host key etc.. finesse? -- ssh host key etc.. finesse?

2
debian/changelog vendored
View File

@ -1,6 +1,8 @@
propellor (0.3.1) UNRELEASED; urgency=medium propellor (0.3.1) UNRELEASED; urgency=medium
* Merge scheduler bug fix from git-annex. * Merge scheduler bug fix from git-annex.
* Support for provisioning hosts with ssh and gpg keys.
* Obnam support.
-- Joey Hess <joeyh@debian.org> Fri, 11 Apr 2014 15:00:11 -0400 -- Joey Hess <joeyh@debian.org> Fri, 11 Apr 2014 15:00:11 -0400

View File

@ -1,109 +1,110 @@
-----BEGIN PGP MESSAGE----- -----BEGIN PGP MESSAGE-----
Version: GnuPG v1 Version: GnuPG v1
hQIMA7ODiaEXBlRZAQ//dUDg5+OW19fUJqnWG7kbHBofa9qoBVMVA/MPlR7I1nAK hQILA7ODiaEXBlRZAQ/4hK79L/K03NtaiKU3whmLdty0JG1zPvGgXLjuMQ2XxL+J
qDjko4jtZtkeLVegQQrvssV3fMt8FpvtyCNOjgLsRPHX3AoO8epm4HdKBdvR2tey Pr98VUjwtYjKvRRc6XQaHNwPojbT8uy825wBL+0iBr7O2Uyog8c5vDPkC+ksVvJ2
iea+jSJBNaJVp8FtID+7Ta5lyxC1/VWI7qOVBz+Dbg9qMY2TCSEXNytevHwAc+aT PJJBkwiXTVh6e7lbHENJUa8yf0z3UQlz++W8qQOMRreVEI6wSJOlxz70WarXgNOB
WWKaVEGgNTe7k6ihPBehu5pWSKEVWVe4k+oHc2eFzcGbeK1CoXpS/Zfxe/EWr6TZ p+zD1bgr+8yaOMAjnDqkUPr5ItFXL5EUy5xL5Kud9A+ukYMYMtLJbHFIe6bMH1fH
b7BEuFb1eJYWYeDWRLQ2B+meW3ktX8goJ5qk6Te1WR1Xr93t3tdmR1qB9g+QFmB9 GajRWbyisaVgT3Rqvejg96oUSV9J83Am4XHUq8gJwOJlULI9mx9CCwQLIjmGbcql
a4W1K23WpnAoCy7auxL84dJQrrAxcvhiS5OzbdVO7KOvtdWzUTMTFO4cif1KhCDV WVKWq+h/ERLOHaMhogMvNSXcdljRFpYRcN5Dll3hJt9DXGtHqfSpfb0ZhK5y/C3s
/1towEuJo4Q7QiEEUAsXIhd9F3hOTSAorj2drfM/n6JmHKlp1cZjyezYRbg2LwL3 afS4pEdCzsghgG2ZEELeRUSsiKKxt9ws524OSOAF1OqGktSUOD1muwm+8whhjr/0
9/Adp4o8R7uuF5WzIJvvSCFDjl1Deh/pWYDW4gEQc3zFmxKbeqhcwle8OpiEIb1O kZIqlX/mesyAtxquBCHT5t0uMN00/ksC5nAZmi7YFibf/tCjQfE2BdtE5Y6AYrqT
eYTkfb6no9jT1AzyUiA4OTLndllfVbAs0Zqxoa4kGw3SQUmgby7pw+VilzzF2SrB 8Rth5Y6kNwGzUYFqIvmScHrsxH6Tjc1n1nKEWeeWOM0Pooq45RlSXLnybReGDRAW
G67n/legtUrZWFFYaxl3IuxseRNXYRorrCZnd1jaM7bPWrwjyCaesk7ROYt83W3A xINqKXEjKqzy4EXsHIBKv87DZJoE+hs3Jk100mtgRNVQYcdzXtiXeBe1EWob/fEz
JXu0KNUo+muXv1yexhtLU2vm+QWr1YwuW5YDi2qJEOwE9w8kA4vsjipf5iDpJ9LS UU2VxjwojPH9MakVPFmDjVw2t60Bhc246ovB8jSyKqLn8yPUnhYqjObEGCuie9Ls
7AFA+oqXJPRw3A+tlSpJ1nXRe3XNNPt2BXafn0oT91nXFpEwiiu0kks/B3fEGrda AYiU8Tl9s7hIV7XpSl/jYLYNo99Zzw/jz8Q8eV3wzndy/9+FbOU4UOxDy+XpBldO
kjGbVXHEhW6+QbgP5mHycrbKjNcBL0XqvzmpTTcnkGP8PXEAvJ8G2ejJvdmguH3r LZzdzUbjyBLqDMKoNuRjMzqq24vSizMGxYV8MImJ2H0+VEUx3g4wMRKUpH9D3kVE
8nKWQtGBdPxQllx0/Twlx+SY3kE7w96JMBRADxHhOGPZE+PqzEPga1e3UPiAibY6 wVfzztZ1bxkpjqQVfHxIJrKwgqHS7pPcgPDrNvhTJn2pM1VGzPjaZ+U/E7mKreFM
Vy6DpDa0tQak+Cr40PFf6Z8gwSf4aTiw4KlS2cZMobvK9T9aDIE55//9Sd1MpkdV mWyjcq4jQhpek1hQ0lGzZEPJTJKOZng1IsxJRatdL3+oeqFQ0hIqm9WvbKChLlMN
0znQKe3iigWl7nNPnFTim9O9TLu8OuKaXo6QLIqCi6IEQJo0MXWDHsNEigql+Z0L N4n8QX1/9gx2lt27Bi+7bmIxn6cQN822xXFiUWlz53aJ1ahx+xG9Gr452nCFQlaG
v0wlIr0T3QsL4iAY654A3gNLEIfw7dHCQU809yxh5H3bnjlgMRw/OBOD9Fjzw4XN 90ci94nsqnn4cKMkEyMNuY33ae85+WYWIo15FbFPv2ReW9R+0g0SABJduNQzr5rA
tPbCUVnqEptKvdO3j0S6+zoWM9KhXUwbIh64B2/Ov2bSVdhLvidkqbRkBp39p32h 88MZTsiAS6rE0sB7adZZ8U133Wdl/rlJ7sMpAWCGT/P3+BJlBHq0Z31DDaH5oTOs
mw4zMWx0aBRSYRuqQ/FwsZcluKv9tUCOABDF0mqHr9H9SYi+88CRETNkbZ+Snmxq uaLeri98dmkEuiQ4cBI6uvFVtR2KnzE80yrCuqyfsNay8UpYK5oJB7WWZ7u0EhhW
wjubLvD5Ujj3CkqbFNB53IqonhMA7J/dcBvnfYSDqKAmuWWJVMpjlyDarOTtoKPw 8WisATSNLVuwtBmN6Z8qpzmwthmAvCNfDLCOKeSA7tdOyetMtBQeOJ6o2o+KZbuv
tiV9uZLXQWeUctidtmivkqX7H0Ec4QvdWOax5phzIx9+auFHtc14ZrzjT/G8/kFS 1F8gMQJDub4tQcT2Hd6yglCTQUAoYdc3sa09XV23GYRiu4LfL9Z9gXMVCUA+XfsT
AW4LkL2z4Jew3gM2UZQnG7JDGppFlg5+0emjjiI59/ekNfdsgT4RpZ8ABJOKoAnD SdlBZ7c/dwp9zZzwEUw0tieUok9uq0POEvnb6MYms6aB+cUsZJiOj3NQ5O3D719B
nxgTBVjx58qbzLu9wPxocquHdD2SN/udqy5Fii+cEhDtFx82P/qft3jqqWT9mhAp 9XKH82ZPTtruiGj/9pwoGa8HV04RoLg2pHxdsbeQ8nf8EYCDo8V5VzhBSFdJ/twy
BFNzt78dCvkIhilgVfyWZZjQl9XcNko7us72SaNkC8hey2iKSovddx51MFV6g0sk ocy6G029Gcm2Suiw8iSrhw77SJEqfxV139TxC8k8BeQOJXqwh0hNasGcpSQDdRxR
D2IcjVepMb4c6W2jr8MKiHmmyf3eFfpBMy/dUoFL8iiRZvIaGhIRMUIKdRjq73uX r0kE0HQt/U9cdOBrAuC8JrSG9UlxCxGRpJXPYn2EeMTv8Ljb+DS/Ovvkjrh2wvVR
wTV0LpDQ5sNmwdeMMhzq6LRNdz62SzSYFnYdWhnGamzHOnjwXLOzY7SBw4kFlg8q Uyv0i1gAOGS+DoYxYJgxuc49yQGSqfk0jM1LCVTxxPWcAb4ykrsxuLFqNsWgeSq/
6g121wd73QC1VO94BpQJnUs/yjzmpdnd615YNtIlPPEFJjNUiUhF078N/pOFjk2w CkkniYCcb9oA5lsnGjW2JOokNOT7Tf1jb47Lrv3J0dtmScn16ACeXSScNndjY8Zf
rOy7nLugrmjcDXOmFAAlLBr8atZB81e6A82Ps1XnpX0MfEb573y9kTRTIPI54G7i +3OuMEazut+LAAogCpxQQqzDgBQ1xoUlsHyj5nwzOINbCE55dJ6oCy/a3bLpmuBC
l3eP2Jep6KIsselxdBlUpS5TwiZXuUfsHb4c4mv1wgmfzEbovhfmpnHTwxy2JCf8 /i4i5+AW5shfPAvHOcOa8Wac6YCkOiOEGfgYQp5iqneXod8WBNs5dxpkRAEw7iIQ
vVAB7RIiqL4YvGKf+UUIAgk9q9Z6oIOjIVsdsaHzlB0bLZFU1lD8aQk7DNOIKCpY Y+0Rh+y/FiV7h6cQ74ZjZSyI4txqNCUs1GMb9XnPyuFrnUao4jkLhYnbfqXEp/IP
Ruzgl0t6HCETvC/kB6yzVAYz/KxuLalQWWjzw0rI5GxjRczAPw4JDC0VKnEorxeo ggKSJAQyeqvipKDNOVt0CM+d0DLsyogp61zDnDBLtb/h4k+154FFkNBZfLQosNjq
i5vVQlAx6ZBtcuVBZuLwXZFheyYfxujYmuG9qGkyff5Zuf2Yf3nPuFsiYtpdF8br evBF87HPBzAShTWlyGd3AtTZS5nQZsVBrq2wQF8X9oJfu9k80GrMo9wgWj4NE25c
wKZwxrqLeiOQz210NUNmiokCqA9inLspBnL4d5Qr+HeAdUFU0a6QMyEsK0kn3iCr BQv22NdmHKY+/KgzrnxcBlrRXAxbTdgKLG3khFJw3lIfdgrIYG9CQkg5A/JsXUa0
o4dK5/lg/IFJ1Z4WIGLkquNVBT+tRHwFxBjtqmUF6Tc9S6mGd+uBPMATckrkyx4F R/LCMg8qq5u9PEWJrWhDQGF7T2wbzLoGiU7ujXe220gayn5a59kfbBQaUTt6c5i4
tCPkcN4HNVSL+FmXfEKQhhTN7FxugsXq//ClnjdSFaluvkwaSn+DOQaeYJIJin4J t2u5oyroMJSZUsou7BubhLEaTaLj5QOlipw3Vb6xtTKdlb8KB9AudA28+jVS/HlN
3fNTZJMsxlSb/Xm6QvQwwVPNM82m11vwSRlTy1YJcSLtKU3HYasV1zYZgbv+VNmy 2b/LnbgoJ9s6F8syyWjyTihpAMRypgyPf4QQuwjQ0FWLdsZiCCjFesNyY7Y0ishx
hoUwyl+zwtVcLwgJIYD7jrt5/mKSCBhrKX/0+n4DOX/2RorOaby9nZPrE4JJ3hHD VnMjRpQrGBL93zdLUoFmDcXKYhmO6oUvh0nOUyhwDiZg34gJMQkRoVVl4ysSnDNh
286y3G9mPBmz7ybDcCQI1uEv1NC1kGVOsnAQysdERAfmFI31iVeBnrVRYq0w6Bhk CbeSDiRBb1ewoTdvwEleGoogYCbO3YoNFDZCUfeTymNxVUrJRQdZ3PL6KmGvFJAA
GVeBVNrx9+OM6etC9uqKJopHFgQNJRM2D1u4/vaK1J0g9U95+Cuy8X3cvr4eyExG fm6+7YDOc1I0D+pa0OqVJnLRV+ib04KmjGGdSdWEtbPdOMolhQjKR2BCEePhcjdr
rF0L6dJwbHocunINDhXc4gEMzmhPI4qT2ZpKgAFjatTFs4v0WieO20MOlM3nvnMq Tm/jrDrfum66qBbcAf+EysG+P8FjXd4sCoj2rtv39cNHmsjFpqNWqOEnrVPhJQlu
+CpZX8qPrNnNplHAkGRzVlOuahjNCDPOhoT5XxBqXvG1HFQCDjFKM5e8u+94g0NE MDmikc3i+F61L4LtNN/TX/rbLmWAHEKI6f/2yAmhrq9fJNP2wGnmr8CbAlRAXrmZ
O42zp/I078Vd6TwzEF/b1JeGEtxuQEJZE4tYOrJhFbQ8WZThscKCKdtRe1l9nBy0 pcvFtxPaXQavn6pNjDFGP1qXSMYr28FV5munVszi+O5EJGo/ntRSKDuYW8UARYq4
F23RcBMJD3jWLCGtJeVNDrOPH1Q/cKya2tD9Pqfudm4Q3v+brN8TA9IDun968a1t Gp+ez8ey9PREiLu9GAKGCGhWSqPcbGX8OhbTO/W9AYsIw4//Wj7lhEelowcwaIQG
To4OONvHqLF0pvzrhjIfgqMebpJMYpJJ60/A47IKQRpYu1oT5SdGkajEi4BQerDx iIGj+Rnni6XR6ixi/fItCoJJSN9O1ZIOBaCCKsEotQhnA8mtmMrjdSp+guxMg5d6
ZsA/X03uVXjrkmB4kP9pFGdevpfqwvhZ6rLMHSJgYtnsFbrX44kaWon7BkUkgnVV bGlFXoU8A3/bQPvdGMo0HGeqRhMLIYbrvU4u3iEwyTYD4dtpS9t6/xq8mt6QDpJF
q1q3hNbwJmlTSTzghTRj8doqUJkjHq0AV8sZlpjOKYXxvX94PnQAhXTnX2Vbu18+ UKcNQlgLscVUBQw+Sni72hLADEbFa86QFg2X6lU+EfHLXcDjpsosj+4odicf8IoH
ANyIbkLPj0SBV/eF3+w82seEQaOqH7kJXfAMzzza+F61Z18HSmzhbwVhjllC52BZ Y+twu7J4p4q2BGvUc2B2s4Q01sviqax99wauDC6x0p/8gRbrjTMVY4Se39xGWsvc
MzFi2UimdoD7JIdvqKa70X7bk3hNwmlQm+xUQsz0yGXvdB/bvDCpUgbG3TslRX5o gYJYNMD4U0GWh4qw4I8W10HP1Vs2Qa0oV7WvWSq9OaAcJ1SRsjdKmRIEFa7m7JkS
kIxou3RRXJ+ZLl4R4CRHRDYwkqwBH2flEXpYfhxcqC6eoJaep+hFtpGPzVtZ4sVQ C9mxsDkepiN/BIs22V4kiEDCA6J78e3R+It2x/UtvoqIxx3UxoQlQMo4KBcNZ/OI
xjOhy4OOMha0Z3m9dVcuj/Ltr4O13W82k3mhFOAiPWE3HigebQZL/YvnrjMEiDw8 wg00B7lCftuR9RajbpqpcZCx5p+NRY+N+LMcvOgOBHK3CzC1WN3E40xFL9yn+fKo
1yoRfeVAOQdhpR3TjmPApyWEEe3dbtXKIwvHJ0zB0nTaCdiI9eZLp7Q/qo1KgDEF 99MW3mB6wEsw1l5ph7iE+SEYeSxScVzCLEQaqNUK+U/+B1RBwQanKEy3zT3tG3Nw
cCuNs0d1UztSvfjIwElUA07i7ixy0Pw87Zjex4r0FzxyYPWnvDhVzh1QtT3r8FVd mF5IYiKgvcWWd0ISjGVWD6bQc6yFUWqMjTi23ZaGFrHoAwqMUcZSCPdGzJ4QETJ4
s4y8cMaPgXL451FpzG0hJwGfiAjKc+mlSF7WiOtzntmUZRwr7pPzZ0ZNDrBdHGvb 2yxG1pMtAxpBQm85hdWloDYA3kmL/StmJH928UlGNIxYhiyd9si5QbONjbRFelfO
+lSynZwhYJsp7/CCnAbdP+13e2A5i8wa3oG7Zo/EsT6k384uhfQ2iYJyKnkyZaOd hSiOh/bU8AjMxuC2Js+B/24XhsZ8StmsxihUajcgKrHLPtGuKyOX5qF+onIONSzG
F9fAJdBpzmr7+PgQGB3J63Lc/sIcMubzCYVNrRu8G2IP0wexp0b53iH0iJECHWaZ Jhnhn1VS6WBW0HXXuiErt/GZD9LPPsDpMTB3PyGYvNZwmPKxXywRj8XISJNSn/6/
l+NjX4pIAR6YmCzWkarJDlqyhdnWqX4AGZMG5HSkaHUGi3FPpKru8cnXkyexTM+j 4kzlPjLmI+i8z+7yflSWLVtw0APxHNn9QHP+Wp8vUYYMycTw+n23787gVI/zvB6L
TsnHp0hgSKQ6HFvnORkdyDbgcrCtQcdYaCXRAHNAuy2Rpz3C3RECB9IEbz54NrI/ zp019sRM0lDuPQ89Ai0vDOteouggYIxzjxflfrjIMePw5+ZJNLDjxdWnwmXvB8oC
NfvlY0u9ge2cnV03nxODGL2XFrW8wNs7p+x8J+xrqkxhpDURKoov2/YjO8aObbkC BQND9ciYAFtXNnc+1rUEAskXaKAipTlvwEPg9ei5+U63biI15AETBVwDZthwUYvC
6dvGeOLKAm3FW40IjxmmghGw+Gm1SDiolMK5lyEc7pZZUM/JYIiCOkyLbJiejPX3 1QL1G6NcXdUgCHEev7vEPM35d63OhtbYGjAYinMH42Y88scHbCgIcgvYl9SydkOy
6Ocb0yFL492TK6873e5Eg2z89WfHU7lDNQtmY5uW8rlfeZmm39OmfWvAFhKZCEHm 4X7tK7MFHJ22G6aV4XM+XPzoOLSqaB5Iz9PBSXjU5AC3wzFtAJzyGMGJROnIEpXG
NT6EoqBSm1BxHHM550Nd0kt/NozrV4Z9nJBg8K2ZqWElr9L48AoAvrk12uGX9zVi nUjo39JRDeVXhHlZSKYda2cthHeyd/EoJjBjR0vJRluKn0gBNy3I3XzE2S1B00xm
ZinkTT5q8EBvHjpWzVA0jN+9zLxzfZeh4GDyK4iZbmOrpVemV0oj4f42Br+AYUiC XMMTBsoJwScqpGSr0TdAHUVa3If+5QdIs4okbtXPiT9N0F2Fe183enUQJnb2l6zT
EXwTRvUf35vpUycxodARfWMFSgHJ5z16cKU0tQ94fYBJ4S7VBGgtw91fpxaw8FH+ bvGY2PGHFfRhebfygXaxNbeEz6DkHXGxIj07gJl6X5eDh0/clpzBLA91xRSWorf6
FUDh78ZnJ++P23qhrYt/2b4zKPFjyUyN5UW5MMzUaJcM7LRpsM1i06j/CstTMcFo /w52wWTUryG/sseFqHjuczVx9HMlqqs6ZBFXSG8p3pUzzyyaRT0T0HlUk8JBYHXv
A0rf0cRAOG7Z2ABgzikKRFtsD7fXFnuT2Jw/yeaeUM5Sp7ndrioxGPk6uDjXiA7u cdsrBnzTqj7ZkFMJim3ZeZU1CJ6/A+AuU1Gdwuu1mLNpvT63+RpLj9mDDoHnsUIe
fU8pKU9rpSWIz9BY3Z4EqMbY66QjcSjsA/6bnxzjYpAdTIa/+uR7L7TJLFUNcY9D 1JNijHwdYlF8vucmnT9N5KXc1t/ttxnlbJWbNVMDCaacREi3IGIdF/QVxdBf76iZ
3WvJEirrrMYiCvYkfh0Pz5OEw/gjcJQEAoSPqsy3TisKSW1G9BfGHceO0UVlmjq+ ORvS40RITFLenZTjfWE4HlZQR36xHb0DdiFdeM+DuLBLEhHuCQCV/txMx3TAlVEp
jgnqihPHOluSEkz2QowIhZtj82z5b4G/cIM4WQx0GMsInBBKbfMHvfYO6CknYwPu Oep4mJvP0Vkq5ZVqZiQdEm/UO3vo7O+eEBFfupmb6AZwXYu/Sdf3SqOzIkbAkiek
ShzE3FkeSfpdimi3B9l2PJM/oXXjD6SLhbUjBRMBhICqXJFxDntxKs94AqBGEyAx d7jGvH0+TrTsstdqt2sH5IsnNkB+vLUxKiDjAlcute0JJK23utUu8fSUjZSMG15Q
5XSOFu7x9WX57/Z7j5t79L0K1o/CQ6k4yMcjqMo0ESU6Cjgqb8ZKWmgiKG8MCGtn 480UFSL3HPzObC7Lcm4pRm7w/JYwhk4UfiZWAh/an24qOuvLNJVNptH/78QfGv2K
UQBQ+TSmJUb5X2sYJF3nnk7+JVA80/1takvAOA8EyIpnLzPeAYPYKnDCl2Li7Rj4 dsihyRv8PabwCikTMqiKzLPSa2ESPYLHX1oIXmF7mxp8fYrc6gUgq071ZOe9T0Dm
Z9y4HRAKSOaTdQMy7bg6LQBNXoCQJe63yFUtpXuPEGuADxSISeItjh8Qcc4NQ454 +hWhufsFApgfi5U4xmdTGwFFYfyqqhGFjYdTPXicQq94t134pGcJB1JXSNXOmDFO
JOsMHZux6cCjsTgsaxeg0b+uLOfdLBeu9cU0mBAkAz5VWY8Bz3mJ4Gp2d8YFndS4 hL3mokPqJF47FJoJLIcKl8oUxfD1gj8Nei42zjOXDS1aFb9Zc1GsRnwy+1g31tD3
Zfgke+g/i2hWGpiRyuiCjobec8pobOIuR31p8wHfkjpHYmRH/iUxEvuwQBgcg/Vj yEoj9Io7z5Pk4OWsc1DBgSFlKwITi3x6VUiZYnQ4AT1cb439dfVcNZCNuoXcuI2o
Wq6WHd/gpvsRF4BdEJDKkoLGKAkhSOlpkNbKB6hEtvkHtyvw2SGgKvAuqB9Zr4Xe KZBw9UK04fIKMSR9vc7yEESwpZGwAwIN0wIrwqjMjk9IriPSZ6LhnlZaKz3Dz6lp
R2drHrjP0QkH7vraAL52m7TEslq0cAWM5hKX+a+3QrCiH2LXRstuCVuee5fYdWEX PuEMLklXxXA8Z8owmGrgNiCLNZoN7E6ODpSJMQAGn7nFwVHaZXOCj7QKfTiSHNqT
kmgKRv0pOc1ELgsEloy0BQcv2MuzacmVVivGbU+U2pW71dJE7Ax1jk+IA7gahjXz 2P04q5TbvhyT7gDkXntvb4SWBIeoLPBJInMFiIUFqSx8pOeIVMCFoNI0tV+AoXoL
WYooN5rIEt+9g+PsrtRPhWlNH5WLurh4CdlsctKRfu1vyVKso5AJUPCyrSEIEYY1 zRNav7i9ooSM1QBqPk1stlbxjFP6AkfSzOCJ3a+qaPkQIY33iOqJya81UOePZZQy
ammcoEP22hlqvJyEEEyMn0zirfvIPu+brRmTBeVIprmhCaoCqtQLkhxt5KU4/saI 6EM449DmHbBdOaJXnNu90Za+jHmhemVIHgangrwb8mlLZeRGYS8rsL6OmjJaBvHT
TWFTQNTwZ6p7UH9pfdhNMnEUfuYoduHrR/LjcMqWziUcWizqlrZvvtOKDVdSe2nJ 2KY8SNnB+6UzPqfWytdGG8RT1xC68VXW3WVzfTQ9BFN2FFFTuCY+s8rDKj07Z5El
jhA5sLUlLreNdNBBCwOp1ifiqJuLAdSUM3l7O3RA4ZJDW4T5oFnSsmM5p6uxOz17 7wdBRiQQGgiVGtRolakuBGD+pFpwVYRbtAi9LmT+2zz4fPpkjeLtyfoac9L6OOiE
3B3WQf3odfw6Xq9Zr1tBIxji8SC9BMq/3Bnh+41yqg2vkSXKieQc8qPdnzcdAEud DlOENN8HpVb/DK+nzzDX9INIjJJXXodiEEUTHjm2SGVemQT2aByW+CCyp71Y/KcP
7eGrpbcx7SpZm94uylo2NOEc+/2G2gt3q4ZE+snXBHl8sbfIObBjR3EEP6yPTUlc RKwmIRpw1r1RijuedGShaG8xdQksdBik5pTnYlet91iR766R/tB2vfEr8PUXCZ7/
mJTcUfZNIqVesZAEwUU5oCsILpt+YtY34dVBT9avrIZo818cAaN3/DOS3P6Lfr5j cR8Jg0Zv3YrUQ/NiYWywD+zZy50RpmTjVIIzgFCerva80jyn2kEsf/7FMQImpTWh
njwzUOSuZoj41jwMkHVzVc7roK2JnHrjDaEGr12hP0FV/lvr+Tv1DzmaEijytq4I ZgDlGfbZmUVwyd8gHXMkuD09Itk/aonIlCyfiuMpTX72ptHvzceQ8DPeuz4oZb1i
7kjFMO1AALS2pKCjl4txUVuWgf3OoCuU0Vd2q8rk4UDHJG7GR0bgIZPe0dbRN8MW FtckUpsDhAgn+yfQ20HOk9MdDy2SjeI4lNJxCl01o/x30vYmaETzBo03+WXTgl5D
CFbWek3juv36BdXX1o8BXrQQx4/3wTcZhYfaBiMwExsdC1sri+nhRO10za9//yZQ 0JG+52OQS/7q8PxBTul20WSGgTb0ZvreH2QLpxHRD/gpOvaYXXsPUhpp4tvIyEqS
etcTPYlUbBMXxFgUu7pXhU31FiyujrZu6tByO2SbrnQF4YWaTQZpAKW6AHzOycU3 7DLi0UR1VZd70/7zh8dOQlEfMWNKzrayUduw1hgAvGXWe5yrHgph40roORn4yvIA
oq+kp60w9J7d0nmlFWJYG7Aw+cF6d2zV20s7b7r39KP9oHgeXOeaTAxUbV5HRnMC bLOaIvAygkcVpTGkKst8K7nQ1yE21hogBWqtxe0SJHPKxJtrePLZYSDBu+DnJtPp
ZJhf0W5Ey7TfQjYaJDNkXkMGA7MnSXnVNcu2DYcgNGvkycFcyVGCNjxTv3eqo4QC zbElXfV+Oyhr2ehLTD46B6iBm2ssFLFOt2ViNj9bT9X3YfFl8sV5U20jdPwR4kZ2
jUFBj0oRNK7CKfmzQEnXkdEhDydEYPKvl+itNdwP5r/Gp2JI2WvtzBLnTXz88PQD V6V2cfQ8kxYqeLE/v/uRZ0wHegTLVJxbZ2bwvNegguHOu3phwnHS21nfC6UFD1wU
+YNuHQuU99odsmMJvd5Ai2+ugJfjPHLAnpZ2vqTbwtQOWKpHEbDtPwhc37/li9a+ tMvVENzBGkGrsVEc+xCukB8gPI6O7PebNTcPY5SOHicgS2zx1HMWcTZh72wM5KCT
eTFfMgQxUiBmoWRztqE8t+OoEeBBINRyDfOkYpdStso0hagu28pxgx/wWkQwWnBA mXqMxr8wR/thg2870MhigaCm0AIjbJC5JbXxvhMSmqfdZSTeeCqzV/59mXACO8he
BQNMcXCmBXlZlIQfsrCC8gJIvZTzYJA3T2dRDv40UNa7F94McR8qJ/qSWoJQOyCD D1LLQ1J1ahpE5tf+6TCjqbsbMHqSduXk1G2hxIhx900h9SkeAJqjOqXZSwg8i/hj
UlLjxuregTtr0cVWnY1vDCvEMjEjZViVqmpoJ3EE3VpJUV9JSacYflyF/CjLG5jX Wwvs25yBve3tuGNkr6M5z6PoayYopiIo705B0y0AVhRJftSczUOERs603BJsVIwr
jV/O1zU+2yzLr9L0xaDSA5Tb7gErC7SzXbgRGiq3ulkSbZZ5v1eLXciX6UH75S/t 6FcdCh6WU/V+rkwCWk9gDGXEGUS61lDwNfJewF1mXRacuP76/X3zheg6fjJ2K6Mc
4tWPjX5llmAXLMAJ6xHRhJnAhjd7Br7sE9cD6NZqCyFrF+Gevz0ENzbww9l40UYZ KsvNo+ap1DU4koB80INqkMC+FUKElRGqgdiJ1BsWfBW9U4gIiV4N6BWVZN/6fU2M
4EufIN/RDREXouIi96Bq2uVBRPWqgcV6HBZQTkWZNWZzN6qrxabxi661JECT4Nmf Qa39w8UEj1iZ05TDQ0JrzJEY/WVjUWqYh4MTa0SSYF4b18gNTKYw5pJ7Ff6z6jlT
uZcJroHL28vkUL4r6qe6JndTLK3KS8Zbg8Xdb+owCfnBPf1O710A3TOToqWTe329 tpNnzRf+kwfhT041zRDeuB3FdjKpIaIvakPxLEdvz4BVEM3Xbsi7c8G4/DndhC6f
7XOpVhGJ3go7lJg2xwgaFM/jCNB6WiExz+dhqvPmiZdLM96CAtDk8zGaI7P+TwcA 3SSq0QC8T77kWDjw6m7/ZGYplAsrbtqFTd2MllkH1KRj8wfk57ZuDOUsV7ShplXI
LUGztjjFR38VMqJsIVMAHOAyFeu/9lw1E4BdlggEJcIBp1U3e+vkKeCvd+yfUgxl RaATN0DicTbbsMWTHBw+/6Z3tc6PET4VFDHvBVWBSo+yEBzruhKnbhtxVJced44b
8Dl97Mb3pANLUFboSXgukKXL7T/7Bp9+8+le6IQ5wsvKC9v0jnJmumyCOrFsBu4e Hpht1opiAhikvkhUJJUYZQ9+QfRQwFsyR6XlW07xArCWkjg6PJlgcX39WTxbnAYR
rW/GNLYqzzc0Y9CBRUvkL10VWsHtb80Ovz8sCbdqQLDLtOicryLTeTM+UIeOpmVn grKgB87pp3qThnOd97cCgppj0ETJOCxEKnpSuT234IqlZcBhdhFMsB92xYMzY9Jq
UUFGrYcSqu0P wNf5JwKp1rm6k4cQldFDlQ58GzeUjQpa20625j4jIWIuZeZ5Nf6FECyBXi4cbEaA
=w6i8 /kCJ1kYezrPgaFt3p6JHzQ==
=5opC
-----END PGP MESSAGE----- -----END PGP MESSAGE-----

View File

@ -78,6 +78,7 @@ Library
Propellor.Property.Git Propellor.Property.Git
Propellor.Property.Gpg Propellor.Property.Gpg
Propellor.Property.Network Propellor.Property.Network
Propellor.Property.Obnam
Propellor.Property.OpenId Propellor.Property.OpenId
Propellor.Property.Reboot Propellor.Property.Reboot
Propellor.Property.Scheduled Propellor.Property.Scheduled