propellor 5.4.1 → 5.5.0
raw patch · 18 files changed
+373/−293 lines, 18 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Propellor.Property.HostingProvider.CloudAtCost: decruft :: Property DebianLike
- Propellor.Property.SiteSpecific.GitAnnexBuilder: androidAutoBuilderContainer :: Times -> TimeOut -> Container
- Propellor.Property.SiteSpecific.GitAnnexBuilder: androidAutoBuilderContainer' :: MachineName -> Property DebianLike -> FilePath -> Times -> TimeOut -> Container
- Propellor.Property.SiteSpecific.JoeySites: backupsBackedupFrom :: [Host] -> HostName -> FilePath -> Property DebianLike
- Propellor.Property.SiteSpecific.JoeySites: kiteShellBox :: Property DebianLike
+ Propellor.Property.Apt: backportInstalled' :: [String] -> [Package] -> Property Debian
+ Propellor.Property.Apt: backportInstalledMin :: [Package] -> Property Debian
+ Propellor.Property.Borg: UsesEnvVar :: (String, String) -> BorgRepoOpt
+ Propellor.Property.DiskImage: noBootloader :: Property (HasInfo + UnixLike)
+ Propellor.Property.Hostname: mailname :: Property UnixLike
+ Propellor.Property.Hostname: mailname' :: ExtractDomain -> Property UnixLike
+ Propellor.Property.SiteSpecific.JoeySites: USBHubPort :: Int -> USBHubPort
+ Propellor.Property.SiteSpecific.JoeySites: autoMountDrive :: Label -> USBHubPort -> Maybe FilePath -> Property DebianLike
+ Propellor.Property.SiteSpecific.JoeySites: homeNAS :: Property DebianLike
+ Propellor.Property.SiteSpecific.JoeySites: homerouterWifiInterface :: String
+ Propellor.Property.SiteSpecific.JoeySites: newtype USBHubPort
+ Propellor.Property.SiteSpecific.JoeySites: rsyncNetBorgRepo :: String -> [BorgRepoOpt] -> BorgRepo
+ Propellor.Property.Sudo: sudoersDFile :: FilePath -> [Line] -> RevertableProperty DebianLike Linux
+ Propellor.Property.Systemd: escapePath :: FilePath -> String
+ Propellor.Types.Bootloader: NoBootloader :: BootloaderInstalled
- Propellor.Property.SiteSpecific.GitAnnexBuilder: armAutoBuilder :: DebianSuite -> Architecture -> Flavor -> Property (HasInfo + Debian)
+ Propellor.Property.SiteSpecific.GitAnnexBuilder: armAutoBuilder :: (DebianSuite -> Architecture -> Flavor -> Property (HasInfo + Debian)) -> DebianSuite -> Architecture -> Flavor -> Property (HasInfo + Debian)
- Propellor.Property.SiteSpecific.JoeySites: downloads :: [Host] -> Property (HasInfo + DebianLike)
+ Propellor.Property.SiteSpecific.JoeySites: downloads :: Property (HasInfo + DebianLike)
- Propellor.Property.SiteSpecific.JoeySites: kgbServer :: Property (HasInfo + Debian)
+ Propellor.Property.SiteSpecific.JoeySites: kgbServer :: Property (HasInfo + DebianLike)
Files
- CHANGELOG +23/−0
- debian/changelog +23/−0
- joeyconfig.hs +49/−114
- propellor.cabal +1/−2
- src/Propellor/Property/Apt.hs +13/−6
- src/Propellor/Property/Borg.hs +4/−0
- src/Propellor/Property/DiskImage.hs +11/−0
- src/Propellor/Property/HostingProvider/CloudAtCost.hs +0/−33
- src/Propellor/Property/Hostname.hs +13/−4
- src/Propellor/Property/Installer/Target.hs +1/−0
- src/Propellor/Property/LetsEncrypt.hs +3/−0
- src/Propellor/Property/OS.hs +1/−0
- src/Propellor/Property/SiteSpecific/Branchable.hs +20/−21
- src/Propellor/Property/SiteSpecific/GitAnnexBuilder.hs +16/−49
- src/Propellor/Property/SiteSpecific/JoeySites.hs +142/−56
- src/Propellor/Property/Sudo.hs +36/−8
- src/Propellor/Property/Systemd.hs +15/−0
- src/Propellor/Types/Bootloader.hs +2/−0
CHANGELOG view
@@ -1,3 +1,26 @@+propellor (5.5.0) unstable; urgency=medium++ * letsencrypt': Pass --expand to support expanding the list of domains+ * Split mailname property out of Hostname.sane, since bad mailname+ guesses can lead to ugly surprises. (API change)+ * Removed HostingProvider.CloudatCost module as it lacks a maintainer.+ (If anyone would like to maintain it, send a patch adding it back.)+ (API change)+ * Added Systemd.escapePath helper function useful when creating mount+ units.+ * Added Sudo.sudoersDFile property.+ * Sudo.enabledFor: Write to /etc/sudoers.d/000users rather than to+ /etc/sudoers. (Any old lines it wrote to /etc/sudoers will be removed.)+ This fixes a potential ordering problem; the property used to append+ the line to /etc/sudoers, but that would override more specific lines+ in the include directory.+ * Borg: Added UsesEnvVar.+ * Added DiskImage.noBootloader, useful for eg, direct booting with+ qemu. Thanks, David Bremner.+ * Added Apt.backportInstalledMin.++ -- Joey Hess <id@joeyh.name> Sat, 20 Oct 2018 21:00:27 -0400+ propellor (5.4.1) unstable; urgency=medium * Modernized and simplified the MetaTypes implementation now that
debian/changelog view
@@ -1,3 +1,26 @@+propellor (5.5.0) unstable; urgency=medium++ * letsencrypt': Pass --expand to support expanding the list of domains+ * Split mailname property out of Hostname.sane, since bad mailname+ guesses can lead to ugly surprises. (API change)+ * Removed HostingProvider.CloudatCost module as it lacks a maintainer.+ (If anyone would like to maintain it, send a patch adding it back.)+ (API change)+ * Added Systemd.escapePath helper function useful when creating mount+ units.+ * Added Sudo.sudoersDFile property.+ * Sudo.enabledFor: Write to /etc/sudoers.d/000users rather than to+ /etc/sudoers. (Any old lines it wrote to /etc/sudoers will be removed.)+ This fixes a potential ordering problem; the property used to append+ the line to /etc/sudoers, but that would override more specific lines+ in the include directory.+ * Borg: Added UsesEnvVar.+ * Added DiskImage.noBootloader, useful for eg, direct booting with+ qemu. Thanks, David Bremner.+ * Added Apt.backportInstalledMin.++ -- Joey Hess <id@joeyh.name> Sat, 20 Oct 2018 21:00:27 -0400+ propellor (5.4.1) unstable; urgency=medium * Modernized and simplified the MetaTypes implementation now that
joeyconfig.hs view
@@ -11,7 +11,6 @@ import qualified Propellor.Property.File as File import qualified Propellor.Property.Apt as Apt import qualified Propellor.Property.Network as Network-import qualified Propellor.Property.Service as Service import qualified Propellor.Property.Ssh as Ssh import qualified Propellor.Property.Cron as Cron import qualified Propellor.Property.Sudo as Sudo@@ -20,7 +19,6 @@ import qualified Propellor.Property.Fstab as Fstab import qualified Propellor.Property.Tor as Tor import qualified Propellor.Property.Dns as Dns-import qualified Propellor.Property.OpenId as OpenId import qualified Propellor.Property.Git as Git import qualified Propellor.Property.Postfix as Postfix import qualified Propellor.Property.Apache as Apache@@ -53,8 +51,8 @@ , baleen , honeybee , kite- , elephant , beaver+ , sow , mouse , peregrine , pell@@ -66,6 +64,7 @@ & osDebian Unstable X86_64 & ipv6 "2001:4830:1600:187::2" & Hostname.sane+ & Hostname.mailname & Apt.serviceInstalledRunning "swapspace" & Laptop.powertopAutoTuneOnBoot & Laptop.trimSSD@@ -79,12 +78,12 @@ & JoeySites.laptopSoftware & JoeySites.userDirHtml & Ssh.userKeys (User "joey") hostContext- [ (SshRsa, "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC1YoyHxZwG5Eg0yiMTJLSWJ/+dMM6zZkZiR4JJ0iUfP+tT2bm/lxYompbSqBeiCq+PYcSC67mALxp1vfmdOV//LWlbXfotpxtyxbdTcQbHhdz4num9rJQz1tjsOsxTEheX5jKirFNC5OiKhqwIuNydKWDS9qHGqsKcZQ8p+n1g9Lr3nJVGY7eRRXzw/HopTpwmGmAmb9IXY6DC2k91KReRZAlOrk0287LaK3eCe1z0bu7LYzqqS+w99iXZ/Qs0m9OqAPnHZjWQQ0fN4xn5JQpZSJ7sqO38TBAimM+IHPmy2FTNVVn9zGM+vN1O2xr3l796QmaUG1+XLL0shfR/OZbb joey@darkstar")+ [ (SshEd25519, "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICfFntnesZcYz2B2T41ay45igfckXRSh5uVffkuCQkLv joey@darkstar") ]- -- & imageBuiltFor honeybee- -- (RawDiskImage "/srv/honeybee.img")- -- (Debootstrapped mempty)- & imageBuiltFor banana+ & imageBuiltFor honeybee+ (RawDiskImage "/srv/honeybee.img")+ (Debootstrapped mempty)+ ! imageBuiltFor banana (RawDiskImage "/srv/banana.img") (Debootstrapped mempty) @@ -156,8 +155,6 @@ & Systemd.nspawned (GitAnnexBuilder.autoBuilderContainer GitAnnexBuilder.stackAutoBuilder (Stable "jessie") X86_32 (Just "ancient") (Cron.Times "45 * * * *") "2h")- & Systemd.nspawned (GitAnnexBuilder.androidAutoBuilderContainer- (Cron.Times "1 1 * * *") "3h") banana :: Host banana = host "banana.kitenet.net" $ props@@ -178,17 +175,17 @@ & cubietech_Cubietruck & hasPartition- ( partition EXT4+ ( partition EXT3 `mountedAt` "/"- `setSize` MegaBytes 8000+ `setSize` MegaBytes 16000 ) & JoeySites.cubieTruckOneWire + & Apt.installed ["firmware-misc-nonfree"] & Apt.installed ["firmware-brcm80211"] -- Workaround for https://bugs.debian.org/844056 `requires` File.hasPrivContent "/lib/firmware/brcm/brcmfmac43362-sdio.txt" anyContext `requires` File.dirExists "/lib/firmware/brcm"- & "/etc/default/rcS" `File.containsLine` "FSCKFIX=yes" & Apt.serviceInstalledRunning "ntp" -- no hardware clock & bootstrappedFrom GitRepoOutsideChroot & Ssh.hostKeys hostContext@@ -201,16 +198,21 @@ (Context "homepower.joeyh.name") (SshEd25519, "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMAmVYddg/RgCbIj+cLcEiddeFXaYFnbEJ3uGj9G/EyV joey@honeybee") & JoeySites.homeRouter+ & JoeySites.homeNAS & Apt.installed ["mtr-tiny", "iftop", "screen"] & Postfix.satellite & check (not <$> inChroot) (setupRevertableProperty autobuilder)+ & check (not <$> inChroot) (undoRevertableProperty ancientautobuilder) -- In case compiler needs more than available ram & Apt.serviceInstalledRunning "swapspace" where autobuilder = Systemd.nspawned $ GitAnnexBuilder.autoBuilderContainer- GitAnnexBuilder.armAutoBuilder+ (GitAnnexBuilder.armAutoBuilder GitAnnexBuilder.standardAutoBuilder) Unstable ARMEL Nothing (Cron.Times "15 15 * * *") "10h"+ ancientautobuilder = Systemd.nspawned $ GitAnnexBuilder.autoBuilderContainer+ (GitAnnexBuilder.armAutoBuilder GitAnnexBuilder.stackAutoBuilder)+ (Stable "jessie") ARMEL (Just "ancient") (Cron.Times "5 15 * * *") "10h" -- This is not a complete description of kite, since it's a -- multiuser system with eg, user passwords that are not deployed@@ -244,13 +246,16 @@ & Apt.serviceInstalledRunning "ntp" & "/etc/timezone" `File.hasContent` ["US/Eastern"] - & Borg.backup "/" (Borg.BorgRepo "joey@eubackup.kitenet.net:/home/joey/lib/backup/kite/kite.borg") Cron.Daily+ & Borg.backup "/" (JoeySites.rsyncNetBorgRepo "kite.borg" []) Cron.Daily [ "--exclude=/proc/*" , "--exclude=/sys/*" , "--exclude=/run/*"+ , "--exclude=/mnt/*" , "--exclude=/tmp/*" , "--exclude=/var/tmp/*" , "--exclude=/var/cache/*"+ , "--exclude=/var/lib/swapspace/*"+ , "--exclude=/var/lib/container/*" , "--exclude=/home/joey/lib" -- These directories are backed up and restored separately. , "--exclude=/srv/git"@@ -260,7 +265,7 @@ , Borg.KeepWeeks 4 , Borg.KeepMonths 6 ]- `requires` Ssh.knownHost hosts "eubackup.kitenet.net" (User "root")+ `requires` Ssh.knownHost hosts "usw-s002.rsync.net" (User "root") `requires` Ssh.userKeys (User "root") (Context "kite.kitenet.net") [ (SshRsa, "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC5Gza2sNqSKfNtUN4dN/Z3rlqw18nijmXFx6df2GtBoZbkIak73uQfDuZLP+AXlyfHocwdkdHEf/zrxgXS4EokQMGLZhJ37Pr3edrEn/NEnqroiffw7kyd7EqaziA6UOezcLTjWGv+Zqg9JhitYs4WWTpNzrPH3yQf1V9FunZnkzb4gJGndts13wGmPEwSuf+QHbgQvjMOMCJwWSNcJGdhDR66hFlxfG26xx50uIczXYAbgLfHp5W6WuR/lcaS9J6i7HAPwcsPDA04XDinrcpl29QwsMW1HyGS/4FSCgrDqNZ2jzP49Bka78iCLRqfl1efyYas/Zo1jQ0x+pxq2RMr root@kite")@@ -280,22 +285,10 @@ & alias "git.joeyh.name" & JoeySites.gitServer hosts - & JoeySites.downloads hosts+ & JoeySites.downloads & JoeySites.gitAnnexDistributor & JoeySites.tmp - & alias "bitlbee.kitenet.net"- & Apt.serviceInstalledRunning "bitlbee"- & "/etc/bitlbee/bitlbee.conf" `File.hasContent`- [ "[settings]"- , "User = bitlbee"- , "AuthMode = Registered"- , "[defaults]"- ]- `onChange` Service.restarted "bitlbee"- & "/etc/default/bitlbee" `File.containsLine` "BITLBEE_PORT=\"6767\""- `onChange` Service.restarted "bitlbee"- & Apt.installed [ "git-annex", "myrepos" , "build-essential", "make"@@ -308,7 +301,18 @@ & alias "nntp.olduse.net" & JoeySites.oldUseNetServer hosts & Systemd.nspawned oldusenetShellBox+ + & alias "znc.kitenet.net"+ & JoeySites.ircBouncer + & alias "kgb.kitenet.net"+ & JoeySites.kgbServer+ + & Systemd.nspawned ancientKitenet+ + & alias "podcatcher.kitenet.net"+ & JoeySites.podcatcher+ & JoeySites.scrollBox & alias "scroll.joeyh.name" & alias "us.scroll.joeyh.name"@@ -318,6 +322,7 @@ [ (RelDomain "mouse-onion", CNAME $ AbsDomain "htieo6yu2qtcn2j3.onion") , (RelDomain "beaver-onion", CNAME $ AbsDomain "tl4xsvaxryjylgxs.onion") , (RelDomain "peregrine-onion", CNAME $ AbsDomain "ahw47zqw6qszoufl.onion")+ , (RelDomain "sow-onion", CNAME $ AbsDomain "urt4g2tq32qktgtp.onion") ] & myDnsPrimary "joeyh.name" [] & myDnsPrimary "ikiwiki.info" []@@ -334,6 +339,7 @@ , "domain kitenet.net" , "search kitenet.net" ]+ & alias "debug-me.joeyh.name" & Apt.installed ["debug-me"] & Systemd.enabled "debug-me"@@ -342,79 +348,21 @@ & Apache.httpsVirtualHost "letsencrypt.joeyh.name" "/var/www/html" (LetsEncrypt.AgreeTOS (Just "id@joeyh.name")) & alias "letsencrypt.joeyh.name"- where -elephant :: Host-elephant = host "elephant.kitenet.net" $ props- & standardSystem Unstable X86_64- [ "Storage, big data, and backups, omnomnom!"- , "(Encrypt all data stored here.)"- ]- & ipv4 "193.234.225.114"- & Ssh.hostKeys hostContext- [ (SshDsa, "ssh-dss AAAAB3NzaC1kc3MAAACBANxXGWac0Yz58akI3UbLkphAa8VPDCGswTS0CT3D5xWyL9OeArISAi/OKRIvxA4c+9XnWtNXS7nYVFDJmzzg8v3ZMx543AxXK82kXCfvTOc/nAlVz9YKJAA+FmCloxpmOGrdiTx1k36FE+uQgorslGW/QTxnOcO03fDZej/ppJifAAAAFQCnenyJIw6iJB1+zuF/1TSLT8UAeQAAAIEA1WDrI8rKnxnh2rGaQ0nk+lOcVMLEr7AxParnZjgC4wt2mm/BmkF/feI1Fjft2z4D+V1W7MJHOqshliuproxhFUNGgX9fTbstFJf66p7h7OLAlwK8ZkpRk/uV3h5cIUPel6aCwjL5M2gN6/yq+gcCTXeHLq9OPyUTmlN77SBL71UAAACBAJJiCHWxPAGooe7Vv3W7EIBbsDyf7b2kDH3bsIlo+XFcKIN6jysBu4kn9utjFlrlPeHUDzGQHe+DmSqTUQQ0JPCRGcAcuJL8XUqhJi6A6ye51M9hVt51cJMXmERx9TjLOP/adkEuxpv3Fj20FxRUr1HOmvRvewSHrJ1GeA1bjbYL")- , (SshRsa, "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCrEQ7aNmRYyLKY7xHILQsyV/w0B3++D98vn5IvjHkDnitrUWjB+vPxlS7LYKLzN9Jx7Hb14R2lg7+wdgtFMxLZZukA8b0tqFpTdRFBvBYGh8IM8Id1iE/6io/NZl+hTQEDp0LJP+RljH1CLfz7J3qtc+v6NbfTP5cOgH104mWYoLWzJGaZ4p53jz6THRWnVXy5nPO3dSBr2f/SQgRuJQWHNIh0jicRGD8H2kzOQzilpo+Y46PWtkufl3Yu3UsP5UMAyLRIXwZ6nNRZqRiVWrX44hoNfDbooTdFobbHlqMl+y6291bOXaOA6PACk8B4IVcC89/gmc9Oe4EaDuszU5kD")- , (SshEcdsa, "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBAJkoPRhUGT8EId6m37uBdYEtq42VNwslKnc9mmO+89ody066q6seHKeFY6ImfwjcyIjM30RTzEwftuVNQnbEB0=")- , (SshEd25519, "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB6VtXi0uygxZeCo26n6PuCTlSFCBcwRifv6N8HdWh2Z")- ]-- & Grub.chainPVGrub "hd0,0" "xen/xvda1" 30- & Postfix.satellite- & Apt.unattendedUpgrades- & Systemd.installed- & Systemd.persistentJournal- & Ssh.userKeys (User "joey") hostContext- [ (SshRsa, "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC4wJuQEGno+nJvtE75IKL6JQ08sJHZ9Bzs9Dvu0zuxSEZE30MWK98/twNwCH9PVf2N9m4apfN7f9GHgHTUongfo8xnLAk4PuBSTV74YgKyOCvNYqANuKKa+76PsS/vFf/or3ct++uTEWsRyYD29cQndufwKA4rthAqHG+fifbLDC53AjcldI0zI1RckpPzT+AMazlnSBFMlpKvGD2uzSXALVRXa3vSqWkWd0z7qmIkpmpq0AAgbDLwrGBcUGV/h0rOa2s8zSeirA0tLmHNROl4cZsX0T/6VBGfBRkrHSxL67xJziATw4WPq6spYlxg84pC/5qJVr9SC5HosppbDqgj joey@elephant")- ]- & Apt.serviceInstalledRunning "swapspace"-- & alias "eubackup.kitenet.net"- & Apt.installed ["sshfs", "rsync", "borgbackup"]- & JoeySites.githubBackup- & JoeySites.rsyncNetBackup hosts-- & alias "podcatcher.kitenet.net"- & JoeySites.podcatcher-- & alias "znc.kitenet.net"- & JoeySites.ircBouncer- & alias "kgb.kitenet.net"- & JoeySites.kgbServer-- & alias "ns3.kitenet.net"- & myDnsSecondary-- & Systemd.nspawned oldusenetShellBox- & Systemd.nspawned ancientKitenet- & Systemd.nspawned openidProvider- `requires` Apt.serviceInstalledRunning "ntp"-- & JoeySites.scrollBox- & alias "scroll.joeyh.name"- & alias "eu.scroll.joeyh.name"-- -- For https port 443, shellinabox with ssh login to- -- kitenet.net- & alias "shell.kitenet.net"- & Systemd.nspawned kiteShellBox- -- Nothing is using http port 80, so listen on- -- that port for ssh, for traveling on bad networks that- -- block 22.- & Ssh.listenPort (Port 80)- beaver :: Host beaver = host "beaver.kitenet.net" $ props- & ipv6 "2001:4830:1600:195::2" & Apt.installed ["ssh"] & Ssh.hostPubKey SshDsa "ssh-dss AAAAB3NzaC1kc3MAAACBAIrLX260fY0Jjj/p0syNhX8OyR8hcr6feDPGOj87bMad0k/w/taDSOzpXe0Wet7rvUTbxUjH+Q5wPd4R9zkaSDiR/tCb45OdG6JsaIkmqncwe8yrU+pqSRCxttwbcFe+UU+4AAcinjVedZjVRDj2rRaFPc9BXkPt7ffk8GwEJ31/AAAAFQCG/gOjObsr86vvldUZHCteaJttNQAAAIB5nomvcqOk/TD07DLaWKyG7gAcW5WnfY3WtnvLRAFk09aq1EuiJ6Yba99Zkb+bsxXv89FWjWDg/Z3Psa22JMyi0HEDVsOevy/1sEQ96AGH5ijLzFInfXAM7gaJKXASD7hPbVdjySbgRCdwu0dzmQWHtH+8i1CMVmA2/a5Y/wtlJAAAAIAUZj2US2D378jBwyX1Py7e4sJfea3WSGYZjn4DLlsLGsB88POuh32aOChd1yzF6r6C2sdoPBHQcWBgNGXcx4gF0B5UmyVHg3lIX2NVSG1ZmfuLNJs9iKNu4cHXUmqBbwFYQJBvB69EEtrOw4jSbiTKwHFmqdA/mw1VsMB+khUaVw==" & Tor.installed & Tor.hiddenServiceAvailable "ssh" (Port 22)- & alias "usbackup.kitenet.net"- & JoeySites.backupsBackedupFrom hosts "eubackup.kitenet.net" "/home/joey/lib/backup"- & Apt.serviceInstalledRunning "anacron"- & Cron.niceJob "system disk backed up" Cron.Weekly (User "root") "/"- "rsync -a -x / /home/joey/lib/backup/beaver.kitenet.net/" +sow :: Host+sow = host "sow.kitenet.net" $ props+ & Apt.installed ["ssh"]+ & Ssh.hostPubKey SshDsa "ssh-dss AAAAB3NzaC1kc3MAAACBAIrLX260fY0Jjj/p0syNhX8OyR8hcr6feDPGOj87bMad0k/w/taDSOzpXe0Wet7rvUTbxUjH+Q5wPd4R9zkaSDiR/tCb45OdG6JsaIkmqncwe8yrU+pqSRCxttwbcFe+UU+4AAcinjVedZjVRDj2rRaFPc9BXkPt7ffk8GwEJ31/AAAAFQCG/gOjObsr86vvldUZHCteaJttNQAAAIB5nomvcqOk/TD07DLaWKyG7gAcW5WnfY3WtnvLRAFk09aq1EuiJ6Yba99Zkb+bsxXv89FWjWDg/Z3Psa22JMyi0HEDVsOevy/1sEQ96AGH5ijLzFInfXAM7gaJKXASD7hPbVdjySbgRCdwu0dzmQWHtH+8i1CMVmA2/a5Y/wtlJAAAAIAUZj2US2D378jBwyX1Py7e4sJfea3WSGYZjn4DLlsLGsB88POuh32aOChd1yzF6r6C2sdoPBHQcWBgNGXcx4gF0B5UmyVHg3lIX2NVSG1ZmfuLNJs9iKNu4cHXUmqBbwFYQJBvB69EEtrOw4jSbiTKwHFmqdA/mw1VsMB+khUaVw=="+ & Tor.installed+ & Tor.hiddenServiceAvailable "ssh" (Port 22)+ mouse :: Host mouse = host "mouse.kitenet.net" $ props & ipv4 "67.223.19.96"@@ -461,6 +409,7 @@ keysafe = host "keysafe.joeyh.name" $ props & ipv4 "139.59.17.168" & Hostname.sane+ & Hostname.mailname & osDebian (Stable "stretch") X86_64 & Apt.stdSourcesList `onChange` Apt.upgrade & Apt.unattendedUpgrades@@ -517,16 +466,6 @@ --------------------------- \____, o ,' ---------------------------- ---------------------------- '--,___________,' ----------------------------- --- My own openid provider. Uses php, so containerized for security--- and administrative sanity.-openidProvider :: Systemd.Container-openidProvider = Systemd.debContainer "openid-provider" $ props- & standardContainer (Stable "stretch")- & alias hn- & OpenId.providerFor [User "joey", User "liw"] hn (Just (Port 8081))- where- hn = "openid.kitenet.net"- -- Exhibit: kite's 90's website on port 1994. ancientKitenet :: Systemd.Container ancientKitenet = Systemd.debContainer "ancient-kitenet" $ props@@ -548,11 +487,6 @@ & alias "shell.olduse.net" & JoeySites.oldUseNetShellBox -kiteShellBox :: Systemd.Container-kiteShellBox = Systemd.debContainer "kiteshellbox" $ props- & standardContainer (Stable "stretch")- & JoeySites.kiteShellBox- type Motd = [String] -- This is my standard system setup.@@ -565,6 +499,7 @@ standardSystemUnhardened suite arch motd = propertyList "standard system" $ props & osDebian suite arch & Hostname.sane+ & Hostname.mailname & Hostname.searchDomain & Locale.available "en_US.UTF-8" & File.hasContent "/etc/motd" ("":motd++[""])@@ -602,22 +537,22 @@ branchableSecondary :: RevertableProperty (HasInfo + DebianLike) DebianLike branchableSecondary = Dns.secondaryFor ["branchable.com"] hosts "branchable.com" --- Currently using kite (ns4) as primary with secondaries--- elephant (ns3) and gandi.+-- Currently using kite (ns4) as primary with gandi as secondary -- kite handles all mail. myDnsPrimary :: Domain -> [(BindDomain, Record)] -> RevertableProperty (HasInfo + DebianLike) DebianLike myDnsPrimary domain extras = Dns.signedPrimary (Weekly Nothing) hosts domain (Dns.mkSOA "ns4.kitenet.net" 100) $ [ (RootDomain, NS $ AbsDomain "ns4.kitenet.net")- , (RootDomain, NS $ AbsDomain "ns3.kitenet.net") , (RootDomain, NS $ AbsDomain "ns6.gandi.net") , (RootDomain, MX 0 $ AbsDomain "kitenet.net") , (RootDomain, TXT "v=spf1 a a:kitenet.net ~all") , JoeySites.domainKey ] ++ extras -monsters :: [Host] -- Systems I don't manage with propellor,-monsters = -- but do want to track their public keys etc.+-- Systems I don't manage with propellor,+-- but do want to track their public keys etc.+monsters :: [Host]+monsters = [ host "usw-s002.rsync.net" $ props & Ssh.hostPubKey SshEd25519 "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB7yTEBGfQYdwG/oeL+U9XPMIh/dW7XNs9T+M79YIOrd" , host "github.com" $ props
propellor.cabal view
@@ -1,5 +1,5 @@ Name: propellor-Version: 5.4.1+Version: 5.5.0 Cabal-Version: 1.20 License: BSD2 Maintainer: Joey Hess <id@joeyh.name>@@ -144,7 +144,6 @@ Propellor.Property.ZFS Propellor.Property.ZFS.Process Propellor.Property.ZFS.Properties- Propellor.Property.HostingProvider.CloudAtCost Propellor.Property.HostingProvider.DigitalOcean Propellor.Property.HostingProvider.Exoscale Propellor.Property.HostingProvider.Linode
src/Propellor/Property/Apt.hs view
@@ -241,6 +241,10 @@ installed :: [Package] -> Property DebianLike installed = installed' ["-y"] +-- | Minimal install of package, without recommends.+installedMin :: [Package] -> Property DebianLike+installedMin = installed' ["--no-install-recommends", "-y"]+ installed' :: [String] -> [Package] -> Property DebianLike installed' params ps = robustly $ check (not <$> isInstalled' ps) go `describe` unwords ("apt installed":ps)@@ -253,19 +257,22 @@ -- dependencies from stable-backports too, you will need to include those -- dependencies in the list of packages passed to this function. backportInstalled :: [Package] -> Property Debian-backportInstalled ps = withOS desc $ \w o -> case o of+backportInstalled = backportInstalled' ["-y"]++-- | Minimal install from the stable-backports suite, without recommends.+backportInstalledMin :: [Package] -> Property Debian+backportInstalledMin = backportInstalled' ["--no-install-recommends", "-y"]++backportInstalled' :: [String] -> [Package] -> Property Debian+backportInstalled' params ps = withOS desc $ \w o -> case o of (Just (System (Debian _ suite) _)) -> case backportSuite suite of Nothing -> unsupportedOS' Just bs -> ensureProperty w $- runApt (["install", "-y"] ++ ((++ '/':bs) <$> ps))+ runApt (("install":params) ++ ((++ '/':bs) <$> ps)) `changesFile` dpkgStatus _ -> unsupportedOS' where desc = unwords ("apt installed backport":ps)---- | Minimal install of package, without recommends.-installedMin :: [Package] -> Property DebianLike-installedMin = installed' ["--no-install-recommends", "-y"] removed :: [Package] -> Property DebianLike removed ps = check (any (== IsInstalled) <$> getInstallStatus ps)
src/Propellor/Property/Borg.hs view
@@ -36,6 +36,9 @@ -- | Use to specify a ssh private key to use when accessing a -- BorgRepo. = UseSshKey FilePath+ -- | Use to specify an environment variable to set when running+ -- borg on a BorgRepo.+ | UsesEnvVar (String, String) repoLoc :: BorgRepo -> String repoLoc (BorgRepo s) = s@@ -53,6 +56,7 @@ runBorgEnv (BorgRepoUsing os _) = map go os where go (UseSshKey k) = ("BORG_RSH", "ssh -i " ++ k)+ go (UsesEnvVar (k, v)) = (k, v) installed :: Property DebianLike installed = withOS desc $ \w o -> case o of
src/Propellor/Property/DiskImage.hs view
@@ -18,6 +18,7 @@ imageBuiltFrom, imageExists, GrubTarget(..),+ noBootloader, ) where import Propellor.Base@@ -228,6 +229,7 @@ ubootFlashKernelFinalized p [FlashKernelInstalled, UbootInstalled p] -> ubootFlashKernelFinalized p+ [NoBootloader] -> noBootloaderFinalized _ -> unbootable "multiple bootloaders are installed; don't know which to use" -- | This property is automatically added to the chroot when building a@@ -476,6 +478,15 @@ ubootFlashKernelFinalized p img mnt loopdevs = ubootFinalized p img mnt loopdevs `before` flashKernelFinalized img mnt loopdevs++-- | Normally a boot loader is installed on a disk image. However,+-- when the disk image will be booted by eg qemu booting the kernel and+-- initrd, no boot loader is needed, and this property can be used.+noBootloader :: Property (HasInfo + UnixLike)+noBootloader = pureInfoProperty "no bootloader" [NoBootloader]++noBootloaderFinalized :: Finalization+noBootloaderFinalized _img _mnt _loopDevs = doNothing isChild :: FilePath -> Maybe MountPoint -> Bool isChild mntpt (Just d)
− src/Propellor/Property/HostingProvider/CloudAtCost.hs
@@ -1,33 +0,0 @@--- | Maintainer: currently unmaintained; your name here!--module Propellor.Property.HostingProvider.CloudAtCost- {-# WARNING "This module does not have a maintainer. It might not work right anymore. If you use it, please consider becoming its maintainer." #-}- where--import Propellor.Base-import qualified Propellor.Property.Hostname as Hostname-import qualified Propellor.Property.File as File-import qualified Propellor.Property.User as User---- Clean up a system as installed by cloudatcost.com-decruft :: Property DebianLike-decruft = propertyList "cloudatcost cleanup" $ props- & Hostname.sane- & grubbugfix- & nukecruft- where- grubbugfix :: Property DebianLike- grubbugfix = tightenTargets $ - "/etc/default/grub" `File.containsLine` "GRUB_DISABLE_LINUX_UUID=true"- `describe` "worked around grub/lvm boot bug #743126"- `onChange` (cmdProperty "update-grub" [] `assume` MadeChange)- `onChange` (cmdProperty "update-initramfs" ["-u"] `assume` MadeChange)- nukecruft :: Property Linux- nukecruft = tightenTargets $- combineProperties "nuked cloudatcost cruft" $ props- & File.notPresent "/etc/rc.local"- & File.notPresent "/etc/init.d/S97-setup.sh"- & File.notPresent "/zang-debian.sh"- & File.notPresent "/bin/npasswd"- & User.nuked (User "user") User.YesReallyDeleteHome-
src/Propellor/Property/Hostname.hs view
@@ -14,8 +14,6 @@ -- (However, when used inside a chroot, avoids setting the current hostname -- as that would impact the system outside the chroot.) ----- Configures </etc/mailname> with the domain part of the hostname.--- -- </etc/hosts> is also configured, with an entry for 127.0.1.1, which is -- standard at least on Debian to set the FDQN. --@@ -46,8 +44,6 @@ , check (not <$> inChroot) $ cmdProperty "hostname" [basehost] `assume` NoChange- , "/etc/mailname" `File.hasContent`- [if null domain then hn else domain] ] where desc = "hostname " ++ hn@@ -84,6 +80,19 @@ | "domain " `isPrefixOf` l = False | "search " `isPrefixOf` l = False | otherwise = True++-- Configures </etc/mailname> with the domain part of the hostname of the+-- `Host` it's used in.+mailname :: Property UnixLike+mailname = mailname' extractDomain++mailname' :: ExtractDomain -> Property UnixLike+mailname' extractdomain = property' ("mailname set from hostname") $ \w ->+ ensureProperty w . go =<< asks hostName+ where+ go mn = "/etc/mailname" `File.hasContent` [if null mn' then mn else mn']+ where+ mn' = extractdomain mn -- | Function to extract the domain name from a HostName. type ExtractDomain = HostName -> String
src/Propellor/Property/Installer/Target.hs view
@@ -24,6 +24,7 @@ -- > seed ver = host "debian.local" $ props -- > & osDebian Unstable X86_64 -- > & Hostname.sane+-- > & Hostname.mailname -- > & Apt.stdSourcesList -- > & Apt.installed ["linux-image-amd64"] -- > & Grub.installed PC
src/Propellor/Property/LetsEncrypt.hs view
@@ -77,6 +77,9 @@ , "--text" , "--noninteractive" , "--keep-until-expiring"+ -- The list of domains may be changed, adding more, so+ -- always request expansion.+ , "--expand" ] ++ map (\d -> "--domain="++d) alldomains getstats = mapM statcertfiles alldomains
src/Propellor/Property/OS.hs view
@@ -58,6 +58,7 @@ -- > -- , oldOsRemoved (Confirmed "foo.example.com") -- > ] -- > & Hostname.sane+-- > & Hostname.mailname -- > & Apt.installed ["linux-image-amd64"] -- > & Apt.installed ["ssh"] -- > & User.hasSomePassword "root"
src/Propellor/Property/SiteSpecific/Branchable.hs view
@@ -6,10 +6,10 @@ import qualified Propellor.Property.User as User import qualified Propellor.Property.Ssh as Ssh import qualified Propellor.Property.Postfix as Postfix-import qualified Propellor.Property.Gpg as Gpg import qualified Propellor.Property.Sudo as Sudo import qualified Propellor.Property.Borg as Borg import qualified Propellor.Property.Cron as Cron+import Propellor.Property.SiteSpecific.JoeySites (rsyncNetBorgRepo) server :: [Host] -> Property (HasInfo + DebianLike) server hosts = propertyList "branchable server" $ props@@ -39,35 +39,34 @@ & Postfix.installed & Postfix.mainCf ("mailbox_command", "procmail -a \"$EXTENSION\"") - & Borg.backup "/" (Borg.BorgRepo "joey@eubackup.kitenet.net:/home/joey/lib/backup/branchable/pell.borg") Cron.Daily+ -- backup everything except the contents of sites, which are+ -- backed up by ikiwiki-hosting.+ & Borg.backup "/" (rsyncNetBorgRepo "pell.borg" []) Cron.Daily [ "--exclude=/proc/*"- , "--exclude=/sys/*"- , "--exclude=/run/*"- , "--exclude=/tmp/*"- , "--exclude=/var/tmp/*"- , "--exclude=/var/backups/ikiwiki-hosting-web/*"- , "--exclude=/var/cache/*"- , "--exclude=/home/*/source/*"- , "--exclude=/home/*/public_html/*"- , "--exclude=/home/*/.git/*"- ]- [ Borg.KeepDays 7- , Borg.KeepWeeks 5- , Borg.KeepMonths 12- , Borg.KeepYears 1- ]- -- gpg key that can be used to decrypt the borg backup key- & Gpg.keyImported (Gpg.GpgKeyId obnamkey) (User "root")+ , "--exclude=/sys/*"+ , "--exclude=/run/*"+ , "--exclude=/tmp/*"+ , "--exclude=/var/tmp/*"+ , "--exclude=/var/backups/ikiwiki-hosting-web/*"+ , "--exclude=/var/cache/*"+ , "--exclude=/home/*/source/*"+ , "--exclude=/home/*/source.git/*"+ , "--exclude=/home/*/public_html/*"+ , "--exclude=/home/*/.git/*"+ ]+ [ Borg.KeepDays 7+ , Borg.KeepWeeks 5+ , Borg.KeepMonths 12+ , Borg.KeepYears 1+ ] & Ssh.userKeys (User "root") (Context "branchable.com") [ (SshRsa, "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC2PqTSupwncqeffNwZQXacdEWp7L+TxllIxH7WjfRMb3U74mQxWI0lwqLVW6Fox430DvhSqF1y5rJBvTHh4i49Tc9lZ7mwAxA6jNOP6bmdfteaKKYmUw5qwtJW0vISBFu28qBO11Nq3uJ1D3Oj6N+b3mM/0D3Y3NoGgF8+2dLdi81u9+l6AQ5Jsnozi2Ni/Osx2oVGZa+IQDO6gX8VEP4OrcJFNJe8qdnvItcGwoivhjbIfzaqNNvswKgGzhYLOAS5KT8HsjvIpYHWkyQ5QUX7W/lqGSbjP+6B8C3tkvm8VLXbmaD+aSkyCaYbuoXC2BoJdS7Jh8phKMwPJmdYVepn") ]- & Ssh.knownHost hosts "eubackup.kitenet.net" (User "root") & Ssh.knownHost hosts "usw-s002.rsync.net" (User "root") & adminuser "joey" & adminuser "liw" where- obnamkey = "41E1A9B9" adminuser u = propertyList ("admin user " ++ u) $ props & User.accountFor (User u) & User.hasSomePassword (User u)
src/Propellor/Property/SiteSpecific/GitAnnexBuilder.hs view
@@ -151,7 +151,7 @@ manualinstall :: Architecture -> Property Linux manualinstall arch = tightenTargets $ check (not <$> doesFileExist binstack) $ propertyList "stack installed from upstream tarball" $ props- & cmdProperty "wget" ["https://www.stackage.org/stack/linux-" ++ archname, "-O", tmptar]+ & cmdProperty "wget" [url, "-O", tmptar] `assume` MadeChange & File.dirExists tmpdir & cmdProperty "tar" ["xf", tmptar, "-C", tmpdir, "--strip-components=1"]@@ -160,62 +160,29 @@ `assume` MadeChange & cmdProperty "rm" ["-rf", tmpdir, tmptar] `assume` MadeChange+ & case arch of+ ARMEL -> setupRevertableProperty $+ "/lib/ld-linux-armhf.so.3"+ `File.isSymlinkedTo`+ File.LinkTarget "/lib/ld-linux.so.3"+ _ -> doNothing where- -- See https://www.stackage.org/stack/ for the list of- -- binaries.- archname = case arch of- X86_32 -> "i386"- X86_64 -> "x86_64"- ARMHF -> "arm"+ url = case arch of+ X86_32 -> "https://www.stackage.org/stack/linux-i386"+ X86_64 -> "https://www.stackage.org/stack/linux-x86_64"+ ARMEL -> "https://github.com/commercialhaskell/stack/releases/download/v1.7.1/stack-1.7.1-linux-arm.tar.gz" -- Probably not available.- a -> architectureToDebianArchString a+ a -> "https://www.stackage.org/stack/linux-" ++ architectureToDebianArchString a binstack = "/usr/bin/stack" tmptar = "/root/stack.tar.gz" tmpdir = "/root/stack" -armAutoBuilder :: DebianSuite -> Architecture -> Flavor -> Property (HasInfo + Debian)-armAutoBuilder suite arch flavor =+armAutoBuilder :: (DebianSuite -> Architecture -> Flavor -> Property (HasInfo + Debian)) -> DebianSuite -> Architecture -> Flavor -> Property (HasInfo + Debian)+armAutoBuilder baseautobuilder suite arch flavor = propertyList "arm git-annex autobuilder" $ props- & standardAutoBuilder suite arch flavor- & buildDepsApt+ & baseautobuilder suite arch flavor -- Works around ghc crash with parallel builds on arm. & (homedir </> ".cabal" </> "config")- `File.lacksLine` "jobs: $ncpus"+ `File.containsLine` "jobs: 1" -- Work around https://github.com/systemd/systemd/issues/7135 & Systemd.containerCfg "--system-call-filter=set_tls"--androidAutoBuilderContainer :: Times -> TimeOut -> Systemd.Container-androidAutoBuilderContainer crontimes timeout =- androidAutoBuilderContainer' "android-git-annex-builder"- (tree "android" Nothing) builddir crontimes timeout---- Android is cross-built in a Debian i386 container, using the Android NDK.-androidAutoBuilderContainer'- :: Systemd.MachineName- -> Property DebianLike- -> FilePath- -> Times- -> TimeOut- -> Systemd.Container-androidAutoBuilderContainer' name setupgitannexdir gitannexdir crontimes timeout =- Systemd.container name $ \d -> bootstrap d $ props- & osDebian (Stable "jessie") X86_32- & Apt.stdSourcesList- & User.accountFor (User builduser)- & File.dirExists gitbuilderdir- & File.ownerGroup homedir (User builduser) (Group builduser)- & flagFile chrootsetup ("/chrootsetup")- `requires` setupgitannexdir- & haskellPkgsInstalled "android"- & Apt.unattendedUpgrades- & buildDepsNoHaskellLibs- & autobuilder "android" crontimes timeout- where- -- Use git-annex's android chroot setup script, which will install- -- ghc-android and the NDK, all build deps, etc, in the home- -- directory of the builder user.- chrootsetup = scriptProperty- [ "cd " ++ gitannexdir ++ " && ./standalone/android/buildchroot-inchroot"- ]- `assume` MadeChange- bootstrap = Chroot.debootstrapped mempty
src/Propellor/Property/SiteSpecific/JoeySites.hs view
@@ -16,6 +16,7 @@ import qualified Propellor.Property.Service as Service import qualified Propellor.Property.User as User import qualified Propellor.Property.Group as Group+import qualified Propellor.Property.Sudo as Sudo import qualified Propellor.Property.Borg as Borg import qualified Propellor.Property.Apache as Apache import qualified Propellor.Property.Postfix as Postfix@@ -23,6 +24,7 @@ import qualified Propellor.Property.Network as Network import qualified Propellor.Property.Fail2Ban as Fail2Ban import qualified Propellor.Property.LetsEncrypt as LetsEncrypt+import qualified Propellor.Property.Mount as Mount import Utility.FileMode import Utility.Split @@ -150,9 +152,8 @@ (User "root") (Context "olduse.net") (SshRsa, "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD0F6L76SChMCIGmeyGhlFMUTgZ3BoTbATiOSs0A7KXQoI1LTE5ZtDzzUkrQRJVpJ640pfMR7cQZyBm8tv+kYIPp0238GrX43c1vgm0L78agDnBU7r2iNMyWIwhssK8O3ZAhp8Q4KCz1r8hP2nIiD0y1D1VWW8h4KWOS7I1XCEAjOTvFvEjTh6a9MyHrcIkv7teUUzTBRjNrsyijCFRk1+pEET54RueoOmEjQcWd/sK1tYRiMZjegRLBOus2wUWsUOvznJ2iniLONUTGAWRnEV+O7hLN6CD44osJ+wkZk8bPAumTS0zcSLckX1jpdHJicmAyeniWSd4FCqm1YE6/xDD")- `requires` Ssh.knownHost hosts "eubackup.kitenet.net" (User "root")- borgrepo = Borg.BorgRepoUsing [Borg.UseSshKey keyfile]- "joey@eubackup.kitenet.net:/home/joey/lib/backup/olduse.net/olduse.net.borg"+ `requires` Ssh.knownHost hosts "usw-s002.rsync.net" (User "root")+ borgrepo = rsyncNetBorgRepo "olduse.net.borg" [Borg.UseSshKey keyfile] keyfile = "/root/.ssh/olduse.net.key" oldUseNetShellBox :: Property DebianLike@@ -177,22 +178,16 @@ `assume` MadeChange `describe` "olduse.net built" -kgbServer :: Property (HasInfo + Debian)+kgbServer :: Property (HasInfo + DebianLike) kgbServer = propertyList desc $ props- & installed+ & Apt.serviceInstalledRunning "kgb-bot"+ & "/etc/default/kgb-bot" `File.containsLine` "BOT_ENABLED=1"+ `describe` "kgb bot enabled"+ `onChange` Service.running "kgb-bot" & File.hasPrivContent "/etc/kgb-bot/kgb.conf" anyContext `onChange` Service.restarted "kgb-bot" where desc = "kgb.kitenet.net setup"- installed :: Property Debian- installed = withOS desc $ \w o -> case o of- (Just (System (Debian _ Unstable) _)) ->- ensureProperty w $ propertyList desc $ props- & Apt.serviceInstalledRunning "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+)" -- git.kitenet.net and git.joeyh.name gitServer :: [Host] -> Property (HasInfo + DebianLike)@@ -205,7 +200,7 @@ (User "root") (Context "git.kitenet.net") (SshRsa, "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDLwUUkpkI9c2Wcnv/E4v9bJ7WcpiNkToltXfzRDd1F31AYrucfSMgzu3rtDpEL+wSnQLua/taJkWUWT/pyXOAh+90K6O/YeBZmY5CK01rYDz3kSTAtwHkMqednsRjdQS6NNJsuWc1reO8a4pKtsToJ3G9VAKufCkt2b8Nhqz0yLvLYwwU/mdI8DmfX6IgXhdy9njVEG/jsQnLFXY6QEfwKbIPs9O6qo4iFJg3defXX+zVMLsh3NE1P2i2VxMjxJEQdPdy9Z1sVpkiQM+mgJuylQQ5flPK8sxhO9r4uoK/JROkjPJNYoJMlsN+QlK04ABb7JV2JwhAL/Y8ypjQ13JdT")- `requires` Ssh.knownHost hosts "eubackup.kitenet.net" (User "root")+ `requires` Ssh.knownHost hosts "usw-s002.rsync.net" (User "root") & Ssh.authorizedKeys (User "family") (Context "git.kitenet.net") & User.accountFor (User "family") & Apt.installed ["git", "rsync", "cgit"]@@ -236,8 +231,7 @@ & Apache.modEnabled "cgi" where sshkey = "/root/.ssh/git.kitenet.net.key"- borgrepo = Borg.BorgRepoUsing [Borg.UseSshKey sshkey]- "joey@eubackup.kitenet.net:/home/joey/lib/backup/git.kitenet.net/git.kitenet.net.borg"+ borgrepo = rsyncNetBorgRepo "git.kitenet.net.borg" [Borg.UseSshKey sshkey] website hn = Apache.httpsVirtualHost' hn "/srv/web/git.kitenet.net/" letos [ Apache.iconDir , " <Directory /srv/web/git.kitenet.net/>"@@ -339,12 +333,11 @@ & File.dirExists d & File.ownerGroup d (User "joey") (Group "joey") -downloads :: [Host] -> Property (HasInfo + DebianLike)-downloads hosts = annexWebSite "/srv/git/downloads.git"+downloads :: Property (HasInfo + DebianLike)+downloads = annexWebSite "/srv/git/downloads.git" "downloads.kitenet.net" "840760dc-08f0-11e2-8c61-576b7e66acfd"- [("eubackup", "ssh://eubackup.kitenet.net/~/lib/downloads/")]- `requires` Ssh.knownHost hosts "eubackup.kitenet.net" (User "joey")+ [] tmp :: Property (HasInfo + DebianLike) tmp = propertyList "tmp.joeyh.name" $ props@@ -375,18 +368,6 @@ where conf = "/home/znc/.znc/configs/znc.conf" -kiteShellBox :: Property DebianLike-kiteShellBox = propertyList "kitenet.net shellinabox" $ props- & Apt.installed ["openssl", "shellinabox", "openssh-client"]- & File.hasContent "/etc/default/shellinabox"- [ "# Deployed by propellor"- , "SHELLINABOX_DAEMON_START=1"- , "SHELLINABOX_PORT=443"- , "SHELLINABOX_ARGS=\"--no-beep --service=/:SSH:kitenet.net\""- ]- `onChange` Service.restarted "shellinabox"- & Service.running "shellinabox"- githubBackup :: Property (HasInfo + DebianLike) githubBackup = propertyList "github-backup box" $ props & Apt.installed ["github-backup", "moreutils"]@@ -413,14 +394,6 @@ (User "joey") "/home/joey/lib/backup" "mkdir -p rsync.net && rsync --delete -az 2318@usw-s002.rsync.net: rsync.net" `requires` Ssh.knownHost hosts "usw-s002.rsync.net" (User "joey") -backupsBackedupFrom :: [Host] -> HostName -> FilePath -> Property DebianLike-backupsBackedupFrom hosts srchost destdir = Cron.niceJob desc- (Cron.Times "@reboot") (User "joey") "/" cmd- `requires` Ssh.knownHost hosts srchost (User "joey")- where- desc = "backups copied from " ++ srchost ++ " on boot"- cmd = "sleep 30m && rsync -az --bwlimit=300K --partial --delete " ++ srchost ++ ":lib/backup/ " ++ destdir </> srchost- podcatcher :: Property DebianLike podcatcher = Cron.niceJob "podcatcher run hourly" (Cron.Times "55 * * * *") (User "joey") "/home/joey/lib/sound/podcasts"@@ -949,6 +922,7 @@ user (userGroup user) `requires` File.dirExists (takeDirectory sshkeyfile) `requires` Ssh.knownHost hosts "kitenet.net" user+ & File.hasPrivContentExposed "/etc/darksky-forecast-url" anyContext where d = "/var/www/html/homepower" sshkeyfile = d </> ".ssh/key"@@ -1042,15 +1016,18 @@ -- rsync server command to be updated too. rsynccommand = "rsync -e 'ssh -i" ++ sshkeyfile ++ "' -avz rrds/ joey@kitenet.net:/srv/web/homepower.joeyh.name/rrds/" --- My home router, running hostapd and dnsmasq for wlan0,+homerouterWifiInterface :: String+homerouterWifiInterface = "wlan0" -- "wlx7cdd90400448" is a wifi dongle++-- My home router, running hostapd and dnsmasq, -- with eth0 connected to a satellite modem, and a fallback ppp connection. homeRouter :: Property (HasInfo + DebianLike) homeRouter = propertyList "home router" $ props- & Network.static "wlan0" (IPv4 "10.1.1.1") Nothing+ & Network.static homerouterWifiInterface (IPv4 "10.1.1.1") Nothing `requires` Network.cleanInterfacesFile & Apt.installed ["hostapd"] & File.hasContent "/etc/hostapd/hostapd.conf"- [ "interface=wlan0"+ [ "interface=" ++ homerouterWifiInterface , "ssid=house" , "hw_mode=g" , "channel=8"@@ -1059,6 +1036,7 @@ `requires` File.hasContent "/etc/default/hostapd" [ "DAEMON_CONF=/etc/hostapd/hostapd.conf" ] `onChange` Service.running "hostapd"+ & Systemd.enabled "hostapd" & File.hasContent "/etc/resolv.conf" [ "domain kitenet.net" , "search kitenet.net"@@ -1069,7 +1047,8 @@ & File.hasContent "/etc/dnsmasq.conf" [ "domain-needed" , "bogus-priv"- , "interface=wlan0"+ , "interface=" ++ homerouterWifiInterface+ , "interface=eth0" , "domain=kitenet.net" -- lease time is short because the homepower -- controller wants to know when clients disconnect@@ -1077,10 +1056,13 @@ , "no-hosts" , "address=/honeybee.kitenet.net/10.1.1.1" , "address=/house.kitenet.net/10.1.1.1"+ , "dhcp-host=0c:98:38:80:6a:f9,10.1.1.134,android-kodama" ] `onChange` Service.restarted "dnsmasq"- & ipmasq "wlan0"- & Apt.serviceInstalledRunning "netplug"+ & ipmasq homerouterWifiInterface+ -- Used to bring down eth0 when satellite is off, which causes ppp+ -- to start, but I am not using this currently.+ & Apt.removed ["netplug"] & Network.static' "eth0" (IPv4 "192.168.1.100") (Just (Network.Gateway (IPv4 "192.168.1.1"))) -- When satellite is down, fall back to dialup@@ -1101,7 +1083,7 @@ ] `before` File.hasPrivContent "/etc/ppp/pap-secrets" (Context "joeyh@arczip.com") --- | Enable IP masqerading, on whatever other interfaces come up than the+-- | Enable IP masqerading, on whatever other interfaces come up, besides the -- provided intif. ipmasq :: String -> Property DebianLike ipmasq intif = File.hasContent ifupscript@@ -1117,6 +1099,7 @@ , "echo 1 > /proc/sys/net/ipv4/ip_forward" ] `before` scriptmode ifupscript+ `before` File.dirExists (takeDirectory pppupscript) `before` File.hasContent pppupscript [ "#!/bin/sh" , "IFACE=$PPP_IFACE " ++ ifupscript@@ -1140,7 +1123,7 @@ , "mpc", "mpd", "ncmpc", "sonata", "mpdtoys" , "bsdgames", "nethack-console" , "xmonad", "libghc-xmonad-dev", "libghc-xmonad-contrib-dev"- , "ttf-bitstream-vera"+ , "ttf-bitstream-vera", "fonts-symbola", "fonts-noto-color-emoji" , "mairix", "offlineimap", "mutt", "slrn" , "mtr", "nmap", "whois", "wireshark", "tcpdump", "iftop" , "pmount", "tree", "pv"@@ -1179,16 +1162,20 @@ ] cubieTruckOneWire :: Property DebianLike-cubieTruckOneWire = - File.hasContent "/etc/easy-peasy-devicetree-squeezy/my.dts" mydts- `onChange` utilitysetup- `requires` utilityinstalled+cubieTruckOneWire = utilitysetup+ `requires` dtsinstalled+ `requires` utilityinstalled where+ dtsinstalled = File.hasContent "/etc/easy-peasy-devicetree-squeezy/my.dts" mydts+ `requires` File.dirExists "/etc/easy-peasy-devicetree-squeezy" utilityinstalled = Git.cloned (User "root") "https://git.joeyh.name/git/easy-peasy-devicetree-squeezy.git" "/usr/local/easy-peasy-devicetree-squeezy" Nothing `onChange` File.isSymlinkedTo "/usr/local/bin/easy-peasy-devicetree-squeezy" (File.LinkTarget "/usr/local/easy-peasy-devicetree-squeezy/easy-peasy-devicetree-squeezy")- utilitysetup = cmdProperty "easy-peasy-devicetree-squeezy"- ["--debian", "sun7i-a20-cubietruck"]- `assume` MadeChange+ `requires` Apt.installed ["pv", "device-tree-compiler", "cpp", "linux-source"]+ utilitysetup = check (not <$> doesFileExist dtb) $ + cmdProperty "easy-peasy-devicetree-squeezy"+ ["--debian", "sun7i-a20-cubietruck"]+ `assume` MadeChange+ dtb = "/etc/flash-kernel/dtbs/sun7i-a20-cubietruck.dtb" mydts = [ "/* Device tree addition enabling onewire sensors on CubieTruck GPIO pin PC21 */" , "#include <dt-bindings/gpio/gpio.h>"@@ -1209,3 +1196,102 @@ , "\t};" , "};" ]++-- My home networked attached storage server.+homeNAS :: Property DebianLike+homeNAS = propertyList "home NAS" $ props+ & Apt.installed ["uhubctl"]+ & "/etc/udev/rules.d/52-startech-hub.rules" `File.hasContent`+ [ "# let users power control startech hub with uhubctl"+ , "ATTR{idVendor}==\"0409\", ATTR{idProduct}==\"005a\", MODE=\"0666\""+ ]+ & autoMountDrive "archive-10" (USBHubPort 1) (Just "archive-older")+ & autoMountDrive "archive-11" (USBHubPort 2) (Just "archive-old")+ & autoMountDrive "archive-12" (USBHubPort 3) (Just "archive")+ & autoMountDrive "passport" (USBHubPort 4) Nothing+ & Apt.installed ["git-annex", "borgbackup"]++newtype USBHubPort = USBHubPort Int++-- Makes a USB drive with the given label automount, and unmount after idle+-- for a while.+--+-- The hub port is turned on and off automatically as needed, using+-- uhubctl.+autoMountDrive :: Mount.Label -> USBHubPort -> Maybe FilePath -> Property DebianLike+autoMountDrive label (USBHubPort port) malias = propertyList desc $ props+ & File.ownerGroup mountpoint (User "joey") (Group "joey")+ `requires` File.dirExists mountpoint+ & case malias of+ Just t -> ("/media/joey/" ++ t) `File.isSymlinkedTo`+ File.LinkTarget mountpoint+ Nothing -> doNothing <!> doNothing+ & File.hasContent ("/etc/systemd/system/" ++ mount)+ [ "[Unit]"+ , "Description=" ++ label+ , "Requires=" ++ hub+ , "After=" ++ hub+ , "[Mount]"+ -- avoid mounting whenever the block device is available,+ -- only want to automount on demand+ , "Options=noauto"+ , "What=" ++ devfile+ , "Where=" ++ mountpoint+ , "[Install]"+ , "WantedBy="+ ]+ `onChange` Systemd.daemonReloaded+ & File.hasContent ("/etc/systemd/system/" ++ hub)+ [ "[Unit]"+ , "Description=Startech usb hub port " ++ show port+ , "PartOf=" ++ mount+ , "[Service]"+ , "Type=oneshot"+ , "RemainAfterExit=true"+ , "ExecStart=/usr/sbin/uhubctl -a on -p " ++ show port+ , "ExecStop=/bin/sh -c 'uhubctl -a off -p " ++ show port +++ -- Powering off the port does not remove device+ -- files, so ask udev to remove the devfile; it will+ -- be added back after the drive next spins up+ -- and so avoid mount happening before the drive is+ -- spun up.+ -- (This only works when the devfile is in+ -- by-label.)+ "; udevadm trigger --action=remove " ++ devfile ++ " || true'"+ , "[Install]"+ , "WantedBy="+ ]+ `onChange` Systemd.daemonReloaded+ & File.hasContent ("/etc/systemd/system/" ++ automount)+ [ "[Unit]"+ , "Description=Automount " ++ label+ , "[Automount]"+ , "Where=" ++ mountpoint+ , "TimeoutIdleSec=300"+ , "[Install]"+ , "WantedBy=multi-user.target"+ ]+ `onChange` Systemd.daemonReloaded+ & Systemd.enabled automount+ & Systemd.started automount+ & Sudo.sudoersDFile ("automount-" ++ label)+ [ "joey ALL= NOPASSWD: " ++ sudocommands+ ]+ where+ devfile = "/dev/disk/by-label/" ++ label+ mountpoint = "/media/joey/" ++ label+ desc = "auto mount " ++ mountpoint+ hub = "startech-hub-port-" ++ show port ++ ".service"+ automount = svcbase ++ ".automount"+ mount = svcbase ++ ".mount"+ svcbase = Systemd.escapePath mountpoint+ sudocommands = intercalate " , " $ map (\c -> "/bin/systemctl " ++ c)+ [ "stop " ++ mountpoint+ , "start " ++ mountpoint+ ]++rsyncNetBorgRepo :: String -> [Borg.BorgRepoOpt] -> Borg.BorgRepo+rsyncNetBorgRepo d os = Borg.BorgRepoUsing os' ("2318@usw-s002.rsync.net:" ++ d)+ where+ -- rsync.net has a newer borg here+ os' = Borg.UsesEnvVar ("BORG_REMOTE_PATH", "borg1") : os
src/Propellor/Property/Sudo.hs view
@@ -7,37 +7,65 @@ import qualified Propellor.Property.Apt as Apt import Propellor.Property.User --- | Allows a user to sudo. If the user has a password, sudo is configured--- to require it. If not, NOPASSWORD is enabled for the user.+-- | Allows a user to run any command with sudo.+-- If the user has a password, sudo is configured to require it.+-- If not, NOPASSWORD is enabled for the user.+--+-- Writes to the file /etc/sudoers.d/000users rather than the main sudoers+-- file. This file should come before other include files that may eg,+-- allow running more specific commands without a password, since sudo+-- uses the last matching configuration line.+--+-- If the main sudoers file contains a conflicting line for+-- the user for ALL commands, the line will be removed.+--+-- Also ensures that the main sudoers file includes /etc/sudoers.d/ enabledFor :: User -> RevertableProperty DebianLike DebianLike enabledFor user@(User u) = setup `requires` Apt.installed ["sudo"] <!> cleanup where setup :: Property UnixLike setup = property' desc $ \w -> do locked <- liftIO $ isLockedPassword user- ensureProperty w $- fileProperty desc+ ensureProperty w $ combineProperties desc $ props+ & containsLine sudoers "#includedir /etc/sudoers.d"+ & fileProperty desc (modify locked . filter (wanted locked))- sudoers+ dfile+ & removeconflicting sudoers where desc = u ++ " is sudoer" cleanup :: Property DebianLike- cleanup = tightenTargets $ - fileProperty desc (filter notuserline) sudoers+ cleanup = tightenTargets $ combineProperties desc $ props+ & removeconflicting sudoers+ & removeconflicting dfile where desc = u ++ " is not sudoer" + removeconflicting = fileProperty "remove conflicting" (filter notuserline)+ sudoers = "/etc/sudoers"+ dfile = "/etc/sudoers.d/000users" sudobaseline = u ++ " ALL=(ALL:ALL)" notuserline l = not (sudobaseline `isPrefixOf` l) sudoline True = sudobaseline ++ " NOPASSWD:ALL" sudoline False = sudobaseline ++ " ALL" wanted locked l- -- TOOD: Full sudoers file format parse.. | notuserline l = True | "NOPASSWD" `isInfixOf` l = locked | otherwise = True modify locked ls | sudoline locked `elem` ls = ls | otherwise = ls ++ [sudoline locked]++-- | Sets up a file in /etc/sudoers.d/, which /etc/sudoers includes,+-- with the specified content.+--+-- The FilePath can be relative to that directory.+sudoersDFile :: FilePath -> [Line] -> RevertableProperty DebianLike Linux+sudoersDFile dfile content = setup `requires` Apt.installed ["sudo"] <!> cleanup+ where+ f = "/etc/sudoers.d" </> dfile+ -- sudoers.d files should not be world readable+ setup = hasContentProtected f content+ cleanup = tightenTargets $ notPresent f
src/Propellor/Property/Systemd.hs view
@@ -13,6 +13,7 @@ networkd, journald, logind,+ escapePath, -- * Configuration installed, Option,@@ -58,7 +59,9 @@ import Utility.Split import Data.List+import Data.Char import qualified Data.Map as M+import Text.Printf type ServiceName = String @@ -459,3 +462,15 @@ -- | Read-only mind mount. bindRo :: Bindable p => p -> RevertableProperty (HasInfo + Linux) (HasInfo + Linux) bindRo p = containerCfg $ "--bind-ro=" ++ toBind p++-- | Escapes a path for inclusion in a systemd unit name,+-- the same as systemd-escape does.+escapePath :: FilePath -> String+escapePath = concatMap escape + . dropWhile (== '/')+ . reverse . dropWhile (== '/') . reverse+ where+ escape '/' = "-"+ escape c+ | ((isAscii c && isAlphaNum c) || c == '_') = [c]+ | otherwise = '\\' : 'x' : printf "%x" c
src/Propellor/Types/Bootloader.hs view
@@ -10,6 +10,7 @@ = GrubInstalled GrubTarget | FlashKernelInstalled | UbootInstalled (FilePath -> FilePath -> Property Linux)+ | NoBootloader deriving (Typeable) -- | Platforms that grub can boot.@@ -19,6 +20,7 @@ show (GrubInstalled _) = "GrubInstalled" show FlashKernelInstalled = "FlashKernelInstalled" show (UbootInstalled _) = "UbootInstalled"+ show NoBootloader = "NoBootloader" instance IsInfo [BootloaderInstalled] where propagateInfo _ = PropagateInfo False