packages feed

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