summaryrefslogtreecommitdiff
path: root/src/Propellor/Property/SiteSpecific/JoeySites.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Propellor/Property/SiteSpecific/JoeySites.hs')
-rw-r--r--src/Propellor/Property/SiteSpecific/JoeySites.hs231
1 files changed, 177 insertions, 54 deletions
diff --git a/src/Propellor/Property/SiteSpecific/JoeySites.hs b/src/Propellor/Property/SiteSpecific/JoeySites.hs
index d8991cb1..d4263031 100644
--- a/src/Propellor/Property/SiteSpecific/JoeySites.hs
+++ b/src/Propellor/Property/SiteSpecific/JoeySites.hs
@@ -19,13 +19,14 @@ import qualified Propellor.Property.Obnam as Obnam
import qualified Propellor.Property.Apache as Apache
import qualified Propellor.Property.Postfix as Postfix
import qualified Propellor.Property.Systemd as Systemd
+import qualified Propellor.Property.Network as Network
import qualified Propellor.Property.Fail2Ban as Fail2Ban
import qualified Propellor.Property.LetsEncrypt as LetsEncrypt
import Utility.FileMode
+import Utility.Split
import Data.List
import System.Posix.Files
-import Data.String.Utils
scrollBox :: Property (HasInfo + DebianLike)
scrollBox = propertyList "scroll server" $ props
@@ -78,7 +79,8 @@ scrollBox = propertyList "scroll server" $ props
`onChange` Ssh.restarted
& User.shellSetTo (User "scroll") s
& User.hasPassword (User "scroll")
- & Apt.serviceInstalledRunning "telnetd"
+ -- telnetd attracted password crackers, so disabled
+ & Apt.removed ["telnetd"]
& Apt.installed ["shellinabox"]
& File.hasContent "/etc/default/shellinabox"
[ "# Deployed by propellor"
@@ -227,23 +229,29 @@ gitServer hosts = propertyList "git.kitenet.net setup" $ props
`requires` Ssh.knownHost hosts "usw-s002.rsync.net" (User "root")
`requires` Ssh.authorizedKeys (User "family") (Context "git.kitenet.net")
`requires` User.accountFor (User "family")
- & Apt.installed ["git", "rsync", "gitweb"]
+ & Apt.installed ["git", "rsync", "cgit"]
& Apt.installed ["git-annex"]
& Apt.installed ["kgb-client"]
& File.hasPrivContentExposed "/etc/kgb-bot/kgb-client.conf" anyContext
`requires` File.dirExists "/etc/kgb-bot/"
& Git.daemonRunning "/srv/git"
- & "/etc/gitweb.conf" `File.containsLines`
- [ "$projectroot = '/srv/git';"
- , "@git_base_url_list = ('git://git.kitenet.net', 'http://git.kitenet.net/git', 'https://git.kitenet.net/git', 'ssh://git.kitenet.net/srv/git');"
- , "# disable snapshot download; overloads server"
- , "$feature{'snapshot'}{'default'} = [];"
- ]
- `describe` "gitweb configured"
- -- Repos push on to github.
- & Ssh.knownHost hosts "github.com" (User "joey")
- -- I keep the website used for gitweb checked into git..
- & Git.cloned (User "root") "/srv/git/joey/git.kitenet.net.git" "/srv/web/git.kitenet.net" Nothing
+ & "/etc/cgitrc" `File.hasContent`
+ [ "clone-url=https://git.joeyh.name/git/$CGIT_REPO_URL git://git.joeyh.name/$CGIT_REPO_URL"
+ , "css=/cgit-css/cgit.css"
+ , "logo=/cgit-css/cgit.png"
+ , "enable-http-clone=1"
+ , "root-title=Joey's git repositories"
+ , "root-desc="
+ , "enable-index-owner=0"
+ , "snapshots=tar.gz"
+ , "enable-git-config=1"
+ , "scan-path=/srv/git"
+ ]
+ `describe` "cgit configured"
+ -- I keep the website used for git.kitenet.net/git.joeyh.name checked into git..
+ & Git.cloned (User "joey") "/srv/git/joey/git.kitenet.net.git" "/srv/web/git.kitenet.net" Nothing
+ -- Don't need global apache configuration for cgit.
+ ! Apache.confEnabled "cgit"
& website "git.kitenet.net"
& website "git.joeyh.name"
& Apache.modEnabled "cgi"
@@ -313,9 +321,9 @@ apacheSite hn middle = Apache.siteEnabled hn $ apachecfg hn middle
apachecfg :: HostName -> Apache.ConfigFile -> Apache.ConfigFile
apachecfg hn middle =
- [ "<VirtualHost *:"++show port++">"
+ [ "<VirtualHost *:" ++ val port ++ ">"
, " ServerAdmin grue@joeyh.name"
- , " ServerName "++hn++":"++show port
+ , " ServerName "++hn++":" ++ val port
]
++ middle ++
[ ""
@@ -328,7 +336,7 @@ apachecfg hn middle =
, "</VirtualHost>"
]
where
- port = 80 :: Int
+ port = Port 80
gitAnnexDistributor :: Property (HasInfo + DebianLike)
gitAnnexDistributor = combineProperties "git-annex distributor, including rsync server and signer" $ props
@@ -369,7 +377,7 @@ tmp = propertyList "tmp.joeyh.name" $ props
-- (Obsolete; need to revert this.)
pumpRss :: Property DebianLike
pumpRss = Cron.job "pump rss" (Cron.Times "15 * * * *") (User "joey") "/srv/web/tmp.joeyh.name/"
- "wget https://rss.io.jpope.org/feed/joeyh@identi.ca.atom -O pump.atom.new --no-check-certificate 2>/dev/null; sed 's/ & / /g' pump.atom.new > pump.atom"
+ "wget https://pump2rss.com/feed/joeyh@identi.ca.atom -O pump.atom.new --no-check-certificate 2>/dev/null; sed 's/ & / /g' pump.atom.new > pump.atom"
ircBouncer :: Property (HasInfo + DebianLike)
ircBouncer = propertyList "IRC bouncer" $ props
@@ -404,8 +412,6 @@ githubBackup = propertyList "github-backup box" $ props
& githubKeys
& Cron.niceJob "github-backup run" (Cron.Times "30 4 * * *") (User "joey")
"/home/joey/lib/backup" backupcmd
- & Cron.niceJob "gitriddance" (Cron.Times "30 4 * * *") (User "joey")
- "/home/joey/lib/backup" gitriddancecmd
where
backupcmd = intercalate "&&" $
[ "mkdir -p github"
@@ -413,11 +419,6 @@ githubBackup = propertyList "github-backup box" $ props
, ". $HOME/.github-keys"
, "github-backup joeyh"
]
- gitriddancecmd = intercalate "&&" $
- [ "cd github"
- , ". $HOME/.github-keys"
- ] ++ map gitriddance githubMirrors
- gitriddance (r, msg) = "(cd " ++ r ++ " && gitriddance " ++ shellEscape msg ++ ")"
githubKeys :: Property (HasInfo + UnixLike)
githubKeys =
@@ -426,19 +427,6 @@ githubKeys =
`onChange` File.ownerGroup f (User "joey") (Group "joey")
--- these repos are only mirrored on github, I don't want
--- all the proprietary features
-githubMirrors :: [(String, String)]
-githubMirrors =
- [ ("ikiwiki", plzuseurl "http://ikiwiki.info/todo/")
- , ("git-annex", plzuseurl "http://git-annex.branchable.com/todo/")
- , ("myrepos", plzuseurl "http://myrepos.branchable.com/todo/")
- , ("propellor", plzuseurl "http://propellor.branchable.com/todo/")
- , ("etckeeper", plzuseurl "http://etckeeper.branchable.com/todo/")
- ]
- where
- plzuseurl u = "Please submit changes to " ++ u ++ " instead of using github pull requests, which are not part of my workflow. Just open a todo item there and link to a git repository containing your changes. Did you know, git is a distributed system? The git repository doesn't even need to be on github! Please send any complaints to Github; they don't allow turning off pull requests or redirecting them elsewhere. -- A robot acting on behalf of Joey Hess"
-
rsyncNetBackup :: [Host] -> Property DebianLike
rsyncNetBackup hosts = Cron.niceJob "rsync.net copied in daily" (Cron.Times "30 5 * * *")
(User "joey") "/home/joey/lib/backup" "mkdir -p rsync.net && rsync --delete -az 2318@usw-s002.rsync.net: rsync.net"
@@ -452,16 +440,6 @@ backupsBackedupFrom hosts srchost destdir = Cron.niceJob desc
desc = "backups copied from " ++ srchost ++ " on boot"
cmd = "sleep 30m && rsync -az --bwlimit=300K --partial --delete " ++ srchost ++ ":lib/backup/ " ++ destdir </> srchost
-obnamRepos :: [String] -> Property UnixLike
-obnamRepos rs = propertyList ("obnam repos for " ++ unwords rs) $
- toProps (mkbase : map mkrepo rs)
- where
- mkbase = mkdir "/home/joey/lib/backup"
- `requires` mkdir "/home/joey/lib"
- mkrepo r = mkdir ("/home/joey/lib/backup/" ++ r ++ ".obnam")
- mkdir d = File.dirExists d
- `before` File.ownerGroup d (User "joey") (Group "joey")
-
podcatcher :: Property DebianLike
podcatcher = Cron.niceJob "podcatcher run hourly" (Cron.Times "55 * * * *")
(User "joey") "/home/joey/lib/sound/podcasts"
@@ -586,8 +564,8 @@ kiteMailServer = propertyList "kitenet.net mail server" $ props
, "# Enable postgrey."
, "smtpd_recipient_restrictions = permit_tls_clientcerts,permit_sasl_authenticated,,permit_mynetworks,reject_unauth_destination,check_policy_service inet:127.0.0.1:10023"
- , "# Enable spamass-milter, amavis-milter, opendkim"
- , "smtpd_milters = unix:/spamass/spamass.sock unix:amavis/amavis.sock inet:localhost:8891"
+ , "# Enable spamass-milter, amavis-milter (opendkim is not enabled because it causes mails forwarded from eg gmail to be rejected)"
+ , "smtpd_milters = unix:/spamass/spamass.sock unix:amavis/amavis.sock"
, "# opendkim is used for outgoing mail"
, "non_smtpd_milters = inet:localhost:8891"
, "milter_connect_macros = j {daemon_name} v {if_name} _"
@@ -694,6 +672,10 @@ dkimInstalled = go `onChange` Service.restarted "opendkim"
& File.ownerGroup "/etc/mail/dkim.key" (User "opendkim") (Group "opendkim")
& "/etc/default/opendkim" `File.containsLine`
"SOCKET=\"inet:8891@localhost\""
+ `onChange`
+ (cmdProperty "/lib/opendkim/opendkim.service.generate" []
+ `assume` MadeChange)
+ `onChange` Service.restarted "opendkim"
& "/etc/opendkim.conf" `File.containsLines`
[ "KeyFile /etc/mail/dkim.key"
, "SubDomains yes"
@@ -707,9 +689,20 @@ dkimInstalled = go `onChange` Service.restarted "opendkim"
domainKey :: (BindDomain, Record)
domainKey = (RelDomain "mail._domainkey", TXT "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCc+/rfzNdt5DseBBmfB3C6sVM7FgVvf4h1FeCfyfwPpVcmPdW6M2I+NtJsbRkNbEICxiP6QY2UM0uoo9TmPqLgiCCG2vtuiG6XMsS0Y/gGwqKM7ntg/7vT1Go9vcquOFFuLa5PnzpVf8hB9+PMFdS4NPTvWL2c5xxshl/RJzICnQIDAQAB")
-hasJoeyCAChain :: Property (HasInfo + UnixLike)
-hasJoeyCAChain = "/etc/ssl/certs/joeyca.pem" `File.hasPrivContentExposed`
- Context "joeyca.pem"
+postfixSaslPasswordClient :: Property (HasInfo + DebianLike)
+postfixSaslPasswordClient = combineProperties "postfix uses SASL password to authenticate with smarthost" $ props
+ & Postfix.satellite
+ & Postfix.mappedFile "/etc/postfix/sasl_passwd"
+ (`File.hasPrivContent` (Context "kitenet.net"))
+ & Postfix.mainCfFile `File.containsLines`
+ [ "# TLS setup for SASL auth to kite"
+ , "smtp_sasl_auth_enable = yes"
+ , "smtp_tls_security_level = encrypt"
+ , "smtp_sasl_tls_security_options = noanonymous"
+ , "relayhost = [kitenet.net]"
+ , "smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd"
+ ]
+ `onChange` Postfix.reloaded
hasPostfixCert :: Context -> Property (HasInfo + UnixLike)
hasPostfixCert ctx = combineProperties "postfix tls cert installed" $ props
@@ -790,6 +783,15 @@ legacyWebSites = propertyList "legacy web sites" $ props
, "# Redirect all to joeyh.name."
, "rewriterule (.*) http://joeyh.name$1 [r]"
]
+ & alias "homepower.joeyh.name"
+ & apacheSite "homepower.joeyh.name"
+ [ "DocumentRoot /srv/web/homepower.joeyh.name"
+ , "<Directory /srv/web/homepower.joeyh.name>"
+ , " Options Indexes ExecCGI"
+ , " AllowOverride None"
+ , Apache.allowAll
+ , "</Directory>"
+ ]
where
kitenetcfg =
-- /var/www is empty
@@ -891,7 +893,7 @@ userDirHtml = File.fileProperty "apache userdir is html" (map munge) conf
-- <http://joeyh.name/blog/entry/a_programmable_alarm_clock_using_systemd/>
--
-- oncalendar example value: "*-*-* 7:30"
-alarmClock :: String -> User -> String -> Property DebianLike
+alarmClock :: String -> User -> String -> Property Linux
alarmClock oncalendar (User user) command = combineProperties "goodmorning timer installed" $ props
& "/etc/systemd/system/goodmorning.timer" `File.hasContent`
[ "[Unit]"
@@ -925,3 +927,124 @@ alarmClock oncalendar (User user) command = combineProperties "goodmorning timer
& Systemd.started "goodmorning.timer"
& "/etc/systemd/logind.conf" `ConfFile.containsIniSetting`
("Login", "LidSwitchIgnoreInhibited", "no")
+
+-- My home power monitor.
+homePowerMonitor :: IsContext c => User -> c -> (SshKeyType, Ssh.PubKeyText) -> Property (HasInfo + DebianLike)
+homePowerMonitor user ctx sshkey = propertyList "home power monitor" $ props
+ & Apache.installed
+ & Apt.installed ["python2", "python-pymodbus"]
+ & File.ownerGroup "/var/www/html" user (userGroup user)
+ & Git.cloned user "git://git.kitenet.net/joey/homepower" d Nothing
+ `onChange` buildpoller
+ & Systemd.enabled servicename
+ `requires` serviceinstalled
+ `onChange` Systemd.started servicename
+ & Cron.niceJob "homepower upload"
+ (Cron.Times "1 * * * *") user d rsynccommand
+ `requires` Ssh.userKeyAt (Just sshkeyfile) user ctx sshkey
+ where
+ d = "/var/www/html/homepower"
+ sshkeyfile = d </> ".ssh/key"
+ buildpoller = userScriptProperty (User "joey")
+ [ "cd " ++ d
+ , "make"
+ ]
+ `assume` MadeChange
+ `requires` Apt.installed ["ghc", "make"]
+ servicename = "homepower"
+ servicefile = "/etc/systemd/system/" ++ servicename ++ ".service"
+ serviceinstalled = servicefile `File.hasContent`
+ [ "[Unit]"
+ , "Description=home power monitor"
+ , ""
+ , "[Service]"
+ , "ExecStart=" ++ d ++ "/poller"
+ , "WorkingDirectory=" ++ d
+ , "User=joey"
+ , "Group=joey"
+ , ""
+ , "[Install]"
+ , "WantedBy=multi-user.target"
+ ]
+ -- Only upload when eth0 is up; eg the satellite internet is up.
+ -- Any changes to the rsync command will need my .authorized_keys
+ -- rsync server command to be updated too.
+ rsynccommand = "if ip route | grep '^default' | grep -q eth0; then rsync -e 'ssh -i" ++ sshkeyfile ++ "' -avz rrds/recent/ joey@kitenet.net:/srv/web/homepower.joeyh.name/rrds/recent/; fi"
+
+-- My home router, running hostapd and dnsmasq for wlan0,
+-- 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
+ `requires` Network.cleanInterfacesFile
+ & Apt.serviceInstalledRunning "hostapd"
+ `requires` File.hasContent "/etc/hostapd/hostapd.conf"
+ [ "interface=wlan0"
+ , "ssid=house"
+ , "hw_mode=g"
+ , "channel=8"
+ ]
+ `requires` File.dirExists "/lib/hostapd"
+ & Apt.serviceInstalledRunning "dnsmasq"
+ `requires` File.hasContent "/etc/dnsmasq.conf"
+ [ "domain-needed"
+ , "bogus-priv"
+ , "interface=wlan0"
+ , "domain=kitenet.net"
+ , "dhcp-range=10.1.1.100,10.1.1.150,24h"
+ , "no-hosts"
+ , "address=/honeybee.kitenet.net/10.1.1.1"
+ ]
+ `requires` File.hasContent "/etc/resolv.conf"
+ [ "domain kitenet.net"
+ , "search kitenet.net"
+ , "nameserver 8.8.8.8"
+ , "nameserver 8.8.4.4"
+ ]
+ & ipmasq "wlan0"
+ & Apt.serviceInstalledRunning "netplug"
+ & Network.dhcp' "eth0"
+ -- When satellite is down, fall back to dialup
+ [ ("pre-up", "poff -a || true")
+ , ("post-down", "pon")
+ ]
+ `requires` Network.cleanInterfacesFile
+ & Apt.installed ["ppp"]
+ `before` File.hasContent "/etc/ppp/peers/provider"
+ [ "user \"joeyh@arczip.com\""
+ , "connect \"/usr/sbin/chat -v -f /etc/chatscripts/pap -T 9734111\""
+ , "/dev/ttyACM0"
+ , "115200"
+ , "noipdefault"
+ , "defaultroute"
+ , "persist"
+ , "noauth"
+ ]
+ `before` File.hasPrivContent "/etc/ppp/pap-secrets" (Context "joeyh@arczip.com")
+
+-- | Enable IP masqerading, on whatever other interfaces come up than the
+-- provided intif.
+ipmasq :: String -> Property DebianLike
+ipmasq intif = File.hasContent ifupscript
+ [ "#!/bin/sh"
+ , "INTIF=" ++ intif
+ , "if [ \"$IFACE\" = $INTIF ] || [ \"$IFACE\" = lo ]; then"
+ , "exit 0"
+ , "fi"
+ , "iptables -F"
+ , "iptables -A FORWARD -i $IFACE -o $INTIF -m state --state ESTABLISHED,RELATED -j ACCEPT"
+ , "iptables -A FORWARD -i $INTIF -o $IFACE -j ACCEPT"
+ , "iptables -t nat -A POSTROUTING -o $IFACE -j MASQUERADE"
+ , "echo 1 > /proc/sys/net/ipv4/ip_forward"
+ ]
+ `before` scriptmode ifupscript
+ `before` File.hasContent pppupscript
+ [ "#!/bin/sh"
+ , "IFACE=$PPP_IFACE " ++ ifupscript
+ ]
+ `before` scriptmode pppupscript
+ `requires` Apt.installed ["iptables"]
+ where
+ ifupscript = "/etc/network/if-up.d/ipmasq"
+ pppupscript = "/etc/ppp/ip-up.d/ipmasq"
+ scriptmode f = f `File.mode` combineModes (readModes ++ executeModes)