diff --git a/.envrc b/.envrc deleted file mode 100644 index 5fd603a..0000000 --- a/.envrc +++ /dev/null @@ -1,3 +0,0 @@ -layout python3 - -source_env_if_exists .envrc.local diff --git a/.gitignore b/.gitignore index 8c736ec..bbb5845 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,3 @@ .secrets.cfg* __pycache__ *.swp -.direnv -.envrc.local -.bw_debug_history diff --git a/Jenkinsfile b/Jenkinsfile index 8b0af2d..ef990d1 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,6 +1,15 @@ pipeline { agent any stages { + stage('editorconfig-checker') { + steps { + sh """ + wget -Oec-linux-amd64.tar.gz https://github.com/editorconfig-checker/editorconfig-checker/releases/latest/download/ec-linux-amd64.tar.gz + tar -xzf ec-linux-amd64.tar.gz && rm ec-linux-amd64.tar.gz + bin/ec-linux-amd64 -no-color -exclude '^bin/' + """ + } + } stage('install_requirements') { steps { sh """ @@ -9,22 +18,13 @@ pipeline { virtualenv -p python3 venv . venv/bin/activate - pip install --upgrade pip isort + pip install --upgrade pip pip install -r requirements.txt """ } } - stage('tests') { + stage('bw test') { parallel { - stage('syntax checking using editorconfig-checker') { - steps { - sh """ - wget -Oec-linux-amd64.tar.gz https://github.com/editorconfig-checker/editorconfig-checker/releases/latest/download/ec-linux-amd64.tar.gz - tar -xzf ec-linux-amd64.tar.gz && rm ec-linux-amd64.tar.gz - bin/ec-linux-amd64 -no-color -exclude '^bin/' - """ - } - } stage('config and metadata determinism') { steps { sh """ @@ -36,7 +36,7 @@ pipeline { """ } } - stage('bw test -i') { + stage('other tests') { steps { sh """ . venv/bin/activate diff --git a/PORT_MAP.md b/PORT_MAP.md index 908b747..c683843 100644 --- a/PORT_MAP.md +++ b/PORT_MAP.md @@ -30,13 +30,13 @@ Rule of thumb: keep ports below 10000 free for stuff that reserves ports. | 20010 | mautrix-telegram | Bridge | | 20020 | mautrix-whatsapp | Bridge | | 20030 | matrix-dimension | Matrix Integrations Manager| -| 20070 | matrix-synapse | sliding-sync | | 20080 | matrix-synapse | client, federation | | 20081 | matrix-synapse | prometheus metrics | | 20090 | matrix-media-repo | media_repo | | 20090 | matrix-media-repo | prometheus metrics | +| 21000 | pleroma | pleroma | | 21010 | grafana | grafana | -| 22000 | forgejo | forgejo | +| 22000 | gitea | gitea | | 22010 | jenkins-ci | Jenkins CI | | 22020 | travelynx | Travelynx Web | | 22030 | octoprint | OctoPrint Web Interface | @@ -45,9 +45,7 @@ Rule of thumb: keep ports below 10000 free for stuff that reserves ports. | 22060 | pretalx | gunicorn | | 22070 | paperless-ng | gunicorn | | 22080 | netbox | gunicorn | -| 22090 | jugendhackt_tools | gunicorn | -| 22100 | powerdnsadmin | gunicorn | -| 22110 | icinga2-statuspage | gunicorn | +| 22090 | openhab | http | | 22999 | nginx | stub_status | | 22100 | ntfy | http | diff --git a/README.md b/README.md index 6663cd4..c102b84 100644 --- a/README.md +++ b/README.md @@ -7,16 +7,3 @@ onto shared webhosting. `bw test` runs according to Jenkinsfile after every commit. [![Build Status](https://jenkins.franzi.business/buildStatus/icon?job=kunsi%2Fbundlewrap%2Fmain)](https://jenkins.franzi.business/job/kunsi/job/bundlewrap/job/main/) - -## automatix - -Ensure you set `bundlewrap: true` in your `~/.automatix.cfg.yaml`. - -## system naming - -All systems should be named after their location and use. - -For example, influxdb hosted at hetzner cloud will be `htz-cloud.influxdb`. - -The only exception to this are name servers, they are named after [demons -in fiction](https://en.wikipedia.org/wiki/List_of_demons_in_fiction). diff --git a/automatix/upgrade_debian_bullseye.yaml b/automatix/upgrade_debian_bullseye.yaml deleted file mode 100644 index 3eaee06..0000000 --- a/automatix/upgrade_debian_bullseye.yaml +++ /dev/null @@ -1,45 +0,0 @@ -name: Upgrade to debian bullseye -systems: - node: foonode - -always: - - has_zfs=python: NODES.node.has_bundle('zfs') - -pipeline: - - manual: "set icinga2 downtime: https://icinga.franzi.business/monitoring/host/schedule-downtime?host={SYSTEMS.node}" - - # apply first so we only see the upgrade changes later - - local: bw apply {SYSTEMS.node} - - manual: update debian version in node groups - - local: "bw apply -o bundle:apt -s symlink:/usr/bin/python pkg_apt: -- {SYSTEMS.node}" - - # double time! - - remote@node: DEBIAN_FRONTEND=noninteractive apt-get -y -q -o Dpkg::Options::=--force-confold dist-upgrade - - remote@node: DEBIAN_FRONTEND=noninteractive apt-get -y -q -o Dpkg::Options::=--force-confold dist-upgrade - - # reboot into bullseye - - remote@node: systemctl reboot - - local: | - exit=1 - while [[ $exit -ne 0 ]]; - do - sleep 1 - ssh {SYSTEMS.node} true - exit=$? - done - - # fix zfs and reboot again - - has_zfs?remote@node: zpool import tank -f - - has_zfs?remote@node: zpool upgrade -a - - has_zfs?remote@node: systemctl reboot - - has_zfs?local: | - exit=1 - while [[ $exit -ne 0 ]]; - do - sleep 1 - ssh {SYSTEMS.node} true - exit=$? - done - - # final apply - - local: bw apply {SYSTEMS.node} diff --git a/bundles/apt/files/deb822-sources b/bundles/apt/files/deb822-sources deleted file mode 100644 index c1b8202..0000000 --- a/bundles/apt/files/deb822-sources +++ /dev/null @@ -1,9 +0,0 @@ -% for uri in sorted(uris): -Types: ${' '.join(sorted(data.get('types', {'deb'})))} -URIs: ${uri} -Suites: ${os_release} -Components: ${' '.join(sorted(data.get('components', {'main'})))} -Architectures: ${' '.join(sorted(data.get('architectures', {'amd64'})))} -Signed-By: /etc/apt/trusted.gpg.d/${name}.list.asc - -% endfor diff --git a/bundles/apt/files/do-unattended-upgrades b/bundles/apt/files/do-unattended-upgrades index 3ed0166..5eb8adf 100644 --- a/bundles/apt/files/do-unattended-upgrades +++ b/bundles/apt/files/do-unattended-upgrades @@ -6,9 +6,9 @@ apt-get update DEBIAN_FRONTEND=noninteractive apt-get -y -q -o Dpkg::Options::=--force-confold dist-upgrade -DEBIAN_FRONTEND=noninteractive apt-get -y -q autoremove +DEBIAN_FRONTEND=noninteractive apt-get -y -q autoclean -DEBIAN_FRONTEND=noninteractive apt-get -y -q clean +DEBIAN_FRONTEND=noninteractive apt-get -y -q autoremove % if clean_old_kernels: existing=$(dpkg --get-selections | grep -E '^linux-(image|headers)-[0-9]' || true) diff --git a/bundles/apt/files/sources.list-debian-bookworm b/bundles/apt/files/sources.list-debian-bookworm deleted file mode 100644 index 852554d..0000000 --- a/bundles/apt/files/sources.list-debian-bookworm +++ /dev/null @@ -1,3 +0,0 @@ -deb http://deb.debian.org/debian/ bookworm main non-free contrib non-free-firmware -deb http://security.debian.org/debian-security bookworm-security main contrib non-free -deb http://deb.debian.org/debian/ bookworm-updates main contrib non-free diff --git a/bundles/apt/files/sources.list-debian-trixie b/bundles/apt/files/sources.list-debian-trixie deleted file mode 100644 index 6ac79f3..0000000 --- a/bundles/apt/files/sources.list-debian-trixie +++ /dev/null @@ -1,3 +0,0 @@ -deb http://deb.debian.org/debian/ trixie main non-free contrib non-free-firmware -deb http://security.debian.org/debian-security trixie-security main contrib non-free -deb http://deb.debian.org/debian/ trixie-updates main contrib non-free diff --git a/bundles/apt/files/sources.list-raspbian-buster b/bundles/apt/files/sources.list-raspbian-buster new file mode 100644 index 0000000..d52d1f9 --- /dev/null +++ b/bundles/apt/files/sources.list-raspbian-buster @@ -0,0 +1 @@ +deb http://raspbian.raspberrypi.org/raspbian/ buster main contrib non-free rpi diff --git a/bundles/apt/files/upgrade-and-reboot b/bundles/apt/files/upgrade-and-reboot index 81516e2..ab99a10 100644 --- a/bundles/apt/files/upgrade-and-reboot +++ b/bundles/apt/files/upgrade-and-reboot @@ -19,7 +19,7 @@ statusfile="/var/tmp/unattended_upgrades.status" # Workaround, because /var/tmp is usually 1777 [[ "$UID" == 0 ]] && chown root:root "$statusfile" -logins=$(ps h -C sshd -o euser | awk '$1 != "root" && $1 != "sshd" && $1 != "sshmon" && $1 != "nobody"') +logins=$(ps h -C sshd -o euser | awk '$1 != "root" && $1 != "sshd" && $1 != "sshmon"') if [[ -n "$logins" ]] then echo "Will abort now, there are active SSH logins: $logins" @@ -46,6 +46,10 @@ fi if [[ -f /var/run/reboot-required ]] && [[ "$auto_reboot_enabled" == "True" ]] then + if [[ -n "$reboot_mail_to" ]] + then + date | mail -s "SYSREBOOTNOW $nodename" "$reboot_mail_to" + fi systemctl reboot fi diff --git a/bundles/apt/files/upgrade-and-reboot.conf b/bundles/apt/files/upgrade-and-reboot.conf index 8eff278..ca71dce 100644 --- a/bundles/apt/files/upgrade-and-reboot.conf +++ b/bundles/apt/files/upgrade-and-reboot.conf @@ -1,2 +1,3 @@ nodename="${node.name}" +reboot_mail_to="${node.metadata.get('apt/unattended-upgrades/reboot_mail_to', '')}" auto_reboot_enabled="${node.metadata.get('apt/unattended-upgrades/reboot_enabled', True)}" diff --git a/bundles/apt/items.py b/bundles/apt/items.py index ea988af..ae0f87a 100644 --- a/bundles/apt/items.py +++ b/bundles/apt/items.py @@ -4,10 +4,11 @@ supported_os = { 'debian': { 10: 'buster', 11: 'bullseye', - 12: 'bookworm', - 13: 'trixie', 99: 'unstable', }, + 'raspbian': { + 10: 'buster', + }, } try: @@ -25,10 +26,6 @@ actions = { 'triggered': True, 'cascade_skip': False, }, - 'apt_execute_update_commands': { - 'command': ' && '.join(sorted(node.metadata.get('apt/additional_update_commands', {'true'}))), - 'triggered': True, - }, } files = { @@ -116,7 +113,7 @@ pkg_apt = { 'mtr': {}, 'ncdu': {}, 'ncurses-term': {}, - 'netcat-openbsd': {}, + 'netcat': {}, 'nmap': {}, 'python3': {}, 'python3-dev': {}, @@ -146,18 +143,12 @@ pkg_apt = { 'cloud-init': { 'installed': False, }, - 'molly-guard': { - 'installed': False, - }, 'netplan.io': { 'installed': False, }, 'popularity-contest': { 'installed': False, }, - 'python3-packaging': { - 'installed': False, - }, 'unattended-upgrades': { 'installed': False, }, @@ -174,44 +165,21 @@ if node.os_version[0] >= 11: } for name, data in node.metadata.get('apt/repos', {}).items(): - if 'items' in data: - files['/etc/apt/sources.list.d/{}.list'.format(name)] = { - 'content_type': 'mako', - 'content': ("\n".join(sorted(data['items']))).format( - os=node.os, - os_release=supported_os[node.os][node.os_version[0]], - ), - 'triggers': { - 'action:apt_update', - }, - } - elif 'uris' in data: - uris = { - x.format( - os=node.os, - os_release=supported_os[node.os][node.os_version[0]], - ) for x in data['uris'] - } - - files['/etc/apt/sources.list.d/{}.sources'.format(name)] = { - 'source': 'deb822-sources', - 'content_type': 'mako', - 'context': { - 'data': data, - 'name': name, - 'os_release': supported_os[node.os][node.os_version[0]], - 'uris': uris, - }, - 'triggers': { - 'action:apt_update', - }, - } + files['/etc/apt/sources.list.d/{}.list'.format(name)] = { + 'content_type': 'mako', + 'content': ("\n".join(sorted(data['items']))).format( + os=node.os, + os_release=supported_os[node.os][node.os_version[0]], + ), + 'triggers': { + 'action:apt_update', + }, + } if data.get('install_gpg_key', True): - if 'items' in data: - files['/etc/apt/sources.list.d/{}.list'.format(name)]['needs'] = { - 'file:/etc/apt/trusted.gpg.d/{}.list.asc'.format(name), - } + files['/etc/apt/sources.list.d/{}.list'.format(name)]['needs'] = { + 'file:/etc/apt/trusted.gpg.d/{}.list.asc'.format(name), + } files['/etc/apt/trusted.gpg.d/{}.list.asc'.format(name)] = { 'source': 'gpg-keys/{}.asc'.format(name), diff --git a/bundles/apt/metadata.py b/bundles/apt/metadata.py index 526f318..141d89a 100644 --- a/bundles/apt/metadata.py +++ b/bundles/apt/metadata.py @@ -21,24 +21,16 @@ defaults = { 'cron/jobs/upgrade-and-reboot' ) def patchday(metadata): - if not node.metadata.get('apt/unattended-upgrades/enabled', True): - return {} - day = metadata.get('apt/unattended-upgrades/day') hour = metadata.get('apt/unattended-upgrades/hour') - spread = metadata.get('apt/unattended-upgrades/spread_in_group', None) - if spread is not None: - spread_nodes = sorted(repo.nodes_in_group(spread)) - day += spread_nodes.index(node) - return { 'cron': { 'jobs': { 'upgrade-and-reboot': '{minute} {hour} * * {day} root /usr/local/sbin/upgrade-and-reboot'.format( minute=node.magic_number % 30, hour=hour, - day=day%7, + day=day, ), }, }, diff --git a/bundles/arch-with-gui/files/autologin.conf b/bundles/arch-with-gui/files/autologin.conf new file mode 100644 index 0000000..9398062 --- /dev/null +++ b/bundles/arch-with-gui/files/autologin.conf @@ -0,0 +1,3 @@ +[Autologin] +User=${user} +Session=i3.desktop diff --git a/bundles/arch-with-gui/items.py b/bundles/arch-with-gui/items.py new file mode 100644 index 0000000..9d3d911 --- /dev/null +++ b/bundles/arch-with-gui/items.py @@ -0,0 +1,103 @@ +from os import listdir +from os.path import join + +actions = { + 'fc-cache_flush': { + 'command': 'fc-cache -f', + 'triggered': True, + 'needs': { + 'pkg_pacman:fontconfig', + }, + }, + 'i3pystatus_create_virtualenv': { + 'command': '/usr/bin/python3 -m virtualenv -p python3 /opt/i3pystatus/venv/', + 'unless': 'test -d /opt/i3pystatus/venv/', + 'needs': { + 'directory:/opt/i3pystatus/src', + 'pkg_pacman:python-virtualenv', + }, + }, + 'i3pystatus_install': { + 'command': ' && '.join([ + 'cd /opt/i3pystatus/src', + '/opt/i3pystatus/venv/bin/pip install --upgrade pip colour netifaces basiciw pytz', + '/opt/i3pystatus/venv/bin/pip install --upgrade -e .', + ]), + 'needs': { + 'action:i3pystatus_create_virtualenv', + }, + 'triggered': True, + }, +} + +directories = { + '/etc/sddm.conf.d': { + 'purge': True, + }, + '/opt/i3pystatus/src': {}, + '/usr/share/fonts/bundlewrap': { + 'purge': True, + 'triggers': { + 'action:fc-cache_flush', + }, + }, +} + +svc_systemd = { + 'sddm': { + 'needs': { + 'pkg_pacman:sddm', + }, + }, +} + +git_deploy = { + '/opt/i3pystatus/src': { + 'repo': 'https://github.com/enkore/i3pystatus.git', + 'rev': 'current', + 'triggers': { + 'action:i3pystatus_install', + }, + }, +} + +for filename in listdir(join(repo.path, 'data', 'arch-with-gui', 'files', 'fonts')): + if filename.startswith('.'): + continue + + if filename.endswith('.vault'): + # XXX remove this once we have a new bundlewrap release + # https://github.com/bundlewrap/bundlewrap/commit/2429b153dd1ca6781cf3812e2dec9c2b646a546b + from os import environ + if environ.get('BW_VAULT_DUMMY_MODE', '0') == '1': + continue + + font_name = filename[:-6] + attrs = { + 'content': repo.vault.decrypt_file_as_base64(join('arch-with-gui', 'files', 'fonts', filename)), + 'content_type': 'base64', + } + else: + font_name = filename + attrs = { + 'source': join('fonts', filename), + 'content_type': 'binary', + } + + files[f'/usr/share/fonts/bundlewrap/{font_name}'] = { + 'triggers': { + 'action:fc-cache_flush', + }, + **attrs, + } + +if node.metadata.get('arch-with-gui/autologin_as', None): + files['/etc/sddm.conf.d/autologin.conf'] = { + 'context': { + 'user': node.metadata.get('arch-with-gui/autologin_as'), + }, + 'content_type': 'mako', + 'before': { + 'svc_systemd:sddm', + }, + } diff --git a/bundles/arch-with-gui/metadata.py b/bundles/arch-with-gui/metadata.py new file mode 100644 index 0000000..869a7f9 --- /dev/null +++ b/bundles/arch-with-gui/metadata.py @@ -0,0 +1,101 @@ +assert node.os == 'arch' + +defaults = { + 'backups': { + 'paths': { + '/etc/netctl', + }, + }, + 'icinga_options': { + 'exclude_from_monitoring': True, + }, + 'pacman': { + 'packages': { + # fonts + 'fontconfig': {}, + 'ttf-dejavu': { + 'needed_by': { + 'pkg_pacman:sddm', + }, + }, + + # login management + 'sddm': {}, + + # networking + 'netctl': {}, + 'rfkill': {}, + 'wpa_supplicant': {}, + 'wpa_actiond': {}, + + # shell and other gui stuff + 'dunst': {}, + 'fish': {}, + 'kitty': {}, + 'libnotify': {}, # provides notify-send + 'light': {}, + 'redshift': {}, + 'rofi': {}, + + # sound + 'pavucontrol': {}, + 'pulseaudio': {}, + 'pulseaudio-zeroconf': {}, + + # window management + 'i3-wm': {}, + 'i3lock': {}, + 'xss-lock': {}, + + # i3pystatus dependencies + 'iw': {}, + 'wireless_tools': {}, + + # Xorg + 'xf86-input-libinput': {}, + 'xorg-server': {}, + 'xorg-setxkbmap': {}, + 'xorg-xev': {}, + 'xorg-xinput': {}, + 'xorg-xset': {}, + + # all them apps + 'browserpass': {}, + 'browserpass-firefox': {}, + 'firefox': {}, + 'gimp': {}, + 'inkscape': {}, + 'maim': {}, + 'mosh': {}, + 'mpv': {}, + 'pass': {}, + 'pass-otp': {}, + 'pdftk': {}, + 'pwgen': {}, + 'qpdfview': {}, + 'sipcalc': {}, + 'the_silver_searcher': {}, + 'tlp': {}, + 'xclip': {}, + 'xdotool': {}, # needed for maim window selection + }, + }, +} + +@metadata_reactor.provides( + 'backups/paths', +) +def backup_every_user_home(metadata): + paths = set() + + for user, config in metadata.get('users', {}).items(): + if config.get('delete', False): + continue + + paths.add(config.get('home', f'/home/{user}')) + + return { + 'backups': { + 'paths': paths, + }, + } diff --git a/bundles/avahi-daemon/files/avahi-daemon.conf b/bundles/avahi-daemon/files/avahi-daemon.conf deleted file mode 100644 index 0ad1412..0000000 --- a/bundles/avahi-daemon/files/avahi-daemon.conf +++ /dev/null @@ -1,22 +0,0 @@ -[server] -host-name=${node.name.split('.')[-1]} -use-ipv4=yes -use-ipv6=${'yes' if node.metadata.get('avahi-daemon/use-ipv6') else 'no'} -allow-interfaces=${','.join(sorted(node.metadata.get('interfaces', {}).keys()))} -ratelimit-interval-usec=1000000 -ratelimit-burst=1000 - -[wide-area] -enable-wide-area=yes - -[publish] -disable-publishing=no -disable-user-service-publishing=no -publish-hinfo=yes -publish-workstation=no -publish-aaaa-on-ipv4=no -publish-a-on-ipv6=no - -[reflector] - -[rlimits] diff --git a/bundles/avahi-daemon/items.py b/bundles/avahi-daemon/items.py deleted file mode 100644 index 0a0f1aa..0000000 --- a/bundles/avahi-daemon/items.py +++ /dev/null @@ -1,18 +0,0 @@ -directories['/etc/avahi/services'] = { - 'purge': True, -} - -files['/etc/avahi/avahi-daemon.conf'] = { - 'content_type': 'mako', - 'triggers': { - 'svc_systemd:avahi-daemon:restart', - }, -} - -svc_systemd['avahi-daemon'] = { - 'needs': { - 'file:/etc/avahi/avahi-daemon.conf', - 'pkg_apt:avahi-daemon', - 'pkg_apt:libnss-mdns', - }, -} diff --git a/bundles/avahi-daemon/metadata.py b/bundles/avahi-daemon/metadata.py deleted file mode 100644 index f6c3ef5..0000000 --- a/bundles/avahi-daemon/metadata.py +++ /dev/null @@ -1,11 +0,0 @@ -defaults = { - 'apt': { - 'packages': { - 'avahi-daemon': {}, - 'libnss-mdns': {}, - }, - }, - 'avahi-daemon': { - 'use-ipv6': True, - } -} diff --git a/bundles/backup-client/files/generate-backup b/bundles/backup-client/files/generate-backup index 3fd9d7d..28ef49d 100644 --- a/bundles/backup-client/files/generate-backup +++ b/bundles/backup-client/files/generate-backup @@ -62,13 +62,10 @@ trap "on_exit" EXIT # redirect stdout and stderr to logfile prepare_and_cleanup_logdir -if [[ -z "$DEBUG" ]] -then - logfile="$logdir/backup--$(date '+%F--%H-%M-%S')--$$.log.gz" - echo "All log output will go to $logfile" | logger -it backup-client - exec > >(gzip >"$logfile") - exec 2>&1 -fi +logfile="$logdir/backup--$(date '+%F--%H-%M-%S')--$$.log.gz" +echo "All log output will go to $logfile" | logger -it backup-client +exec > >(gzip >"$logfile") +exec 2>&1 # this is where the real work starts ts_begin=$(date +%s) diff --git a/bundles/backup-client/items.py b/bundles/backup-client/items.py index facd113..6538803 100644 --- a/bundles/backup-client/items.py +++ b/bundles/backup-client/items.py @@ -19,12 +19,12 @@ else: if node.metadata.get('backups/exclude_from_backups', False): # make sure nobody tries to do something funny - for file in { + for file in [ '/etc/backup.priv', '/usr/local/bin/generate-backup', '/usr/local/bin/generate-backup-with-retries', '/var/tmp/backup.monitoring', # status file - }: + ]: files[file] = { 'delete': True, } @@ -33,17 +33,14 @@ else: backup_target = repo.get_node(node.metadata.get('backup-client/target')) files['/etc/backup.priv'] = { - 'content': repo.libs.ssh.generate_ed25519_private_key( - node.metadata.get('backup-client/user-name'), - backup_target, - ), + 'content': repo.vault.decrypt_file(join('backup', 'keys', f'{node.name}.key.vault')), 'mode': '0400', } files['/usr/local/bin/generate-backup'] = { 'content_type': 'mako', 'context': { - 'username': node.metadata.get('backup-client/user-name'), + 'username': node.metadata['backup-client']['user-name'], 'server': backup_target.metadata.get('backup-server/my_hostname'), 'port': backup_target.metadata.get('backup-server/my_ssh_port'), 'paths': backup_paths, diff --git a/bundles/backup-server/files/check_backup_for_node b/bundles/backup-server/files/check_backup_for_node index bf57012..b7866f8 100644 --- a/bundles/backup-server/files/check_backup_for_node +++ b/bundles/backup-server/files/check_backup_for_node @@ -2,6 +2,7 @@ from datetime import datetime from json import load +from subprocess import check_output from sys import argv, exit from time import time @@ -17,17 +18,29 @@ try: with open(f'/etc/backup-server/config.json', 'r') as f: server_settings = load(f) - with open(f'/etc/backup-server/backups.json', 'r') as f: - backups = load(f) + # get all existing snapshots for NODE + for line in check_output('LC_ALL=C zfs list -H -t snapshot -o name', shell=True).splitlines(): + line = line.decode('UTF-8') - if NODE not in backups: + if line.startswith('{}/{}@'.format(server_settings['zfs-base'], NODE)): + _, snapname = line.split('@', 1) + + if 'zfs-auto-snap' in snapname: + # migration from auto-snapshots, ignore + continue + + ts, bucket = snapname.split('-', 1) + snaps.add(int(ts)) + + if not snaps: print('No backups found!') exit(2) - delta = NOW - backups[NODE] + last_snap = sorted(snaps)[-1] + delta = NOW - last_snap print('Last backup was on {} UTC'.format( - datetime.fromtimestamp(backups[NODE]).strftime('%Y-%m-%d %H:%M:%S'), + datetime.fromtimestamp(last_snap).strftime('%Y-%m-%d %H:%M:%S'), )) # One day without backups is still okay. There may be fluctuations diff --git a/bundles/backup-server/files/check_backup_for_node-cron b/bundles/backup-server/files/check_backup_for_node-cron deleted file mode 100644 index ff1a368..0000000 --- a/bundles/backup-server/files/check_backup_for_node-cron +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python3 - -from json import load, dump -from subprocess import check_output -from shutil import move -from os import remove -from collections import defaultdict - -with open('/etc/backup-server/config.json', 'r') as f: - server_settings = load(f) - -snapshots = defaultdict(set) - -for line in check_output('LC_ALL=C zfs list -H -t snapshot -o name', shell=True).splitlines(): - line = line.decode('UTF-8') - - if line.startswith('{}/'.format(server_settings['zfs-base'])): - try: - dataset, snapname = line.split('@', 1) - - dataset = dataset.split('/')[-1] - ts, bucket = snapname.split('-', 1) - - snapshots[dataset].add(int(ts)) - except Exception as e: - print(f"Exception while parsing snapshot name {line!r}: {e!r}") - -backups = {} -for dataset, snaps in snapshots.items(): - backups[dataset] = sorted(snaps)[-1] - -with open('/etc/backup-server/backups.tmp.json', 'w') as f: - dump(backups, f) - -move( - '/etc/backup-server/backups.tmp.json', - '/etc/backup-server/backups.json', -) diff --git a/bundles/backup-server/files/rotate-single-backup-client b/bundles/backup-server/files/rotate-single-backup-client index c76c6b5..ee49e26 100644 --- a/bundles/backup-server/files/rotate-single-backup-client +++ b/bundles/backup-server/files/rotate-single-backup-client @@ -33,11 +33,12 @@ for line in check_output('LC_ALL=C zfs list -H -t snapshot -o name', shell=True) if line.startswith('{}/{}@'.format(server_settings['zfs-base'], NODE)): _, snapname = line.split('@', 1) - ts, bucket = snapname.split('-', 1) - if not ts.isdigit(): + if 'zfs-auto-snap' in snapname: + # migration from auto-snapshots, ignore continue + ts, bucket = snapname.split('-', 1) buckets.setdefault(bucket, set()).add(int(ts)) syslog(f'classified {line} as {bucket} from {ts}') diff --git a/bundles/backup-server/items.py b/bundles/backup-server/items.py index e872231..c70512c 100644 --- a/bundles/backup-server/items.py +++ b/bundles/backup-server/items.py @@ -1,7 +1,6 @@ repo.libs.tools.require_bundle(node, 'zfs') from os.path import join - from bundlewrap.metadata import metadata_to_json dataset = node.metadata.get('backup-server/zfs-base') @@ -18,9 +17,6 @@ files = { '/usr/local/share/icinga/plugins/check_backup_for_node': { 'mode': '0755', }, - '/usr/local/share/icinga/plugins/check_backup_for_node-cron': { - 'mode': '0755', - }, } directories['/etc/backup-server/clients'] = { @@ -30,6 +26,9 @@ directories['/etc/backup-server/clients'] = { sudoers = {} for nodename, config in node.metadata.get('backup-server/clients', {}).items(): + with open(join(repo.path, 'data', 'backup', 'keys', f'{nodename}.pub'), 'r') as f: + pubkey = f.read().strip() + sudoers[config['user']] = nodename users[config['user']] = { @@ -41,10 +40,7 @@ for nodename, config in node.metadata.get('backup-server/clients', {}).items(): } files[f'/srv/backups/{nodename}/.ssh/authorized_keys'] = { - 'content': repo.libs.ssh.generate_ed25519_public_key( - config['user'], - node, - ), + 'content': pubkey, 'owner': config['user'], 'mode': '0400', 'needs': { diff --git a/bundles/backup-server/metadata.py b/bundles/backup-server/metadata.py index 6714288..098e264 100644 --- a/bundles/backup-server/metadata.py +++ b/bundles/backup-server/metadata.py @@ -1,5 +1,3 @@ -from bundlewrap.exceptions import BundleError - defaults = { 'backup-server': { 'my_ssh_port': 22, @@ -10,14 +8,6 @@ defaults = { 'c-*', }, }, - 'systemd-timers': { - 'timers': { - 'check_backup_for_node-cron': { - 'command': '/usr/local/share/icinga/plugins/check_backup_for_node-cron', - 'when': '*-*-* *:00/5:00', # every five minutes - } - }, - }, 'zfs': { # The whole point of doing backups is to keep them for a long # time, which eliminates the need for this check. @@ -45,15 +35,8 @@ def get_my_clients(metadata): continue my_clients[rnode.name] = { - 'exclude_from_monitoring': rnode.metadata.get( - 'backup-client/exclude_from_monitoring', - rnode.metadata.get( - 'icinga_options/exclude_from_monitoring', - False, - ), - ), - 'one_backup_every_hours': rnode.metadata.get('backup-client/one_backup_every_hours', 24), 'user': rnode.metadata.get('backup-client/user-name'), + 'one_backup_every_hours': rnode.metadata.get('backup-client/one_backup_every_hours', 24), 'retain': { 'daily': rnode.metadata.get('backups/retain/daily', retain_defaults['daily']), 'weekly': rnode.metadata.get('backups/retain/weekly', retain_defaults['weekly']), @@ -79,28 +62,25 @@ def zfs_pool(metadata): return {} crypt_devices = {} + pool_devices = set() unlock_actions = set() - devices = metadata.get('backup-server/encrypted-devices') - - pool_devices = set() - - for device, dconfig in devices.items(): - crypt_devices[dconfig['device']] = { - 'dm-name': f'backup-{device}', - 'passphrase': dconfig['passphrase'], + for number, (device, passphrase) in enumerate(sorted(metadata.get('backup-server/encrypted-devices', {}).items())): + crypt_devices[device] = { + 'dm-name': f'backup{number}', + 'passphrase': passphrase, } - pool_devices.add(f'/dev/mapper/backup-{device}') - unlock_actions.add(f'action:dm-crypt_open_backup-{device}') + pool_devices.add(f'/dev/mapper/backup{number}') + unlock_actions.add(f'action:dm-crypt_open_backup{number}') - pool_config = [{ + pool_opts = { 'devices': pool_devices, - }] + } if len(pool_devices) > 2: - pool_config[0]['type'] = 'raidz' + pool_opts['type'] = 'raidz' elif len(pool_devices) > 1: - pool_config[0]['type'] = 'mirror' + pool_opts['type'] = 'mirror' return { 'backup-server': { @@ -113,8 +93,9 @@ def zfs_pool(metadata): 'pools': { 'backups': { 'when_creating': { - 'config': pool_config, - **metadata.get('backup-server/zpool_create_options', {}), + 'config': [ + pool_opts, + ], }, 'needs': unlock_actions, # That's a bit hacky. We do it this way to auto-import @@ -168,11 +149,11 @@ def monitoring(metadata): continue services[f'BACKUPS FOR NODE {client}'] = { - 'command_on_monitored_host': '/usr/local/share/icinga/plugins/check_backup_for_node {} {}'.format( + 'command_on_monitored_host': 'sudo /usr/local/share/icinga/plugins/check_backup_for_node {} {}'.format( client, config['one_backup_every_hours'], ), - 'vars.sshmon_timeout': 40, + 'vars.sshmon_timeout': 20, } return { diff --git a/bundles/basic/files/htoprc b/bundles/basic/files/htoprc index f9dfd53..68ef687 100644 --- a/bundles/basic/files/htoprc +++ b/bundles/basic/files/htoprc @@ -32,8 +32,8 @@ account_guest_in_cpu_meter=0 color_scheme=0 enable_mouse=0 delay=10 -left_meters=Tasks LoadAverage Uptime Memory CPU LeftCPUs2 CPU +left_meters=Tasks LoadAverage Uptime Memory CPU LeftCPUs CPU left_meter_modes=2 2 2 1 1 1 2 -right_meters=Hostname CPU RightCPUs2 +right_meters=Hostname CPU RightCPUs right_meter_modes=2 3 1 hide_function_bar=0 diff --git a/bundles/basic/items.py b/bundles/basic/items.py index c2cdd49..d25d4c7 100644 --- a/bundles/basic/items.py +++ b/bundles/basic/items.py @@ -24,23 +24,13 @@ files = { 'before': { 'action:', 'pkg_apt:', + 'pkg_pacman:', }, }, } -if node.has_any_bundle([ - 'dovecot', - 'nginx', - 'postfix', -]): - actions['generate-dhparam'] = { - 'command': 'openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048', - 'unless': 'test -f /etc/ssl/certs/dhparam.pem', - } - - locale_needs = set() -for locale in sorted(node.metadata.get('locale/installed')): +for locale in sorted(node.metadata['locale']['installed']): actions[f'ensure_locale_{locale}_is_enabled'] = { 'command': f"sed -i '/{locale}/s/^# *//g' /etc/locale.gen", 'unless': f"grep -e '^{locale}' /etc/locale.gen", @@ -51,15 +41,17 @@ for locale in sorted(node.metadata.get('locale/installed')): } locale_needs = {f'action:ensure_locale_{locale}_is_enabled'} -actions['locale-gen'] = { - 'triggered': True, - 'command': 'locale-gen', +actions = { + 'locale-gen': { + 'triggered': True, + 'command': 'locale-gen', + }, } description = [] if not node.metadata.get('icinga_options/exclude_from_monitoring', False): - description.append('icingaweb2: https://icinga.franzi.business/monitoring/host/show?host={}'.format(node.name)) + description.append('icingaweb2: https://icinga.kunsmann.eu/monitoring/host/show?host={}'.format(node.name)) if node.has_bundle('telegraf'): description.append('Grafana: https://grafana.kunsmann.eu/d/{}'.format(UUID(int=node.magic_number).hex[:10])) diff --git a/bundles/bird/files/bird.conf b/bundles/bird/files/bird.conf index b3ebbc9..0e6e876 100644 --- a/bundles/bird/files/bird.conf +++ b/bundles/bird/files/bird.conf @@ -19,9 +19,7 @@ protocol static { ipv4; % for route in sorted(node.metadata.get('bird/static_routes', set())): -% for name, config in sorted(node.metadata.get('bird/bgp_neighbors', {}).items()): - route ${route} via ${config['local_ip']}; -% endfor + route ${route} via ${node.metadata.get('bird/my_ip')}; % endfor } % endif diff --git a/bundles/bird/items.py b/bundles/bird/items.py index 4c4b51c..38a1549 100644 --- a/bundles/bird/items.py +++ b/bundles/bird/items.py @@ -1,5 +1,10 @@ +if node.os == 'arch': + filename = '/etc/bird.conf' +else: + filename = '/etc/bird/bird.conf' + files = { - '/etc/bird/bird.conf': { + filename: { 'content_type': 'mako', 'triggers': { 'svc_systemd:bird:reload', @@ -10,7 +15,7 @@ files = { svc_systemd = { 'bird': { 'needs': { - f'file:/etc/bird/bird.conf', + f'file:{filename}', }, }, } diff --git a/bundles/bird/metadata.py b/bundles/bird/metadata.py index f6096a7..fd285d3 100644 --- a/bundles/bird/metadata.py +++ b/bundles/bird/metadata.py @@ -1,5 +1,4 @@ from ipaddress import ip_network - from bundlewrap.exceptions import NoSuchNode from bundlewrap.metadata import atomic @@ -13,9 +12,18 @@ defaults = { }, }, }, + 'pacman': { + 'packages': { + 'bird': { + 'needed_by': { + 'svc_systemd:bird', + }, + }, + }, + }, 'sysctl': { 'options': { - 'net.ipv4.conf.all.forwarding': '1', + 'net.ipv4.ip_forward': '1', 'net.ipv6.conf.all.forwarding': '1', }, }, @@ -34,9 +42,6 @@ def neighbor_info_from_wireguard(metadata): except NoSuchNode: continue - if not rnode.has_bundle('bird'): - continue - neighbors[name] = { 'local_ip': config['my_ip'], 'local_as': my_as, @@ -56,10 +61,7 @@ def neighbor_info_from_wireguard(metadata): ) def my_ip(metadata): if node.has_bundle('wireguard'): - wg_ifaces = sorted({iface for iface in metadata.get('interfaces').keys() if iface.startswith('wg_')}) - if not wg_ifaces: - return {} - my_ip = sorted(metadata.get(f'interfaces/{wg_ifaces[0]}/ips'))[0].split('/')[0] + my_ip = sorted(metadata.get('interfaces/wg0/ips'))[0].split('/')[0] else: my_ip = str(sorted(repo.libs.tools.resolve_identifier(repo, node.name))[0]) @@ -81,7 +83,7 @@ def firewall(metadata): return { 'firewall': { 'port_rules': { - '179/tcp': atomic(sources), + '179': atomic(sources), }, }, } diff --git a/bundles/c3voc-addons/items.py b/bundles/c3voc-addons/items.py index cd7612b..a8116a2 100644 --- a/bundles/c3voc-addons/items.py +++ b/bundles/c3voc-addons/items.py @@ -1,19 +1,5 @@ from bundlewrap.exceptions import BundleError -supported_os = { - 'debian': { - 10: 'buster', - 11: 'bullseye', - 12: 'bookworm', - 99: 'unstable', - }, -} - -try: - supported_os[node.os][node.os_version[0]] -except (KeyError, IndexError): - raise BundleError(f'{node.name}: OS {node.os} {node.os_version} is not supported by bundle:apt') - CONFLICTING_BUNDLES = { 'apt', 'nginx', @@ -71,18 +57,6 @@ actions = { 'svc_systemd:', }, }, - 'apt_update': { - 'command': 'apt-get update', - 'needed_by': { - 'pkg_apt:', - }, - 'triggered': True, - 'cascade_skip': False, - }, - 'apt_execute_update_commands': { - 'command': ' && '.join(sorted(node.metadata.get('apt/additional_update_commands', {'true'}))), - 'triggered': True, - }, } directories = { @@ -118,30 +92,6 @@ files = { }, } -for name, data in node.metadata.get('apt/repos', {}).items(): - files['/etc/apt/sources.list.d/{}.list'.format(name)] = { - 'content_type': 'mako', - 'content': ("\n".join(sorted(data['items']))).format( - os=node.os, - os_release=supported_os[node.os][node.os_version[0]], - ), - 'triggers': { - 'action:apt_update', - }, - } - - if data.get('install_gpg_key', True): - files['/etc/apt/sources.list.d/{}.list'.format(name)]['needs'] = { - 'file:/etc/apt/trusted.gpg.d/{}.list.asc'.format(name), - } - - files['/etc/apt/trusted.gpg.d/{}.list.asc'.format(name)] = { - 'source': 'gpg-keys/{}.asc'.format(name), - 'triggers': { - 'action:apt_update', - }, - } - for crontab, content in node.metadata.get('cron/jobs', {}).items(): files['/etc/cron.d/{}'.format(crontab)] = { 'source': 'cron_template', diff --git a/bundles/cron/items.py b/bundles/cron/items.py index 577bb59..81409b8 100644 --- a/bundles/cron/items.py +++ b/bundles/cron/items.py @@ -1,3 +1,10 @@ +if node.os == 'arch': + service_name = 'cronie' + package_name = 'pkg_pacman:cronie' +else: + service_name = 'cron' + package_name = 'pkg_apt:cron' + files = { '/etc/crontab': { 'content_type': 'mako', @@ -10,16 +17,16 @@ files = { directories = { '/etc/cron.d': { 'purge': True, - 'after': { + 'needs': { 'pkg_apt:', }, }, } svc_systemd = { - 'cron': { + service_name: { 'needs': { - 'pkg_apt:cron', + package_name, }, }, } diff --git a/bundles/cron/metadata.py b/bundles/cron/metadata.py index 67b2b22..66d612a 100644 --- a/bundles/cron/metadata.py +++ b/bundles/cron/metadata.py @@ -4,4 +4,9 @@ defaults = { 'cron': {}, }, }, + 'pacman': { + 'packages': { + 'cronie': {}, + }, + }, } diff --git a/bundles/dhcpd/files/dhcpd.conf b/bundles/dhcpd/files/dhcpd.conf new file mode 100644 index 0000000..97e734b --- /dev/null +++ b/bundles/dhcpd/files/dhcpd.conf @@ -0,0 +1,36 @@ +<% + import re + from ipaddress import ip_network +%> +ddns-update-style none; + +authoritative; + +% for interface, subnet in sorted(dhcp_config.get('subnets', {}).items()): +<% + network = ip_network(subnet['subnet']) +%> +# interface ${interface} provides ${subnet['subnet']} +subnet ${network.network_address} netmask ${network.netmask} { +% if subnet.get('range_lower', None) and subnet.get('range_higher', None): + range ${subnet['range_lower']} ${subnet['range_higher']}; +% endif + interface "${interface}"; + default-lease-time ${subnet.get('default-lease-time', 600)}; + max-lease-time ${subnet.get('max-lease-time', 3600)}; +% for option, value in sorted(subnet.get('options', {}).items()): +% if re.match('([^0-9\.,\ ])', value): + option ${option} "${value}"; +% else: + option ${option} ${value}; +% endif +% endfor +} +% endfor + +% for identifier, allocation in dhcp_config.get('fixed_allocations', {}).items(): +host ${identifier} { + hardware ethernet ${allocation['mac']}; + fixed-address ${allocation['ipv4']}; +} +% endfor diff --git a/bundles/dhcpd/files/isc-dhcp-server b/bundles/dhcpd/files/isc-dhcp-server new file mode 100644 index 0000000..4b0120d --- /dev/null +++ b/bundles/dhcpd/files/isc-dhcp-server @@ -0,0 +1,18 @@ +# Defaults for isc-dhcp-server (sourced by /etc/init.d/isc-dhcp-server) + +# Path to dhcpd's config file (default: /etc/dhcp/dhcpd.conf). +#DHCPDv4_CONF=/etc/dhcp/dhcpd.conf +#DHCPDv6_CONF=/etc/dhcp/dhcpd6.conf + +# Path to dhcpd's PID file (default: /var/run/dhcpd.pid). +#DHCPDv4_PID=/var/run/dhcpd.pid +#DHCPDv6_PID=/var/run/dhcpd6.pid + +# Additional options to start dhcpd with. +# Don't use options -cf or -pf here; use DHCPD_CONF/ DHCPD_PID instead +#OPTIONS="" + +# On what interfaces should the DHCP server (dhcpd) serve DHCP requests? +# Separate multiple interfaces with spaces, e.g. "eth0 eth1". +INTERFACESv4="${' '.join(sorted(node.metadata.get('dhcpd/subnets', {})))}" +INTERFACESv6="" diff --git a/bundles/dhcpd/items.py b/bundles/dhcpd/items.py new file mode 100644 index 0000000..bdf9944 --- /dev/null +++ b/bundles/dhcpd/items.py @@ -0,0 +1,41 @@ +files = { + '/etc/dhcp/dhcpd.conf': { + 'content_type': 'mako', + 'context': { + 'dhcp_config': node.metadata['dhcpd'], + }, + 'needs': { + 'pkg_apt:isc-dhcp-server' + }, + 'triggers': { + 'svc_systemd:isc-dhcp-server:restart', + }, + }, + '/etc/default/isc-dhcp-server': { + 'content_type': 'mako', + 'needs': { + 'pkg_apt:isc-dhcp-server' + }, + 'triggers': { + 'svc_systemd:isc-dhcp-server:restart', + }, + }, +} + +actions = { + # needed for dhcp-lease-list + 'dhcpd_download_oui.txt': { + 'command': 'wget http://standards-oui.ieee.org/oui.txt -O /usr/local/etc/oui.txt', + 'unless': 'test -f /usr/local/etc/oui.txt', + }, +} + +svc_systemd = { + 'isc-dhcp-server': { + 'needs': { + 'pkg_apt:isc-dhcp-server', + 'file:/etc/dhcp/dhcpd.conf', + 'file:/etc/default/isc-dhcp-server', + }, + }, +} diff --git a/bundles/dhcpd/metadata.py b/bundles/dhcpd/metadata.py new file mode 100644 index 0000000..cc091af --- /dev/null +++ b/bundles/dhcpd/metadata.py @@ -0,0 +1,54 @@ +defaults = { + 'apt': { + 'packages': { + 'isc-dhcp-server': {}, + }, + }, + 'bash_aliases': { + 'leases': 'sudo dhcp-lease-list | tail -n +4 | sort -k 2,2', + }, +} + + +@metadata_reactor.provides( + 'dhcpd/fixed_allocations', +) +def get_static_allocations(metadata): + allocations = {} + for rnode in repo.nodes: + if rnode.metadata.get('location', '') != metadata.get('location', ''): + continue + + for iface_name, iface_config in rnode.metadata.get('interfaces', {}).items(): + if iface_config.get('dhcp', False): + try: + allocations[f'{rnode.name}_{iface_name}'] = { + 'ipv4': sorted(iface_config['ips'])[0], + 'mac': iface_config['mac'], + } + except KeyError: + pass + + return { + 'dhcpd': { + 'fixed_allocations': allocations, + } + } + + +@metadata_reactor.provides( + 'nftables/rules/10-dhcpd', +) +def nftables(metadata): + rules = set() + for iface in node.metadata.get('dhcpd/subnets', {}): + rules.add(f'inet filter input udp dport {{ 67, 68 }} iif {iface} accept') + + return { + 'nftables': { + 'rules': { + # can't use port_rules here, because we're generating interface based rules. + '10-dhcpd': sorted(rules), + }, + } + } diff --git a/bundles/docker-engine/files/check_docker_container b/bundles/docker-engine/files/check_docker_container deleted file mode 100644 index ea94173..0000000 --- a/bundles/docker-engine/files/check_docker_container +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python3 - -from json import loads -from subprocess import check_output -from sys import argv - -try: - container_name = argv[1] - - docker_ps = check_output([ - 'docker', - 'container', - 'ls', - '--all', - '--format', - 'json', - '--filter', - f'name={container_name}' - ]) - - docker_json = loads(f"[{','.join([l for l in docker_ps.decode().splitlines() if l])}]") - - containers = [ - container - for container in docker_json - if container['Names'] == container_name - ] - - if not containers: - print(f'CRITICAL: container {container_name} not found!') - exit(2) - - if len(containers) > 1: - print(f'Found more than one container matching {container_name}!') - print(docker_ps) - exit(3) - - if containers[0]['State'] != 'running': - print(f'WARNING: container {container_name} not "running"') - exit(2) - - print(f"OK: {containers[0]['Status']}") -except Exception as e: - print(repr(e)) - exit(2) diff --git a/bundles/docker-engine/files/docker-wrapper b/bundles/docker-engine/files/docker-wrapper deleted file mode 100644 index 2821d29..0000000 --- a/bundles/docker-engine/files/docker-wrapper +++ /dev/null @@ -1,67 +0,0 @@ -#!/bin/bash - -[[ -n "$DEBUG" ]] && set -x - -ACTION="$1" - -set -euo pipefail - -if [[ -z "$ACTION" ]] -then - echo "Usage: $0 start|stop" - exit 1 -fi - -PUID="$(id -u "${user}")" -PGID="$(id -g "${user}")" - -if [ "$ACTION" == "start" ] -then - # just exit if the container is actually running already. - set +e - /usr/local/share/icinga/plugins/check_docker_container "${name}" && exit 0 - set -e - - docker rm "${name}" || true - - docker pull "${image}" - - docker run -d \ - --name "${name}" \ - --env "PUID=$PUID" \ - --env "PGID=$PGID" \ - --env "TZ=${timezone}" \ -% for k, v in sorted(environment.items()): - --env "${k}=${v}" \ -% endfor - --network aaarghhh \ -% for host_port, container_port in sorted(ports.items()): - --publish "127.0.0.1:${host_port}:${container_port}" \ -% endfor -% for host_path, container_path in sorted(volumes.items()): -% if host_path.startswith('/'): - --volume "${host_path}:${container_path}" \ -% else: - --volume "/var/opt/docker-engine/${name}/${host_path}:${container_path}" \ -% endif -% endfor - --restart unless-stopped \ -% if command: - "${image}" \ - "${command}" -% else: - "${image}" -% endif - -elif [ "$ACTION" == "stop" ] -then - docker stop "${name}" - -else - echo "Unknown action $ACTION" - exit 1 -fi - -% if node.has_bundle('nftables'): -systemctl reload nftables -% endif diff --git a/bundles/docker-engine/files/docker-wrapper.service b/bundles/docker-engine/files/docker-wrapper.service deleted file mode 100644 index a908c86..0000000 --- a/bundles/docker-engine/files/docker-wrapper.service +++ /dev/null @@ -1,14 +0,0 @@ -[Unit] -Description=docker-engine app ${name} -After=network.target -Requires=${' '.join(sorted(requires))} - -[Service] -WorkingDirectory=/var/opt/docker-engine/${name}/ -ExecStart=/opt/docker-engine/${name} start -ExecStop=/opt/docker-engine/${name} stop -Type=simple -RemainAfterExit=true - -[Install] -WantedBy=multi-user.target diff --git a/bundles/docker-engine/items.py b/bundles/docker-engine/items.py deleted file mode 100644 index 253daff..0000000 --- a/bundles/docker-engine/items.py +++ /dev/null @@ -1,126 +0,0 @@ -from bundlewrap.metadata import metadata_to_json - -deps = { - 'pkg_apt:docker-ce', - 'pkg_apt:docker-ce-cli', -} - -directories['/opt/docker-engine'] = { - 'purge': True, -} -directories['/var/opt/docker-engine'] = {} - -files['/etc/docker/daemon.json'] = { - 'content': metadata_to_json(node.metadata.get('docker-engine/config')), - 'triggers': { - 'svc_systemd:docker:restart', - }, - # install config before installing packages to ensure the config is - # applied to the first start as well - 'before': deps, -} - -svc_systemd['docker'] = { - 'needs': deps, -} - -files['/usr/local/share/icinga/plugins/check_docker_container'] = { - 'mode': '0755', -} - -actions['docker_create_nondefault_network'] = { - # - # By default, containers inherit the DNS settings as defined in the - # /etc/resolv.conf configuration file. Containers that attach to the - # default bridge network receive a copy of this file. Containers that - # attach to a custom network use Docker's embedded DNS server. The embedded - # DNS server forwards external DNS lookups to the DNS servers configured on - # the host. - 'command': 'docker network create aaarghhh', - 'unless': 'docker network ls | grep -q -F aaarghhh', - 'needs': { - 'svc_systemd:docker', - }, -} - -for app, config in node.metadata.get('docker-engine/containers', {}).items(): - volumes = config.get('volumes', {}) - user = config.get('user', f'docker-{app}') - directories[f'/var/opt/docker-engine/{app}'] = { - 'owner': user, - 'group': user, - } - - files[f'/opt/docker-engine/{app}'] = { - 'source': 'docker-wrapper', - 'content_type': 'mako', - 'context': { - 'command': config.get('command'), - 'environment': config.get('environment', {}), - 'image': config['image'], - 'name': app, - 'ports': config.get('ports', {}), - 'timezone': node.metadata.get('timezone'), - 'user': user, - 'volumes': volumes, - }, - 'mode': '0755', - 'triggers': { - f'svc_systemd:docker-{app}:restart', - }, - } - - users[user] = { - 'groups': { - 'docker', - }, - 'after': { - 'action:docker_create_nondefault_network', - 'svc_systemd:docker', - }, - } - if user == f'docker-{app}': - users[user]['home'] = f'/var/opt/docker-engine/{app}' - - files[f'/usr/local/lib/systemd/system/docker-{app}.service'] = { - 'source': 'docker-wrapper.service', - 'content_type': 'mako', - 'context': { - 'name': app, - 'requires': { - *set(config.get('requires', set())), - 'docker.service', - } - }, - 'triggers': { - 'action:systemd-reload', - f'svc_systemd:docker-{app}:restart', - }, - } - - svc_systemd[f'docker-{app}'] = { - 'needs': { - *deps, - f'directory:/var/opt/docker-engine/{app}', - f'file:/opt/docker-engine/{app}', - f'file:/usr/local/lib/systemd/system/docker-{app}.service', - f'user:{user}', - 'svc_systemd:docker', - *set(config.get('needs', set())), - }, - } - - for volume in volumes: - if not volume.startswith('/'): - volume = f'/var/opt/docker-engine/{app}/{volume}' - - directories[volume] = { - 'owner': user, - 'group': user, - 'needed_by': { - f'svc_systemd:docker-{app}', - }, - # don't do anything if the directory exists, docker images - # mangle owners - 'unless': f'test -d {volume}', - } diff --git a/bundles/docker-engine/metadata.py b/bundles/docker-engine/metadata.py deleted file mode 100644 index 4600233..0000000 --- a/bundles/docker-engine/metadata.py +++ /dev/null @@ -1,92 +0,0 @@ -defaults = { - 'apt': { - 'packages': { - 'docker-ce': {}, - 'docker-ce-cli': {}, - 'docker-compose-plugin': {}, - }, - 'repos': { - 'docker': { - 'items': { - 'deb https://download.docker.com/linux/debian {os_release} stable', - }, - }, - }, - }, - 'nftables': { - 'forward': { - 'docker-engine': [ - 'ct state { related, established } accept', - 'ip saddr 172.16.0.0/12 accept', - ], - }, - 'postrouting': { - 'docker-engine': [ - 'ip saddr 172.16.0.0/12 masquerade', - ], - }, - }, - 'docker-engine': { - 'config': { - 'iptables': False, - 'no-new-privileges': True, - }, - }, - 'zfs': { - 'datasets': { - 'tank/docker-data': {}, - }, - }, -} - - -@metadata_reactor.provides( - 'icinga2_api/docker-engine/services', -) -def monitoring(metadata): - services = { - 'DOCKER PROCESS': { - 'command_on_monitored_host': '/usr/lib/nagios/plugins/check_procs -C dockerd -c 1:', - }, - } - - for app in metadata.get('docker-engine/containers', {}): - services[f'DOCKER CONTAINER {app}'] = { - 'command_on_monitored_host': f'sudo /usr/local/share/icinga/plugins/check_docker_container {app}' - } - - return { - 'icinga2_api': { - 'docker-engine': { - 'services': services, - }, - }, - } - - -@metadata_reactor.provides( - 'backups/paths', - 'zfs/datasets', -) -def zfs(metadata): - datasets = {} - - for app in metadata.get('docker-engine/containers', {}): - datasets[f'tank/docker-data/{app}'] = { - 'mountpoint': f'/var/opt/docker-engine/{app}', - 'needed_by': { - f'directory:/var/opt/docker-engine/{app}', - }, - } - - return { - 'backups': { - 'paths': { - v['mountpoint'] - for v in datasets.values() - }, - }, - 'zfs': { - 'datasets': datasets, - }, - } diff --git a/bundles/docker-goauthentik/metadata.py b/bundles/docker-goauthentik/metadata.py deleted file mode 100644 index 9d742fa..0000000 --- a/bundles/docker-goauthentik/metadata.py +++ /dev/null @@ -1,89 +0,0 @@ -assert node.has_bundle('docker-engine') - -defaults = { - 'docker-engine': { - 'containers': { - 'goauthentik-server': { - 'image': 'ghcr.io/goauthentik/server:latest', - 'command': 'server', - 'environment': { - 'AUTHENTIK_POSTGRESQL__HOST': 'goauthentik-postgresql', - 'AUTHENTIK_POSTGRESQL__NAME': 'goauthentik', - 'AUTHENTIK_POSTGRESQL__PASSWORD': repo.vault.password_for(f'{node.name} postgresql goauthentik'), - 'AUTHENTIK_POSTGRESQL__USER': 'goauthentik', - 'AUTHENTIK_REDIS__HOST': 'goauthentik-redis', - 'AUTHENTIK_SECRET_KEY': repo.vault.password_for(f'{node.name} goauthentik secret key'), - }, - 'volumes': { - 'media': '/media', - 'templates': '/templates', - }, - 'ports': { - '9000': '9000', - '9443': '9443', - }, - 'needs': { - 'svc_systemd:docker-goauthentik-postgresql', - 'svc_systemd:docker-goauthentik-redis', - }, - 'requires': { - 'docker-goauthentik-postgresql.service', - 'docker-goauthentik-redis.service', - }, - }, - 'goauthentik-worker': { - 'image': 'ghcr.io/goauthentik/server:latest', - 'command': 'worker', - 'user': 'docker-goauthentik-server', - 'environment': { - 'AUTHENTIK_POSTGRESQL__HOST': 'goauthentik-postgresql', - 'AUTHENTIK_POSTGRESQL__NAME': 'goauthentik', - 'AUTHENTIK_POSTGRESQL__PASSWORD': repo.vault.password_for(f'{node.name} postgresql goauthentik'), - 'AUTHENTIK_POSTGRESQL__USER': 'goauthentik', - 'AUTHENTIK_REDIS__HOST': 'goauthentik-redis', - 'AUTHENTIK_SECRET_KEY': repo.vault.password_for(f'{node.name} goauthentik secret key'), - }, - 'volumes': { - '/var/opt/docker-engine/goauthentik-server/media': '/media', - '/var/opt/docker-engine/goauthentik-server/certs': '/certs', - '/var/opt/docker-engine/goauthentik-server/templates': '/templates', - }, - 'needs': { - 'svc_systemd:docker-goauthentik-postgresql', - 'svc_systemd:docker-goauthentik-redis', - }, - 'requires': { - 'docker-goauthentik-postgresql.service', - 'docker-goauthentik-redis.service', - }, - }, - 'goauthentik-postgresql': { - 'image': 'docker.io/library/postgres:16-alpine', - 'environment': { - 'POSTGRES_PASSWORD': repo.vault.password_for(f'{node.name} postgresql goauthentik'), - 'POSTGRES_USER': 'goauthentik', - 'POSTGRES_DB': 'goauthentik', - }, - 'volumes': { - 'database': '/var/lib/postgresql/data', - }, - }, - 'goauthentik-redis': { - 'image': 'docker.io/library/redis:alpine', - }, - }, - }, - 'nginx': { - 'vhosts': { - 'goauthentik': { - 'locations': { - '/': { - 'target': 'http://127.0.0.1:9000/', - 'websockets': True, - 'max_body_size': '5000m', - }, - }, - }, - }, - }, -} diff --git a/bundles/docker-immich/files/immich-auto-album-share.py b/bundles/docker-immich/files/immich-auto-album-share.py deleted file mode 100644 index cafd32c..0000000 --- a/bundles/docker-immich/files/immich-auto-album-share.py +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/env python3 - -import logging -from json import loads -from os import environ -from subprocess import check_output -from sys import exit - -import psycopg2 - -PSQL_HOST = environ['DB_HOSTNAME'] -PSQL_USER = environ['DB_USERNAME'] -PSQL_PASS = environ['DB_PASSWORD'] -PSQL_DB = environ['DB_DATABASE_NAME'] - -logging.basicConfig(level=logging.INFO) - -docker_networks = loads(check_output(['docker', 'network', 'inspect', 'aaarghhh'])) - -container_ip = None -# why the fuck is this a list of networks, even though we have to provide -# a network name to inspect ... -for network in docker_networks: - if network['Name'] != 'aaarghhh': - continue - - for _, container in network['Containers'].items(): - if container['Name'] == PSQL_HOST: - container_ip = container['IPv4Address'].split('/')[0] - -if not container_ip: - logging.error(f'could not find ip address for container {PSQL_HOST=} in json') - logging.debug(f'{docker_networks=}') - exit(0) - -logging.debug(f'{PSQL_HOST=} {container_ip=}') - -conn = psycopg2.connect( - dbname=PSQL_DB, - host=container_ip, - password=PSQL_PASS, - user=PSQL_USER, -) - -with conn: - with conn.cursor() as cur: - cur.execute('SELECT "id","ownerId","albumName" FROM albums;') - albums = { - i[0]: { - 'owner': i[1], - 'name': i[2], - } - for i in cur.fetchall() - } - logging.debug(f'{albums=}') - - with conn.cursor() as cur: - cur.execute('SELECT "id","name" FROM users;') - users = { - i[0]: i[1] - for i in cur.fetchall() - } - logging.debug(f'{users=}') - -for album_id, album in albums.items(): - log = logging.getLogger(album["name"]) - with conn: - with conn.cursor() as cur: - cur.execute('SELECT "usersId" FROM albums_shared_users_users WHERE "albumsId" = %s;', (album_id,)) - album_shares = [i[0] for i in cur.fetchall()] - log.info(f'album is shared with {len(album_shares)} users') - log.debug(f'{album_shares=}') - for user_id, user_name in users.items(): - if user_id == album['owner'] or user_id in album_shares: - continue - - log.info(f'sharing album with user {user_name}') - try: - with conn.cursor() as cur: - cur.execute( - 'INSERT INTO albums_shared_users_users ("albumsId","usersId","role") VALUES (%s, %s, %s);', - (album_id, user_id, 'viewer'), - ) - except Exception: - log.exception('failure while creating share') - -conn.close() diff --git a/bundles/docker-immich/items.py b/bundles/docker-immich/items.py deleted file mode 100644 index 8c9d54e..0000000 --- a/bundles/docker-immich/items.py +++ /dev/null @@ -1,3 +0,0 @@ -files['/usr/local/bin/immich-auto-album-share.py'] = { - 'mode': '0755', -} diff --git a/bundles/docker-immich/metadata.py b/bundles/docker-immich/metadata.py deleted file mode 100644 index 3952922..0000000 --- a/bundles/docker-immich/metadata.py +++ /dev/null @@ -1,92 +0,0 @@ -assert node.has_bundle('docker-engine') - -defaults = { - 'apt': { - 'packages': { - 'python3-psycopg2': {}, - }, - }, - 'docker-engine': { - 'containers': { - 'immich': { - 'image': 'ghcr.io/imagegenius/immich:latest', - 'environment': { - 'DB_DATABASE_NAME': 'immich', - 'DB_HOSTNAME': 'immich-postgresql', - 'DB_PASSWORD': repo.vault.password_for(f'{node.name} postgresql immich'), - 'DB_USERNAME': 'immich', - 'REDIS_HOSTNAME': 'immich-redis', - }, - 'volumes': { - 'config': '/config', - 'libraries': '/libraries', - 'photos': '/photos', - }, - 'ports': { - '8080': '8080', - }, - 'needs': { - 'svc_systemd:docker-immich-postgresql', - 'svc_systemd:docker-immich-redis', - }, - 'requires': { - 'docker-immich-postgresql.service', - 'docker-immich-redis.service', - }, - }, - 'immich-postgresql': { - 'image': 'tensorchord/pgvecto-rs:pg14-v0.2.0', - 'environment': { - 'POSTGRES_PASSWORD': repo.vault.password_for(f'{node.name} postgresql immich'), - 'POSTGRES_USER': 'immich', - 'POSTGRES_DB': 'immich', - }, - 'volumes': { - 'database': '/var/lib/postgresql/data', - }, - }, - 'immich-redis': { - 'image': 'docker.io/redis:6.2-alpine', - }, - }, - }, - 'docker-immich': { - 'enable_auto_album_share': False, - }, - 'nginx': { - 'vhosts': { - 'immich': { - 'locations': { - '/': { - 'target': 'http://127.0.0.1:8080/', - 'websockets': True, - 'max_body_size': '5000m', - }, - }, - }, - }, - }, -} - - -@metadata_reactor.provides( - 'systemd-timers/timers/immich-auto-album-share', -) -def auto_album_share(metadata): - if not metadata.get('docker-immich/enable_auto_album_share'): - return {} - - return { - 'systemd-timers': { - 'timers': { - 'immich-auto-album-share': { - 'command': '/usr/local/bin/immich-auto-album-share.py', - 'environment': metadata.get('docker-engine/containers/immich/environment'), - 'when': 'minutely', - 'requisite': { - 'docker-immich-postgresql.service', - }, - }, - }, - }, - } diff --git a/bundles/dovecot/files/dovecot-sql.conf b/bundles/dovecot/files/dovecot-sql.conf index 75c06ae..86cb8db 100644 --- a/bundles/dovecot/files/dovecot-sql.conf +++ b/bundles/dovecot/files/dovecot-sql.conf @@ -3,4 +3,3 @@ driver = pgsql default_pass_scheme = MD5-CRYPT password_query = SELECT username as user, password FROM mailbox WHERE username = '%u' AND active = true user_query = SELECT '/var/mail/vmail/' || maildir as home, 65534 as uid, 65534 as gid FROM mailbox WHERE username = '%u' AND active = true -iterate_query = SELECT username as user FROM mailbox WHERE active = true diff --git a/bundles/dovecot/files/dovecot.conf b/bundles/dovecot/files/dovecot.conf index 73afeaf..885b36a 100644 --- a/bundles/dovecot/files/dovecot.conf +++ b/bundles/dovecot/files/dovecot.conf @@ -28,43 +28,33 @@ namespace inbox { mail_location = maildir:/var/mail/vmail/%d/%n protocols = imap lmtp sieve -ssl = required -ssl_cert = = 17: + # TODO verify this is still needed when upgrading to 1.12 + extra_install_cmds.append('export NODE_OPTIONS=--openssl-legacy-provider') + actions = { 'element-web_yarn': { 'command': ' && '.join([ + *extra_install_cmds, 'cd /opt/element-web', 'yarn install --pure-lockfile --ignore-scripts', 'yarn build', ]), 'needs': { - 'action:apt_execute_update_commands', + 'action:nodejs_install_yarn', 'pkg_apt:nodejs', }, 'triggered': True, diff --git a/bundles/element-web/metadata.py b/bundles/element-web/metadata.py index 5ee7449..0ce259a 100644 --- a/bundles/element-web/metadata.py +++ b/bundles/element-web/metadata.py @@ -11,26 +11,6 @@ defaults = { }, } -@metadata_reactor.provides( - 'nodejs/version', -) -def nodejs(metadata): - version = tuple([int(i) for i in metadata.get('element-web/version')[1:].split('.')]) - - if version >= (1, 11, 71): - return { - 'nodejs': { - 'version': 22, - }, - } - else: - return { - 'nodejs': { - 'version': 18, - }, - } - - @metadata_reactor.provides( 'nginx/vhosts/element-web', ) diff --git a/bundles/forgejo/items.py b/bundles/forgejo/items.py deleted file mode 100644 index f94c360..0000000 --- a/bundles/forgejo/items.py +++ /dev/null @@ -1,65 +0,0 @@ -users = { - 'git': { - 'home': '/var/lib/forgejo', - }, -} - -directories = { - '/var/lib/forgejo/.ssh': { - 'mode': '0700', - 'owner': 'git', - 'group': 'git', - }, - '/var/lib/forgejo': { - 'owner': 'git', - 'mode': '0700', - 'triggers': { - 'svc_systemd:forgejo:restart', - }, - }, -} - -files = { - '/usr/local/lib/systemd/system/forgejo.service': { - 'content_type': 'mako', - 'context': node.metadata.get('forgejo'), - 'triggers': { - 'action:systemd-reload', - 'svc_systemd:forgejo:restart', - }, - }, - '/etc/forgejo/app.ini': { - 'content_type': 'mako', - 'context': node.metadata.get('forgejo'), - 'triggers': { - 'svc_systemd:forgejo:restart', - }, - }, - '/usr/local/bin/forgejo': { - 'content_type': 'download', - 'source': 'https://codeberg.org/forgejo/forgejo/releases/download/v{0}/forgejo-{0}-linux-amd64'.format(node.metadata.get('forgejo/version')), - 'content_hash': node.metadata.get('forgejo/sha1', None), - 'mode': '0755', - 'triggers': { - 'svc_systemd:forgejo:restart', - }, - }, -} - -if node.metadata.get('forgejo/install_ssh_key', False): - files['/var/lib/forgejo/.ssh/id_ed25519'] = { - 'content': repo.vault.decrypt_file(f'forgejo/files/ssh-keys/{node.name}.key.vault'), - 'mode': '0600', - 'owner': 'git', - 'group': 'git', - } - -svc_systemd = { - 'forgejo': { - 'needs': { - 'file:/etc/forgejo/app.ini', - 'file:/usr/local/bin/forgejo', - 'file:/usr/local/lib/systemd/system/forgejo.service', - }, - }, -} diff --git a/bundles/forgejo/metadata.py b/bundles/forgejo/metadata.py deleted file mode 100644 index 16190e2..0000000 --- a/bundles/forgejo/metadata.py +++ /dev/null @@ -1,107 +0,0 @@ -defaults = { - 'backups': { - 'paths': { - '/var/lib/forgejo', - }, - }, - 'forgejo': { - 'app_name': 'Forgejo', - 'database': { - 'username': 'forgejo', - 'password': repo.vault.password_for('{} postgresql forgejo'.format(node.name)), - 'database': 'forgejo', - }, - 'disable_registration': True, - 'email_domain_blocklist': set(), - 'enable_git_hooks': False, - 'internal_token': repo.vault.password_for('{} forgejo internal_token'.format(node.name)), - 'lfs_secret_key': repo.vault.password_for('{} forgejo lfs_secret_key'.format(node.name)), - 'oauth_secret_key': repo.vault.password_for('{} forgejo oauth_secret_key'.format(node.name)), - 'security_secret_key': repo.vault.password_for('{} forgejo security_secret_key'.format(node.name)), - }, - 'icinga2_api': { - 'forgejo': { - 'services': { - 'FORGEJO PROCESS': { - 'command_on_monitored_host': '/usr/local/share/icinga/plugins/check_systemd_unit forgejo', - }, - 'FORGEJO UPDATE': { - 'vars.notification.mail': True, - 'check_interval': '60m', - }, - }, - }, - }, - 'openssh': { - 'allowed_users': { - 'git', - }, - }, - 'postgresql': { - 'roles': { - 'forgejo': { - 'password': repo.vault.password_for('{} postgresql forgejo'.format(node.name)), - }, - }, - 'databases': { - 'forgejo': { - 'owner': 'forgejo', - }, - }, - }, - 'zfs': { - 'datasets': { - 'tank/forgejo': { - 'mountpoint': '/var/lib/forgejo', - 'needed_by': { - 'directory:/var/lib/forgejo', - }, - }, - }, - }, -} - - -@metadata_reactor.provides( - 'icinga2_api/forgejo', -) -def update_monitoring(metadata): - return { - 'icinga2_api': { - 'forgejo': { - 'services': { - 'FORGEJO UPDATE': { - 'command_on_monitored_host': '/usr/local/share/icinga/plugins/check_forgejo_for_new_release codeberg.org forgejo/forgejo v{}'.format(metadata.get('forgejo/version')), - }, - }, - }, - }, - } - - -@metadata_reactor.provides( - 'nginx/vhosts/forgejo', -) -def nginx(metadata): - if not node.has_bundle('nginx'): - raise DoNotRunAgain - - return { - 'nginx': { - 'vhosts': { - 'forgejo': { - 'domain': metadata.get('forgejo/domain'), - 'locations': { - '/': { - 'target': 'http://127.0.0.1:22000', - }, - '/debug': { - 'return': 403, - }, - }, - 'website_check_path': '/user/login', - 'website_check_string': 'Sign in', - }, - }, - }, - } diff --git a/bundles/gce-workaround/items.py b/bundles/gce-workaround/items.py new file mode 100644 index 0000000..583e055 --- /dev/null +++ b/bundles/gce-workaround/items.py @@ -0,0 +1,33 @@ +svc_systemd = {} +pkg_apt = {} + +for i in { + 'gce-disk-expand', + 'google-cloud-packages-archive-keyring', + 'google-cloud-sdk', + 'google-compute-engine', + 'google-compute-engine-oslogin', + 'google-guest-agent', + 'google-osconfig-agent', +}: + pkg_apt[i] = { + 'installed': False, + } + +for i in { + 'google-accounts-daemon.service', + 'google-accounts-manager.service', + 'google-clock-skew-daemon.service', + 'google-clock-sync-manager.service', + 'google-guest-agent.service', + 'google-osconfig-agent.service', + 'google-shutdown-scripts.service', + 'google-startup-scripts.service', + 'sshguard.service', + + 'google-oslogin-cache.timer', +}: + svc_systemd[i] = { + 'enabled': False, + 'running': False, + } diff --git a/bundles/forgejo/files/app.ini b/bundles/gitea/files/app.ini similarity index 94% rename from bundles/forgejo/files/app.ini rename to bundles/gitea/files/app.ini index 557a20c..a904681 100644 --- a/bundles/forgejo/files/app.ini +++ b/bundles/gitea/files/app.ini @@ -1,10 +1,9 @@ APP_NAME = ${app_name} RUN_USER = git RUN_MODE = prod -WORK_PATH = /var/lib/forgejo [repository] -ROOT = /var/lib/forgejo/repositories +ROOT = /home/git/gitea-repositories MAX_CREATION_LIMIT = 0 DEFAULT_BRANCH = main @@ -22,6 +21,7 @@ ROOT_URL = https://${domain}/ DISABLE_SSH = false SSH_PORT = 22 LFS_START_SERVER = true +LFS_CONTENT_PATH = /var/lib/gitea/data/lfs LFS_JWT_SECRET = ${lfs_secret_key} OFFLINE_MODE = true START_SSH_SERVER = false @@ -67,7 +67,7 @@ EMAIL_DOMAIN_BLOCKLIST = ${','.join(sorted(email_domain_blocklist))} [mailer] ENABLED = true -PROTOCOL = sendmail +MAILER_TYPE = sendmail FROM = "${app_name}" [session] diff --git a/bundles/forgejo/files/forgejo.service b/bundles/gitea/files/gitea.service similarity index 55% rename from bundles/forgejo/files/forgejo.service rename to bundles/gitea/files/gitea.service index 76a5096..24f1505 100644 --- a/bundles/forgejo/files/forgejo.service +++ b/bundles/gitea/files/gitea.service @@ -5,13 +5,14 @@ After=network.target Requires=postgresql.service [Service] -RestartSec=10 +RestartSec=2s Type=simple User=git Group=git -WorkingDirectory=/var/lib/forgejo -ExecStart=/usr/local/bin/forgejo web -c /etc/forgejo/app.ini +WorkingDirectory=/var/lib/gitea/ +ExecStart=/usr/local/bin/gitea web -c /etc/gitea/app.ini Restart=always +Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea [Install] WantedBy=multi-user.target diff --git a/bundles/gitea/items.py b/bundles/gitea/items.py new file mode 100644 index 0000000..2e2f518 --- /dev/null +++ b/bundles/gitea/items.py @@ -0,0 +1,71 @@ +users = { + 'git': {}, +} + +directories = { + '/home/git': { + 'mode': '0755', + 'owner': 'git', + 'group': 'git', + }, + '/home/git/.ssh': { + 'mode': '0755', + 'owner': 'git', + 'group': 'git', + }, + '/var/lib/gitea': { + 'owner': 'git', + 'mode': '0700', + 'triggers': { + 'svc_systemd:gitea:restart', + }, + }, +} + +files = { + '/etc/systemd/system/gitea.service': { + 'content_type': 'mako', + 'context': node.metadata.get('gitea'), + 'triggers': { + 'action:systemd-reload', + 'svc_systemd:gitea:restart', + }, + }, + '/etc/gitea/app.ini': { + 'content_type': 'mako', + 'context': node.metadata.get('gitea'), + 'triggers': { + 'svc_systemd:gitea:restart', + }, + }, + '/usr/local/bin/gitea': { + 'content_type': 'download', + #'source': 'https://dl.gitea.io/gitea/{version}/gitea-{version}-linux-amd64'.format(version=node.metadata.get('gitea/version')), + 'source': 'https://github.com/go-gitea/gitea/releases/download/v{version}/gitea-{version}-linux-amd64'.format( + version=node.metadata.get('gitea/version'), + ), + 'content_hash': node.metadata.get('gitea/sha1', None), + 'mode': '0755', + 'triggers': { + 'svc_systemd:gitea:restart', + }, + }, +} + +if node.metadata['gitea'].get('install_ssh_key', False): + files['/home/git/.ssh/id_ed25519'] = { + 'content': repo.vault.decrypt_file(f'gitea/files/ssh-keys/{node.name}.key.vault'), + 'mode': '0600', + 'owner': 'git', + 'group': 'git', + } + +svc_systemd = { + 'gitea': { + 'needs': { + 'file:/etc/gitea/app.ini', + 'file:/etc/systemd/system/gitea.service', + 'file:/usr/local/bin/gitea', + }, + }, +} diff --git a/bundles/gitea/metadata.py b/bundles/gitea/metadata.py new file mode 100644 index 0000000..81bd36c --- /dev/null +++ b/bundles/gitea/metadata.py @@ -0,0 +1,113 @@ +defaults = { + 'backups': { + 'paths': { + '/home/git', + '/var/lib/gitea', + }, + }, + 'gitea': { + 'app_name': 'Gitea', + 'database': { + 'username': 'gitea', + 'password': repo.vault.password_for('{} postgresql gitea'.format(node.name)), + 'database': 'gitea', + }, + 'disable_registration': True, + 'email_domain_blocklist': set(), + 'enable_git_hooks': False, + 'internal_token': repo.vault.password_for('{} gitea internal_token'.format(node.name)), + 'lfs_secret_key': repo.vault.password_for('{} gitea lfs_secret_key'.format(node.name)), + 'oauth_secret_key': repo.vault.password_for('{} gitea oauth_secret_key'.format(node.name)), + 'security_secret_key': repo.vault.password_for('{} gitea security_secret_key'.format(node.name)), + }, + 'icinga2_api': { + 'gitea': { + 'services': { + 'GITEA PROCESS': { + 'command_on_monitored_host': '/usr/local/share/icinga/plugins/check_systemd_unit gitea', + }, + }, + }, + }, + 'openssh': { + 'allowed_users': { + 'git', + }, + }, + 'postgresql': { + 'roles': { + 'gitea': { + 'password': repo.vault.password_for('{} postgresql gitea'.format(node.name)), + }, + }, + 'databases': { + 'gitea': { + 'owner': 'gitea', + }, + }, + }, + 'zfs': { + 'datasets': { + 'tank/gitea': {}, + 'tank/gitea/home': { + 'mountpoint': '/home/git', + 'needed_by': { + 'directory:/home/git', + }, + }, + 'tank/gitea/var': { + 'mountpoint': '/var/lib/gitea', + 'needed_by': { + 'directory:/var/lib/gitea', + }, + }, + }, + }, +} + + +@metadata_reactor.provides( + 'nginx/vhosts/gitea', +) +def nginx(metadata): + if not node.has_bundle('nginx'): + raise DoNotRunAgain + + return { + 'nginx': { + 'vhosts': { + 'gitea': { + 'domain': metadata.get('gitea/domain'), + 'locations': { + '/': { + 'target': 'http://127.0.0.1:22000', + }, + '/debug': { + 'return': 403, + }, + }, + 'website_check_path': '/user/login', + 'website_check_string': 'Sign In', + }, + }, + }, + } + + +@metadata_reactor.provides( + 'icinga2_api/gitea/services', +) +def icinga_check_for_new_release(metadata): + return { + 'icinga2_api': { + 'gitea': { + 'services': { + 'GITEA UPDATE': { + 'command_on_monitored_host': '/usr/local/share/icinga/plugins/check_github_for_new_release go-gitea/gitea v{}'.format(metadata.get('gitea/version')), + 'vars.notification.mail': True, + 'check_interval': '60m', + }, + }, + }, + }, + } diff --git a/bundles/grafana/dashboard-rows/smartd.py b/bundles/grafana/dashboard-rows/smartd.py index 88b7b0b..f2fb257 100644 --- a/bundles/grafana/dashboard-rows/smartd.py +++ b/bundles/grafana/dashboard-rows/smartd.py @@ -47,7 +47,7 @@ def dashboard_row_smartd(panel_id, node): 'renderer': 'flot', 'seriesOverrides': [], 'spaceLength': 10, - 'span': 12, + 'span': 8, 'stack': False, 'steppedLine': False, 'targets': [ @@ -114,5 +114,115 @@ def dashboard_row_smartd(panel_id, node): 'alignLevel': None } }, + { + 'aliasColors': {}, + 'bars': False, + 'dashLength': 10, + 'dashes': False, + 'datasource': None, + 'fieldConfig': { + 'defaults': { + 'displayName': '${__field.labels.device}' + }, + 'overrides': [] + }, + 'fill': 0, + 'fillGradient': 0, + 'hiddenSeries': False, + 'id': next(panel_id), + 'legend': { + 'alignAsTable': False, + 'avg': False, + 'current': False, + 'hideEmpty': True, + 'hideZero': True, + 'max': False, + 'min': False, + 'rightSide': False, + 'show': True, + 'total': False, + 'values': False + }, + 'lines': True, + 'linewidth': 1, + 'NonePointMode': 'None', + 'options': { + 'alertThreshold': True + }, + 'percentage': False, + 'pluginVersion': '7.5.5', + 'pointradius': 2, + 'points': False, + 'renderer': 'flot', + 'seriesOverrides': [], + 'spaceLength': 10, + 'span': 4, + 'stack': False, + 'steppedLine': False, + 'targets': [ + { + 'groupBy': [ + {'type': 'time', 'params': ['$__interval']}, + {'type': 'fill', 'params': ['linear']}, + ], + 'orderByTime': "ASC", + 'policy': "default", + 'query': f"""from(bucket: "telegraf") + |> range(start: v.timeRangeStart, stop: v.timeRangeStop) + |> filter(fn: (r) => + r["_measurement"] == "smartd_stats" and + r["_field"] == "power_on_hours" and + r["host"] == "{node.name}" + ) + |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false) + |> yield(name: "fan")""", + 'resultFormat': 'time_series', + 'select': [[ + {'type': 'field', 'params': ['value']}, + {'type': 'mean', 'params': []}, + ]], + "tags": [] + }, + ], + 'thresholds': [], + 'timeRegions': [], + 'title': 'fans', + 'tooltip': { + 'shared': True, + 'sort': 0, + 'value_type': 'individual' + }, + 'type': 'graph', + 'xaxis': { + 'buckets': None, + 'mode': 'time', + 'name': None, + 'show': True, + 'values': [] + }, + 'yaxes': [ + { + 'format': 'hours', + 'label': None, + 'logBase': 1, + 'max': None, + 'min': None, + 'show': True, + 'decimals': 0, + }, + { + 'format': 'short', + 'label': None, + 'logBase': 1, + 'max': None, + 'min': None, + 'show': False, + } + ], + 'yaxis': { + 'align': False, + 'alignLevel': None + } + }, ], } diff --git a/bundles/grafana/metadata.py b/bundles/grafana/metadata.py index f27cb81..2f0f4d7 100644 --- a/bundles/grafana/metadata.py +++ b/bundles/grafana/metadata.py @@ -43,7 +43,6 @@ def nginx(metadata): 'locations': { '/': { 'target': 'http://127.0.0.1:21010', - 'websockets': True, }, '/api/ds/query': { 'target': 'http://127.0.0.1:21010', diff --git a/bundles/hedgedoc/files/hedgedoc.service b/bundles/hedgedoc/files/hedgedoc.service index 5bafd07..2bd0de4 100644 --- a/bundles/hedgedoc/files/hedgedoc.service +++ b/bundles/hedgedoc/files/hedgedoc.service @@ -33,11 +33,7 @@ ProtectSystem=strict ProtectHome=true PrivateTmp=true SystemCallArchitectures=native -# FIXME -# causes problems on bookworm -# see https://github.com/hedgedoc/hedgedoc/issues/4686 -# cmmented out for now ... -#SystemCallFilter=@system-service +SystemCallFilter=@system-service # You may have to adjust these settings User=hedgedoc diff --git a/bundles/hedgedoc/items.py b/bundles/hedgedoc/items.py index 732f465..ac66fcb 100644 --- a/bundles/hedgedoc/items.py +++ b/bundles/hedgedoc/items.py @@ -1,5 +1,3 @@ -from semver import compare - repo.libs.tools.require_bundle(node, 'nodejs') git_deploy = { @@ -49,29 +47,16 @@ directories = { }, } -if compare(node.metadata.get('hedgedoc/version'), '1.9.7') <= 0: - command = ' && '.join([ - 'cd /opt/hedgedoc', - 'yarn workspaces focus --production', - 'yarn install --ignore-scripts', - 'yarn build', - ]) -elif compare(node.metadata.get('hedgedoc/version'), '1.9.9') >= 0: - command = ' && '.join([ - 'cd /opt/hedgedoc', - 'bin/setup', - 'yarn install --immutable', - 'yarn build', - ]) - actions = { 'hedgedoc_yarn': { 'command': ' && '.join([ 'cd /opt/hedgedoc', - 'yarn install --immutable', + 'yarn install --production=true --pure-lockfile --ignore-scripts', + 'yarn install --ignore-scripts', 'yarn build', ]), 'needs': { + 'action:nodejs_install_yarn', 'file:/opt/hedgedoc/config.json', 'git_deploy:/opt/hedgedoc', 'pkg_apt:nodejs', diff --git a/bundles/homeassistant/files/check_homeassistant_update b/bundles/homeassistant/files/check_homeassistant_update deleted file mode 100644 index 853c467..0000000 --- a/bundles/homeassistant/files/check_homeassistant_update +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env python3 - -from sys import exit - -from packaging.version import parse -from requests import get - -API_TOKEN = "${token}" -DOMAIN = "${domain}" - -try: - r = get("https://version.home-assistant.io/stable.json") - r.raise_for_status() - stable_version = parse(r.json()["homeassistant"]["generic-x86-64"]) -except Exception as e: - print(f"Could not get stable version information from home-assistant.io: {e!r}") - exit(3) - -try: - r = get( - f"https://{DOMAIN}/api/config", - headers={"Authorization": f"Bearer {API_TOKEN}", "Content-Type": "application/json"}, - ) - r.raise_for_status() - running_version = parse(r.json()["version"]) -except Exception as e: - print(f"Could not get running version information from homeassistant: {e!r}") - exit(3) - -try: - if stable_version > running_version: - print( - f"There is a newer version available: {stable_version} (currently installed: {running_version})" - ) - exit(2) - else: - print( - f"Currently running version {running_version} matches newest release on home-assistant.io" - ) - exit(0) -except Exception as e: - print(repr(e)) - exit(3) diff --git a/bundles/homeassistant/files/homeassistant.service b/bundles/homeassistant/files/homeassistant.service deleted file mode 100644 index ed0f2a9..0000000 --- a/bundles/homeassistant/files/homeassistant.service +++ /dev/null @@ -1,17 +0,0 @@ -[Unit] -Description=Home Assistant -After=network-online.target - -[Service] -Type=simple -User=homeassistant -Environment="VIRTUAL_ENV=/opt/homeassistant/venv" -Environment="PATH=/opt/homeassistant/venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" -WorkingDirectory=/var/opt/homeassistant -ExecStart=/opt/homeassistant/venv/bin/hass -c "/var/opt/homeassistant" -RestartForceExitStatus=100 -Restart=on-failure -RestartSec=2 - -[Install] -WantedBy=multi-user.target diff --git a/bundles/homeassistant/items.py b/bundles/homeassistant/items.py deleted file mode 100644 index 92f097b..0000000 --- a/bundles/homeassistant/items.py +++ /dev/null @@ -1,79 +0,0 @@ -if node.has_bundle('pyenv'): - python_version = sorted(node.metadata.get('pyenv/python_versions'))[-1] - python_path = f'/opt/pyenv/versions/{python_version}/bin/python' -else: - python_path = '/usr/bin/python3' - -users = { - 'homeassistant': { - 'home': '/var/opt/homeassistant', - "groups": ["dialout"], - }, -} - -directories = { - '/opt/homeassistant': { - 'owner': 'homeassistant', - }, - '/var/opt/homeassistant': { - 'owner': 'homeassistant', - }, -} - -files = { - '/etc/systemd/system/homeassistant.service': { - 'triggers': { - 'action:systemd-reload', - 'svc_systemd:homeassistant:restart', - }, - }, - '/usr/local/share/icinga/plugins/check_homeassistant_update': { - 'content_type': 'mako', - 'context': { - 'token': node.metadata.get('homeassistant/api_secret'), - 'domain': node.metadata.get('homeassistant/domain'), - }, - 'mode': '0755', - }, -} - -actions = { - 'homeassistant_create_virtualenv': { - 'command': f'sudo -u homeassistant virtualenv -p {python_path} /opt/homeassistant/venv/', - 'unless': 'test -d /opt/homeassistant/venv/', - 'needs': { - 'directory:/opt/homeassistant', - 'user:homeassistant', - }, - }, - 'homeassistant_install': { - 'command': 'sudo -u homeassistant /opt/homeassistant/venv/bin/pip install homeassistant', - 'unless': 'test -f /opt/homeassistant/venv/bin/hass', - 'needs': { - 'action:homeassistant_create_virtualenv', - 'pkg_apt:bluez', - 'pkg_apt:libffi-dev', - 'pkg_apt:libssl-dev', - 'pkg_apt:libjpeg-dev', - 'pkg_apt:zlib1g-dev', - 'pkg_apt:autoconf', - 'pkg_apt:build-essential', - 'pkg_apt:libopenjp2-7', - 'pkg_apt:libtiff6', - 'pkg_apt:libturbojpeg0-dev', - 'pkg_apt:tzdata', - }, - 'triggers': { - 'svc_systemd:homeassistant:restart', - }, - }, -} - -svc_systemd = { - 'homeassistant': { - 'needs': { - 'action:homeassistant_install', - 'file:/etc/systemd/system/homeassistant.service', - }, - }, -} diff --git a/bundles/homeassistant/metadata.py b/bundles/homeassistant/metadata.py deleted file mode 100644 index f1c76de..0000000 --- a/bundles/homeassistant/metadata.py +++ /dev/null @@ -1,71 +0,0 @@ -defaults = { - 'apt': { - 'packages': { - 'autoconf': {}, - 'bluez': {}, - 'build-essential': {}, - 'ffmpeg': {}, - 'libffi-dev': {}, - 'libjpeg-dev': {}, - 'libopenjp2-7': {}, - 'libssl-dev': {}, - 'libtiff6': {}, - 'libturbojpeg0-dev': {}, - 'python3-packaging': {}, - 'tzdata': {}, - 'zlib1g-dev': {}, - }, - }, - 'backups': { - 'paths': { - '/opt/homeassistant', - '/var/opt/homeassistant', - }, - }, -} - - -@metadata_reactor.provides( - 'icinga2_api/homeassistant/services', -) -def icinga_check_for_new_release(metadata): - return { - 'icinga2_api': { - 'homeassistant': { - 'services': { - 'HOMEASSISTANT UPDATE': { - 'check_interval': '60m', - 'command_on_monitored_host': '/usr/local/share/icinga/plugins/check_homeassistant_update', - 'vars.notification.mail': True, - 'vars.sshmon_timeout': 20, - }, - }, - }, - }, - } - - -@metadata_reactor.provides( - 'nginx/vhosts/homeassistant', -) -def nginx(metadata): - if not node.has_bundle('nginx'): - raise DoNotRunAgain - - return { - 'nginx': { - 'vhosts': { - 'homeassistant': { - 'domain': metadata.get('homeassistant/domain'), - 'website_check_path': '/auth/authorize', - 'website_check_string': 'Home Assistant', - 'locations': { - '/': { - 'target': 'http://127.0.0.1:8123', - 'websockets': True, - }, - }, - }, - }, - }, - } diff --git a/bundles/icinga2-statuspage/files/icinga2-statuspage.service b/bundles/icinga2-statuspage/files/icinga2-statuspage.service deleted file mode 100644 index 8a8e4a2..0000000 --- a/bundles/icinga2-statuspage/files/icinga2-statuspage.service +++ /dev/null @@ -1,16 +0,0 @@ -[Unit] -Description=icinga2-statuspage -After=network.target -Requires=postgresql.service - -[Service] -User=www-data -Group=www-data -Environment=APP_CONFIG=/opt/icinga2-statuspage/config.json -WorkingDirectory=/opt/icinga2-statuspage/src -ExecStart=/usr/bin/gunicorn statuspage:app --workers 4 --max-requests 1200 --max-requests-jitter 50 --log-level=info --bind=127.0.0.1:22110 -Restart=always -RestartSec=10 - -[Install] -WantedBy=multi-user.target diff --git a/bundles/icinga2-statuspage/items.py b/bundles/icinga2-statuspage/items.py deleted file mode 100644 index fb3c413..0000000 --- a/bundles/icinga2-statuspage/items.py +++ /dev/null @@ -1,34 +0,0 @@ -directories['/opt/icinga2-statuspage/src'] = {} - -git_deploy['/opt/icinga2-statuspage/src'] = { - 'repo': 'https://git.franzi.business/kunsi/icinga-dynamic-statuspage.git', - 'rev': 'main', - 'triggers': { - 'svc_systemd:icinga2-statuspage:restart', - }, -} - -files['/opt/icinga2-statuspage/config.json'] = { - 'content': repo.libs.faults.dict_as_json(node.metadata.get('icinga2-statuspage')), - 'triggers': { - 'svc_systemd:icinga2-statuspage:restart', - }, -} - -files['/usr/local/lib/systemd/system/icinga2-statuspage.service'] = { - 'triggers': { - 'action:systemd-reload', - 'svc_systemd:icinga2-statuspage:restart', - }, -} - - -svc_systemd['icinga2-statuspage'] = { - 'needs': { - 'file:/opt/icinga2-statuspage/config.json', - 'git_deploy:/opt/icinga2-statuspage/src', - 'pkg_apt:gunicorn', - 'pkg_apt:python3-flask', - 'pkg_apt:python3-psycopg2', - }, -} diff --git a/bundles/icinga2-statuspage/metadata.py b/bundles/icinga2-statuspage/metadata.py deleted file mode 100644 index ffe5dcf..0000000 --- a/bundles/icinga2-statuspage/metadata.py +++ /dev/null @@ -1,47 +0,0 @@ -defaults = { - 'apt': { - 'packages': { - 'gunicorn': {}, - 'python3-flask': {}, - 'python3-psycopg2': {}, - }, - }, -} - - -@metadata_reactor.provides( - 'icinga2-statuspage', -) -def import_db_settings_from_icinga(metadata): - return { - 'icinga2-statuspage': { - 'DB_USER': 'icinga2', - 'DB_PASS': metadata.get('postgresql/roles/icinga2/password'), - 'DB_NAME': 'icinga2', - }, - } - - -@metadata_reactor.provides( - 'nginx/vhosts/icinga2-statuspage', -) -def nginx(metadata): - if not node.has_bundle('nginx'): - raise DoNotRunAgain - - return { - 'nginx': { - 'vhosts': { - 'icinga2-statuspage': { - 'domain': metadata.get('icinga2-statuspage/DOMAIN'), - 'locations': { - '/': { - 'target': 'http://127.0.0.1:22110', - }, - }, - 'website_check_path': '/', - 'website_check_string': 'status page', - }, - }, - }, - } diff --git a/bundles/icinga2/files/check_freifunk_node b/bundles/icinga2/files/check_freifunk_node index 22725b7..2723f13 100644 --- a/bundles/icinga2/files/check_freifunk_node +++ b/bundles/icinga2/files/check_freifunk_node @@ -1,8 +1,7 @@ #!/usr/bin/env python3 -from sys import argv, exit - from requests import get +from sys import argv, exit meshviewer_url = argv[1] node_id = argv[2] diff --git a/bundles/icinga2/files/check_omm.py b/bundles/icinga2/files/check_omm.py deleted file mode 100644 index 25bf9b0..0000000 --- a/bundles/icinga2/files/check_omm.py +++ /dev/null @@ -1,132 +0,0 @@ -#!/usr/bin/env python3 - -import re -from hashlib import md5 -from sys import argv, exit - -# Supress SSL certificate warnings for ssl_verify=False -import urllib3 -from lxml import html -from requests import Session - -USERNAME_FIELD = "g2" -PASSWORD_FIELD = "g3" -CRSF_FIELD = "password" - -STATUS_OK = 0 -STATUS_WARNING = 1 -STATUS_CRITICAL = 2 -STATUS_UNKNOWN = 3 - - -class OMMCrawler: - def __init__(self, hostname, username, password): - self.session = Session() - urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) - self.session.verify = False - - self.url = f"https://{hostname}" - self.login_data = { - USERNAME_FIELD: username, - PASSWORD_FIELD: password, - CRSF_FIELD: md5(password.encode()).hexdigest(), - } - self.logged_in = False - - def login(self): - # if we have multiple dect masters, find out which one is the current master - current_master_url = self.session.get(self.url, verify=False).url - self.hostname = re.search(r"^(.*[\\\/])", current_master_url).group(0)[:-1] - - response = self.session.post(f"{self.url}/login_set.html", data=self.login_data) - response.raise_for_status() - - # set cookie - pass_value = re.search(r"(?<=pass=)\d+(?=;)", response.text).group(0) - self.session.cookies.set("pass", pass_value) - self.logged_in = True - - def get_station_status(self): - if not self.logged_in: - self.login() - - data = {} - response = self.session.get(f"{self.url}/fp_pnp_status.html") - response.raise_for_status() - tree = html.fromstring(response.text) - xpath_results = tree.xpath('//tr[@class="l0" or @class="l1"]') - - for result in xpath_results: - bubble_is_in_inactive_cluster = False - bubble_is_connected = False - bubble_is_active = False - - bubble_name = result.xpath("td[4]/text()")[0] - try: - bubble_is_connected = result.xpath("td[11]/img/@alt")[0] == "yes" - - if bubble_is_connected: - try: - bubble_is_active = result.xpath("td[12]/img/@alt")[0] == "yes" - except IndexError: - # If an IndexError occurs, there is no image in the - # 12th td. This means this bubble is in the not inside - # an active DECT cluster, but is a backup bubble. - # This is probably fine. - bubble_is_active = False - bubble_is_in_inactive_cluster = True - else: - bubble_is_active = False - except: - # There is no Image in the 11th td. This usually means there - # is a warning message in the 10th td. We do not care about - # that, currently. - pass - - data[bubble_name] = { - "is_connected": bubble_is_connected, - "is_active": bubble_is_active, - "is_in_inactive_cluster": bubble_is_in_inactive_cluster, - } - return data - - def handle_station_data(self): - try: - data = self.get_station_status() - except Exception as e: - print(f"Something went wrong. You should take a look at {self.url}") - print(repr(e)) - exit(STATUS_UNKNOWN) - - critical = False - for name, status in data.items(): - if not status["is_active"] and not status["is_connected"]: - print( - f"Base station {name} is not active or connected! Check manually!" - ) - critical = True - elif not status["is_active"] and not status["is_in_inactive_cluster"]: - # Bubble is part of an active DECT cluster, but not active. - # This shouldn't happen. - print( - f"Base station {name} is not active but connected! Check manually!" - ) - critical = True - elif not status["is_connected"]: - # This should never happen. Seeing this state means OMM - # itself is broken. - print( - f"Base station {name} is not connected but active! Check manually!" - ) - critical = True - - if critical: - exit(STATUS_CRITICAL) - else: - print(f"OK - {len(data)} base stations connected") - exit(STATUS_OK) - - -if __name__ == "__main__": - omm = OMMCrawler(argv[1], argv[2], argv[3]) - omm.handle_station_data() diff --git a/bundles/icinga2/files/check_sipgate_account_balance b/bundles/icinga2/files/check_sipgate_account_balance index 65054ba..8e8ce2d 100644 --- a/bundles/icinga2/files/check_sipgate_account_balance +++ b/bundles/icinga2/files/check_sipgate_account_balance @@ -1,17 +1,15 @@ #!/usr/bin/env python3 -from json import load +from requests import get from sys import exit -from requests import get - -with open('/etc/icinga2/notification_config.json') as f: - CONFIG = load(f) +SIPGATE_USER = '${node.metadata['icinga2']['sipgate_user']}' +SIPGATE_PASS = '${node.metadata['icinga2']['sipgate_pass']}' try: r = get( 'https://api.sipgate.com/v2/balance', - auth=(CONFIG['sipgate']['user'], CONFIG['sipgate']['password']), + auth=(SIPGATE_USER, SIPGATE_PASS), headers={'Accept': 'application/json'}, ) diff --git a/bundles/icinga2/files/check_spam_blocklist b/bundles/icinga2/files/check_spam_blocklist index 2b1a3c3..bf14a82 100644 --- a/bundles/icinga2/files/check_spam_blocklist +++ b/bundles/icinga2/files/check_spam_blocklist @@ -1,37 +1,36 @@ #!/usr/bin/env python3 from concurrent.futures import ThreadPoolExecutor, as_completed -from ipaddress import IPv6Address, ip_address +from ipaddress import ip_address, IPv6Address from subprocess import check_output from sys import argv, exit -BLOCKLISTS = { - '0spam.fusionzero.com': set(), - 'bl.mailspike.org': set(), - 'bl.spamcop.net': set(), - 'blackholes.brainerd.net': set(), - 'dnsbl-1.uceprotect.net': set(), - 'l2.spews.dnsbl.sorbs.net': set(), - 'list.dsbl.org': set(), - 'multihop.dsbl.org': set(), - 'ns1.unsubscore.com': set(), - 'opm.blitzed.org': set(), - 'psbl.surriel.com': set(), - 'rbl.efnet.org': set(), - 'rbl.schulte.org': set(), - 'spamguard.leadmon.net': set(), - 'ubl.unsubscore.com': set(), - 'unconfirmed.dsbl.org': set(), - 'virbl.dnsbl.bit.nl': set(), - 'zen.spamhaus.org': { - # https://www.spamhaus.org/news/article/807/using-our-public-mirrors-check-your-return-codes-now. - '127.255.255.252', # Typing Error - '127.255.255.254', # public resolver / generic rdns - '127.255.255.255', # rate limited - }, -} -def check_list(ip_list, blocklist, warn_ips): + +BLOCKLISTS = [ + '0spam.fusionzero.com', + 'bl.mailspike.org', + 'bl.spamcop.net', + 'blackholes.brainerd.net', + 'dnsbl-1.uceprotect.net', + 'dnsbl-2.uceprotect.net', + 'l2.spews.dnsbl.sorbs.net', + 'list.dsbl.org', + 'map.spam-rbl.com', + 'multihop.dsbl.org', + 'ns1.unsubscore.com', + 'opm.blitzed.org', + 'psbl.surriel.com', + 'rbl.efnet.org', + 'rbl.schulte.org', + 'spamguard.leadmon.net', + 'ubl.unsubscore.com', + 'unconfirmed.dsbl.org', + 'virbl.dnsbl.bit.nl', + 'zen.spamhaus.org', +] + +def check_list(ip_list, blocklist): dns_name = '{}.{}'.format( '.'.join(ip_list), blocklist, @@ -44,22 +43,17 @@ def check_list(ip_list, blocklist, warn_ips): result = check_output([ 'dig', '+tries=2', - '+time=10', + '+time=5', '+short', dns_name ]).decode().splitlines() for item in result: - if item.startswith(';;'): - continue msgs.append('{} listed in {} as {}'.format( ip, blocklist, item, )) - if item in warn_ips and returncode < 2: - returncode = 1 - else: - returncode = 2 + returncode = 2 except Exception as e: if e.returncode == 9: # no reply from server @@ -86,8 +80,8 @@ exitcode = 0 with ThreadPoolExecutor(max_workers=len(BLOCKLISTS)) as executor: futures = set() - for blocklist, warn_ips in BLOCKLISTS.items(): - futures.add(executor.submit(check_list, ip_list, blocklist, warn_ips)) + for blocklist in BLOCKLISTS: + futures.add(executor.submit(check_list, ip_list, blocklist)) for future in as_completed(futures): msgs, this_exitcode = future.result() diff --git a/bundles/icinga2/files/icinga2/downtimes.conf b/bundles/icinga2/files/icinga2/downtimes.conf index 6dffabd..0052816 100644 --- a/bundles/icinga2/files/icinga2/downtimes.conf +++ b/bundles/icinga2/files/icinga2/downtimes.conf @@ -1,18 +1,31 @@ -% for dt in downtimes: -object ScheduledDowntime "${dt['name']}" { - host_name = "${dt['host']}" +% for monitored_node in sorted(repo.nodes): +<% + auto_updates_enabled = ( + monitored_node.has_any_bundle(['apt', 'c3voc-addons']) + or ( + monitored_node.has_bundle('pacman') + and monitored_node.metadata.get('pacman/unattended-upgrades/is_enabled', False) + ) + ) and not monitored_node.metadata.get('icinga_options/exclude_from_monitoring', False) +%>\ +% if auto_updates_enabled: +object ScheduledDowntime "unattended_upgrades" { + host_name = "${monitored_node.name}" - author = "${dt['name']}" - comment = "${dt['comment']}" + author = "unattended-upgrades" + comment = "Downtime for upgrade-and-reboot of node ${monitored_node.name}" fixed = true ranges = { -% for d,t in dt['times'].items(): - "${d}" = "${t}" -% endfor +% if monitored_node.has_bundle('pacman'): + "${days[monitored_node.metadata.get('pacman/unattended-upgrades/day')]}" = "${monitored_node.metadata.get('pacman/unattended-upgrades/hour')}:${monitored_node.magic_number%30}-${monitored_node.metadata.get('pacman/unattended-upgrades/hour')}:${(monitored_node.magic_number%30)+30}" +% else: + "${days[monitored_node.metadata.get('apt/unattended-upgrades/day')]}" = "${monitored_node.metadata.get('apt/unattended-upgrades/hour')}:${monitored_node.magic_number%30}-${monitored_node.metadata.get('apt/unattended-upgrades/hour')}:${(monitored_node.magic_number%30)+30}" +% endif } child_options = "DowntimeTriggeredChildren" } +% endif % endfor diff --git a/bundles/icinga2/files/icinga2/groups.conf b/bundles/icinga2/files/icinga2/groups.conf index 513568c..cc18159 100644 --- a/bundles/icinga2/files/icinga2/groups.conf +++ b/bundles/icinga2/files/icinga2/groups.conf @@ -33,11 +33,3 @@ object ServiceGroup "checks_with_sms" { assign where service.vars.notification.sms == true ignore where host.vars.notification.sms == false } - -object ServiceGroup "statuspage" { - display_name = "Checks which are show on the public status page" - - assign where service.vars.notification.sms == true - ignore where host.vars.notification.sms == false - ignore where host.vars.show_on_statuspage == false -} diff --git a/bundles/icinga2/files/icinga2/hosts_template.conf b/bundles/icinga2/files/icinga2/hosts_template.conf index ac56ef2..1c4f957 100644 --- a/bundles/icinga2/files/icinga2/hosts_template.conf +++ b/bundles/icinga2/files/icinga2/hosts_template.conf @@ -14,8 +14,7 @@ object Host "${rnode.name}" { vars.os = "${rnode.os}" # used for status page - vars.pretty_name = "${rnode.metadata.get('icinga_options/pretty_name', rnode.metadata.get('hostname'))}" - vars.show_on_statuspage = ${str(rnode.metadata.get('icinga_options/show_on_statuspage', True)).lower()} + vars.pretty_name = "${rnode.metadata.get('icinga_options/pretty_name', rnode.name)}" vars.period = "${rnode.metadata.get('icinga_options/period', '24x7')}" @@ -23,25 +22,6 @@ object Host "${rnode.name}" { vars.notification.mail = true } -% if rnode.ipmi_hostname: -object Host "${rnode.name} IPMI" { - import "generic-host" - - address = "${rnode.ipmi_hostname}" - - vars.location = "${rnode.metadata.get('location', 'unknown')}" - vars.os = "ipmi" - - vars.pretty_name = "${rnode.metadata.get('icinga_options/pretty_name', rnode.metadata.get('hostname'))} IPMI" - vars.show_on_statuspage = false - - vars.period = "${rnode.metadata.get('icinga_options/period', '24x7')}" - - vars.notification.sms = ${str(rnode.metadata.get('icinga_options/vars.notification.sms', True)).lower()} - vars.notification.mail = true -} -% endif - % for depends_on_host in sorted(rnode.metadata.get('icinga_options/also_affected_by', set())): object Dependency "${rnode.name}_depends_on_${depends_on_host}" { parent_host_name = "${depends_on_host}" diff --git a/bundles/icinga2/files/icinga_statusmonitor.py b/bundles/icinga2/files/icinga_statusmonitor.py index bc33759..e816ada 100644 --- a/bundles/icinga2/files/icinga_statusmonitor.py +++ b/bundles/icinga2/files/icinga_statusmonitor.py @@ -9,11 +9,6 @@ app = Flask(__name__) @app.route('/status') def statuspage(): everything_fine = True - try: - check_output(['/usr/local/share/icinga/plugins/check_mounts']) - except: - everything_fine = False - try: check_output(['/usr/lib/nagios/plugins/check_procs', '-C', 'icinga2', '-c', '1:']) except: diff --git a/bundles/icinga2/files/icinga_statusmonitor.service b/bundles/icinga2/files/icinga_statusmonitor.service index b651357..3bfd258 100644 --- a/bundles/icinga2/files/icinga_statusmonitor.service +++ b/bundles/icinga2/files/icinga_statusmonitor.service @@ -3,6 +3,8 @@ Description=Icinga2 Statusmonitor After=network.target [Service] +User=nagios +Group=nagios Environment="FLASK_APP=/etc/icinga2/icinga_statusmonitor.py" ExecStart=/usr/bin/python3 -m flask run WorkingDirectory=/tmp diff --git a/bundles/icinga2/files/icingaweb2/monitoring_config.ini b/bundles/icinga2/files/icingaweb2/monitoring_config.ini deleted file mode 100644 index 8194280..0000000 --- a/bundles/icinga2/files/icingaweb2/monitoring_config.ini +++ /dev/null @@ -1,5 +0,0 @@ -[settings] -acknowledge_sticky = 1 -hostdowntime_all_services = 1 -hostdowntime_end_fixed = P1W -servicedowntime_end_fixed = P2D diff --git a/bundles/icinga2/files/scripts/icinga_notification_wrapper b/bundles/icinga2/files/scripts/icinga_notification_wrapper index fbecd8e..f988be8 100644 --- a/bundles/icinga2/files/scripts/icinga_notification_wrapper +++ b/bundles/icinga2/files/scripts/icinga_notification_wrapper @@ -3,14 +3,21 @@ import email.mime.text import smtplib from argparse import ArgumentParser -from json import dumps, load +from json import dumps +from requests import post from subprocess import run from sys import argv -from requests import post +SIPGATE_USER='${node.metadata['icinga2']['sipgate_user']}' +SIPGATE_PASS='${node.metadata['icinga2']['sipgate_pass']}' -with open('/etc/icinga2/notification_config.json') as f: - CONFIG = load(f) +STATUS_TO_EMOJI = { + 'critical': '🔥', + 'down': '🚨🚨🚨', + 'ok': '🆗', + 'up': '👌', + 'warning': '⚡', +} parser = ArgumentParser( prog='icinga_notification_wrapper', @@ -65,31 +72,36 @@ def notify_per_sms(): output_text = '' else: output_text = '\n\n{}'.format(args.output) - - message_text = 'ICINGA: {host}{service} is {state}{output}'.format( - host=args.host_name, - service=('/'+args.service_name if args.service_name else ''), - state=args.state.upper(), - output=output_text, - ) - + if args.state.lower() in STATUS_TO_EMOJI: + message_text = '{emoji} {host}{service} {emoji}{output}'.format( + emoji=STATUS_TO_EMOJI[args.state.lower()], + host=args.host_name, + service=('/'+args.service_name if args.service_name else ''), + state=args.state.upper(), + output=output_text, + ) + else: + message_text = 'ICINGA: {host}{service} is {state}{output}'.format( + host=args.host_name, + service=('/'+args.service_name if args.service_name else ''), + state=args.state.upper(), + output=output_text, + ) message = { 'message': message_text, 'smsId': 's0', # XXX what does this mean? Documentation is unclear 'recipient': args.sms } - headers = { 'Content-type': 'application/json', 'Accept': 'application/json' } - try: r = post( 'https://api.sipgate.com/v2/sessions/sms', json=message, headers=headers, - auth=(CONFIG['sipgate']['user'], CONFIG['sipgate']['password']), + auth=(SIPGATE_USER, SIPGATE_PASS), ) if r.status_code == 204: @@ -100,45 +112,6 @@ def notify_per_sms(): log_to_syslog('Sending a SMS to "{}" failed: {}'.format(args.sms, repr(e))) -def notify_per_ntfy(): - message_text = 'ICINGA: {host}{service} is {state}\n\n{output}'.format( - host=args.host_name, - service=('/'+args.service_name if args.service_name else ''), - state=args.state.upper(), - output=args.output, - ) - - if args.service_name: - subject = '[ICINGA] {}/{}'.format(args.host_name, args.service_name) - else: - subject = '[ICINGA] {}'.format(args.host_name) - - if args.notification_type.lower() == 'recovery': - priority = 'default' - else: - priority = 'urgent' - - headers = { - 'Title': subject, - 'Priority': priority, - } - - try: - r = post( - CONFIG['ntfy']['url'], - data=message_text, - headers=headers, - auth=(CONFIG['ntfy']['user'], CONFIG['ntfy']['password']), - timeout=10, - ) - - r.raise_for_status() - except Exception as e: - log_to_syslog('Sending a Notification failed: {}'.format(repr(e))) - return False - return True - - def notify_per_mail(): if args.notification_type.lower() == 'recovery': # Do not send recovery emails. @@ -202,8 +175,4 @@ if __name__ == '__main__': notify_per_mail() if args.sms: - ntfy_worked = False - if CONFIG['ntfy']['user']: - ntfy_worked = notify_per_ntfy() - if not args.service_name or not ntfy_worked: - notify_per_sms() + notify_per_sms() diff --git a/bundles/icinga2/items.py b/bundles/icinga2/items.py index 6f8de54..1a42e70 100644 --- a/bundles/icinga2/items.py +++ b/bundles/icinga2/items.py @@ -76,6 +76,8 @@ files = { }, '/usr/local/share/icinga/plugins/check_sipgate_account_balance': { 'mode': '0755', + 'content_type': 'mako', + 'cascade_skip': False, # contains faults }, '/usr/local/share/icinga/plugins/check_freifunk_node': { 'mode': '0755', @@ -112,22 +114,11 @@ files = { 'svc_systemd:icinga2:restart', }, }, - '/etc/icinga2/notification_config.json': { - 'content': repo.libs.faults.dict_as_json({ - 'sipgate': { - 'user': node.metadata.get('icinga2/sipgate/user'), - 'password': node.metadata.get('icinga2/sipgate/pass'), - }, - 'ntfy': { - 'url': node.metadata.get('icinga2/ntfy/url'), - 'user': node.metadata.get('icinga2/ntfy/user'), - 'password': node.metadata.get('icinga2/ntfy/pass'), - }, - }), - }, '/etc/icinga2/scripts/icinga_notification_wrapper': { 'source': 'scripts/icinga_notification_wrapper', + 'content_type': 'mako', 'mode': '0755', + 'cascade_skip': False, # contains faults }, '/etc/icinga2/features-available/ido-pgsql.conf': { 'source': 'icinga2/ido-pgsql.conf', @@ -254,11 +245,6 @@ files = { 'mode': '0660', 'group': 'icingaweb2', }, - '/etc/icingaweb2/modules/monitoring/config.ini': { - 'source': 'icingaweb2/monitoring_config.ini', - 'mode': '0660', - 'group': 'icingaweb2', - }, '/etc/icingaweb2/groups.ini': { 'source': 'icingaweb2/groups.ini', 'mode': '0660', @@ -276,13 +262,13 @@ files = { 'group': 'icingaweb2', }, - # monitoring + # Statusmonitor '/etc/icinga2/icinga_statusmonitor.py': { 'triggers': { 'svc_systemd:icinga_statusmonitor:restart', }, }, - '/usr/local/lib/systemd/system/icinga_statusmonitor.service': { + '/etc/systemd/system/icinga_statusmonitor.service': { 'triggers': { 'action:systemd-reload', 'svc_systemd:icinga_statusmonitor:restart', @@ -290,12 +276,8 @@ files = { }, } -svc_systemd['icinga_statusmonitor'] = { - 'needs': { - 'file:/etc/icinga2/icinga_statusmonitor.py', - 'file:/usr/local/lib/systemd/system/icinga_statusmonitor.service', - 'pkg_apt:python3-flask', - }, +pkg_pip = { + 'easysnmp': {}, # for check_usv_snmp } actions = { @@ -337,30 +319,44 @@ for name in files: for name in symlinks: icinga_run_deps.add(f'symlink:{name}') -svc_systemd['icinga2'] = { - 'needs': icinga_run_deps, +svc_systemd = { + 'icinga2': { + 'needs': icinga_run_deps, + }, + 'icinga_statusmonitor': { + 'needs': { + 'file:/etc/icinga2/icinga_statusmonitor.py', + 'file:/etc/systemd/system/icinga_statusmonitor.service', + 'pkg_apt:python3-flask', + }, + }, } + # The actual hosts and services management starts here bundles = set() -downtimes = [] -for rnode in sorted(repo.nodes): +for rnode in repo.nodes: if rnode.metadata.get('icinga_options/exclude_from_monitoring', False): continue - host_ips = repo.libs.tools.resolve_identifier(repo, rnode.name, only_physical=True) + host_ips = repo.libs.tools.resolve_identifier(repo, rnode.name) icinga_ips = {} - for ip_type in ('ipv4', 'ipv6'): - for ip in sorted(host_ips[ip_type]): - if ip.is_private and not ip.is_link_local: - icinga_ips[ip_type] = str(ip) - break - else: - if host_ips[ip_type]: - icinga_ips[ip_type] = sorted(host_ips[ip_type])[0] + # XXX for the love of god, PLEASE remove this once DNS is no longer + # hosted at GCE + if rnode.in_group('gce'): + icinga_ips['ipv4'] = rnode.metadata.get('external_ipv4') + else: + for ip_type in ('ipv4', 'ipv6'): + for ip in sorted(host_ips[ip_type]): + if ip.is_private and not ip.is_link_local: + icinga_ips[ip_type] = str(ip) + break + else: + if host_ips[ip_type]: + icinga_ips[ip_type] = sorted(host_ips[ip_type])[0] if not icinga_ips: raise ValueError(f'{rnode.name} requests monitoring, but has neither IPv4 nor IPv6 addresses!') @@ -383,25 +379,6 @@ for rnode in sorted(repo.nodes): bundles |= set(rnode.metadata.get('icinga2_api', {}).keys()) - if rnode.has_any_bundle(['apt', 'c3voc-addons']): - day = rnode.metadata.get('apt/unattended-upgrades/day') - hour = rnode.metadata.get('apt/unattended-upgrades/hour') - minute = rnode.magic_number%30 - - spread = rnode.metadata.get('apt/unattended-upgrades/spread_in_group', None) - if spread is not None: - spread_nodes = sorted(repo.nodes_in_group(spread)) - day += spread_nodes.index(rnode) - - downtimes.append({ - 'name': 'unattended-upgrades', - 'host': rnode.name, - 'comment': f'Downtime for upgrade-and-reboot of node {rnode.name}', - 'times': { - DAYS_TO_STRING[day%7]: f'{hour}:{minute}-{hour}:{minute+15}', - }, - }) - files['/etc/icinga2/conf.d/groups.conf'] = { 'source': 'icinga2/groups.conf', 'content_type': 'mako', @@ -422,7 +399,7 @@ files['/etc/icinga2/conf.d/downtimes.conf'] = { 'source': 'icinga2/downtimes.conf', 'content_type': 'mako', 'context': { - 'downtimes': downtimes, + 'days': DAYS_TO_STRING, }, 'owner': 'nagios', 'group': 'nagios', diff --git a/bundles/icinga2/metadata.py b/bundles/icinga2/metadata.py index c25ca41..9bf7d26 100644 --- a/bundles/icinga2/metadata.py +++ b/bundles/icinga2/metadata.py @@ -17,9 +17,10 @@ defaults = { 'icinga2': {}, 'icinga2-ido-pgsql': {}, 'icingaweb2': {}, - 'python3-easysnmp': {}, + 'icingaweb2-module-monitoring': {}, + + # neeeded for statusmonitor 'python3-flask': {}, - 'snmp': {}, } }, 'icinga2': { @@ -40,6 +41,9 @@ defaults = { 'check_interval': '30m', 'vars.notification.mail': True, }, + 'ICINGA STATUSMONITOR': { + 'command_on_monitored_host': '/usr/local/share/icinga/plugins/check_systemd_unit icinga_statusmonitor', + }, 'IDO-PGSQL': { 'check_command': 'ido', 'vars.ido_type': 'IdoPgsqlConnection', @@ -53,20 +57,6 @@ defaults = { 'icingaweb2': { 'setup-token': repo.vault.password_for(f'{node.name} icingaweb2 setup-token'), }, - 'php': { - 'packages': { - 'curl', - 'gd', - 'intl', - 'imagick', - 'ldap', - 'mysql', - 'opcache', - 'pgsql', - 'readline', - 'xml', - }, - }, 'postgresql': { 'roles': { 'icinga2': { @@ -113,29 +103,13 @@ def add_users_from_json(metadata): @metadata_reactor.provides( - 'nginx/vhosts/icingaweb2', - 'nginx/vhosts/icinga_statusmonitor', + 'firewall/port_rules/5665', ) -def nginx(metadata): - if not node.has_bundle('nginx'): - raise DoNotRunAgain - +def firewall(metadata): return { - 'nginx': { - 'vhosts': { - 'icingaweb2': { - 'domain': metadata.get('icinga2/web_domain'), - 'webroot': '/usr/share/icingaweb2/public', - 'locations': { - '/api/': { - 'target': 'https://127.0.0.1:5665/', - }, - '/statusmonitor/': { - 'target': 'http://127.0.0.1:5000/', - }, - }, - 'extras': True, - }, + 'firewall': { + 'port_rules': { + '5665': atomic(metadata.get('icinga2/restrict-to', set())), }, }, } diff --git a/bundles/influxdb2/metadata.py b/bundles/influxdb2/metadata.py index 1a7b2a0..68fda00 100644 --- a/bundles/influxdb2/metadata.py +++ b/bundles/influxdb2/metadata.py @@ -10,7 +10,7 @@ defaults = { 'repos': { 'influxdb': { 'items': { - 'deb https://repos.influxdata.com/{os} stable main', + 'deb https://repos.influxdata.com/{os} {os_release} stable', }, }, }, diff --git a/bundles/infobeamer-cms/files/infobeamer-cms-runperiodic.service b/bundles/infobeamer-cms/files/infobeamer-cms-runperiodic.service index bf63eb1..8be500a 100644 --- a/bundles/infobeamer-cms/files/infobeamer-cms-runperiodic.service +++ b/bundles/infobeamer-cms/files/infobeamer-cms-runperiodic.service @@ -4,8 +4,7 @@ After=network.target Requires=infobeamer-cms.service [Service] -Environment=SETTINGS=/opt/infobeamer-cms/settings.toml -WorkingDirectory=/opt/infobeamer-cms/src User=infobeamer-cms Group=infobeamer-cms -ExecStart=/opt/infobeamer-cms/venv/bin/python syncer.py +WorkingDirectory=/opt/infobeamer-cms +ExecStart=curl -s -H "Host: ${domain}" http://127.0.0.1:8000/sync diff --git a/bundles/infobeamer-cms/files/infobeamer-cms-runperiodic.timer b/bundles/infobeamer-cms/files/infobeamer-cms-runperiodic.timer index 049b063..48b52f4 100644 --- a/bundles/infobeamer-cms/files/infobeamer-cms-runperiodic.timer +++ b/bundles/infobeamer-cms/files/infobeamer-cms-runperiodic.timer @@ -2,7 +2,7 @@ Description=Run infobeamer-cms sync [Timer] -OnCalendar=minutely +OnCalendar=*:0/5 Persistent=true [Install] diff --git a/bundles/infobeamer-cms/files/settings.toml b/bundles/infobeamer-cms/files/settings.toml new file mode 100644 index 0000000..12dcdb7 --- /dev/null +++ b/bundles/infobeamer-cms/files/settings.toml @@ -0,0 +1,4 @@ +<% + from tomlkit import dumps as toml_dumps + from bundlewrap.utils.text import toml_clean +%>${toml_clean(toml_dumps(repo.libs.faults.resolve_faults(config), sort_keys=True))} diff --git a/bundles/infobeamer-cms/items.py b/bundles/infobeamer-cms/items.py index aa424a1..226fc23 100644 --- a/bundles/infobeamer-cms/items.py +++ b/bundles/infobeamer-cms/items.py @@ -1,4 +1,8 @@ actions = { + 'infobeamer-cms_set_directory_permissions': { + 'triggered': True, + 'command': 'chown -R infobeamer-cms:infobeamer-cms /opt/infobeamer-cms/src/static/' + }, 'infobeamer-cms_create_virtualenv': { 'command': '/usr/bin/python3 -m virtualenv -p python3 /opt/infobeamer-cms/venv/', 'unless': 'test -d /opt/infobeamer-cms/venv/', @@ -8,11 +12,7 @@ actions = { }, }, 'infobeamer-cms_install_requirements': { - 'command': ' && '.join([ - 'cd /opt/infobeamer-cms/src', - '/opt/infobeamer-cms/venv/bin/pip install --upgrade pip gunicorn -r requirements.txt', - 'rsync /opt/infobeamer-cms/src/static/* /opt/infobeamer-cms/static/', - ]), + 'command': 'cd /opt/infobeamer-cms/src && /opt/infobeamer-cms/venv/bin/pip install --upgrade pip gunicorn -r requirements.txt', 'needs': { 'action:infobeamer-cms_create_virtualenv', }, @@ -23,12 +23,13 @@ actions = { git_deploy = { '/opt/infobeamer-cms/src': { 'rev': 'master', - 'repo': 'https://github.com/voc/infobeamer-cms.git', + 'repo': 'https://github.com/sophieschi/36c3-cms.git', 'needs': { 'directory:/opt/infobeamer-cms/src', }, 'triggers': { 'svc_systemd:infobeamer-cms:restart', + 'action:infobeamer-cms_set_directory_permissions', 'action:infobeamer-cms_install_requirements', }, }, @@ -36,9 +37,6 @@ git_deploy = { directories = { '/opt/infobeamer-cms/src': {}, - '/opt/infobeamer-cms/static': { - 'owner': 'infobeamer-cms', - }, } config = node.metadata.get('infobeamer-cms/config', {}) @@ -68,7 +66,10 @@ for room, device_id in sorted(node.metadata.get('infobeamer-cms/rooms', {}).item files = { '/opt/infobeamer-cms/settings.toml': { - 'content': repo.libs.faults.dict_as_toml(config), + 'content_type': 'mako', + 'context': { + 'config': config, + }, 'triggers': { 'svc_systemd:infobeamer-cms:restart', }, @@ -96,11 +97,19 @@ files = { }, } +pkg_pip = { + 'github-flask': { + 'needed_by': { + 'svc_systemd:infobeamer-cms', + }, + }, +} + svc_systemd = { 'infobeamer-cms': { 'needs': { 'action:infobeamer-cms_install_requirements', - 'directory:/opt/infobeamer-cms/static', + 'action:infobeamer-cms_set_directory_permissions', 'file:/etc/systemd/system/infobeamer-cms.service', 'file:/opt/infobeamer-cms/settings.toml', 'git_deploy:/opt/infobeamer-cms/src', @@ -108,12 +117,8 @@ svc_systemd = { }, 'infobeamer-cms-runperiodic.timer': { 'needs': { - 'action:infobeamer-cms_install_requirements', - 'directory:/opt/infobeamer-cms/static', - 'file:/etc/systemd/system/infobeamer-cms-runperiodic.service', 'file:/etc/systemd/system/infobeamer-cms-runperiodic.timer', - 'file:/opt/infobeamer-cms/settings.toml', - 'git_deploy:/opt/infobeamer-cms/src', + 'file:/etc/systemd/system/infobeamer-cms-runperiodic.service', }, }, } diff --git a/bundles/infobeamer-cms/metadata.py b/bundles/infobeamer-cms/metadata.py index 4413d5a..8d8703b 100644 --- a/bundles/infobeamer-cms/metadata.py +++ b/bundles/infobeamer-cms/metadata.py @@ -1,15 +1,11 @@ -from datetime import datetime, timedelta, timezone - -assert node.has_bundle('redis') +from datetime import datetime, timedelta defaults = { 'infobeamer-cms': { 'config': { 'MAX_UPLOADS': 5, 'PREFERRED_URL_SCHEME': 'https', - 'REDIS_HOST': '127.0.0.1', 'SESSION_COOKIE_NAME': '__Host-sess', - 'STATIC_PATH': '/opt/infobeamer-cms/static', 'URL_KEY': repo.vault.password_for(f'{node.name} infobeamer-cms url key'), 'VERSION': 1, }, @@ -33,13 +29,15 @@ def nginx(metadata): '/': { 'target': 'http://127.0.0.1:8000', }, + '/sync': { + 'return': 403, + }, '/static': { - 'alias': '/opt/infobeamer-cms/static', + 'alias': '/opt/infobeamer-cms/src/static', }, }, 'website_check_path': '/', 'website_check_string': 'Share your projects', - 'do_not_set_content_security_headers': True, }, }, }, @@ -47,12 +45,11 @@ def nginx(metadata): @metadata_reactor.provides( - 'infobeamer-cms/config/DOMAIN', 'infobeamer-cms/config/TIME_MAX', 'infobeamer-cms/config/TIME_MIN', ) def event_times(metadata): - event_start = datetime.strptime(metadata.get('infobeamer-cms/event_start_date'), '%Y-%m-%d').replace(tzinfo=timezone.utc) + event_start = datetime.strptime(metadata.get('infobeamer-cms/event_start_date'), '%Y-%m-%d') event_duration = metadata.get('infobeamer-cms/event_duration_days', 4) event_end = event_start + timedelta(days=event_duration) @@ -60,7 +57,6 @@ def event_times(metadata): return { 'infobeamer-cms': { 'config': { - 'DOMAIN': metadata.get('infobeamer-cms/domain'), 'TIME_MAX': int(event_end.timestamp()), 'TIME_MIN': int(event_start.timestamp()), }, diff --git a/bundles/infobeamer-monitor/files/infobeamer-monitor.service b/bundles/infobeamer-monitor/files/infobeamer-monitor.service deleted file mode 100644 index 7be13a2..0000000 --- a/bundles/infobeamer-monitor/files/infobeamer-monitor.service +++ /dev/null @@ -1,15 +0,0 @@ -[Unit] -Description=infobeamer-monitor -After=network.target - -[Service] -Type=exec -Restart=always -RestartSec=5s -ExecStart=/opt/infobeamer-cms/venv/bin/python monitor.py -User=infobeamer-cms -Group=infobeamer-cms -WorkingDirectory=/opt/infobeamer-monitor/ - -[Install] -WantedBy=multi-user.target diff --git a/bundles/infobeamer-monitor/files/monitor.py b/bundles/infobeamer-monitor/files/monitor.py deleted file mode 100644 index 7646fa6..0000000 --- a/bundles/infobeamer-monitor/files/monitor.py +++ /dev/null @@ -1,217 +0,0 @@ -#!/usr/bin/env python3 - -import logging -from datetime import datetime -from json import dumps -from time import sleep -from zoneinfo import ZoneInfo - -import paho.mqtt.client as mqtt -from requests import RequestException, get - -try: - # python 3.11 - from tomllib import loads as toml_load -except ImportError: - from rtoml import load as toml_load - -with open("config.toml") as f: - CONFIG = toml_load(f.read()) - - -logging.basicConfig( - format="[%(levelname)s %(name)s] %(message)s", - level=logging.INFO, -) - -LOG = logging.getLogger("main") -TZ = ZoneInfo("Europe/Berlin") -DUMP_TIME = "0900" - -state = None - -client = mqtt.Client() -client.username_pw_set(CONFIG["mqtt"]["user"], CONFIG["mqtt"]["password"]) -client.connect(CONFIG["mqtt"]["host"], 1883, 60) -client.loop_start() - - -def mqtt_out(message, level="INFO", device=None): - key = "infobeamer" - if device: - key += f"/{device['id']}" - if device["description"]: - message = f"[{device['description']}] {message}" - else: - message = f"[{device['serial']}] {message}" - - client.publish( - CONFIG["mqtt"]["topic"], - dumps( - { - "level": level, - "component": key, - "msg": message, - } - ), - ) - - -def mqtt_dump_state(device): - if not device["is_online"]: - return - - out = [] - if device["location"]: - out.append("Location: {}".format(device["location"])) - out.append("Setup: {} ({})".format(device["setup"]["name"], device["setup"]["id"])) - out.append("Resolution: {}".format(device["run"].get("resolution", "unknown"))) - - mqtt_out( - " - ".join(out), - device=device, - ) - -def is_dump_time(): - return datetime.now(TZ).strftime("%H%M") == DUMP_TIME - -mqtt_out("Monitor starting up") -while True: - try: - try: - r = get( - "https://info-beamer.com/api/v1/device/list", - auth=("", CONFIG["api_key"]), - ) - r.raise_for_status() - ib_state = r.json()["devices"] - except RequestException as e: - LOG.exception("Could not get device data from info-beamer") - mqtt_out( - f"Could not get device data from info-beamer: {e!r}", - level="WARN", - ) - else: - new_state = {} - for device in sorted(ib_state, key=lambda x: x["id"]): - did = str(device["id"]) - - if did in new_state: - mqtt_out("DUPLICATE DETECTED!", level="ERROR", device=device) - continue - - new_state[did] = device - # force information output for every online device at 09:00 CE(S)T - must_dump_state = is_dump_time() - - if state is not None: - if did not in state: - LOG.info( - "new device found: {} [{}]".format( - did, - device["description"], - ) - ) - mqtt_out( - "new device found!", - device=device, - ) - must_dump_state = True - - else: - if device["is_online"] != state[did]["is_online"]: - online_status = ( - "online from {}".format(device["run"]["public_addr"]) - if device["is_online"] - else "offline" - ) - - LOG.info("device {} is now {}".format(did, online_status)) - mqtt_out( - f"status changed to {online_status}", - level="INFO" if device["is_online"] else "WARN", - device=device, - ) - must_dump_state = True - - if device["description"] != state[did]["description"]: - LOG.info( - "device {} changed name to {}".format( - did, device["description"] - ) - ) - must_dump_state = True - - if device["is_online"]: - if device["maintenance"]: - mqtt_out( - "maintenance required: {}".format( - " ".join(sorted(device["maintenance"])) - ), - level="WARN", - device=device, - ) - - if ( - device["location"] != state[did]["location"] - or device["setup"]["id"] != state[did]["setup"]["id"] - or device["run"].get("resolution") - != state[did]["run"].get("resolution") - ): - must_dump_state = True - - if must_dump_state: - mqtt_dump_state(device) - else: - LOG.info("adding device {} to empty state".format(device["id"])) - - state = new_state - - try: - r = get( - "https://info-beamer.com/api/v1/account", - auth=("", CONFIG["api_key"]), - ) - r.raise_for_status() - ib_account = r.json() - except RequestException as e: - LOG.exception("Could not get account data from info-beamer") - mqtt_out( - f"Could not get account data from info-beamer: {e!r}", - level="WARN", - ) - else: - available_credits = ib_account["balance"] - if is_dump_time(): - mqtt_out(f"Available Credits: {available_credits}") - - if available_credits < 50: - mqtt_out( - f"balance has dropped below 50 credits! (available: {available_credits})", - level="ERROR", - ) - elif available_credits < 100: - mqtt_out( - f"balance has dropped below 100 credits! (available: {available_credits})", - level="WARN", - ) - - for quota_name, quota_config in sorted(ib_account["quotas"].items()): - value = quota_config["count"]["value"] - limit = quota_config["count"]["limit"] - if value > limit * 0.9: - mqtt_out( - f"quota {quota_name} is over 90% (limit {limit}, value {value})", - level="ERROR", - ) - elif value > limit * 0.8: - mqtt_out( - f"quota {quota_name} is over 80% (limit {limit}, value {value})", - level="WARN", - ) - - sleep(60) - except KeyboardInterrupt: - break - -mqtt_out("Monitor exiting") diff --git a/bundles/infobeamer-monitor/items.py b/bundles/infobeamer-monitor/items.py deleted file mode 100644 index 683d240..0000000 --- a/bundles/infobeamer-monitor/items.py +++ /dev/null @@ -1,30 +0,0 @@ -assert node.has_bundle('infobeamer-cms') # uses same venv - -files['/opt/infobeamer-monitor/config.toml'] = { - 'content': repo.libs.faults.dict_as_toml(node.metadata.get('infobeamer-monitor')), - 'triggers': { - 'svc_systemd:infobeamer-monitor:restart', - }, -} - -files['/opt/infobeamer-monitor/monitor.py'] = { - 'mode': '0755', - 'triggers': { - 'svc_systemd:infobeamer-monitor:restart', - }, -} - -files['/usr/local/lib/systemd/system/infobeamer-monitor.service'] = { - 'triggers': { - 'action:systemd-reload', - 'svc_systemd:infobeamer-monitor:restart', - }, -} - -svc_systemd['infobeamer-monitor'] = { - 'needs': { - 'file:/opt/infobeamer-monitor/config.toml', - 'file:/opt/infobeamer-monitor/monitor.py', - 'file:/usr/local/lib/systemd/system/infobeamer-monitor.service', - }, -} diff --git a/bundles/ipmitool/metadata.py b/bundles/ipmitool/metadata.py index e908366..a340a7a 100644 --- a/bundles/ipmitool/metadata.py +++ b/bundles/ipmitool/metadata.py @@ -19,4 +19,9 @@ defaults = { '/usr/bin/ipmitool *', }, }, + 'pacman': { + 'packages': { + 'ipmitool': {}, + }, + }, } diff --git a/bundles/jellyfin/files/jellyfin-sudoers b/bundles/jellyfin/files/jellyfin-sudoers deleted file mode 100644 index 1d138d6..0000000 --- a/bundles/jellyfin/files/jellyfin-sudoers +++ /dev/null @@ -1,7 +0,0 @@ -Cmnd_Alias RESTARTSERVER_SYSTEMD = /usr/bin/systemd-run systemctl restart jellyfin -Cmnd_Alias STARTSERVER_SYSTEMD = /usr/bin/systemd-run systemctl start jellyfin -Cmnd_Alias STOPSERVER_SYSTEMD = /usr/bin/systemd-run systemctl stop jellyfin - -jellyfin ALL=(ALL) NOPASSWD: RESTARTSERVER_SYSTEMD -jellyfin ALL=(ALL) NOPASSWD: STARTSERVER_SYSTEMD -jellyfin ALL=(ALL) NOPASSWD: STOPSERVER_SYSTEMD diff --git a/bundles/jellyfin/items.py b/bundles/jellyfin/items.py deleted file mode 100644 index 6bd828d..0000000 --- a/bundles/jellyfin/items.py +++ /dev/null @@ -1,5 +0,0 @@ -files['/etc/sudoers.d/jellyfin-sudoers'] = { - 'after': { - 'pkg_apt:jellyfin', - }, -} diff --git a/bundles/jellyfin/metadata.py b/bundles/jellyfin/metadata.py deleted file mode 100644 index 8c4e9ff..0000000 --- a/bundles/jellyfin/metadata.py +++ /dev/null @@ -1,69 +0,0 @@ -from bundlewrap.metadata import atomic - -defaults = { - 'apt': { - 'packages': { - 'jellyfin': {}, - }, - 'repos': { - 'jellyfin': { - 'uris': { - 'https://repo.jellyfin.org/{os}' - }, - }, - }, - }, - 'backups': { - 'paths': { - f'/var/lib/jellyfin/{x}' for x in ('data', 'metadata', 'plugins', 'root') - }, - }, - 'icinga2_api': { - 'transmission': { - 'services': { - 'JELLYFIN PROCESS': { - 'command_on_monitored_host': '/usr/lib/nagios/plugins/check_procs -C jellyfin -c 1:', - }, - }, - }, - }, -} - - -@metadata_reactor.provides( - 'nginx/vhosts/jellyfin', -) -def nginx(metadata): - if not node.has_bundle('nginx'): - raise DoNotRunAgain - - if 'jellyfin' not in metadata.get('nginx/vhosts', {}): - return {} - - return { - 'nginx': { - 'vhosts': { - 'jellyfin': { - 'do_not_add_content_security_headers': True, - 'locations': { - '/': { - 'target': 'http://127.0.0.1:8096', - 'websockets': True, - }, - }, - }, - }, - }, - } - -@metadata_reactor.provides( - 'firewall/port_rules', -) -def firewall(metadata): - return { - 'firewall': { - 'port_rules': { - '8096/tcp': atomic(metadata.get('jellyfin/restrict-to', set())), - }, - }, - } diff --git a/bundles/jool/items.py b/bundles/jool/items.py deleted file mode 100644 index 5ce5bac..0000000 --- a/bundles/jool/items.py +++ /dev/null @@ -1,15 +0,0 @@ -actions['modprobe_jool'] = { - 'command': 'modprobe jool', - 'unless': 'lsmod | grep -F jool', -} - -actions['jool_add_nat64_instance'] = { - 'command': 'jool instance add "nat64" --netfilter --pool6 64:ff9b::/96', - 'unless': 'jool instance display --no-headers --csv | grep -E ",nat64,netfilter$"', - 'needs': { - 'action:modprobe_jool', - 'pkg_apt:jool-dkms', - 'pkg_apt:jool-tools', - 'pkg_apt:linux-headers-amd64', - }, -} diff --git a/bundles/jool/metadata.py b/bundles/jool/metadata.py deleted file mode 100644 index 9ef83dd..0000000 --- a/bundles/jool/metadata.py +++ /dev/null @@ -1,14 +0,0 @@ -defaults = { - 'apt': { - 'packages': { - 'jool-dkms': {}, - 'jool-tools': {}, - 'linux-headers-amd64': {}, - }, - }, - 'modules': { - 'jool': [ - 'jool', - ], - }, -} diff --git a/bundles/jugendhackt_tools/files/jugendhackt_tools.service b/bundles/jugendhackt_tools/files/jugendhackt_tools.service deleted file mode 100644 index 2d0a36c..0000000 --- a/bundles/jugendhackt_tools/files/jugendhackt_tools.service +++ /dev/null @@ -1,16 +0,0 @@ -[Unit] -Description=jugendhackt_tools web service -After=network.target -Requires=postgresql.service - -[Service] -User=jugendhackt_tools -Group=jugendhackt_tools -Environment=CONFIG_PATH=/opt/jugendhackt_tools/config.toml -WorkingDirectory=/opt/jugendhackt_tools/src -ExecStart=/opt/jugendhackt_tools/venv/bin/gunicorn jugendhackt_tools.wsgi --name jugendhackt_tools --workers 4 --max-requests 1200 --max-requests-jitter 50 --log-level=info --bind=127.0.0.1:22090 -Restart=always -RestartSec=5 - -[Install] -WantedBy=multi-user.target diff --git a/bundles/jugendhackt_tools/items.py b/bundles/jugendhackt_tools/items.py deleted file mode 100644 index c2d0c6e..0000000 --- a/bundles/jugendhackt_tools/items.py +++ /dev/null @@ -1,75 +0,0 @@ -directories['/opt/jugendhackt_tools/src'] = {} - -git_deploy['/opt/jugendhackt_tools/src'] = { - 'repo': 'https://github.com/kunsi/jugendhackt_schedule.git', - 'rev': 'main', - 'triggers': { - 'action:jugendhackt_tools_install', - 'action:jugendhackt_tools_migrate', - 'svc_systemd:jugendhackt_tools:restart', - }, -} - -actions['jugendhackt_tools_create_virtualenv'] = { - 'command': '/usr/bin/python3 -m virtualenv -p python3 /opt/jugendhackt_tools/venv/', - 'unless': 'test -d /opt/jugendhackt_tools/venv/', - 'needs': { - # actually /opt/jugendhackt_tools, but we don't create that - 'directory:/opt/jugendhackt_tools/src', - }, -} - -actions['jugendhackt_tools_install'] = { - 'command': ' && '.join([ - 'cd /opt/jugendhackt_tools/src', - '/opt/jugendhackt_tools/venv/bin/pip install --upgrade pip wheel gunicorn psycopg2-binary', - '/opt/jugendhackt_tools/venv/bin/pip install --upgrade -r requirements.txt', - ]), - 'needs': { - 'action:jugendhackt_tools_create_virtualenv', - }, - 'triggered': True, -} - -actions['jugendhackt_tools_migrate'] = { - 'command': ' && '.join([ - 'cd /opt/jugendhackt_tools/src', - 'CONFIG_PATH=/opt/jugendhackt_tools/config.toml /opt/jugendhackt_tools/venv/bin/python manage.py migrate', - 'CONFIG_PATH=/opt/jugendhackt_tools/config.toml /opt/jugendhackt_tools/venv/bin/python manage.py collectstatic --noinput', - ]), - 'needs': { - 'action:jugendhackt_tools_install', - 'file:/opt/jugendhackt_tools/config.toml', - 'postgres_db:jugendhackt_tools', - 'postgres_role:jugendhackt_tools', - }, - 'triggered': True, -} - -files['/opt/jugendhackt_tools/config.toml'] = { - 'content': repo.libs.faults.dict_as_toml(node.metadata.get('jugendhackt_tools')), - 'triggers': { - 'svc_systemd:jugendhackt_tools:restart', - }, -} - -files['/usr/local/lib/systemd/system/jugendhackt_tools.service'] = { - 'triggers': { - 'action:systemd-reload', - 'svc_systemd:jugendhackt_tools:restart', - }, -} - -svc_systemd['jugendhackt_tools'] = { - 'needs': { - 'action:jugendhackt_tools_migrate', - 'file:/opt/jugendhackt_tools/config.toml', - 'file:/usr/local/lib/systemd/system/jugendhackt_tools.service', - 'git_deploy:/opt/jugendhackt_tools/src', - 'user:jugendhackt_tools', - }, -} - -users['jugendhackt_tools'] = { - 'home': '/opt/jugendhackt_tools/src', -} diff --git a/bundles/jugendhackt_tools/metadata.py b/bundles/jugendhackt_tools/metadata.py deleted file mode 100644 index 0b3d073..0000000 --- a/bundles/jugendhackt_tools/metadata.py +++ /dev/null @@ -1,28 +0,0 @@ -defaults = { - 'jugendhackt_tools': { - 'django_secret': repo.vault.random_bytes_as_base64_for(f'{node.name} jugendhackt_tools django_secret'), - 'django_debug': False, - 'static_root': '/opt/jugendhackt_tools/src/static/', - 'database': { - 'ENGINE': 'django.db.backends.postgresql', - 'NAME': 'jugendhackt_tools', - 'USER': 'jugendhackt_tools', - 'PASSWORD': repo.vault.password_for(f'{node.name} postgresql jugendhackt_tools'), - 'HOST': 'localhost', - 'PORT': '5432' - }, - }, - 'postgresql': { - 'roles': { - 'jugendhackt_tools': { - 'password': repo.vault.password_for(f'{node.name} postgresql jugendhackt_tools'), - }, - }, - 'databases': { - 'jugendhackt_tools': { - 'owner': 'jugendhackt_tools', - }, - }, - }, -} - diff --git a/bundles/kea-dhcp-server/files/kea-lease-list b/bundles/kea-dhcp-server/files/kea-lease-list deleted file mode 100644 index 7919b0c..0000000 --- a/bundles/kea-dhcp-server/files/kea-lease-list +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python3 - -from csv import DictReader -from datetime import datetime, timezone -from os import scandir -from os.path import join - - -def parse(): - NOW = datetime.now() - active_leases = {} - for file in scandir("/var/lib/kea/"): - with open(file.path) as f: - for row in DictReader(f): - expires = datetime.fromtimestamp(int(row["expire"])) - - if expires >= NOW: - if ( - row["address"] not in active_leases - or active_leases[row["address"]]["expires_dt"] < expires - ): - row["expires_dt"] = expires - active_leases[row["address"]] = row - return active_leases.values() - - -def print_table(leases): - print(""" address | MAC | expires | hostname ------------------+-------------------+---------+----------""") - for lease in sorted(leases, key=lambda r: r["address"]): - print( - f' {lease["address"]:<15} | {lease["hwaddr"].lower()} | {lease["expires_dt"]:%H:%M} | {lease["hostname"]}' - ) - - -if __name__ == "__main__": - print_table(parse()) diff --git a/bundles/kea-dhcp-server/items.py b/bundles/kea-dhcp-server/items.py deleted file mode 100644 index c6219cf..0000000 --- a/bundles/kea-dhcp-server/items.py +++ /dev/null @@ -1,56 +0,0 @@ -kea_config = { - 'Dhcp4': { - **node.metadata.get('kea-dhcp-server/config'), - 'interfaces-config': { - 'interfaces': sorted(node.metadata.get('kea-dhcp-server/subnets', {}).keys()), - }, - 'subnet4': [], - 'loggers': [{ - 'name': 'kea-dhcp4', - 'output_options': [{ - # -> journal - 'output': 'stdout', - }], - 'severity': 'WARN', - }], - }, -} - -for iface, config in sorted(node.metadata.get('kea-dhcp-server/subnets', {}).items()): - kea_config['Dhcp4']['subnet4'].append({ - 'subnet': config['subnet'], - 'pools': [{ - 'pool': f'{config["lower"]} - {config["higher"]}', - }], - 'option-data': [ - { - 'name': k, - 'data': v, - } for k, v in sorted(config.get('options', {}).items()) - ], - 'reservations': [ - { - 'ip-address': v['ip'], - 'hw-address': v['mac'], - 'hostname': k, - } for k, v in sorted(node.metadata.get(f'kea-dhcp-server/fixed_allocations/{iface}', {}).items()) - ] - }) - -files['/etc/kea/kea-dhcp4.conf'] = { - 'content': repo.libs.faults.dict_as_json(kea_config), - 'triggers': { - 'svc_systemd:kea-dhcp4-server:restart', - }, -} - -files['/usr/local/bin/kea-lease-list'] = { - 'mode': '0500', -} - -svc_systemd['kea-dhcp4-server'] = { - 'needs': { - 'file:/etc/kea/kea-dhcp4.conf', - 'pkg_apt:kea-dhcp4-server', - }, -} diff --git a/bundles/kea-dhcp-server/metadata.py b/bundles/kea-dhcp-server/metadata.py deleted file mode 100644 index 6a25c1f..0000000 --- a/bundles/kea-dhcp-server/metadata.py +++ /dev/null @@ -1,83 +0,0 @@ -from ipaddress import ip_address, ip_network - -defaults = { - 'apt': { - 'packages': { - 'kea-dhcp4-server': {}, - }, - }, - 'kea-dhcp-server': { - 'config': { - 'authoritative': True, - 'rebind-timer': 450, - 'renew-timer': 300, - 'valid-lifetime': 600, - 'expired-leases-processing': { - 'max-reclaim-leases': 0, - 'max-reclaim-time': 0, - }, - 'lease-database': { - 'lfc-interval': 3600, - 'name': '/var/lib/kea/kea-leases4.csv', - 'persist': True, - 'type': 'memfile', - }, - }, - }, -} - - -@metadata_reactor.provides( - 'kea-dhcp-server/fixed_allocations', -) -def get_static_allocations(metadata): - result = {} - mapping = {} - - for iface, config in metadata.get('kea-dhcp-server/subnets', {}).items(): - result[iface] = {} - mapping[iface] = ip_network(config['subnet']) - - for rnode in repo.nodes: - if ( - rnode.metadata.get('location', '') != metadata.get('location', '') - or rnode == node - ): - continue - - for iface_name, iface_config in rnode.metadata.get('interfaces', {}).items(): - if iface_config.get('dhcp', False) and iface_config.get('mac'): - for ip in iface_config.get('ips', set()): - ipaddr = ip_address(ip) - - for kea_iface, kea_subnet in mapping.items(): - if ipaddr in kea_subnet: - result[kea_iface][f'{rnode.name}_{iface_name}'] = { - 'ip': ip, - 'mac': iface_config['mac'], - } - break - - return { - 'kea-dhcp-server': { - 'fixed_allocations': result, - } - } - - -@metadata_reactor.provides( - 'nftables/input/10-kea-dhcp-server', -) -def nftables(metadata): - rules = set() - for iface in node.metadata.get('kea-dhcp-server/subnets', {}): - rules.add(f'udp dport {{ 67, 68 }} iifname {iface} accept') - - return { - 'nftables': { - 'input': { - # can't use port_rules here, because we're generating interface based rules. - '10-kea-dhcp-server': sorted(rules), - }, - } - } diff --git a/bundles/kernel-modules/files/modules b/bundles/kernel-modules/files/modules deleted file mode 100644 index 5abf592..0000000 --- a/bundles/kernel-modules/files/modules +++ /dev/null @@ -1,8 +0,0 @@ -# This file is managed using bundlewrap -% for identifier, modules in sorted(node.metadata.get('modules', {}).items()): - -# ${identifier} -% for module in modules: -${module} -% endfor -% endfor diff --git a/bundles/kernel-modules/items.py b/bundles/kernel-modules/items.py deleted file mode 100644 index dd848fd..0000000 --- a/bundles/kernel-modules/items.py +++ /dev/null @@ -1,3 +0,0 @@ -files['/etc/modules'] = { - 'content_type': 'mako', -} diff --git a/bundles/kodi/metadata.py b/bundles/kodi/metadata.py index 0fe2061..e217b21 100644 --- a/bundles/kodi/metadata.py +++ b/bundles/kodi/metadata.py @@ -43,15 +43,15 @@ defaults = { @metadata_reactor.provides( - 'firewall/port_rules', - 'firewall/port_rules', + 'firewall/port_rules/8080', + 'firewall/port_rules/9090', ) def firewall(metadata): return { 'firewall': { 'port_rules': { - '8080/tcp': atomic(metadata.get('kodi/restrict-to', {'*'})), - '9090/tcp': atomic(metadata.get('kodi/restrict-to', {'*'})), + '8080': atomic(metadata.get('kodi/restrict-to', {'*'})), + '9090': atomic(metadata.get('kodi/restrict-to', {'*'})), }, }, } diff --git a/bundles/letsencrypt/items.py b/bundles/letsencrypt/items.py index dd0b9c2..585cf8e 100644 --- a/bundles/letsencrypt/items.py +++ b/bundles/letsencrypt/items.py @@ -12,10 +12,6 @@ actions = { 'needs': { 'svc_systemd:nginx', }, - 'after': { - 'svc_systemd:nginx:reload', - 'svc_systemd:nginx:restart', - }, }, } diff --git a/bundles/letsencrypt/metadata.py b/bundles/letsencrypt/metadata.py index ffeb084..310dadd 100644 --- a/bundles/letsencrypt/metadata.py +++ b/bundles/letsencrypt/metadata.py @@ -13,6 +13,15 @@ defaults = { }, }, }, + 'pacman': { + 'packages': { + 'dehydrated': { + 'needed_by': { + 'action:letsencrypt_update_certificates', + }, + }, + }, + }, } @@ -30,7 +39,6 @@ def cron(metadata): '/usr/bin/dehydrated --cleanup', ], 'when': '04:{}:00'.format(node.magic_number % 60), - 'exclude_from_monitoring': True, }, }, }, diff --git a/bundles/lldp/items.py b/bundles/lldp/items.py index 7646f10..ac02aa1 100644 --- a/bundles/lldp/items.py +++ b/bundles/lldp/items.py @@ -1,29 +1,28 @@ -if node.os != 'routeros': - directories = { - '/etc/lldpd.d': { - 'purge': True, - 'triggers': { - 'svc_systemd:lldpd:restart', - }, +directories = { + '/etc/lldpd.d': { + 'purge': True, + 'triggers': { + 'svc_systemd:lldpd:restart', }, - } + }, +} - files = { - '/etc/lldpd.conf': { - 'delete': True, +files = { + '/etc/lldpd.conf': { + 'delete': True, + }, + '/etc/lldpd.d/bundlewrap.conf': { + 'content_type': 'mako', + 'triggers': { + 'svc_systemd:lldpd:restart', }, - '/etc/lldpd.d/bundlewrap.conf': { - 'content_type': 'mako', - 'triggers': { - 'svc_systemd:lldpd:restart', - }, - }, - } + }, +} - svc_systemd = { - 'lldpd': { - 'needs': { - 'file:/etc/lldpd.d/bundlewrap.conf', - }, +svc_systemd = { + 'lldpd': { + 'needs': { + 'file:/etc/lldpd.d/bundlewrap.conf', }, - } + }, +} diff --git a/bundles/lldp/metadata.py b/bundles/lldp/metadata.py index 2f1875c..7a499dd 100644 --- a/bundles/lldp/metadata.py +++ b/bundles/lldp/metadata.py @@ -10,4 +10,15 @@ defaults = { }, }, }, + 'pacman': { + 'packages': { + 'lldpd': { + 'needed_by': { + 'directory:/etc/lldpd.d', + 'file:/etc/lldpd.conf', + 'svc_systemd:lldpd', + }, + }, + }, + }, } diff --git a/bundles/lm-sensors/metadata.py b/bundles/lm-sensors/metadata.py index 01a6d1a..ffd3900 100644 --- a/bundles/lm-sensors/metadata.py +++ b/bundles/lm-sensors/metadata.py @@ -4,6 +4,11 @@ defaults = { 'lm-sensors': {}, }, }, + 'pacman': { + 'packages': { + 'lm_sensors': {}, + }, + }, 'telegraf': { 'input_plugins': { 'builtin': { diff --git a/bundles/matrix-dimension/files/matrix-dimension.service b/bundles/matrix-dimension/files/matrix-dimension.service new file mode 100644 index 0000000..9d2bebc --- /dev/null +++ b/bundles/matrix-dimension/files/matrix-dimension.service @@ -0,0 +1,14 @@ +[Unit] +Description=Matrix Dimension +After=network.target + +[Service] +User=matrix-dimension +Group=matrix-dimension +Environment="NODE_ENV=production" +ExecStart=/usr/bin/node ${config['install_dir']}/build/app/index.js +WorkingDirectory=${config['install_dir']} +Restart=on-failure + +[Install] +WantedBy=multi-user.target diff --git a/bundles/matrix-dimension/files/production.yaml b/bundles/matrix-dimension/files/production.yaml new file mode 100644 index 0000000..321f6d2 --- /dev/null +++ b/bundles/matrix-dimension/files/production.yaml @@ -0,0 +1,93 @@ +# The web settings for the service (API and UI). +# It is best to have this run on localhost and use a reverse proxy to access Dimension. +web: + port: 20030 + address: '127.0.0.1' + +# Homeserver configuration +homeserver: + # The domain name of the homeserver. This is used in many places, such as with go-neb + # setups, to identify the homeserver. + name: "${config['homeserver']['name']}" + + # The URL that Dimension, go-neb, and other services provisioned by Dimension should + # use to access the homeserver with. + clientServerUrl: "${config['homeserver']['clientServerUrl']}" + + # The URL that Dimension should use when trying to communicate with federated APIs on + # the homeserver. If not supplied or left empty Dimension will try to resolve the address + # through the normal federation process. + #federationUrl: "https://t2bot.io:8448" + + # The URL that Dimension will redirect media requests to for downloading media such as + # stickers. If not supplied or left empty Dimension will use the clientServerUrl. + #mediaUrl: "https://t2bot.io" + + # The access token Dimension should use for miscellaneous access to the homeserver, and + # for tracking custom sticker pack updates. This should be a user configured on the homeserver + # and be dedicated to Dimension (create a user named "dimension" on your homeserver). For + # information on how to acquire an access token, visit https://t2bot.io/docs/access_tokens + accessToken: "${config['homeserver']['accessToken']}" + +# These users can modify the integrations this Dimension supports. +# To access the admin interface, open Dimension in Riot and click the settings icon. +admins: +% for i in config['admins']: + - "${i}" +% endfor +# IPs and CIDR ranges listed here will be blocked from being widgets. +# Note: Widgets may still be embedded with restricted content, although not through Dimension directly. +widgetBlacklist: + - 10.0.0.0/8 + - 172.16.0.0/12 + - 192.168.0.0/16 + - 127.0.0.0/8 + +database: + # Where the database for Dimension is + uri: "postgres://${node.metadata['matrix-dimension']['database']['user']}:${node.metadata['matrix-dimension']['database']['password']}@${node.metadata['matrix-dimension']['database'].get('host', 'localhost')}/${node.metadata['matrix-dimension']['database']['database']}" + + # Where to store misc information for the utility bot account. + botData: "${config['data_dir']}/dimension.bot.json" + +# Display settings that apply to self-hosted go-neb instances +goneb: + # The avatars to set for each bot. Usually these don't need to be changed, however if your homeserver + # is not able to reach t2bot.io then you should specify your own here. To not use an avatar for a bot, + # make the bot's avatar an empty string. + avatars: + giphy: "mxc://t2bot.io/c5eaab3ef0133c1a61d3c849026deb27" + imgur: "mxc://t2bot.io/6749eaf2b302bb2188ae931b2eeb1513" + github: "mxc://t2bot.io/905b64b3cd8e2347f91a60c5eb0832e1" + wikipedia: "mxc://t2bot.io/7edfb54e9ad9e13fec0df22636feedf1" + travisci: "mxc://t2bot.io/7f4703126906fab8bb27df34a17707a8" + rss: "mxc://t2bot.io/aace4fcbd045f30afc1b4e5f0928f2f3" + google: "mxc://t2bot.io/636ad10742b66c4729bf89881a505142" + guggy: "mxc://t2bot.io/e7ef0ed0ba651aaf907655704f9a7526" + echo: "mxc://t2bot.io/3407ff2db96b4e954fcbf2c6c0415a13" + circleci: "mxc://t2bot.io/cf7d875845a82a6b21f5f66de78f6bee" + jira: "mxc://t2bot.io/f4a38ebcc4280ba5b950163ca3e7c329" + +# Settings for interacting with Telegram. Currently only applies for importing +# sticker packs from Telegram. +telegram: + # Talk to @BotFather on Telegram to get a token + botToken: "${config['telegram']['botToken']}" + +# Custom sticker pack options. +# Largely based on https://github.com/turt2live/matrix-sticker-manager +stickers: + # Whether or not to allow people to add custom sticker packs + enabled: true + + # The sticker manager bot to promote + stickerBot: "@stickers:t2bot.io" + + # The sticker manager URL to promote + managerUrl: "https://stickers.t2bot.io" + + +# Settings for controlling how logging works +logging: + console: true + consoleLevel: info diff --git a/bundles/matrix-dimension/items.py b/bundles/matrix-dimension/items.py new file mode 100644 index 0000000..9744754 --- /dev/null +++ b/bundles/matrix-dimension/items.py @@ -0,0 +1,78 @@ +repo.libs.tools.require_bundle(node, 'nodejs') + + +directories = { + node.metadata['matrix-dimension']['install_dir']: { + 'owner': 'matrix-dimension', + 'group': 'matrix-dimension', + }, +} + +git_deploy = { + node.metadata['matrix-dimension']['install_dir']: { + 'rev': node.metadata.get('matrix-dimension/version', 'master'), # doesn't have releases yet + 'repo': 'https://github.com/turt2live/matrix-dimension.git', + 'triggers': { + 'action:matrix_dimension_build', + }, + 'needs': { + 'directory:{}'.format(node.metadata.get('matrix-dimension/install_dir')), + 'directory:{}'.format(node.metadata.get('matrix-dimension/data_dir')), + }, + }, +} + +files = { + '{}/config/production.yaml'.format(node.metadata.get('matrix-dimension/install_dir')): { + 'owner': 'matrix-dimension', + 'group': 'matrix-dimension', + 'content_type': 'mako', + 'context': { + 'config': node.metadata.get('matrix-dimension', {}), + }, + 'needs': { + 'git_deploy:{}'.format(node.metadata.get('matrix-dimension/install_dir')), + }, + 'triggers': { + 'svc_systemd:matrix-dimension:restart', + }, + }, + '/etc/systemd/system/matrix-dimension.service': { + 'content_type': 'mako', + 'context': { + 'config': node.metadata.get('matrix-dimension', {}), + }, + 'triggers': { + 'action:systemd-reload', + 'svc_systemd:matrix-dimension:restart', + }, + }, +} + +actions = { + 'matrix_dimension_build': { + 'command': ' && '.join([ + 'cd ' + node.metadata.get('matrix-dimension/install_dir'), + 'sudo -u matrix-dimension npm install --legacy-peer-deps', + 'sudo -u matrix-dimension NODE_OPTIONS=--openssl-legacy-provider npm run build', + ]), + 'needs': { + 'pkg_apt:nodejs', + }, + 'triggered': True, + 'triggers': { + 'svc_systemd:matrix-dimension:restart', + }, + }, +} + +svc_systemd = { + 'matrix-dimension': { + 'needs': { + 'action:matrix_dimension_build', + 'file:{}/config/production.yaml'.format(node.metadata.get('matrix-dimension/install_dir')), + 'postgres_db:matrix-dimension', + 'postgres_role:matrix-dimension', + }, + }, +} diff --git a/bundles/matrix-dimension/metadata.py b/bundles/matrix-dimension/metadata.py new file mode 100644 index 0000000..c3f037d --- /dev/null +++ b/bundles/matrix-dimension/metadata.py @@ -0,0 +1,110 @@ +defaults = { + 'backups': { + 'paths': { + '/opt/matrix-dimension', + '/var/opt/matrix-dimension', + }, + }, + 'icinga2_api': { + 'matrix-dimension': { + 'services': { + 'MATRIX-DIMENSION PROCESS': { + 'command_on_monitored_host': '/usr/lib/nagios/plugins/check_procs -a matrix-dimension -c 1:', + }, + }, + }, + }, + 'matrix-dimension': { + 'install_dir': '/opt/matrix-dimension', + 'data_dir': '/var/opt/matrix-dimension', + 'database': { + 'user': 'matrix-dimension', + 'password': repo.vault.password_for('{} postgresql matrix-dimension'.format(node.name)), + 'database': 'matrix-dimension', + }, + }, + 'postgresql': { + 'roles': { + 'matrix-dimension': { + 'password': repo.vault.password_for('{} postgresql matrix-dimension'.format(node.name)), + }, + }, + 'databases': { + 'matrix-dimension': { + 'owner': 'matrix-dimension', + }, + }, + }, + 'users': { + 'matrix-dimension': { + 'home': '/var/opt/matrix-dimension', + }, + }, +} + + +@metadata_reactor.provides( + 'nginx/vhosts/matrix-dimension', +) +def nginx_config(metadata): + return { + 'nginx': { + 'vhosts': { + 'matrix-dimension': { + 'domain': metadata.get('matrix-dimension/url'), + 'do_not_set_content_security_headers': True, + 'max_body_size': '50M', + 'locations': { + '/': { + 'target': 'http://127.0.0.1:20030', + }, + }, + }, + }, + }, + } + + +@metadata_reactor.provides( + 'zfs/datasets', +) +def zfs(metadata): + return { + 'zfs': { + 'datasets': { + 'tank/matrix-dimension': {}, + 'tank/matrix-dimension/install': { + 'mountpoint': metadata.get('matrix-dimension/install_dir'), + 'needed_by': { + 'directory:{}'.format(metadata.get('matrix-dimension/install_dir')), + }, + }, + 'tank/matrix-dimension/var': { + 'mountpoint': metadata.get('matrix-dimension/data_dir'), + 'needed_by': { + 'directory:{}'.format(metadata.get('matrix-dimension/data_dir')), + }, + }, + }, + }, + } + + +# XXX enable this once there are releases for matrix-dimension +#@metadata_reactor.provides( +# 'icinga2_api/matrix-dimension/services', +#) +#def icinga_check_for_new_release(metadata): +# return { +# 'icinga2_api': { +# 'matrix-dimension': { +# 'services': { +# 'MATRIX-DIMENSION UPDATE': { +# 'command_on_monitored_host': '/usr/local/share/icinga/plugins/check_github_for_new_release turt2live/matrix-dimension {}'.format(metadata.get('matrix-dimension/version')), +# 'vars.notification.mail': True, +# 'check_interval': '60m', +# }, +# }, +# }, +# }, +# } diff --git a/bundles/matrix-media-repo/files/config.yaml b/bundles/matrix-media-repo/files/config.yaml index 3726bb2..3623928 100644 --- a/bundles/matrix-media-repo/files/config.yaml +++ b/bundles/matrix-media-repo/files/config.yaml @@ -1,11 +1,8 @@ # General repo configuration repo: - bindAddress: '${node.metadata.get('matrix-media-repo/listen-addr', '127.0.0.1')}' - port: ${node.metadata.get('matrix-media-repo/port', 20090)} + bindAddress: '${node.metadata['matrix-media-repo'].get('listen-addr', '127.0.0.1')}' + port: ${node.metadata['matrix-media-repo'].get('port', 20090)} logDirectory: '-' - logColors: false - jsonLogs: false - logLevel: 'info' trustAnyForwardedAddress: false useForwardedHost: true @@ -13,67 +10,73 @@ federation: backoffAt: 20 database: - postgres: "postgres://${node.metadata.get('matrix-media-repo/database/user')}:${node.metadata.get('matrix-media-repo/database/password')}@${node.metadata.get('matrix-media-repo/database/host', 'localhost')}/${node.metadata.get('matrix-media-repo/database/database')}?sslmode=disable" + postgres: "postgres://${node.metadata['matrix-media-repo']['database']['user']}:${node.metadata['matrix-media-repo']['database']['password']}@${node.metadata['matrix-media-repo']['database'].get('host', 'localhost')}/${node.metadata['matrix-media-repo']['database']['database']}?sslmode=disable" pool: maxConnections: 25 maxIdleConnections: 5 homeservers: -% for homeserver, config in node.metadata.get('matrix-media-repo/homeservers').items(): +% for homeserver, config in node.metadata['matrix-media-repo'].get('homeservers', {}).items(): - name: ${homeserver} csApi: "${config['domain']}" backoffAt: ${config.get('backoff_at', 10)} adminApiKind: "${config.get('api', 'matrix')}" -% if config.get('signing_key_path'): - signingKeyPath: "${config['signing_key_path']}" -% endif % endfor accessTokens: - maxCacheTimeSeconds: 10 + maxCacheTimeSeconds: 0 useLocalAppserviceConfig: false admins: -% for user in sorted(node.metadata.get('matrix-media-repo/admins')): +% for user in sorted(node.metadata['matrix-media-repo']['admins']): - "${user}" % endfor sharedSecretAuth: enabled: false - token: "${node.metadata.get('matrix-media-repo/shared-secret-token')}" + token: "${node.metadata['matrix-media-repo']['shared-secret-token']}" datastores: - type: file - id: "${node.metadata.get('matrix-media-repo/datastore_id')}" enabled: true - forKinds: ['all'] + forKinds: + - 'thumbnails' + - 'remote_media' + - 'local_media' + - 'archives' opts: path: /var/matrix/media archiving: enabled: true - selfService: ${str(node.metadata.get('matrix-media-repo/archive/self-service')).lower()} - targetBytesPerPart: ${node.metadata.get('matrix-media-repo/archive/mb_per_part', node.metadata.get('matrix-media-repo/upload_max_mb')*2)*1024*1024} + selfService: ${str(node.metadata['matrix-media-repo']['archive']['self-service']).lower()} + targetBytesPerPart: ${node.metadata['matrix-media-repo']['archive'].get('mb_per_part', node.metadata['matrix-media-repo']['upload_max_mb']*2)*1024*1024} uploads: - maxBytes: ${node.metadata.get('matrix-media-repo/upload_max_mb')*1024*1024} + maxBytes: ${node.metadata['matrix-media-repo']['upload_max_mb']*1024*1024} minBytes: 100 - #reportedMaxBytes: 0 - maxPending: 5 - maxAgeSeconds: 1800 + reportedMaxBytes: 0 quotas: enabled: false downloads: - maxBytes: ${node.metadata.get('matrix-media-repo/download_max_mb')*1024*1024} - numWorkers: ${node.metadata.get('matrix-media-repo/workers')} + maxBytes: ${node.metadata['matrix-media-repo']['download_max_mb']*1024*1024} + numWorkers: ${node.metadata['matrix-media-repo']['workers']} failureCacheMinutes: 5 + cache: + enabled: true + maxSizeBytes: ${node.metadata['matrix-media-repo']['download_max_mb']*10*1024*1024} + maxFileSizeBytes: ${node.metadata['matrix-media-repo']['upload_max_mb']*1024*1024} + trackedMinutes: 30 + minDownloads: 5 + minCacheTimeSeconds: 300 + minEvictedTimeSeconds: 60 expireAfterDays: 0 urlPreviews: enabled: true - maxPageSizeBytes: ${node.metadata.get('matrix-media-repo/preview_max_mb')*1024*1024} + maxPageSizeBytes: ${node.metadata['matrix-media-repo']['preview_max_mb']*1024*1024} previewUnsafeCertificates: false numWords: 50 maxLength: 200 @@ -81,7 +84,7 @@ urlPreviews: maxTitleLength: 150 filePreviewTypes: - "image/*" - numWorkers: ${node.metadata.get('matrix-media-repo/workers')} + numWorkers: ${node.metadata['matrix-media-repo']['workers']} disallowedNetworks: - "127.0.0.1/8" - "10.0.0.0/8" @@ -100,8 +103,8 @@ urlPreviews: oEmbed: false thumbnails: - maxSourceBytes: ${node.metadata.get('matrix-media-repo/preview_max_mb')*1024*1024} - numWorkers: ${node.metadata.get('matrix-media-repo/workers')} + maxSourceBytes: ${node.metadata['matrix-media-repo']['preview_max_mb']*1024*1024} + numWorkers: ${node.metadata['matrix-media-repo']['workers']} sizes: - width: 32 height: 32 @@ -131,14 +134,14 @@ thumbnails: - "video/mp4" allowAnimated: true defaultAnimated: false - maxAnimateSizeBytes: ${node.metadata.get('matrix-media-repo/preview_max_mb')*1024*1024} + maxAnimateSizeBytes: ${node.metadata['matrix-media-repo']['preview_max_mb']*1024*1024} stillFrame: 0.5 expireAfterDays: 0 rateLimit: enabled: true - requestsPerSecond: 100 - burst: 5000 + requestsPerSecond: 10 + burst: 50 identicons: enabled: true diff --git a/bundles/matrix-media-repo/items.py b/bundles/matrix-media-repo/items.py index faf08ad..ba2b2bb 100644 --- a/bundles/matrix-media-repo/items.py +++ b/bundles/matrix-media-repo/items.py @@ -19,6 +19,9 @@ files = { '/opt/matrix-media-repo/config.yaml': { 'owner': 'matrix-media-repo', 'content_type': 'mako', + 'triggers': { + 'svc_systemd:matrix-media-repo:restart', + }, }, '/etc/systemd/system/matrix-media-repo.service': { 'triggers': { diff --git a/bundles/matrix-stickerpicker/files/sticker-import b/bundles/matrix-stickerpicker/files/sticker-import deleted file mode 100644 index fd765c9..0000000 --- a/bundles/matrix-stickerpicker/files/sticker-import +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -/opt/matrix-stickerpicker/venv/bin/sticker-import \ - --config /opt/matrix-stickerpicker/config.json \ - --session /opt/matrix-stickerpicker/sticker-import.session \ - --output-dir /var/opt/matrix-stickerpicker/ \ - "$@" diff --git a/bundles/matrix-stickerpicker/items.py b/bundles/matrix-stickerpicker/items.py deleted file mode 100644 index 0cbe6c5..0000000 --- a/bundles/matrix-stickerpicker/items.py +++ /dev/null @@ -1,47 +0,0 @@ -actions['matrix-stickerpicker_create_virtualenv'] = { - 'command': '/usr/bin/python3 -m virtualenv -p python3 /opt/matrix-stickerpicker/venv/', - 'unless': 'test -d /opt/matrix-stickerpicker/venv/', - 'needs': { - # actually /opt/matrix-stickerpicker, but we don't create that - 'directory:/opt/matrix-stickerpicker/src', - }, -} - -actions['matrix-stickerpicker_install'] = { - 'command': 'cd /opt/matrix-stickerpicker/src && /opt/matrix-stickerpicker/venv/bin/pip install --upgrade pip .', - 'needs': { - 'action:matrix-stickerpicker_create_virtualenv', - }, - 'triggered': True, -} - -users['matrix-stickerpicker'] = { - 'home': '/opt/matrix-stickerpicker', -} - -files['/usr/local/bin/sticker-import'] = { - 'mode': '0700', -} - -files['/opt/matrix-stickerpicker/config.json'] = { - 'content': repo.libs.faults.dict_as_json(node.metadata.get('matrix-stickerpicker/config')), -} - -directories['/opt/matrix-stickerpicker/src'] = {} - -directories['/var/opt/matrix-stickerpicker'] = {} - -git_deploy['/opt/matrix-stickerpicker/src'] = { - 'repo': 'https://github.com/maunium/stickerpicker.git', - 'rev': node.metadata.get('matrix-stickerpicker/version', 'master'), - 'triggers': { - 'action:matrix-stickerpicker_install', - }, -} - -symlinks['/opt/matrix-stickerpicker/src/web/packs'] = { - 'target': '/var/opt/matrix-stickerpicker', - 'after': { - 'git_deploy:/opt/matrix-stickerpicker/src', - }, -} diff --git a/bundles/matrix-stickerpicker/metadata.py b/bundles/matrix-stickerpicker/metadata.py deleted file mode 100644 index e491a9d..0000000 --- a/bundles/matrix-stickerpicker/metadata.py +++ /dev/null @@ -1,37 +0,0 @@ -defaults = { - 'backups': { - 'paths': { - '/var/opt/matrix-stickerpicker', - }, - }, - 'zfs': { - 'datasets': { - 'tank/matrix-stickerpicker': { - 'mountpoint': '/var/opt/matrix-stickerpicker', - 'needed_by': { - 'directory:/var/opt/matrix-stickerpicker', - }, - }, - }, - }, -} - - -@metadata_reactor.provides( - 'nginx/vhosts/matrix-stickerpicker', -) -def nginx(metadata): - if not node.has_bundle('nginx'): - raise DoNotRunAgain - - return { - 'nginx': { - 'vhosts': { - 'matrix-stickerpicker': { - 'domain': metadata.get('matrix-stickerpicker/domain'), - 'do_not_set_content_security_headers': True, - 'webroot': '/opt/matrix-stickerpicker/src/web/', - }, - }, - }, - } diff --git a/bundles/matrix-synapse/files/homeserver.yaml b/bundles/matrix-synapse/files/homeserver.yaml index 9c43437..c5f9af3 100644 --- a/bundles/matrix-synapse/files/homeserver.yaml +++ b/bundles/matrix-synapse/files/homeserver.yaml @@ -62,14 +62,10 @@ allow_guest_access: false enable_metrics: True -% if appservice_configs: app_service_config_files: -% for config in sorted(appservice_configs): +% for config in sorted(appservice_configs): - "${config}" -% endfor -% else: -app_service_config_files: [] -% endif +% endfor signing_key_path: "/etc/matrix-synapse/homeserver.signing.key" trusted_key_servers: @@ -85,7 +81,7 @@ password_config: email: enable_notifs: false - notif_from: "Matrix " + notif_from: "Matrix \ -[Unit] -Description=matrix-org sliding-sync proxy -After=network.target -Requires=postgresql.service - -[Service] -User=matrix-synapse -Group=matrix-synapse -Environment=SYNCV3_SERVER=https://${node.metadata.get('matrix-synapse/baseurl')} -Environment=SYNCV3_DB=${db_string} -Environment=SYNCV3_SECRET=${node.metadata.get('matrix-synapse/sliding_sync/secret')} -Environment=SYNCV3_BINDADDR=127.0.0.1:20070 -ExecStart=/usr/local/bin/matrix-sliding-sync -Restart=always -RestartSec=10s - -[Install] -WantedBy=multi-user.target diff --git a/bundles/matrix-synapse/files/synapse-purge-unused-rooms b/bundles/matrix-synapse/files/synapse-purge-unused-rooms index 4e5f1e1..aa54ebb 100644 --- a/bundles/matrix-synapse/files/synapse-purge-unused-rooms +++ b/bundles/matrix-synapse/files/synapse-purge-unused-rooms @@ -1,9 +1,9 @@ #!/usr/bin/env python3 from os import environ +from requests import get, post from sys import argv, exit -from requests import get, post SYNAPSE_MAX_ROOMS_TO_GET = 20000 SYNAPSE_HOST = 'http://[::1]:20080/' diff --git a/bundles/matrix-synapse/files/synapse-reset-federation-timeout b/bundles/matrix-synapse/files/synapse-reset-federation-timeout deleted file mode 100644 index 258270a..0000000 --- a/bundles/matrix-synapse/files/synapse-reset-federation-timeout +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env python3 - -from os import environ -from sys import argv, exit - -from requests import post - -SYNAPSE_HOST = "http://[::1]:20080/" - -if "MATRIX_AUTH_TOKEN" in environ: - SYNAPSE_AUTH_TOKEN = environ["MATRIX_AUTH_TOKEN"] -else: - print("Usage: MATRIX_AUTH_TOKEN='your_token_here' {}".format(argv[0])) - exit(255) - -if len(argv) != 2: - print(f"Usage: {argv[0]} ") - exit(1) - -r = post( - SYNAPSE_HOST - + "_synapse/admin/v1/federation/destinations/{}/reset_connection".format(argv[1]), - headers={ - "Authorization": "Bearer {}".format(SYNAPSE_AUTH_TOKEN), - }, -) - -r.raise_for_status() -print(r.json()) diff --git a/bundles/matrix-synapse/items.py b/bundles/matrix-synapse/items.py index 527cc5e..7305e6b 100644 --- a/bundles/matrix-synapse/items.py +++ b/bundles/matrix-synapse/items.py @@ -1,15 +1,7 @@ files = { '/etc/matrix-synapse/homeserver.yaml': { 'content_type': 'mako', - 'context': node.metadata.get('matrix-synapse'), - 'needs': { - 'pkg_apt:matrix-synapse-py3', - }, - 'triggers': { - 'svc_systemd:matrix-synapse:restart', - }, - }, - '/etc/matrix-synapse/log.yaml': { + 'context': node.metadata['matrix-synapse'], 'needs': { 'pkg_apt:matrix-synapse-py3', }, @@ -20,9 +12,6 @@ files = { '/etc/matrix-synapse/scripts/synapse-purge-unused-rooms': { 'mode': '0755', }, - '/etc/matrix-synapse/scripts/synapse-reset-federation-timeout': { - 'mode': '0755', - }, '/etc/systemd/system/matrix-synapse.service.d/override.conf': { 'needs': { 'pkg_apt:matrix-synapse-py3', @@ -32,6 +21,9 @@ files = { 'svc_systemd:matrix-synapse:restart', }, }, + '/etc/matrix-synapse/homeserver.signing.key': { + 'content': repo.vault.decrypt_file('matrix-synapse/{}/homeserver_signing.key.vault'.format(node.name)), + }, '/etc/matrix-synapse/conf.d/server_name.yaml': { # We don't actually need this file. However, if we don't put the # server name in there, synapse will somehow remove it from @@ -39,7 +31,7 @@ files = { # Our override.conf ensures this file is never read, so we don't # need to restart synapse after changing stuff in here. 'content_type': 'mako', - 'context': node.metadata.get('matrix-synapse'), + 'context': node.metadata['matrix-synapse'], }, '/etc/matrix-synapse/conf.d/report_stats.yaml': { # see comment above @@ -50,7 +42,6 @@ svc_systemd = { 'matrix-synapse': { 'needs': { 'file:/etc/matrix-synapse/homeserver.yaml', - 'file:/etc/matrix-synapse/log.yaml', 'file:/etc/systemd/system/matrix-synapse.service.d/override.conf', 'pkg_apt:matrix-synapse-py3', 'postgres_db:synapse', diff --git a/bundles/matrix-synapse/metadata.py b/bundles/matrix-synapse/metadata.py index eac3005..df14735 100644 --- a/bundles/matrix-synapse/metadata.py +++ b/bundles/matrix-synapse/metadata.py @@ -15,7 +15,6 @@ defaults = { }, 'backups': { 'paths': { - '/etc/matrix-synapse', # to backup the signing key '/var/lib/matrix-synapse', }, }, @@ -118,12 +117,8 @@ def nginx(metadata): } locations = { - '/_client/': { - 'target': 'http://127.0.0.1:20070', - }, '/_matrix': { 'target': 'http://[::1]:20080', - 'max_body_size': '50M', }, '/_synapse': { 'target': 'http://[::1]:20080', @@ -132,14 +127,13 @@ def nginx(metadata): } if node.has_bundle('matrix-media-repo'): - for path in ('/_matrix/media', '/_matrix/client/v1/media', '/_matrix/federation/v1/media'): - locations[path] = { - 'target': 'http://localhost:20090', - 'max_body_size': '{}M'.format(metadata.get('matrix-media-repo/upload_max_mb')), - # matrix-media-repo needs this to be the - # homeserver address. - 'x_forwarded_host': metadata.get('matrix-synapse/server_name'), - } + locations['/_matrix/media'] = { + 'target': 'http://localhost:20090', + 'max_body_size': '{}M'.format(metadata.get('matrix-media-repo/upload_max_mb')), + # matrix-media-repo needs this to be the + # homeserver address. + 'x_forwarded_host': metadata.get('matrix-synapse/server_name'), + } vhosts = { 'matrix-synapse': { @@ -160,20 +154,3 @@ def nginx(metadata): 'vhosts': vhosts }, } - -@metadata_reactor.provides( - 'matrix-synapse/trusted_key_servers', -) -def autotrust_our_own_servers(metadata): - domains = set() - for rnode in repo.nodes: - if not rnode.has_bundle('matrix-synapse'): - continue - - domains.add(rnode.metadata.get('matrix-synapse/server_name')) - - return { - 'matrix-synapse': { - 'trusted_key_servers': domains, - }, - } diff --git a/bundles/mautrix-telegram/files/config.yaml b/bundles/mautrix-telegram/files/config.yaml index 1fbe165..0a3ad1c 100644 --- a/bundles/mautrix-telegram/files/config.yaml +++ b/bundles/mautrix-telegram/files/config.yaml @@ -180,7 +180,7 @@ logging: telethon: level: INFO aiohttp: - level: WARNING + level: INFO root: level: INFO handlers: [console] diff --git a/bundles/minecraft/metadata.py b/bundles/minecraft/metadata.py index 4bd5223..4c7626b 100644 --- a/bundles/minecraft/metadata.py +++ b/bundles/minecraft/metadata.py @@ -150,13 +150,13 @@ def heap_to_java_opts(metadata): @metadata_reactor.provides( - 'firewall/port_rules', + 'firewall/port_rules/25565', ) def firewall(metadata): return { 'firewall': { 'port_rules': { - '25565/tcp': atomic(metadata.get('minecraft/restrict-to', set())), + '25565': atomic(metadata.get('minecraft/restrict-to', set())), }, }, } diff --git a/bundles/miniflux/files/miniflux.conf b/bundles/miniflux/files/miniflux.conf index fd0b26e..0c03f45 100644 --- a/bundles/miniflux/files/miniflux.conf +++ b/bundles/miniflux/files/miniflux.conf @@ -5,6 +5,5 @@ CLEANUP_ARCHIVE_UNREAD_DAYS=-1 DATABASE_URL="user=miniflux password=${dbpassword} dbname=miniflux sslmode=disable host=localhost" LISTEN_ADDR=127.0.0.1:22040 POLLING_FREQUENCY=15 -PROXY_MEDIA_TYPES=image,audio -PROXY_OPTION=all +PROXY_IMAGES=all WORKER_POOL_SIZE=5 diff --git a/bundles/miniflux/items.py b/bundles/miniflux/items.py index 6ea55ae..4e8e015 100644 --- a/bundles/miniflux/items.py +++ b/bundles/miniflux/items.py @@ -2,8 +2,8 @@ files = { '/etc/miniflux.conf': { 'content_type': 'mako', 'context': { - 'dbpassword': node.metadata.get('postgresql/roles/miniflux/password'), - 'base_url': node.metadata.get('miniflux/domain'), + 'dbpassword': node.metadata['postgresql']['roles']['miniflux']['password'], + 'base_url': node.metadata['miniflux']['domain'], }, 'triggers': { 'svc_systemd:miniflux:restart', diff --git a/bundles/miniflux/metadata.py b/bundles/miniflux/metadata.py index b14fd15..8c51627 100644 --- a/bundles/miniflux/metadata.py +++ b/bundles/miniflux/metadata.py @@ -6,7 +6,7 @@ defaults = { 'repos': { 'miniflux': { 'items': { - 'deb [trusted=yes] https://repo.miniflux.app/apt/ /', + 'deb https://apt.miniflux.app/ /', }, }, }, diff --git a/bundles/mixcloud-downloader/files/download.sh b/bundles/mixcloud-downloader/files/download.sh index b7d97de..963d44d 100644 --- a/bundles/mixcloud-downloader/files/download.sh +++ b/bundles/mixcloud-downloader/files/download.sh @@ -1,15 +1,11 @@ #!/bin/bash -OPTS="--netrc" -OPTS="$OPTS --netrc-location /opt/mixcloud-downloader/netrc" -OPTS="$OPTS --retry-sleep linear=1::2" -OPTS="$OPTS --retry-sleep fragment:exp=1:60" -OPTS="$OPTS --extractor-retries 5" +OPTS="" if [[ -n "$DEBUG" ]] then set -x else - OPTS="$OPTS -q" + OPTS="-q" fi set -euo pipefail @@ -25,7 +21,7 @@ pip install --upgrade pip yt-dlp errors=0 -for i in Neosignal tasmo starkato b4m ProjectPoltergeist jakehunnter davem_dokebi El1s4 +for i in Neosignal tasmo starkato b4m Alexeyan jakehunnter davem_dokebi tasmo do echo "> mixcloud $i" >&2 if ! [[ -d "/storage/nas/Musik/mixcloud/$i" ]] @@ -57,7 +53,7 @@ do ) || errors=1 done -for i in tschunkelmusik zotanmew +for i in tschunkelmusik do echo "> soundcloud $i" >&2 if ! [[ -d "/storage/nas/Musik/mixcloud/$i" ]] diff --git a/bundles/mixcloud-downloader/files/netrc b/bundles/mixcloud-downloader/files/netrc deleted file mode 100644 index 40def1b..0000000 --- a/bundles/mixcloud-downloader/files/netrc +++ /dev/null @@ -1,3 +0,0 @@ -% for domain, data in sorted(node.metadata.get('mixcloud-downloader/netrc', {}).items()): -machine ${domain} login ${data['username']} password ${data['password']} -% endfor diff --git a/bundles/mixcloud-downloader/items.py b/bundles/mixcloud-downloader/items.py index 8c66ce8..a45acdc 100644 --- a/bundles/mixcloud-downloader/items.py +++ b/bundles/mixcloud-downloader/items.py @@ -6,9 +6,3 @@ files['/opt/mixcloud-downloader/download.sh'] = { directories['/opt/mixcloud-downloader'] = { 'owner': 'kunsi', } - -files['/opt/mixcloud-downloader/netrc'] = { - 'content_type': 'mako', - 'mode': '0400', - 'owner': 'kunsi', -} diff --git a/bundles/molly-guard/files/10-check-unattended-upgrades b/bundles/molly-guard/files/10-check-unattended-upgrades new file mode 100644 index 0000000..6adafdb --- /dev/null +++ b/bundles/molly-guard/files/10-check-unattended-upgrades @@ -0,0 +1,9 @@ +#!/bin/bash + +# Checks wether upgrade-and-reboot is currently running. + +if [[ -f "/var/lib/bundlewrap/soft-${node.name}/UNATTENDED" ]] +then + echo "Sorry, can't $MOLLYGUARD_CMD now, upgrade-and-reboot is running" + exit 1 +fi diff --git a/bundles/molly-guard/files/30-query-hostname b/bundles/molly-guard/files/30-query-hostname new file mode 100644 index 0000000..3e4fc4c --- /dev/null +++ b/bundles/molly-guard/files/30-query-hostname @@ -0,0 +1,29 @@ +#!/bin/sh + +# This script will ask for the bundlewrap node name. This replaces the +# original script, which will ask for the hostname, which sometimes +# is not enough to properly identify the system. + +NODE_NAME="${node.name}" + +# If this is not a terminal, do nothing +test -t 0 || exit 0 + +sigh() +{ + echo "Sorry, input does not match. Won't $MOLLYGUARD_CMD $NODE_NAME ..." >&2 + exit 1 +} + +trap 'echo;sigh' 1 2 3 9 10 12 15 + +echo -n "Please enter the bundlewrap node name of this System to $MOLLYGUARD_CMD: " +read NODE_NAME_USER || : + +NODE_NAME_USER="$(echo "$NODE_NAME_USER" | tr '[:upper:]' '[:lower:]')" + +[ "$NODE_NAME_USER" = "$NODE_NAME" ] || sigh + +trap - 1 2 3 9 10 12 15 + +exit 0 diff --git a/bundles/molly-guard/files/rc b/bundles/molly-guard/files/rc new file mode 100644 index 0000000..4b6f808 --- /dev/null +++ b/bundles/molly-guard/files/rc @@ -0,0 +1 @@ +# currently unused diff --git a/bundles/molly-guard/items.py b/bundles/molly-guard/items.py new file mode 100644 index 0000000..1d6d82f --- /dev/null +++ b/bundles/molly-guard/items.py @@ -0,0 +1,27 @@ +directories = { + '/etc/molly-guard/messages.d': { + 'purge': True, + 'after': { + 'pkg_apt:molly-guard', + }, + }, + '/etc/molly-guard/run.d': { + 'purge': True, + 'after': { + 'pkg_apt:molly-guard', + }, + }, +} + +files = { + '/etc/molly-guard/rc': {}, + + '/etc/molly-guard/run.d/10-check-unattended-upgrades': { + 'content_type': 'mako', + 'mode': '0755', + }, + '/etc/molly-guard/run.d/30-query-hostname': { + 'content_type': 'mako', + 'mode': '0755', + }, +} diff --git a/bundles/molly-guard/metadata.py b/bundles/molly-guard/metadata.py new file mode 100644 index 0000000..d8571e2 --- /dev/null +++ b/bundles/molly-guard/metadata.py @@ -0,0 +1,7 @@ +defaults = { + 'apt': { + 'packages': { + 'molly-guard': {}, + }, + }, +} diff --git a/bundles/mosquitto/files/tasmota-telegraf-plugin b/bundles/mosquitto/files/tasmota-telegraf-plugin index 4927002..3aef6d6 100644 --- a/bundles/mosquitto/files/tasmota-telegraf-plugin +++ b/bundles/mosquitto/files/tasmota-telegraf-plugin @@ -7,6 +7,7 @@ from time import sleep import paho.mqtt.client as mqtt + BROKER_HOST = argv[1] BROKER_TOPIC = argv[2] diff --git a/bundles/mosquitto/items.py b/bundles/mosquitto/items.py index 1b16413..92eb1b5 100644 --- a/bundles/mosquitto/items.py +++ b/bundles/mosquitto/items.py @@ -5,6 +5,12 @@ files = { 'svc_systemd:mosquitto:restart', }, }, + '/usr/local/bin/tasmota-telegraf-plugin': { + 'mode': '0755', + 'needs': { + 'pkg_apt:python3-paho-mqtt', + }, + }, } svc_systemd = { @@ -17,12 +23,6 @@ svc_systemd = { } if node.has_bundle('telegraf'): - files['/usr/local/bin/tasmota-telegraf-plugin'] = { - 'mode': '0755', - 'needs': { - 'pkg_apt:python3-paho-mqtt', - }, - 'triggers': { - 'svc_systemd:telegraf:restart', - }, + files['/usr/local/bin/tasmota-telegraf-plugin']['triggers'] = { + 'svc_systemd:telegraf:restart', } diff --git a/bundles/mosquitto/metadata.py b/bundles/mosquitto/metadata.py index 213dac6..08bd6de 100644 --- a/bundles/mosquitto/metadata.py +++ b/bundles/mosquitto/metadata.py @@ -1,10 +1,12 @@ from bundlewrap.metadata import atomic + defaults = { 'apt': { 'packages': { 'mosquitto': {}, 'mosquitto-clients': {}, + 'python3-paho-mqtt': {}, # for telegraf plugin }, }, 'icinga2_api': { @@ -23,9 +25,6 @@ defaults = { }, } -if node.has_bundle('telegraf'): - defaults['apt']['packages']['python3-paho-mqtt'] = {} - @metadata_reactor.provides( 'firewall/port_rules', @@ -35,7 +34,7 @@ def firewall(metadata): result = {} for listener in metadata.get('mosquitto/listeners').keys(): - result[f'{listener}/tcp'] = atomic(sources) + result[listener] = atomic(sources) return { 'firewall': { diff --git a/bundles/netbox/items.py b/bundles/netbox/items.py index 9edbf0b..ca54922 100644 --- a/bundles/netbox/items.py +++ b/bundles/netbox/items.py @@ -1,138 +1,124 @@ -users['netbox'] = { - 'home': '/opt/netbox', -} - -directories['/opt/netbox/src'] = {} - -directories['/opt/netbox/media'] = { - 'owner': 'netbox', -} - -directories['/opt/netbox/scripts'] = { - 'owner': 'netbox', -} - -git_deploy['/opt/netbox/src'] = { - 'repo': 'https://github.com/netbox-community/netbox.git', - 'rev': node.metadata.get('netbox/version'), - 'triggers': { - 'action:netbox_install', - 'svc_systemd:netbox-web:restart', - 'svc_systemd:netbox-worker:restart', +users = { + 'netbox': { + 'home': '/opt/netbox', }, - 'tags': { - 'netbox-install', +} + +directories = { + '/opt/netbox/src': {}, + '/opt/netbox/media': { + 'owner': 'netbox', + }, + '/opt/netbox/scripts': { + 'owner': 'netbox', + }, +} + +git_deploy = { + '/opt/netbox/src': { + 'repo': 'https://github.com/netbox-community/netbox.git', + 'rev': node.metadata.get('netbox/version'), + 'triggers': { + 'action:netbox_install', + 'action:netbox_upgrade', + 'svc_systemd:netbox-web:restart', + 'svc_systemd:netbox-worker:restart', + }, }, } # This is a recreation of https://github.com/netbox-community/netbox/blob/develop/upgrade.sh -actions['netbox_create_virtualenv'] = { - 'command': '/usr/bin/python3 -m virtualenv -p python3 /opt/netbox/venv', - 'unless': 'test -d /opt/netbox/venv/', - 'needed_by': { - 'action:netbox_install', +actions = { + 'netbox_create_virtualenv': { + 'command': '/usr/bin/python3 -m virtualenv -p python3 /opt/netbox/venv', + 'unless': 'test -d /opt/netbox/venv/', + 'needed_by': { + 'action:netbox_install', + }, }, -} - -actions['netbox_install'] = { - 'triggered': True, - 'command': ' && '.join([ - 'cd /opt/netbox/src', - '/opt/netbox/venv/bin/pip install --upgrade --upgrade-strategy=eager pip wheel setuptools django-auth-ldap gunicorn', - '/opt/netbox/venv/bin/pip install --upgrade --upgrade-strategy=eager -r requirements.txt', - ]), - 'needs': { - 'pkg_apt:build-essential', - 'pkg_apt:graphviz', - 'pkg_apt:libffi-dev', - 'pkg_apt:libldap2-dev', - 'pkg_apt:libpq-dev', - 'pkg_apt:libsasl2-dev', - 'pkg_apt:libssl-dev', - 'pkg_apt:libxml2-dev', - 'pkg_apt:libxslt1-dev', - 'pkg_apt:python3-dev', - 'pkg_apt:zlib1g-dev', - }, - 'tags': { - 'netbox-install', - }, -} - -last_action = 'netbox_install' -for upgrade_command in ( - 'migrate', - 'trace_paths --no-input', - 'collectstatic --no-input', - 'remove_stale_contenttypes --no-input', - 'reindex --lazy', - 'clearsessions', -): - actions[f'netbox_upgrade_{upgrade_command.split()[0]}'] = { + 'netbox_install': { 'triggered': True, - 'command': f'/opt/netbox/venv/bin/python /opt/netbox/src/netbox/manage.py {upgrade_command}', + 'command': ' && '.join([ + 'cd /opt/netbox/src', + '/opt/netbox/venv/bin/pip install --upgrade pip wheel setuptools django-auth-ldap gunicorn', + '/opt/netbox/venv/bin/pip install --upgrade -r requirements.txt', + ]), 'needs': { - f'action:{last_action}', + 'pkg_apt:build-essential', + 'pkg_apt:graphviz', + 'pkg_apt:libffi-dev', + 'pkg_apt:libldap2-dev', + 'pkg_apt:libpq-dev', + 'pkg_apt:libsasl2-dev', + 'pkg_apt:libssl-dev', + 'pkg_apt:libxml2-dev', + 'pkg_apt:libxslt1-dev', + 'pkg_apt:python3-dev', + 'pkg_apt:zlib1g-dev', + } + }, + 'netbox_upgrade': { + 'triggered': True, + 'command': ' && '.join([ + '/opt/netbox/venv/bin/python /opt/netbox/src/netbox/manage.py migrate', + '/opt/netbox/venv/bin/python /opt/netbox/src/netbox/manage.py collectstatic --no-input', + '/opt/netbox/venv/bin/python /opt/netbox/src/netbox/manage.py remove_stale_contenttypes --no-input', + '/opt/netbox/venv/bin/python /opt/netbox/src/netbox/manage.py clearsessions', + ]), + 'needs': { + 'action:netbox_install', + 'file:/opt/netbox/src/netbox/netbox/configuration.py', }, - 'tags': { - 'netbox-upgrade', + }, +} + +files = { + '/etc/systemd/system/netbox-web.service': { + 'triggers': { + 'action:systemd-reload', + 'svc_systemd:netbox-web:restart', }, - 'triggered_by': { - 'tag:netbox-install', + }, + '/etc/systemd/system/netbox-worker.service': { + 'triggers': { + 'action:systemd-reload', + 'svc_systemd:netbox-worker:restart', + }, + }, + '/opt/netbox/src/netbox/netbox/configuration.py': { + 'content_type': 'mako', + 'triggers': { + 'svc_systemd:netbox-web:restart', + 'svc_systemd:netbox-worker:restart', + }, + 'needs': { + 'git_deploy:/opt/netbox/src', + }, + }, + '/opt/netbox/gunicorn_config.py': { + 'content_type': 'mako', + 'triggers': { + 'svc_systemd:netbox-web:restart', }, - } - last_action = f'netbox_upgrade_{upgrade_command.split()[0]}' - -files['/usr/local/lib/systemd/system/netbox-web.service'] = { - 'triggers': { - 'action:systemd-reload', - 'svc_systemd:netbox-web:restart', }, } -files['/usr/local/lib/systemd/system/netbox-worker.service'] = { - 'triggers': { - 'action:systemd-reload', - 'svc_systemd:netbox-worker:restart', - }, -} - -files['/opt/netbox/src/netbox/netbox/configuration.py'] = { - 'content_type': 'mako', - 'triggers': { - 'svc_systemd:netbox-web:restart', - 'svc_systemd:netbox-worker:restart', - }, - 'needs': { - 'git_deploy:/opt/netbox/src', - }, - 'tags': { - 'netbox-install', - }, -} - -files['/opt/netbox/gunicorn_config.py'] = { - 'content_type': 'mako', - 'triggers': { - 'svc_systemd:netbox-web:restart', - }, -} - -svc_systemd['netbox-web'] = { - 'needs': { - 'file:/usr/local/lib/systemd/system/netbox-web.service', - 'file:/opt/netbox/gunicorn_config.py', - 'file:/opt/netbox/src/netbox/netbox/configuration.py', - 'tag:netbox-install', - 'tag:netbox-upgrade', - }, -} - -svc_systemd['netbox-worker'] = { - 'needs': { - 'file:/usr/local/lib/systemd/system/netbox-worker.service', - 'file:/opt/netbox/src/netbox/netbox/configuration.py', - 'tag:netbox-install', - 'tag:netbox-upgrade', +svc_systemd = { + 'netbox-web': { + 'needs': { + 'action:netbox_install', + 'action:netbox_upgrade', + 'file:/etc/systemd/system/netbox-web.service', + 'file:/opt/netbox/gunicorn_config.py', + 'file:/opt/netbox/src/netbox/netbox/configuration.py', + }, + }, + 'netbox-worker': { + 'needs': { + 'action:netbox_install', + 'action:netbox_upgrade', + 'file:/etc/systemd/system/netbox-worker.service', + 'file:/opt/netbox/src/netbox/netbox/configuration.py', + }, }, } diff --git a/bundles/nextcloud/metadata.py b/bundles/nextcloud/metadata.py deleted file mode 100644 index 73c7264..0000000 --- a/bundles/nextcloud/metadata.py +++ /dev/null @@ -1,93 +0,0 @@ -defaults = { - 'backups': { - 'paths': { - '/var/www/nextcloud', - }, - }, - 'php': { - 'clear_env': False, - 'memory_limit': 512, - 'post_max_size': 500, # MB - 'packages': { - 'apcu', - 'bcmath', - 'bz2', - 'curl', - 'gd', - 'gmp', - 'imagick', - 'intl', - 'mbstring', - 'opcache', - 'pgsql', - 'redis', - 'xml', - 'yaml', - 'zip', - }, - }, - 'postgresql': { - 'roles': { - 'nextcloud': { - 'password': repo.vault.password_for(f'{node.name} postgresql nextcloud'), - }, - }, - 'databases': { - 'nextcloud': { - 'owner': 'nextcloud', - }, - }, - }, - 'systemd-timers': { - 'timers': { - 'nextcloud-cron': { - 'command': '/usr/bin/php -f /var/www/nextcloud/cron.php', - 'pwd': '/var/www/nextcloud', - 'user': 'www-data', - 'when': '*:00/5', - 'requisite': { - 'postgresql.service', - }, - }, - }, - }, - 'zfs': { - 'datasets': { - 'tank/nextcloud': { - 'mountpoint': '/var/www/nextcloud', - 'needed_by': { - 'directory:/var/www/nextcloud', - }, - }, - }, - }, -} - - -@metadata_reactor.provides( - 'nginx/vhosts/nextcloud', -) -def nginx(metadata): - if not node.has_bundle('nginx'): - raise DoNotRunAgain - - return { - 'nginx': { - 'vhosts': { - 'nextcloud': { - 'domain': metadata.get('nextcloud/domain'), - 'php': True, - 'extras': True, - 'max_body_size': '500M', - 'index': [ - 'index.php', - 'index.html', - '/index.php$request_uri', - ], - 'webroot_config': { - 'owner': 'www-data', - }, - }, - }, - }, - } diff --git a/bundles/nfs-client/items.py b/bundles/nfs-client/items.py index 97cebc4..918d02c 100644 --- a/bundles/nfs-client/items.py +++ b/bundles/nfs-client/items.py @@ -1,3 +1,8 @@ +if node.has_bundle('pacman'): + package = 'pkg_pacman:nfs-utils' +else: + package = 'pkg_apt:nfs-common' + for mount, data in node.metadata.get('nfs-client/mounts',{}).items(): data['mount'] = mount data['mount_options'] = set(data.get('mount_options', set())) @@ -37,7 +42,7 @@ for mount, data in node.metadata.get('nfs-client/mounts',{}).items(): 'file:/etc/systemd/system/{}.automount'.format(unitname), 'directory:{}'.format(data['mountpoint']), 'svc_systemd:systemd-networkd', - 'pkg_apt:nfs-common', + package, }, } else: @@ -53,7 +58,7 @@ for mount, data in node.metadata.get('nfs-client/mounts',{}).items(): 'file:/etc/systemd/system/{}.mount'.format(unitname), 'directory:{}'.format(data['mountpoint']), 'svc_systemd:systemd-networkd', - 'pkg_apt:nfs-common', + package, }, } diff --git a/bundles/nfs-client/metadata.py b/bundles/nfs-client/metadata.py index 93bf66e..c59ee60 100644 --- a/bundles/nfs-client/metadata.py +++ b/bundles/nfs-client/metadata.py @@ -4,6 +4,11 @@ defaults = { 'nfs-common': {}, }, }, + 'pacman': { + 'packages': { + 'nfs-utils': {}, + }, + }, } if node.has_bundle('telegraf'): diff --git a/bundles/nfs-server/files/avahi.service b/bundles/nfs-server/files/avahi.service deleted file mode 100644 index 394cdca..0000000 --- a/bundles/nfs-server/files/avahi.service +++ /dev/null @@ -1,10 +0,0 @@ - - - - NFS ${path} on %h - - _nfs._tcp - 2049 - path=${path} - - diff --git a/bundles/nfs-server/files/exports b/bundles/nfs-server/files/exports index ac9c8f8..ad2ca4c 100644 --- a/bundles/nfs-server/files/exports +++ b/bundles/nfs-server/files/exports @@ -1,4 +1,4 @@ -% for path, shares in sorted(node.metadata.get('nfs-server/shares', {}).items()): +% for path, shares in sorted(node.metadata['nfs-server']['shares'].items()): % for share_target, share_options in sorted(shares.items()): % for ip_list in repo.libs.tools.resolve_identifier(repo, share_target).values(): % for ip in sorted(ip_list): diff --git a/bundles/nfs-server/items.py b/bundles/nfs-server/items.py index ce025cf..dacbc48 100644 --- a/bundles/nfs-server/items.py +++ b/bundles/nfs-server/items.py @@ -1,40 +1,25 @@ -from re import sub - -files['/etc/exports'] = { - 'content_type': 'mako', - 'triggers': { - 'action:nfs_reload_shares', +files = { + '/etc/exports': { + 'content_type': 'mako', + 'triggers': { + 'action:nfs_reload_shares', + }, + }, + '/etc/default/nfs-kernel-server': { + 'source': 'etc-default', + 'triggers': { + 'svc_systemd:nfs-server:restart', + }, }, } -files['/etc/default/nfs-kernel-server'] = { - 'source': 'etc-default', - 'triggers': { - 'svc_systemd:nfs-server:restart', +actions = { + 'nfs_reload_shares': { + 'command': 'exportfs -a', + 'triggered': True, }, } -actions['nfs_reload_shares'] = { - 'command': 'exportfs -a', - 'triggered': True, +svc_systemd = { + 'nfs-server': {}, } - -svc_systemd['nfs-server'] = {} - -if node.has_bundle('avahi-daemon'): - for path, shares in node.metadata.get('nfs-server/shares', {}).items(): - create_avahi_file = False - for share_target, share_options in shares.items(): - if ',insecure,' in f',{share_options},': - create_avahi_file = True - - if create_avahi_file: - share_name_normalized = sub('[^a-z0-9-_]+', '_', path) - - files[f'/etc/avahi/services/nfs{share_name_normalized}.service'] = { - 'source': 'avahi.service', - 'content_type': 'mako', - 'context': { - 'path': path, - }, - } diff --git a/bundles/nfs-server/metadata.py b/bundles/nfs-server/metadata.py index d2f833c..4b9e8d5 100644 --- a/bundles/nfs-server/metadata.py +++ b/bundles/nfs-server/metadata.py @@ -33,11 +33,8 @@ def firewall(metadata): ips.add(share_target) rules = {} - ports = ('111', '2049', '1110', '4045', '35295') - if metadata.get('nfs-server/version', 3) == 4: - ports = ('111', '2049') - for port in ports: - for proto in ('/tcp', '/udp'): + for port in ('111', '2049', '1110', '4045', '35295'): # TODO find out if we need more ports + for proto in ('', '/udp'): rules[port + proto] = atomic(ips) return { diff --git a/bundles/nftables/files/nftables.conf b/bundles/nftables/files/nftables.conf index 56fba34..4034ad4 100644 --- a/bundles/nftables/files/nftables.conf +++ b/bundles/nftables/files/nftables.conf @@ -14,24 +14,11 @@ table inet filter { iif lo accept -% for address in sorted(blocked_v4): - ip saddr ${address} drop -% endfor -% for address in sorted(blocked_v6): - ip6 saddr ${address} drop -% endfor - icmp type timestamp-request drop icmp type timestamp-reply drop - meta l4proto {icmp, ipv6-icmp} accept + ip protocol icmp accept -% for ruleset, rules in sorted(input.items()): - - # ${ruleset} -% for rule in rules: - ${rule} -% endfor -% endfor + ip6 nexthdr ipv6-icmp accept } chain output { @@ -45,36 +32,15 @@ table inet filter { icmp type timestamp-request drop icmp type timestamp-reply drop -% for ruleset, rules in sorted(forward.items()): - - # ${ruleset} -% for rule in rules: - ${rule} -% endfor -% endfor } } table nat { chain prerouting { type nat hook prerouting priority -100 -% for ruleset, rules in sorted(prerouting.items()): - - # ${ruleset} -% for rule in rules: - ${rule} -% endfor -% endfor } chain postrouting { type nat hook postrouting priority 100 -% for ruleset, rules in sorted(postrouting.items()): - - # ${ruleset} -% for rule in rules: - ${rule} -% endfor -% endfor } } diff --git a/bundles/nftables/items.py b/bundles/nftables/items.py index fc943d4..42bf2e4 100644 --- a/bundles/nftables/items.py +++ b/bundles/nftables/items.py @@ -1,3 +1,8 @@ +if node.has_bundle('pacman'): + package = 'pkg_pacman:nftables' +else: + package = 'pkg_apt:nftables' + directories = { # used by other bundles '/etc/nftables-rules.d': { @@ -10,14 +15,8 @@ directories = { files = { '/etc/nftables.conf': { - 'content_type': 'mako', - 'context': { - 'blocked_v4': node.metadata.get('nftables/blocked_v4', set()), - 'blocked_v6': node.metadata.get('nftables/blocked_v6', set()), - 'forward': node.metadata.get('nftables/forward', {}), - 'input': node.metadata.get('nftables/input', {}), - 'postrouting': node.metadata.get('nftables/postrouting', {}), - 'prerouting': node.metadata.get('nftables/prerouting', {}), + 'needs': { + 'directory:/etc/nftables-rules.d', }, 'triggers': { 'svc_systemd:nftables:reload', @@ -33,11 +32,26 @@ files = { }, } +for ruleset, rules in node.metadata.get('nftables/rules', {}).items(): + files[f'/etc/nftables-rules.d/{ruleset}'] = { + 'source': 'rules-template', + 'content_type': 'mako', + 'context': { + 'rules': rules, + }, + 'needed_by': { + 'svc_systemd:nftables', + }, + 'triggers': { + 'svc_systemd:nftables:reload', + }, + } + svc_systemd = { 'nftables': { 'needs': { 'file:/etc/nftables.conf', - 'pkg_apt:nftables', + package, }, }, } diff --git a/bundles/nftables/metadata.py b/bundles/nftables/metadata.py index 4fac791..08396ce 100644 --- a/bundles/nftables/metadata.py +++ b/bundles/nftables/metadata.py @@ -6,13 +6,26 @@ defaults = { 'nftables': {}, }, }, - 'nftables': { - 'blocked_v4': repo.libs.firewall.global_ip4_blocklist, - 'blocked_v6': repo.libs.firewall.global_ip6_blocklist, + 'pacman': { + 'packages': { + 'nftables': {}, +# https://github.com/bundlewrap/bundlewrap/issues/688 +# 'iptables': { +# 'installed': False, +# 'needed_by': { +# 'pkg_pacman:iptables-nft', +# }, +# }, + 'iptables-nft': { + 'needed_by': { + 'pkg_pacman:nftables', + }, + }, + }, }, } -if not node.has_bundle('vmhost') and not node.has_bundle('docker-engine'): +if not node.has_bundle('vmhost'): # see comment in bundles/vmhost/items.py defaults['apt']['packages']['iptables'] = { 'installed': False, @@ -22,7 +35,7 @@ if not node.has_bundle('vmhost') and not node.has_bundle('docker-engine'): } @metadata_reactor.provides( - 'nftables/input/99-port_rules', + 'nftables/rules/99-port_rules', ) def port_rules_to_nftables(metadata): # Using this, bundles can simply set up port based rules. This @@ -36,47 +49,46 @@ def port_rules_to_nftables(metadata): if '/' in portdef: port, proto = portdef.split('/', 2) - if proto not in ('tcp', 'udp'): + if proto not in {'udp'}: raise BundleError(f'firewall/port_rules: illegal identifier {portdef} in metadata for {node.name}') else: port = portdef - proto = None + proto = 'tcp' for target in targets: - if ( - (port == '*' and target == '*') - or (target == '*' and proto is None) - or (port != '*' and proto is None) - ): - raise BundleError(f'firewall/port_rules: illegal combination of port, target and protocol: "{port}" "{target}" "{proto}"') + if port == '*' and target == '*': + raise BundleError('firewall/port_rules: setting both port and target to * is unsupported') comment = f'comment "port_rules {target}"' if port != '*': if ':' in port: parts = port.split(':') - port_str = f'{proto} dport {{ {parts[0]}-{parts[1]} }} ' + port_str = f'{proto} dport {{ {parts[0]}-{parts[1]} }}' else: - port_str = f'{proto} dport {port} ' - elif proto is not None: - port_str = f'meta l4proto {proto} ' + port_str = f'{proto} dport {port}' else: - port_str = '' + port_str = f'meta l4proto {proto}' - if target == '*': - ruleset.add(f'{port_str}accept {comment}') + if target in ('ipv4', 'ipv6'): + version_str = f'meta nfproto {target}' else: - resolved = repo.libs.tools.resolve_identifier(repo, target, linklocal=True) + version_str = '' + + if target in ('*', 'ipv4', 'ipv6'): + ruleset.add(f'inet filter input {version_str} {port_str} accept {comment}') + else: + resolved = repo.libs.tools.resolve_identifier(repo, target) for address in resolved['ipv4']: - ruleset.add(f'{port_str}ip saddr {address} accept {comment}') + ruleset.add(f'inet filter input meta nfproto ipv4 {port_str} ip saddr {address} accept {comment}') for address in resolved['ipv6']: - ruleset.add(f'{port_str}ip6 saddr {address} accept {comment}') + ruleset.add(f'inet filter input meta nfproto ipv6 {port_str} ip6 saddr {address} accept {comment}') return { 'nftables': { - 'input': { + 'rules': { # order does not matter here. '99-port_rules': sorted(ruleset), }, diff --git a/bundles/nginx/files/arch-override.conf b/bundles/nginx/files/arch-override.conf new file mode 100644 index 0000000..5496fe6 --- /dev/null +++ b/bundles/nginx/files/arch-override.conf @@ -0,0 +1,9 @@ +[Service] +ExecStart= +ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf + +ExecReload= +ExecReload=/bin/sh -c "/bin/kill -s HUP $(/bin/cat /var/run/nginx.pid)" + +ExecStop= +ExecStop=/bin/sh -c "/bin/kill -s TERM $(/bin/cat /var/run/nginx.pid)" diff --git a/bundles/nginx/files/nginx.conf b/bundles/nginx/files/nginx.conf index b020d3c..3f4a9a9 100644 --- a/bundles/nginx/files/nginx.conf +++ b/bundles/nginx/files/nginx.conf @@ -1,4 +1,4 @@ -user www-data; +user ${username}; worker_processes ${worker_processes}; pid /var/run/nginx.pid; @@ -10,9 +10,6 @@ events { http { include /etc/nginx/mime.types; - types { - application/javascript mjs; - } default_type application/octet-stream; charset UTF-8; override_charset on; @@ -26,7 +23,7 @@ http { send_timeout 10; access_log off; - error_log /dev/null; + error_log off; client_body_buffer_size 16K; client_header_buffer_size 4k; diff --git a/bundles/nginx/files/site_template b/bundles/nginx/files/site_template index 96875c8..bccff8c 100644 --- a/bundles/nginx/files/site_template +++ b/bundles/nginx/files/site_template @@ -12,26 +12,27 @@ server { % if ssl: location / { - return 301 https://${domain}$request_uri; + return 308 https://$host$request_uri; } -% if ssl == 'letsencrypt': +% if ssl == 'letsencrypt': location /.well-known/acme-challenge/ { alias /var/lib/dehydrated/acme-challenges/; } -% endif +% endif } -% if domain_aliases and force_domain: server { - server_name ${' '.join(sorted(domain_aliases))}; - +% if domain_aliases: + server_name ${domain} ${' '.join(sorted(domain_aliases))}; +% else: + server_name ${domain}; +% endif root ${webroot if webroot else '/var/www/{}/'.format(vhost)}; index ${' '.join(index)}; - listen 443 ssl; - listen [::]:443 ssl; - http2 on; + listen 443 ssl http2; + listen [::]:443 ssl http2; % if ssl == 'letsencrypt': ssl_certificate /var/lib/dehydrated/certs/${domain}/fullchain.pem; @@ -47,65 +48,17 @@ server { ssl_session_cache shared:SSL:10m; ssl_session_tickets off; - add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; - -% if ssl == 'letsencrypt': - location /.well-known/acme-challenge/ { - alias /var/lib/dehydrated/acme-challenges/; - } -% endif - - location / { - return 301 https://${domain}$request_uri; - } -} - -% endif -server { -% if domain_aliases and not force_domain: - server_name ${domain} ${' '.join(sorted(domain_aliases))}; -% else: - server_name ${domain}; -% endif - - root ${webroot if webroot else '/var/www/{}/'.format(vhost)}; - index ${' '.join(index)}; - - listen 443 ssl; - listen [::]:443 ssl; - http2 on; - -% if ssl == 'letsencrypt': - ssl_certificate /var/lib/dehydrated/certs/${domain}/fullchain.pem; - ssl_certificate_key /var/lib/dehydrated/certs/${domain}/privkey.pem; -% else: - ssl_certificate /etc/nginx/ssl/${vhost}.crt; - ssl_certificate_key /etc/nginx/ssl/${vhost}.key; -% endif - ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305; - ssl_dhparam /etc/ssl/certs/dhparam.pem; - ssl_prefer_server_ciphers off; - ssl_protocols TLSv1.2 TLSv1.3; - ssl_session_cache shared:SSL:10m; - ssl_session_tickets off; - ssl_session_timeout 1d; - add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; % endif resolver 8.8.8.8 8.8.4.4 valid=300s; resolver_timeout 5s; -% if create_logs: +% if create_access_log: access_log /var/log/nginx/access-${vhost}.log gdpr; - error_log /var/log/nginx/error-${vhost}.log; -% else: - # regular access_log is disabled - # error_log is disabled % endif -% if create_timing_log: access_log /var/log/nginx-timing/${vhost}.log anon_timing; -% endif + # error_log is disabled globally % if max_body_size: client_max_body_size ${max_body_size}; @@ -149,18 +102,18 @@ server { % if 'target' in options: proxy_pass ${options['target']}; proxy_http_version ${options.get('http_version', '1.1')}; - proxy_set_header Host ${options.get('proxy_pass_host', domain)}; + proxy_set_header Host ${domain}; % if options.get('websockets', False): proxy_set_header Connection "upgrade"; proxy_set_header Upgrade $http_upgrade; % endif proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Forwarded-Host ${options.get('x_forwarded_host', options.get('proxy_pass_host', domain))}; + proxy_set_header X-Forwarded-Host ${options.get('x_forwarded_host', domain)}; % for option, value in options.get('proxy_set_header', {}).items(): proxy_set_header ${option} ${value}; % endfor -% if location != '/' and location != '= /': +% if location != '/': proxy_set_header X-Script-Name ${location}; % endif proxy_buffering off; @@ -191,18 +144,9 @@ server { % endfor % endif % if php: - location ~ \.php(?:$|/) { + location ~ \.php$ { include fastcgi.conf; fastcgi_pass unix:/run/php/php${php_version}-fpm.sock; -% if not do_not_set_content_security_headers: - fastcgi_hide_header Referrer-Policy; - fastcgi_hide_header X-Frame-Options; - fastcgi_hide_header X-Content-Type-Options; - fastcgi_hide_header X-XSS-Protection; -% endif - fastcgi_hide_header Permissions-Policy; - fastcgi_request_buffering off; - proxy_buffering off; } % if not max_body_size: client_max_body_size 5M; diff --git a/bundles/nginx/items.py b/bundles/nginx/items.py index 304dcd7..88852e0 100644 --- a/bundles/nginx/items.py +++ b/bundles/nginx/items.py @@ -1,5 +1,12 @@ from datetime import datetime, timedelta +if node.has_bundle('pacman'): + package = 'pkg_pacman:nginx' + username = 'http' +else: + package = 'pkg_apt:nginx' + username = 'www-data' + directories = { '/etc/nginx/sites': { 'purge': True, @@ -17,9 +24,9 @@ directories = { }, }, '/var/log/nginx-timing': { - 'owner': 'www-data', + 'owner': username, 'needs': { - 'pkg_apt:nginx', + package, }, }, '/var/www': {}, @@ -27,12 +34,12 @@ directories = { files = { '/etc/logrotate.d/nginx': { - 'content_type': 'mako', 'source': 'logrotate.conf', }, '/etc/nginx/nginx.conf': { 'content_type': 'mako', 'context': { + 'username': username, **node.metadata['nginx'], }, 'triggers': { @@ -61,13 +68,28 @@ files = { '/var/www/error.html': {}, '/var/www/not_found.html': {}, } +if node.has_bundle('pacman'): + files['/etc/systemd/system/nginx.service.d/bundlewrap.conf'] = { + 'source': 'arch-override.conf', + 'triggers': { + 'action:systemd-reload', + 'svc_systemd:nginx:restart', + }, + } + +actions = { + 'nginx-generate-dhparam': { + 'command': 'openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048', + 'unless': 'test -f /etc/ssl/certs/dhparam.pem', + }, +} svc_systemd = { 'nginx': { 'needs': { - 'action:generate-dhparam', + 'action:nginx-generate-dhparam', 'directory:/var/log/nginx-timing', - 'pkg_apt:nginx', + package, }, }, } @@ -102,9 +124,8 @@ for vhost, config in node.metadata.get('nginx/vhosts', {}).items(): 'source': 'site_template', 'content_type': 'mako', 'context': { - 'create_logs': config.get('create_logs', False), - 'create_timing_log': config.get('timing_log', True), - 'php_version': node.metadata.get('php/__version', ''), + 'create_access_log': config.get('access_log', node.metadata.get('nginx/access_log', False)), + 'php_version': node.metadata.get('php/version', ''), 'security_txt': security_txt_enabled, 'vhost': vhost, **config, diff --git a/bundles/nginx/metadata.py b/bundles/nginx/metadata.py index 28395ff..ba2d18a 100644 --- a/bundles/nginx/metadata.py +++ b/bundles/nginx/metadata.py @@ -33,6 +33,11 @@ defaults = { 'nginx': { 'worker_connections': 768, }, + 'pacman': { + 'packages': { + 'nginx': {}, + }, + }, } if node.has_bundle('telegraf'): @@ -76,7 +81,6 @@ def letsencrypt(metadata): domains[domain] = config.get('domain_aliases', set()) vhosts[vhost] = { 'ssl': 'letsencrypt', - 'force_domain': True, } return { @@ -99,9 +103,6 @@ def index_files(metadata): vhosts = {} for vhost, config in metadata.get('nginx/vhosts', {}).items(): - if 'index' in config: - continue - vhosts[vhost] = { 'index': [ 'index.html', @@ -168,15 +169,15 @@ def monitoring(metadata): @metadata_reactor.provides( - 'firewall/port_rules', - 'firewall/port_rules', + 'firewall/port_rules/80', + 'firewall/port_rules/443', ) def firewall(metadata): return { 'firewall': { 'port_rules': { - '80/tcp': atomic(metadata.get('nginx/restrict-to', {'*'})), - '443/tcp': atomic(metadata.get('nginx/restrict-to', {'*'})), + '80': atomic(metadata.get('nginx/restrict-to', {'*'})), + '443': atomic(metadata.get('nginx/restrict-to', {'*'})), }, }, } @@ -188,15 +189,12 @@ def firewall(metadata): def telegraf_anon_timing(metadata): result = {} - for vname, vconfig in metadata.get('nginx/vhosts', {}).items(): - if not vconfig.get('timing_log', True): - continue - - result[f'nginx-{vname}'] = { - 'files': [f'/var/log/nginx-timing/{vname}.log'], + for vhost in metadata.get('nginx/vhosts', {}): + result[f'nginx-{vhost}'] = { + 'files': [f'/var/log/nginx-timing/{vhost}.log'], 'from_beginning': False, - 'grok_patterns': [r'%{LOGPATTERN}'], - 'grok_custom_patterns': r'LOGPATTERN \[%{HTTPDATE:ts:ts-httpd}\] %{NUMBER:request_time:float} (?:%{NUMBER:upstream_response_time:float}|-) "%{WORD:verb:tag} %{NOTSPACE:request} HTTP/%{NUMBER:http_version:float}" %{NUMBER:resp_code:tag}', + 'grok_patterns': ['%{LOGPATTERN}'], + 'grok_custom_patterns': 'LOGPATTERN \[%{HTTPDATE:ts:ts-httpd}\] %{NUMBER:request_time:float} (?:%{NUMBER:upstream_response_time:float}|-) "%{WORD:verb:tag} %{NOTSPACE:request} HTTP/%{NUMBER:http_version:float}" %{NUMBER:resp_code:tag}', 'data_format': 'grok', 'name_override': 'nginx_timing', } diff --git a/bundles/nodejs/items.py b/bundles/nodejs/items.py index e69de29..dc8607c 100644 --- a/bundles/nodejs/items.py +++ b/bundles/nodejs/items.py @@ -0,0 +1,9 @@ +actions = { + 'nodejs_install_yarn': { + 'command': 'npm install -g yarn@latest', + 'unless': 'test -e /usr/lib/node_modules/yarn', + 'needs': { + 'pkg_apt:nodejs', + }, + }, +} diff --git a/bundles/nodejs/metadata.py b/bundles/nodejs/metadata.py index 5c0f7ad..4609903 100644 --- a/bundles/nodejs/metadata.py +++ b/bundles/nodejs/metadata.py @@ -1,24 +1,17 @@ defaults = { 'apt': { 'additional_update_commands': { - # update npm and yarn to latest version + # update npm to latest version 'npm install -g npm@latest', 'npm install -g yarn@latest', }, 'packages': { - 'nodejs': { - 'triggers': { - 'action:apt_execute_update_commands', - }, - }, - 'npm': { - 'installed': False, - 'triggers': { - 'action:apt_execute_update_commands', - }, - }, + 'nodejs': {}, }, }, + 'nodejs': { + 'version': 18, + }, } @metadata_reactor.provides( @@ -26,13 +19,13 @@ defaults = { ) def nodejs_from_version(metadata): version = metadata.get('nodejs/version') - return { 'apt': { 'repos': { - 'nodejs': { + 'node': { 'items': { - f'deb https://deb.nodesource.com/node_{version}.x nodistro main', + f'deb https://deb.nodesource.com/node_{version}.x {{os_release}} main', + f'deb-src https://deb.nodesource.com/node_{version}.x {{os_release}} main', }, }, }, diff --git a/bundles/ntfy/files/server.yml b/bundles/ntfy/files/server.yml index babb90b..8add6f3 100644 --- a/bundles/ntfy/files/server.yml +++ b/bundles/ntfy/files/server.yml @@ -11,7 +11,7 @@ # - iOS push notifications for self-hosted servers (to calculate the Firebase poll_request topic) # - Matrix Push Gateway (to validate that the pushkey is correct) # -base-url: "https://${node.metadata.get('ntfy/domain')}" +base-url: "https://${node.metadata.get('ntfy/domain', 'ntfy')}" # Listen address for the HTTP & HTTPS web server. If "listen-https" is set, you must also # set "key-file" and "cert-file". Format: []:, e.g. "1.2.3.4:8080". @@ -85,11 +85,7 @@ cache-startup-queries: | # ntfy user and group by running: chown ntfy.ntfy . # auth-file: "/var/lib/ntfy/user.db" -% if node.metadata.get('ntfy/allow_unauthorized_write'): auth-default-access: "write-only" -% else: -auth-default-access: "deny-all" -% endif # If set, the X-Forwarded-For header is used to determine the visitor IP address # instead of the remote address of the connection. @@ -97,7 +93,7 @@ auth-default-access: "deny-all" # WARNING: If you are behind a proxy, you must set this, otherwise all visitors are rate limited # as if they are one. # -behind-proxy: true +# behind-proxy: false # If enabled, clients can attach files to notifications as attachments. Minimum settings to enable attachments # are "attachment-cache-dir" and "base-url". @@ -157,17 +153,6 @@ manager-interval: "1m" # # web-root: app -# Various feature flags used to control the web app, and API access, mainly around user and -# account management. -# -# - enable-signup allows users to sign up via the web app, or API -# - enable-login allows users to log in via the web app, or API -# - enable-reservations allows users to reserve topics (if their tier allows it) -# -enable-signup: false -enable-login: true -enable-reservations: false - # Server URL of a Firebase/APNS-connected ntfy server (likely "https://ntfy.sh"). # # iOS users: @@ -196,7 +181,7 @@ visitor-subscription-limit: 64 # visitor-request-limit-burst: 60 visitor-request-limit-replenish: "5s" -visitor-request-limit-exempt-hosts: "${','.join(sorted(ratelimit_exempt_hosts))}" +visitor-request-limit-exempt-hosts: "localhost" # Rate limiting: Allowed emails per visitor: # - visitor-email-limit-burst is the initial bucket of emails each visitor has @@ -205,54 +190,12 @@ visitor-request-limit-exempt-hosts: "${','.join(sorted(ratelimit_exempt_hosts))} # visitor-email-limit-burst: 16 # visitor-email-limit-replenish: "1h" -# Rate limiting: Enable subscriber-based rate limiting (mostly used for UnifiedPush) +# Rate limiting: Attachment size and bandwidth limits per visitor: +# - visitor-attachment-total-size-limit is the total storage limit used for attachments per visitor +# - visitor-attachment-daily-bandwidth-limit is the total daily attachment download/upload traffic limit per visitor # -# If enabled, subscribers may opt to have published messages counted against their own rate limits, as opposed -# to the publisher's rate limits. This is especially useful to increase the amount of messages that high-volume -# publishers (e.g. Matrix/Mastodon servers) are allowed to send. -# -# Once enabled, a client may send a "Rate-Topics: ,,..." header when subscribing to topics via -# HTTP stream, or websockets, thereby registering itself as the "rate visitor", i.e. the visitor whose rate limits -# to use when publishing on this topic. Note: Setting the rate visitor requires READ-WRITE permission on the topic. -# -# UnifiedPush only: If this setting is enabled, publishing to UnifiedPush topics will lead to a HTTP 507 response if -# no "rate visitor" has been previously registered. This is to avoid burning the publisher's "visitor-message-daily-limit". -# -# visitor-subscriber-rate-limiting: false - -# Payments integration via Stripe -# -# - stripe-secret-key is the key used for the Stripe API communication. Setting this values -# enables payments in the ntfy web app (e.g. Upgrade dialog). See https://dashboard.stripe.com/apikeys. -# - stripe-webhook-key is the key required to validate the authenticity of incoming webhooks from Stripe. -# Webhooks are essential up keep the local database in sync with the payment provider. See https://dashboard.stripe.com/webhooks. -# - billing-contact is an email address or website displayed in the "Upgrade tier" dialog to let people reach -# out with billing questions. If unset, nothing will be displayed. -# -# stripe-secret-key: -# stripe-webhook-key: -# billing-contact: - -# Metrics -# -# ntfy can expose Prometheus-style metrics via a /metrics endpoint, or on a dedicated listen IP/port. -# Metrics may be considered sensitive information, so before you enable them, be sure you know what you are -# doing, and/or secure access to the endpoint in your reverse proxy. -# -# - enable-metrics enables the /metrics endpoint for the default ntfy server (i.e. HTTP, HTTPS and/or Unix socket) -# - metrics-listen-http exposes the metrics endpoint via a dedicated [IP]:port. If set, this option implicitly -# enables metrics as well, e.g. "10.0.1.1:9090" or ":9090" -# -# enable-metrics: false -# metrics-listen-http: - -# Profiling -# -# ntfy can expose Go's net/http/pprof endpoints to support profiling of the ntfy server. If enabled, ntfy will listen -# on a dedicated listen IP/port, which can be accessed via the web browser on http://:/debug/pprof/. -# This can be helpful to expose bottlenecks, and visualize call flows. See https://pkg.go.dev/net/http/pprof for details. -# -# profile-listen-http: +# visitor-attachment-total-size-limit: "100M" +# visitor-attachment-daily-bandwidth-limit: "500M" # Log level, can be TRACE, DEBUG, INFO, WARN or ERROR # This option can be hot-reloaded by calling "kill -HUP $pid" or "systemctl reload ntfy". diff --git a/bundles/ntfy/items.py b/bundles/ntfy/items.py index cb3c50b..d9a93bb 100644 --- a/bundles/ntfy/items.py +++ b/bundles/ntfy/items.py @@ -1,57 +1,43 @@ -ratelimit_exempt_hosts = set() -for identifier in node.metadata.get('ntfy/ratelimit-exempt-hosts', set()): - ips = repo.libs.tools.resolve_identifier(repo, identifier) - ratelimit_exempt_hosts |= {str(ip) for ip in ips['ipv4']} - ratelimit_exempt_hosts |= {str(ip) for ip in ips['ipv6']} - - -files['/etc/ntfy/server.yml'] = { - 'content_type': 'mako', - 'context': { - 'ratelimit_exempt_hosts': ratelimit_exempt_hosts, - }, - 'after': { - 'pkg_apt:ntfy', - }, - 'triggers': { - 'svc_systemd:ntfy:restart', +files = { + '/etc/ntfy/server.yml': { + 'content_type': 'mako', + 'needs': { + 'pkg_apt:ntfy', + }, + 'triggers': { + 'svc_systemd:ntfy:restart', + }, }, } -directories['/var/lib/ntfy'] = { - 'owner': 'ntfy', - 'group': 'ntfy', - 'mode': '0700', - 'before': { - 'pkg_apt:ntfy', +directories = { + '/opt/ntfy': {}, + '/var/lib/ntfy': { + 'owner': 'ntfy', + 'group': 'ntfy', + }, + '/var/cache/ntfy': { + 'owner': 'ntfy', + 'group': 'ntfy', + }, + '/var/opt/ntfy': { + 'owner': 'ntfy', + 'group': 'ntfy', }, } -directories['/var/cache/ntfy'] = { - 'owner': 'ntfy', - 'group': 'ntfy', - 'mode': '0700', - 'before': { - 'pkg_apt:ntfy', +svc_systemd = { + 'ntfy': { + 'needs': { + 'file:/etc/ntfy/server.yml', + 'pkg_apt:ntfy', + }, }, } -directories['/var/opt/ntfy'] = { - 'owner': 'ntfy', - 'group': 'ntfy', - 'before': { - 'pkg_apt:ntfy', +users = { + 'ntfy': { + 'home': '/opt/ntfy', }, } - -svc_systemd['ntfy'] = { - 'needs': { - 'file:/etc/ntfy/server.yml', - 'pkg_apt:ntfy', - }, -} - -users['ntfy'] = { - 'home': '/var/lib/ntfy', -} diff --git a/bundles/ntfy/metadata.py b/bundles/ntfy/metadata.py index 5b6f81d..a49ae55 100644 --- a/bundles/ntfy/metadata.py +++ b/bundles/ntfy/metadata.py @@ -19,9 +19,6 @@ defaults = { "/var/opt/ntfy", }, }, - 'ntfy': { - 'allow_unauthorized_write': False, - }, 'zfs': { 'datasets': { 'tank/ntfy': {}, @@ -76,10 +73,6 @@ def nginx(metadata): 'ntfy': { 'domain': metadata.get('ntfy/domain'), 'locations': locations, - # This only does websockets connections, which stay - # open for a very long time. This only generates - # useless metrics. - 'timing_log': False, 'website_check_path': '/', 'website_check_string': 'ntfy', }, diff --git a/bundles/octoprint/files/check_octoprint_update b/bundles/octoprint/files/check_octoprint_update index ff89a3e..c7ae90a 100644 --- a/bundles/octoprint/files/check_octoprint_update +++ b/bundles/octoprint/files/check_octoprint_update @@ -1,8 +1,7 @@ #!/usr/bin/env python3 -from sys import exit - from requests import get +from sys import exit api_key = '${api_key}' diff --git a/bundles/oidentd/files/oidentd.service b/bundles/oidentd/files/oidentd.service index 64ac97f..06b9a6d 100644 --- a/bundles/oidentd/files/oidentd.service +++ b/bundles/oidentd/files/oidentd.service @@ -1,7 +1,6 @@ [Unit] Description=RFC 1413 compliant ident daemon -Requires=network.target -After=network-online.target +After=network.target [Service] ExecStart=/usr/sbin/oidentd -i -u oident -g oident diff --git a/bundles/oidentd/items.py b/bundles/oidentd/items.py index fae03b3..723f9fe 100644 --- a/bundles/oidentd/items.py +++ b/bundles/oidentd/items.py @@ -1,26 +1,24 @@ -files['/etc/oidentd.conf'] = { - 'content_type': 'mako', - 'triggers': { - 'svc_systemd:oidentd:restart', +files = { + '/etc/oidentd.conf': { + 'content_type': 'mako', + 'triggers': { + 'svc_systemd:oidentd:restart', + }, + }, + '/usr/local/lib/systemd/system/oidentd.service': { + 'triggers': { + 'action:systemd-reload', + 'svc_systemd:oidentd:restart', + }, }, } -files['/usr/local/lib/systemd/system/oidentd.service'] = { - 'triggers': { - 'action:systemd-reload', - 'svc_systemd:oidentd:restart', +svc_systemd = { + 'oidentd': { + 'needs': { + 'pkg_apt:oidentd', + 'file:/etc/oidentd.conf', + 'file:/usr/local/lib/systemd/system/oidentd.service', + }, }, } - -svc_systemd['oidentd'] = { - 'needs': { - 'pkg_apt:oidentd', - 'file:/etc/oidentd.conf', - 'file:/usr/local/lib/systemd/system/oidentd.service', - }, -} - -svc_systemd['oidentd.socket'] = { - 'running': False, - 'enabled': False, -} diff --git a/bundles/oidentd/metadata.py b/bundles/oidentd/metadata.py index dbc27a1..f9d4390 100644 --- a/bundles/oidentd/metadata.py +++ b/bundles/oidentd/metadata.py @@ -10,13 +10,13 @@ defaults = { @metadata_reactor.provides( - 'firewall/port_rules', + 'firewall/port_rules/113', ) def firewall(metadata): return { 'firewall': { 'port_rules': { - '113/tcp': atomic(metadata.get('oidentd/restrict-to', {'*'})), + '113': atomic(metadata.get('oidentd/restrict-to', {'*'})), }, }, } diff --git a/bundles/openhab/files/backup-pre-hook b/bundles/openhab/files/backup-pre-hook new file mode 100644 index 0000000..fbf0eda --- /dev/null +++ b/bundles/openhab/files/backup-pre-hook @@ -0,0 +1,5 @@ +#!/bin/bash + +find /var/lib/openhab/backups -type f -mtime +3 -delete + +/usr/share/openhab/runtime/bin/backup --full diff --git a/bundles/openhab/files/openhab b/bundles/openhab/files/openhab new file mode 100644 index 0000000..9893987 --- /dev/null +++ b/bundles/openhab/files/openhab @@ -0,0 +1,62 @@ +# openHAB service options + +######################### +## PORTS +## The ports openHAB will bind its HTTP/HTTPS web server to. + +OPENHAB_HTTP_PORT=22090 +#OPENHAB_HTTPS_PORT=8443 + +######################### +## HTTP(S) LISTEN ADDRESS +## The listen address used by the HTTP(S) server. +## 0.0.0.0 (default) allows a connection from any location +## 127.0.0.1 only allows the local machine to connect + +OPENHAB_HTTP_ADDRESS=127.0.0.1 + +######################### +## BACKUP DIRECTORY +## Set the following variable to specify the backup location. +## runtime/bin/backup and runtime/bin/restore will use this path for the zip files. + +#OPENHAB_BACKUPS=/var/lib/openhab/backups + +######################### +## JAVA OPTIONS +## Additional options for the JAVA_OPTS environment variable. +## These will be appended to the execution of the openHAB Java runtime in front of all other options. +## +## A couple of independent examples: +## EXTRA_JAVA_OPTS="-Dgnu.io.rxtx.SerialPorts=/dev/ttyZWAVE:/dev/ttyUSB0:/dev/ttyS0:/dev/ttyS2:/dev/ttyACM0:/dev/ttyAMA0" +## EXTRA_JAVA_OPTS="-Djna.library.path=/lib/arm-linux-gnueabihf/ -Duser.timezone=Europe/Berlin -Dgnu.io.rxtx.SerialPorts=/dev/ttyZWave" + +EXTRA_JAVA_OPTS="${extra_java_opts}" + +######################### +## OPENHAB DEFAULTS PATHS +## The following settings override the default apt/rpm locations and should be used with caution. +## openHAB will fail to update itself if you're using different paths. +## Only set these if you are testing and are confident in debugging. + +#OPENHAB_HOME=/usr/share/openhab +#OPENHAB_CONF=/etc/openhab +#OPENHAB_RUNTIME=/usr/share/openhab/runtime +#OPENHAB_USERDATA=/var/lib/openhab +#OPENHAB_LOGDIR=/var/log/openhab + +######################### +## OPENHAB USER AND GROUP +## The user and group that takes ownership of openHAB. Only available for init.d systems. +## To edit user and group for systemd, see the service file at /usr/lib/systemd/system/openhab.service. + +#OPENHAB_USER=openhab +#OPENHAB_GROUP=openhab + +######################### +## SYSTEMD START MODE +## The Karaf startmode for the openHAB runtime. Only available for systemctl/systemd systems. +## Defaults to daemon when unset here. Multiple options can be used without quotes. +## debug increases log output. daemon launches the Karaf/openHAB processes. + +#OPENHAB_STARTMODE=debug diff --git a/bundles/openhab/items.py b/bundles/openhab/items.py new file mode 100644 index 0000000..eabe1d0 --- /dev/null +++ b/bundles/openhab/items.py @@ -0,0 +1,32 @@ +extra_java_opts = [] + +for opt, value in sorted(node.metadata.get('openhab/java_opts', {}).items()): + if value is None: + extra_java_opts.append(f'-D{opt}') + else: + extra_java_opts.append(f'-D{opt}={value}') + +files = { + '/etc/default/openhab': { + 'content_type': 'mako', + 'context': { + 'extra_java_opts': ' '.join(extra_java_opts), + }, + 'triggers': { + 'svc_systemd:openhab:restart', + }, + }, + '/etc/backup-pre-hooks.d/40-openhab': { + 'source': 'backup-pre-hook', + 'mode': '0755', + } +} + +svc_systemd = { + 'openhab': { + 'needs': { + 'pkg_apt:openhab', + 'pkg_apt:openhab-addons', + }, + }, +} diff --git a/bundles/openhab/metadata.py b/bundles/openhab/metadata.py new file mode 100644 index 0000000..e6a87cc --- /dev/null +++ b/bundles/openhab/metadata.py @@ -0,0 +1,55 @@ +defaults = { + 'apt': { + 'packages': { + 'openjdk-17-jre': {}, + 'openhab': { + 'needs': { + 'pkg_apt:openjdk-17-jre', + }, + }, + 'openhab-addons': { + 'needs': { + 'pkg_apt:openhab', + }, + }, + }, + 'repos': { + 'openhab': { + 'items': { + 'deb https://openhab.jfrog.io/artifactory/openhab-linuxpkg stable main', + }, + }, + }, + }, + 'backups': { + 'paths': { + '/usr/share/openhab/addons', # not included in openhab backup + '/var/lib/openhab', + }, + }, +} + + +@metadata_reactor.provides( + 'nginx/vhosts/openhab', +) +def nginx(metadata): + if not node.has_bundle('nginx'): + raise DoNotRunAgain + + return { + 'nginx': { + 'vhosts': { + 'openhab': { + 'domain': metadata.get('openhab/domain'), + 'locations': { + '/': { + 'target': 'http://localhost:22090/', + }, + }, + 'website_check_path': '/', + 'website_check_string': 'openHAB', + }, + }, + }, + } diff --git a/bundles/openssh/items.py b/bundles/openssh/items.py index 0b9fa04..a93b873 100644 --- a/bundles/openssh/items.py +++ b/bundles/openssh/items.py @@ -27,22 +27,29 @@ files = { }, } +if node.has_bundle('pacman'): + package = 'pkg_pacman:openssh' + service = 'sshd' +else: + package = 'pkg_apt:openssh-server' + service = 'ssh' + actions = { 'sshd_check_config': { 'command': 'sshd -T -C user=root -C host=localhost -C addr=localhost', 'triggered': True, 'triggers': { - 'svc_systemd:ssh:restart', + 'svc_systemd:{}:restart'.format(service), }, }, } svc_systemd = { - 'ssh': { + service: { 'needs': { 'file:/etc/systemd/system/ssh.service.d/bundlewrap.conf', 'file:/etc/ssh/sshd_config', - 'pkg_apt:openssh-server', + package, }, }, } diff --git a/bundles/openssh/metadata.py b/bundles/openssh/metadata.py index 4db6d78..3cad1b9 100644 --- a/bundles/openssh/metadata.py +++ b/bundles/openssh/metadata.py @@ -8,16 +8,21 @@ defaults = { 'openssh-sftp-server': {}, }, }, + 'pacman': { + 'packages': { + 'openssh': {}, + }, + }, } @metadata_reactor.provides( - 'firewall/port_rules', + 'firewall/port_rules/22', ) def firewall(metadata): return { 'firewall': { 'port_rules': { - '22/tcp': atomic(metadata.get('openssh/restrict-to', {'*'})), + '22': atomic(metadata.get('openssh/restrict-to', {'*'})), }, }, } diff --git a/bundles/openvpn-client/items.py b/bundles/openvpn-client/items.py new file mode 100644 index 0000000..7d35517 --- /dev/null +++ b/bundles/openvpn-client/items.py @@ -0,0 +1,25 @@ +from os.path import join + +directories = { + '/etc/openvpn/client': { + 'mode': '0750', + 'owner': 'openvpn', + 'group': None, + 'purge': True, + }, +} + +for fname, config in node.metadata.get('openvpn-client/configs', {}).items(): + files[f'/etc/openvpn/client/{fname}.conf'] = { + 'content': repo.vault.decrypt_file(join('openvpn-client', f'{fname}.conf.vault')), + 'triggers': { + f'svc_systemd:openvpn-client@{config}:restart', + } if config.get('running', True) else set(), + } + + svc_systemd[f'openvpn-client@{fname}'] = { + 'needs': { + f'file:/etc/openvpn/client/{fname}.conf', + }, + **config, + } diff --git a/bundles/openvpn-client/metadata.py b/bundles/openvpn-client/metadata.py new file mode 100644 index 0000000..9c5b722 --- /dev/null +++ b/bundles/openvpn-client/metadata.py @@ -0,0 +1,20 @@ +defaults = { + 'apt': { + 'packages': { + 'openvpn': { + 'needed_by': { + 'directory:/etc/openvpn/client', + }, + }, + }, + }, + 'pacman': { + 'packages': { + 'openvpn': { + 'needed_by': { + 'directory:/etc/openvpn/client', + }, + }, + }, + }, +} diff --git a/bundles/pacman/files/check_unattended_upgrades b/bundles/pacman/files/check_unattended_upgrades new file mode 100644 index 0000000..1cafab5 --- /dev/null +++ b/bundles/pacman/files/check_unattended_upgrades @@ -0,0 +1,38 @@ +#!/bin/bash + +statusfile="/var/tmp/unattended_upgrades.status" +if ! [[ -f "$statusfile" ]] +then + echo "Status file not found" + exit 3 +fi + +mtime=$(stat -c %Y $statusfile) +now=$(date +%s) +if (( $now - $mtime > 60*60*24*8 )) +then + echo "Status file is older than 8 days!" + exit 3 +fi + +exitcode=$(cat $statusfile) +case "$exitcode" in + abort_ssh) + echo "Upgrades skipped due to active SSH login" + exit 1 + ;; + 0) + if [[ -f /var/run/reboot-required ]] + then + echo "OK, but updates require a reboot" + exit 1 + else + echo "OK" + exit 0 + fi + ;; + *) + echo "Last exitcode was $exitcode" + exit 2 + ;; +esac diff --git a/bundles/pacman/files/do-unattended-upgrades b/bundles/pacman/files/do-unattended-upgrades new file mode 100644 index 0000000..a04b5fc --- /dev/null +++ b/bundles/pacman/files/do-unattended-upgrades @@ -0,0 +1,18 @@ +#!/bin/bash + +set -xeuo pipefail + +pacman -Syu --noconfirm --noprogressbar + +% for affected, restarts in sorted(restart_triggers.items()): +up_since=$(systemctl show "${affected}" | sed -n 's/^ActiveEnterTimestamp=//p' || echo 0) +up_since_ts=$(date -d "$up_since" +%s || echo 0) +now=$(date +%s) + +if [ $((now - up_since_ts)) -lt 3600 ] +then +% for restart in sorted(restarts): + systemctl restart "${restart}" || true +% endfor +fi +% endfor diff --git a/bundles/pacman/files/faillock.conf b/bundles/pacman/files/faillock.conf new file mode 100644 index 0000000..19c0ff3 --- /dev/null +++ b/bundles/pacman/files/faillock.conf @@ -0,0 +1,2 @@ +# just disable faillock. +deny = 0 diff --git a/bundles/pacman/files/pacman.conf b/bundles/pacman/files/pacman.conf new file mode 100644 index 0000000..834108e --- /dev/null +++ b/bundles/pacman/files/pacman.conf @@ -0,0 +1,52 @@ +[options] +Architecture = auto +CheckSpace +Color +HoldPkg = ${' '.join(sorted(node.metadata.get('pacman/ask_before_removal')))} +ILoveCandy +IgnorePkg = ${' '.join(sorted(node.metadata.get('pacman/ignore_packages', set())))} +LocalFileSigLevel = Optional +NoExtract=${' '.join(sorted(node.metadata.get('pacman/no_extract', set())))} +ParallelDownloads = ${node.metadata.get('pacman/parallel_downloads')} +SigLevel = Required DatabaseOptional +VerbosePkgLists + +% for line in sorted(node.metadata.get('pacman/additional_config', set())): +${line} +% endfor + +[core] +Server = ${node.metadata.get('pacman/repository')} +Include = /etc/pacman.d/mirrorlist + +[extra] +Server = ${node.metadata.get('pacman/repository')} +Include = /etc/pacman.d/mirrorlist + +[community] +Server = ${node.metadata.get('pacman/repository')} +Include = /etc/pacman.d/mirrorlist +% if node.metadata.get('pacman/enable_multilib', False): + +[multilib] +Server = ${node.metadata.get('pacman/repository')} +Include = /etc/pacman.d/mirrorlist +% endif +% if node.metadata.get('pacman/enable_aurto', True): + +[aurto] +Server = https://aurto.kunbox.net/ +SigLevel = Optional TrustAll +% endif +% if node.has_bundle('zfs'): + +[archzfs] +Server = http://archzfs.com/archzfs/x86_64 + +% if node.metadata.get('pacman/linux-lts', False): +[zfs-linux-lts] +% else: +[zfs-linux] +% endif +Server = http://kernels.archzfs.com/$repo/ +% endif diff --git a/bundles/pacman/files/upgrade-and-reboot b/bundles/pacman/files/upgrade-and-reboot new file mode 100644 index 0000000..b8339ce --- /dev/null +++ b/bundles/pacman/files/upgrade-and-reboot @@ -0,0 +1,53 @@ +#!/bin/bash + +# With systemd, we can force logging to the journal. This is better than +# spamming the world with cron mails. You can then view these logs using +# "journalctl -rat upgrade-and-reboot". +if which logger >/dev/null 2>&1 +then + # Dump stdout and stderr to logger, which will then put everything + # into the journal. + exec 1> >(logger -t upgrade-and-reboot -p user.info) + exec 2> >(logger -t upgrade-and-reboot -p user.error) +fi + +. /etc/upgrade-and-reboot.conf + +echo "Starting upgrade-and-reboot for node $nodename ..." + +statusfile="/var/tmp/unattended_upgrades.status" +# Workaround, because /var/tmp is usually 1777 +[[ "$UID" == 0 ]] && chown root:root "$statusfile" + +logins=$(ps h -C sshd -o euser | awk '$1 != "root" && $1 != "sshd" && $1 != "sshmon"') +if [[ -n "$logins" ]] +then + echo "Will abort now, there are active SSH logins: $logins" + echo "abort_ssh" > "$statusfile" + exit 1 +fi + +softlockdir=/var/lib/bundlewrap/soft-$nodename +mkdir -p "$softlockdir" +printf '{"comment": "UPDATE", "date": %s, "expiry": %s, "id": "UNATTENDED", "items": ["*"], "user": "root@localhost"}\n' \ + $(date +%s) \ + $(date -d 'now + 30 mins' +%s) \ + >"$softlockdir"/UNATTENDED +trap 'rm -f "$softlockdir"/UNATTENDED' EXIT + +do-unattended-upgrades +ret=$? + +echo "$ret" > "$statusfile" +if (( $ret != 0 )) +then + exit 1 +fi + +if [[ -n "$reboot_mail_to" ]] +then + date | mail -s "SYSREBOOTNOW $nodename" "$reboot_mail_to" +fi +systemctl reboot + +echo "upgrade-and-reboot for node $nodename is DONE" diff --git a/bundles/pacman/files/upgrade-and-reboot.conf b/bundles/pacman/files/upgrade-and-reboot.conf new file mode 100644 index 0000000..ca71dce --- /dev/null +++ b/bundles/pacman/files/upgrade-and-reboot.conf @@ -0,0 +1,3 @@ +nodename="${node.name}" +reboot_mail_to="${node.metadata.get('apt/unattended-upgrades/reboot_mail_to', '')}" +auto_reboot_enabled="${node.metadata.get('apt/unattended-upgrades/reboot_enabled', True)}" diff --git a/bundles/pacman/items.py b/bundles/pacman/items.py new file mode 100644 index 0000000..4d95a99 --- /dev/null +++ b/bundles/pacman/items.py @@ -0,0 +1,113 @@ +from bundlewrap.exceptions import BundleError + +if not node.os == 'arch': + raise BundleError(f'{node.name}: bundle:pacman requires arch linux') + +files = { + '/etc/pacman.conf': { + 'content_type': 'mako', + }, + '/etc/upgrade-and-reboot.conf': { + 'content_type': 'mako', + }, + '/etc/security/faillock.conf': {}, + '/usr/local/sbin/upgrade-and-reboot': { + 'mode': '0700', + }, + '/usr/local/sbin/do-unattended-upgrades': { + 'content_type': 'mako', + 'mode': '0700', + 'context': { + 'restart_triggers': node.metadata.get('pacman/restart_triggers', {}), + } + }, + '/usr/local/share/icinga/plugins/check_unattended_upgrades': { + 'mode': '0755', + }, +} + +svc_systemd['paccache.timer'] = { + 'needs': { + 'pkg_pacman:pacman-contrib', + }, +} + +pkg_pacman = { + 'at': {}, + 'autoconf': {}, + 'automake': {}, + 'binutils': {}, + 'bison': {}, + 'bzip2': {}, + 'curl': {}, + 'dialog': {}, + 'diffutils': {}, + 'dnsutils': {}, + 'fakeroot': {}, + 'file': {}, + 'findutils': {}, + 'flex': {}, + 'fwupd': {}, + 'gawk': {}, + 'gcc': {}, + 'gettext': {}, + 'git': {}, + 'gnu-netcat': {}, + 'grep': {}, + 'groff': {}, + 'gzip': {}, + 'htop': {}, + 'jq': {}, + 'ldns': {}, + 'less': {}, + 'libtool': {}, + 'logrotate': {}, + 'lsof': {}, + 'm4': {}, + 'mailutils': {}, + 'make': {}, + 'man-db': {}, + 'man-pages': {}, + 'moreutils': {}, + 'mtr': {}, + 'ncdu': {}, + 'nmap': {}, + 'pacman-contrib': {}, + 'patch': {}, + 'pkgconf': {}, + 'python': {}, + 'python-setuptools': { + 'needed_by': { + 'pkg_pip:', + }, + }, + 'python-pip': { + 'needed_by': { + 'pkg_pip:', + }, + }, + 'python-virtualenv': {}, + 'rsync': {}, + 'run-parts': {}, + 'sed': {}, + 'tar': {}, + 'texinfo': {}, + 'tmux': {}, + 'tree': {}, + 'unzip': {}, + 'vim': {}, + 'wget': {}, + 'which': {}, + 'whois': {}, + 'zip': {}, +} + +if node.metadata.get('pacman/linux-lts', False): + pkg_pacman['linux-lts'] = {} + pkg_pacman['acpi_call-lts'] = {} +else: + pkg_pacman['linux'] = {} + pkg_pacman['acpi_call'] = {} + +for pkg, config in node.metadata.get('pacman/packages', {}).items(): + pkg_pacman[pkg] = config diff --git a/bundles/pacman/metadata.py b/bundles/pacman/metadata.py new file mode 100644 index 0000000..fb69a04 --- /dev/null +++ b/bundles/pacman/metadata.py @@ -0,0 +1,54 @@ +defaults = { + 'pacman': { + 'ask_before_removal': { + 'glibc', + 'pacman', + }, + 'no_extract': { + 'etc/cron.d/0hourly', + # don't install systemd-homed pam module. It produces a lot of spam in + # journal about systemd-homed not being active, so just get rid of it. + # Requires reinstall of systemd package, though + 'usr/lib/security/pam_systemd_home.so', + }, + 'parallel_downloads': 4, + 'repository': 'http://ftp.uni-kl.de/pub/linux/archlinux/$repo/os/$arch', + 'unattended-upgrades': { + 'day': 5, + 'hour': 21, + }, + }, +} + + +@metadata_reactor.provides( + 'cron/jobs/upgrade-and-reboot', + 'icinga2_api/pacman/services', +) +def patchday(metadata): + if not metadata.get('pacman/unattended-upgrades/is_enabled', False): + return {} + + day = metadata.get('pacman/unattended-upgrades/day') + hour = metadata.get('pacman/unattended-upgrades/hour') + + return { + 'cron': { + 'jobs': { + 'upgrade-and-reboot': '{minute} {hour} * * {day} root /usr/local/sbin/upgrade-and-reboot'.format( + minute=node.magic_number % 30, + hour=hour, + day=day, + ), + }, + }, + 'icinga2_api': { + 'pacman': { + 'services': { + 'UNATTENDED UPGRADES': { + 'command_on_monitored_host': '/usr/local/share/icinga/plugins/check_unattended_upgrades', + }, + }, + }, + }, + } diff --git a/bundles/paperless-ng/files/paperless-consumer.service b/bundles/paperless-ng/files/paperless-consumer.service index 5f43db2..60a95f9 100644 --- a/bundles/paperless-ng/files/paperless-consumer.service +++ b/bundles/paperless-ng/files/paperless-consumer.service @@ -5,12 +5,8 @@ Requires=redis.service [Service] User=paperless Group=paperless -Environment=PAPERLESS_CONFIGURATION_PATH=/opt/paperless/paperless.conf -WorkingDirectory=/opt/paperless/src/paperless-ngx/src +WorkingDirectory=/opt/paperless/src/src ExecStart=/opt/paperless/venv/bin/python manage.py document_consumer -Restart=always -RestartSec=10 -SyslogIdentifier=paperless-consumer [Install] WantedBy=multi-user.target diff --git a/bundles/paperless-ng/files/paperless-scheduler.service b/bundles/paperless-ng/files/paperless-scheduler.service index 5ed83f0..54cfeae 100644 --- a/bundles/paperless-ng/files/paperless-scheduler.service +++ b/bundles/paperless-ng/files/paperless-scheduler.service @@ -5,12 +5,8 @@ Requires=redis.service [Service] User=paperless Group=paperless -Environment=PAPERLESS_CONFIGURATION_PATH=/opt/paperless/paperless.conf -WorkingDirectory=/opt/paperless/src/paperless-ngx/src -ExecStart=/opt/paperless/venv/bin/celery --app paperless beat --loglevel INFO -Restart=always -RestartSec=10 -SyslogIdentifier=paperless-scheduler +WorkingDirectory=/opt/paperless/src/src +ExecStart=/opt/paperless/venv/bin/python manage.py qcluster [Install] WantedBy=multi-user.target diff --git a/bundles/paperless-ng/files/paperless-taskqueue.service b/bundles/paperless-ng/files/paperless-taskqueue.service deleted file mode 100644 index d7be698..0000000 --- a/bundles/paperless-ng/files/paperless-taskqueue.service +++ /dev/null @@ -1,16 +0,0 @@ -[Unit] -Description=Paperless task queue -Requires=redis.service - -[Service] -User=paperless -Group=paperless -Environment=PAPERLESS_CONFIGURATION_PATH=/opt/paperless/paperless.conf -WorkingDirectory=/opt/paperless/src/paperless-ngx/src -ExecStart=/opt/paperless/venv/bin/celery --app paperless worker --loglevel INFO -Restart=always -RestartSec=10 -SyslogIdentifier=paperless-taskqueue - -[Install] -WantedBy=multi-user.target diff --git a/bundles/paperless-ng/files/paperless-webserver.service b/bundles/paperless-ng/files/paperless-webserver.service index 7c41aa7..9bcd926 100644 --- a/bundles/paperless-ng/files/paperless-webserver.service +++ b/bundles/paperless-ng/files/paperless-webserver.service @@ -7,15 +7,8 @@ Requires=redis.service [Service] User=paperless Group=paperless -Environment=PAPERLESS_CONFIGURATION_PATH=/opt/paperless/paperless.conf -Environment=GRANIAN_PORT=22070 -Environment=GRANIAN_WORKERS=4 -Environment=GRANIAN_HOST=::1 -WorkingDirectory=/opt/paperless/src/paperless-ngx/src -ExecStart=/opt/paperless/venv/bin/granian --interface asginl --ws "paperless.asgi:application" -Restart=always -RestartSec=10 -SyslogIdentifier=paperless-webserver +WorkingDirectory=/opt/paperless/src/src +ExecStart=/opt/paperless/venv/bin/gunicorn -c /opt/paperless/src/gunicorn.conf.py -b 127.0.0.1:22070 paperless.asgi:application [Install] WantedBy=multi-user.target diff --git a/bundles/paperless-ng/files/paperless.conf b/bundles/paperless-ng/files/paperless.conf index d943063..7972eef 100644 --- a/bundles/paperless-ng/files/paperless.conf +++ b/bundles/paperless-ng/files/paperless.conf @@ -11,14 +11,14 @@ PAPERLESS_DBSSLMODE=disable PAPERLESS_CONSUMPTION_DIR=/mnt/paperless/consume PAPERLESS_DATA_DIR=/mnt/paperless/data PAPERLESS_MEDIA_ROOT=/mnt/paperless/media -PAPERLESS_STATICDIR=/opt/paperless/src/paperless-ngx/static -PAPERLESS_FILENAME_FORMAT={{ created_year }}/{{ created_month }}/{{ correspondent }}/{{ asn }}_{{ title }} +PAPERLESS_STATICDIR=/opt/paperless/static +PAPERLESS_FILENAME_FORMAT={created_year}/{created_month}/{correspondent}/{asn}_{title} # Security and hosting PAPERLESS_SECRET_KEY=${repo.vault.random_bytes_as_base64_for(f'{node.name} paperless secret key')} -PAPERLESS_ALLOWED_HOSTS=${node.metadata.get('paperless/domain')} -PAPERLESS_CORS_ALLOWED_HOSTS=http://${node.metadata.get('paperless/domain')},https://${node.metadata.get('paperless/domain')} +PAPERLESS_ALLOWED_HOSTS=${node.metadata.get('nginx/vhosts/paperless/domain', '127.0.0.1')} +PAPERLESS_CORS_ALLOWED_HOSTS=http://${node.metadata.get('nginx/vhosts/paperless/domain', '127.0.0.1')},https://${node.metadata.get('nginx/vhosts/paperless/domain', '127.0.0.1')} #PAPERLESS_FORCE_SCRIPT_NAME= #PAPERLESS_STATIC_URL=/static/ #PAPERLESS_AUTO_LOGIN_USERNAME= @@ -28,10 +28,7 @@ PAPERLESS_CORS_ALLOWED_HOSTS=http://${node.metadata.get('paperless/domain')},htt # OCR settings PAPERLESS_OCR_LANGUAGE=${'+'.join(sorted(node.metadata.get('paperless/ocr_languages', {'deu', 'eng'})))} -PAPERLESS_OCR_MODE=skip -PAPERLESS_OCR_SKIP_ARCHIVE_FILE=never -PAPERLESS_OCR_USER_ARGS='{"invalidate_digital_signatures": true}' -PAPERLESS_PRE_CONSUME_SCRIPT=/opt/paperless/pre-consume.sh +PAPERLESS_OCR_MODE=skip_noarchive #PAPERLESS_OCR_OUTPUT_TYPE=pdfa #PAPERLESS_OCR_PAGES=1 #PAPERLESS_OCR_IMAGE_DPI=300 diff --git a/bundles/paperless-ng/files/pre-consume.sh b/bundles/paperless-ng/files/pre-consume.sh deleted file mode 100644 index e7937ba..0000000 --- a/bundles/paperless-ng/files/pre-consume.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -[[ -n "$DEBUG" ]] && set -x -set -euo pipefail - -pdfinfo "${DOCUMENT_WORKING_PATH}" | grep -q "Encrypted:" - -if pdfinfo "${DOCUMENT_WORKING_PATH}" | grep -q "Encrypted: yes" -then - qpdf --replace-input --decrypt "${DOCUMENT_WORKING_PATH}" -fi diff --git a/bundles/paperless-ng/items.py b/bundles/paperless-ng/items.py index 6b80397..84e9e43 100644 --- a/bundles/paperless-ng/items.py +++ b/bundles/paperless-ng/items.py @@ -1,97 +1,146 @@ -version = node.metadata.get('paperless/version') -workers = ('consumer', 'scheduler', 'taskqueue', 'webserver') - -users['paperless'] = { - 'home': '/opt/paperless', -} - -directories['/opt/paperless'] = {} - -files['/opt/paperless/paperless.conf'] = { - 'content_type': 'mako', - 'triggers': { - f'svc_systemd:paperless-{worker}:restart' - for worker in workers +users = { + 'paperless': { + 'home': '/opt/paperless', }, } -files['/opt/paperless/pre-consume.sh'] = { - 'mode': '0755', -} - -actions['paperless_create_virtualenv'] = { - 'command': '/usr/bin/python3 -m virtualenv -p python3 /opt/paperless/venv/', - 'unless': 'test -d /opt/paperless/venv/', - 'needs': { - 'directory:/opt/paperless', - 'pkg_apt:python3', - 'pkg_apt:python3-pip', - 'pkg_apt:python3-virtualenv', +directories = { + '/opt/paperless/src': {}, + '/opt/paperless/static': { + 'owner': 'paperless', }, } -actions['paperless_install'] = { - 'command': ' && '.join([ - f'wget -qO /opt/paperless/{version}.tar.xz https://github.com/paperless-ngx/paperless-ngx/releases/download/{version}/paperless-ngx-{version}.tar.xz', - 'rm -rf /opt/paperless/src/', - 'mkdir -p /opt/paperless/src/', - f'tar -C /opt/paperless/src -xf /opt/paperless/{version}.tar.xz', - f'rm /opt/paperless/{version}.tar.xz', - 'cd /opt/paperless/src/paperless-ngx', - '/opt/paperless/venv/bin/pip install --upgrade pip', - '/opt/paperless/venv/bin/pip install --upgrade -r requirements.txt', - f'echo "{version}" > /opt/paperless/version', - ]), - 'unless': f'''bash -c '[[ "$(cat /opt/paperless/version)" == "{version}" ]]' ''', - 'after': { - 'pkg_apt:', - }, - 'needs': { - 'action:paperless_create_virtualenv', - }, - 'triggers': { - 'action:paperless_migrate_database', - *{ - f'svc_systemd:paperless-{worker}:restart' for worker in workers - } - }, -} - -actions['paperless_migrate_database'] = { - 'command': ' && '.join([ - 'cd /opt/paperless/src/paperless-ngx/src', - 'sudo -Hu paperless PAPERLESS_CONFIGURATION_PATH=/opt/paperless/paperless.conf /opt/paperless/venv/bin/python manage.py migrate', - ]), - 'triggered': True, - 'needs': { - # /mnt/paperless is NOT created by this bundle. - 'action:paperless_install', - 'directory:/mnt/paperless', - 'file:/opt/paperless/paperless.conf', - 'user:paperless', - 'postgres_db:paperless', - }, -} - -for worker in workers: - files[f'/etc/systemd/system/paperless-{worker}.service'] = { - 'delete': True, +git_deploy = { + '/opt/paperless/src': { + 'repo': 'https://github.com/jonaswinkler/paperless-ng.git', + 'rev': node.metadata.get('paperless/version'), 'triggers': { - 'action:systemd-reload', - }, - } - - files[f'/usr/local/lib/systemd/system/paperless-{worker}.service'] = { - 'triggers': { - 'action:systemd-reload', - f'svc_systemd:paperless-{worker}:restart', - }, - } - - svc_systemd[f'paperless-{worker}'] = { - 'needs': { - 'action:paperless_install', + 'action:paperless_collectstatic', + 'action:paperless_compile_frontend', + 'action:paperless_install_deps', 'action:paperless_migrate_database', - f'file:/usr/local/lib/systemd/system/paperless-{worker}.service', + 'svc_systemd:paperless-consumer:restart', + 'svc_systemd:paperless-scheduler:restart', + 'svc_systemd:paperless-webserver:restart', }, - } + }, +} + +files = { + '/etc/systemd/system/paperless-consumer.service': { + 'triggers': { + 'action:systemd-reload', + 'svc_systemd:paperless-consumer:restart', + }, + }, + '/etc/systemd/system/paperless-scheduler.service': { + 'triggers': { + 'action:systemd-reload', + 'svc_systemd:paperless-scheduler:restart', + }, + }, + '/etc/systemd/system/paperless-webserver.service': { + 'triggers': { + 'action:systemd-reload', + 'svc_systemd:paperless-webserver:restart', + }, + }, + '/opt/paperless/src/paperless.conf': { + 'content_type': 'mako', + 'needs': { + 'git_deploy:/opt/paperless/src', + }, + 'triggers': { + 'svc_systemd:paperless-consumer:restart', + 'svc_systemd:paperless-scheduler:restart', + 'svc_systemd:paperless-webserver:restart', + }, + }, +} + +actions = { + 'paperless_create_virtualenv': { + 'command': '/usr/bin/python3 -m virtualenv -p python3 /opt/paperless/venv/', + 'unless': 'test -d /opt/paperless/venv/', + 'needs': { + # actually /opt/paperless, but we don't create that + 'directory:/opt/paperless/src', + 'pkg_apt:python3', + 'pkg_apt:python3-pip', + 'pkg_apt:python3-virtualenv', + }, + }, + 'paperless_install_deps': { + 'command': + 'cd /opt/paperless/src && ' + '/opt/paperless/venv/bin/pip install --upgrade pip && ' + '/opt/paperless/venv/bin/pip install --upgrade -r requirements.txt', + 'triggered': True, + 'needs': { + 'action:paperless_create_virtualenv', + }, + }, + 'paperless_migrate_database': { + 'command': + 'cd /opt/paperless/src/src && ' + 'sudo -Hu paperless /opt/paperless/venv/bin/python manage.py migrate', + 'triggered': True, + 'needs': { + # /mnt/paperless is NOT created by this bundle. + 'action:paperless_install_deps', + 'directory:/mnt/paperless', + 'directory:/opt/paperless/static', + 'file:/opt/paperless/src/paperless.conf', + 'user:paperless', + 'postgres_db:paperless', + }, + }, + 'paperless_compile_frontend': { + 'command': + 'cd /opt/paperless/src/src-ui && ' + 'npm install && ' + 'node_modules/.bin/ng build --prod', + 'triggered': True, + 'needs': { + 'file:/opt/paperless/src/paperless.conf', + 'pkg_apt:nodejs', + }, + }, + 'paperless_collectstatic': { + 'command': + 'cd /opt/paperless/src/src && ' + 'sudo -Hu paperless /opt/paperless/venv/bin/python manage.py collectstatic', + 'triggered': True, + 'needs': { + 'directory:/opt/paperless/static', + 'file:/opt/paperless/src/paperless.conf', + 'action:paperless_create_virtualenv', + }, + }, +} + +svc_systemd = { + 'paperless-consumer': { + 'needs': { + 'action:paperless_migrate_database', + 'file:/etc/systemd/system/paperless-consumer.service', + 'git_deploy:/opt/paperless/src', + }, + }, + 'paperless-scheduler': { + 'needs': { + 'action:paperless_migrate_database', + 'file:/etc/systemd/system/paperless-scheduler.service', + 'git_deploy:/opt/paperless/src', + }, + }, + 'paperless-webserver': { + 'needs': { + 'action:paperless_compile_frontend', + 'action:paperless_migrate_database', + 'file:/etc/systemd/system/paperless-webserver.service', + 'git_deploy:/opt/paperless/src', + }, + }, +} diff --git a/bundles/paperless-ng/metadata.py b/bundles/paperless-ng/metadata.py index 8db5342..1424e08 100644 --- a/bundles/paperless-ng/metadata.py +++ b/bundles/paperless-ng/metadata.py @@ -6,12 +6,9 @@ defaults = { 'gnupg': {}, 'imagemagick': {}, 'libmagic-dev': {}, - 'default-libmysqlclient-dev': {}, 'libpq-dev': {}, - 'mariadb-client': {}, 'mime-support': {}, 'optipng': {}, - 'poppler-utils': {}, 'python3-wheel': {}, # for OCRmyPDF @@ -22,8 +19,6 @@ defaults = { 'pngquant': {}, 'qpdf': {}, 'tesseract-ocr': {}, - 'tesseract-ocr-deu': {}, - 'tesseract-ocr-eng': {}, 'unpaper': {}, 'zlib1g': {}, }, @@ -33,9 +28,6 @@ defaults = { '/mnt/paperless', }, }, - 'nodejs': { - 'version': 22, - }, 'postgresql': { 'roles': { 'paperless': { @@ -64,55 +56,3 @@ def paperless_tesseract_languages(metadata): 'packages': packages, }, } - - -@metadata_reactor.provides( - 'icinga2_api/paperless/services', -) -def icinga_check_for_new_release(metadata): - return { - 'icinga2_api': { - 'paperless': { - 'services': { - 'PAPERLESS UPDATE': { - 'command_on_monitored_host': '/usr/local/share/icinga/plugins/check_github_for_new_release paperless-ngx/paperless-ngx {}'.format(metadata.get('paperless/version')), - 'vars.notification.mail': True, - 'check_interval': '60m', - }, - }, - }, - }, - } - - -@metadata_reactor.provides( - 'nginx/vhosts/paperless', -) -def nginx(metadata): - if not node.has_bundle('nginx'): - raise DoNotRunAgain - - return { - 'nginx': { - 'vhosts': { - 'paperless': { - 'domain': metadata.get('paperless/domain'), - 'locations': { - '/': { - 'target': 'http://[::1]:22070', - 'websockets': True, - 'proxy_set_header': { - 'X-Forwarded-Host': '$server_name', - }, - }, - '/static/': { - 'alias': '/opt/paperless/src/paperless-ngx/static/', - }, - }, - 'max_body_size': '100M', - 'website_check_path': '/accounts/login/', - 'website_check_string': 'Paperless-ngx', - }, - }, - }, - } diff --git a/bundles/php/files/8.2/fpm.conf b/bundles/php/files/8.2/fpm.conf deleted file mode 100644 index f3aa189..0000000 --- a/bundles/php/files/8.2/fpm.conf +++ /dev/null @@ -1,27 +0,0 @@ -[global] -pid=/run/php/php8.0-fpm.pid -; We're using journal, put logs there -error_log=/var/log/php8.0-fpm.log -daemonize=yes - -; The one and only worker pool we have -[www] -user=www-data -group=www-data -listen=/run/php/php8.2-fpm.sock -listen.owner=www-data -listen.group=www-data -listen.mode=0600 - -; Process Manager Settings -pm=dynamic -pm.max_children=${num_cpus*4} -pm.start_servers=${num_cpus} -pm.max_spare_servers=${num_cpus*2} -pm.min_spare_servers=${num_cpus} -pm.process_idle_timeout=30s -pm.max_requests=1024 - -% if not clear_env: -clear_env=no -% endif diff --git a/bundles/php/files/8.2/php.ini b/bundles/php/files/8.2/php.ini deleted file mode 100644 index 40c16d5..0000000 --- a/bundles/php/files/8.2/php.ini +++ /dev/null @@ -1,108 +0,0 @@ -[PHP] -; Only needed for libapache2-mod-php? -engine = On -short_open_tag = Off -precision = 14 -output_buffering = 4096 -zlib.output_compression = Off -implicit_flush = Off -serialize_precision = -1 -disable_functions = pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals -ignore_user_abort = Off -zend.enable_gc = On -expose_php = Off - -max_execution_time = 30 -max_input_time = 60 -memory_limit = ${memory_limit}M - -error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT -display_startup_errors = Off -log_errors = On -log_errors_max_len = 1024 -ignore_repeated_errors = Off -ignore_repeated_source = Off -report_memleaks = On -html_errors = On -error_log = syslog -syslog.ident = php8.2 -syslog.filter = ascii - -arg_separator.output = "&" -variables_order = "GPCS" -request_order = "GP" -register_argc_argv = Off -auto_globals_jit = On -post_max_size = ${post_max_size}M -default_mimetype = "text/html" -default_charset = "UTF-8" - -enable_dl = Off -file_uploads = On -upload_max_filesize = ${post_max_size}M -max_file_uploads = 20 - -allow_url_fopen = On -allow_url_include = Off -default_socket_timeout = 10 - -[CLI Server] -cli_server.color = On - -[mail function] -mail.add_x_header = Off - -[ODBC] -odbc.allow_persistent = On -odbc.check_persistent = On -odbc.max_persistent = -1 -odbc.max_links = -1 -odbc.defaultlrl = 4096 -odbc.defaultbinmode = 1 - -[PostgreSQL] -pgsql.allow_persistent = On -pgsql.auto_reset_persistent = Off -pgsql.max_persistent = -1 -pgsql.max_links = -1 -pgsql.ignore_notice = 0 -pgsql.log_notice = 0 - -[bcmath] -bcmath.scale = 0 - -[Session] -session.save_handler = files -session.use_strict_mode = 0 -session.use_cookies = 1 -session.use_only_cookies = 1 -session.name = PHPSESSID -session.auto_start = 0 -session.cookie_lifetime = 0 -session.cookie_path = / -session.cookie_domain = -session.cookie_httponly = -session.cookie_samesite = -session.serialize_handler = php -session.gc_probability = 1 -session.gc_divisor = 1000 -session.gc_maxlifetime = 1440 -session.referer_check = -session.cache_limiter = nocache -session.cache_expire = 180 -session.use_trans_sid = 0 -session.sid_length = 32 -session.trans_sid_tags = "a=href,area=href,frame=src,form=" -session.sid_bits_per_character = 6 - -[Assertion] -zend.assertions = -1 - -[opcache] -opcache.enable = 1 -opcache.save_comments = 1 -opcache.revalidate_freq = 60 -opcache.jit = 1255 -opcache.jit_buffer_size = 256M -opcache.memory_consumption = 256 -opcache.max_accelerated_files = 1048793 diff --git a/bundles/php/items.py b/bundles/php/items.py index c836efa..f4479d7 100644 --- a/bundles/php/items.py +++ b/bundles/php/items.py @@ -1,64 +1,58 @@ -version = node.metadata.get('php/__version') +version = node.metadata['php']['version'] -directories['/var/lib/php/sessions'] = { - 'owner': 'www-data', - 'mode': None, - 'after': { - 'pkg_apt:', - } -} - -files[f'/etc/php/{version}/fpm/php-fpm.conf'] = { - 'source': f'{version}/fpm.conf', - 'content_type': 'mako', - 'context': { - 'num_cpus': node.metadata.get('vm/cpu'), - 'clear_env': node.metadata.get('php/clear_env', True), +files = { + f'/etc/php/{version}/fpm/php-fpm.conf': { + 'source': f'{version}/fpm.conf', + 'content_type': 'mako', + 'context': { + 'num_cpus': node.metadata['vm']['cpu'], + 'clear_env': node.metadata.get('php/clear_env', True), + }, + 'needs': { + # "all php packages" + 'pkg_apt:' + }, + 'triggers': { + f'svc_systemd:php{version}-fpm:restart', + }, }, - 'after': { - # "all php packages" - 'pkg_apt:' + f'/etc/php/{version}/fpm/php.ini': { + 'source': f'{version}/php.ini', + 'content_type': 'mako', + 'context': { + 'num_cpus': node.metadata['vm']['cpu'], + 'post_max_size': node.metadata['php'].get('post_max_size', 10), + 'memory_limit': node.metadata.get('php/memory_limit', 256), + }, + 'needs': { + # "all php packages" + 'pkg_apt:' + }, + 'triggers': { + f'svc_systemd:php{version}-fpm:restart', + }, }, - 'triggers': { - f'svc_systemd:php{version}-fpm:restart', + f'/etc/php/{version}/cli/php.ini': { + 'source': f'{version}/php.ini', + 'content_type': 'mako', + 'context': { + 'num_cpus': node.metadata['vm']['cpu'], + 'post_max_size': node.metadata['php'].get('post_max_size', 10), + 'memory_limit': node.metadata.get('php/memory_limit', 256), + }, + 'needs': { + # "all php packages" + 'pkg_apt:' + }, }, } -files[f'/etc/php/{version}/fpm/php.ini'] = { - 'source': f'{version}/php.ini', - 'content_type': 'mako', - 'context': { - 'num_cpus': node.metadata.get('vm/cpu'), - 'post_max_size': node.metadata.get('php/post_max_size', 10), - 'memory_limit': node.metadata.get('php/memory_limit', 256), - }, - 'after': { - # "all php packages" - 'pkg_apt:' - }, - 'triggers': { - f'svc_systemd:php{version}-fpm:restart', - }, -} - -files[f'/etc/php/{version}/cli/php.ini'] = { - 'source': f'{version}/php.ini', - 'content_type': 'mako', - 'context': { - 'num_cpus': node.metadata.get('vm/cpu'), - 'post_max_size': node.metadata.get('php/post_max_size', 10), - 'memory_limit': node.metadata.get('php/memory_limit', 256), - }, - 'after': { - # "all php packages" - 'pkg_apt:' - }, -} - -svc_systemd[f'php{version}-fpm'] = { - 'needs': { - 'pkg_apt:', - f'file:/etc/php/{version}/fpm/php-fpm.conf', - f'file:/etc/php/{version}/fpm/php.ini', +svc_systemd = { + f'php{version}-fpm': { + 'needs': { + 'pkg_apt:', + f'file:/etc/php/{version}/fpm/php-fpm.conf', + f'file:/etc/php/{version}/fpm/php.ini', + }, }, } diff --git a/bundles/php/metadata.py b/bundles/php/metadata.py index edb8399..d14954e 100644 --- a/bundles/php/metadata.py +++ b/bundles/php/metadata.py @@ -1,11 +1,12 @@ -OS_PHP_VERSION = { - 12: '8.2', - 13: '8.4', -} - defaults = { - 'php': { - '__version': OS_PHP_VERSION[node.os_version[0]], + 'apt': { + 'repos': { + 'php': { + 'items': { + 'deb https://packages.sury.org/php/ {os_release} main', + }, + }, + }, }, } @@ -14,7 +15,7 @@ defaults = { 'apt/packages', ) def php_packages_with_features(metadata): - version = metadata.get('php/__version') + version = metadata.get('php/version') packages = { f'php{version}': {}, diff --git a/bundles/pleroma/files/pleroma.config.exs b/bundles/pleroma/files/pleroma.config.exs new file mode 100644 index 0000000..64c2c0b --- /dev/null +++ b/bundles/pleroma/files/pleroma.config.exs @@ -0,0 +1,35 @@ +import Config + +config :pleroma, + configurable_from_database: true + +config :pleroma, Pleroma.Web.Endpoint, + url: [host: "${node.metadata['pleroma']['url']}", scheme: "https", port: 443], + http: [port: 21000, ip: {127, 0, 0, 1}], + secret_key_base: "${node.metadata['pleroma']['secret_key']}", + secure_cookie_flag: true + +config :pleroma, :instance, + static_dir: "/var/pleroma/static/" + +config :pleroma, Pleroma.Upload, + uploader: Pleroma.Uploaders.Local, + filters: [Pleroma.Upload.Filter.Dedupe] + +config :pleroma, Pleroma.Uploaders.Local, + uploads: "/var/pleroma/uploads/" + +config :pleroma, :media_proxy, + enabled: false, + redirect_on_failure: true + #base_url: "https://cache.pleroma.social" + +# Configure your database +config :pleroma, Pleroma.Repo, + adapter: Ecto.Adapters.Postgres, + username: "pleroma", + password: "${node.metadata['postgresql']['roles']['pleroma']['password']}", + database: "pleroma", + hostname: "localhost", + pool_size: 10, + timeout: 60000 diff --git a/bundles/pleroma/files/pleroma.service b/bundles/pleroma/files/pleroma.service new file mode 100644 index 0000000..085b041 --- /dev/null +++ b/bundles/pleroma/files/pleroma.service @@ -0,0 +1,22 @@ +[Unit] +Description=Pleroma social network +After=network.target +Requires=postgresql.service + +[Service] +User=pleroma +WorkingDirectory=/opt/pleroma +Environment="HOME=/opt/pleroma" +Environment="PLEROMA_CONFIG_PATH=/opt/pleroma/pleroma.config.exs" +Environment="PLUG_TMPDIR=/tmp/pleroma" +ExecStart=/opt/pleroma/release/bin/pleroma start +ExecStop=/opt/pleroma/release/bin/pleroma stop +Restart=always + +PrivateTmp=true +ProtectHome=true +ProtectSystem=full +CapabilityBoundingSet=~CAP_SYS_ADMIN + +[Install] +WantedBy=multi-user.target diff --git a/bundles/pleroma/items.py b/bundles/pleroma/items.py new file mode 100644 index 0000000..a03b973 --- /dev/null +++ b/bundles/pleroma/items.py @@ -0,0 +1,88 @@ +version = node.metadata['pleroma']['version'] + +users = { + 'pleroma': { + 'home': '/opt/pleroma', + }, +} + +directories = { + '/opt/pleroma': {}, + '/var/pleroma': { + 'owner': 'pleroma', + }, + '/var/pleroma/uploads': { + 'owner': 'pleroma', + }, + '/var/pleroma/static': { + 'owner': 'pleroma', + }, + '/var/pleroma/static/emoji': { + 'owner': 'pleroma', + }, +} + +if node.has_bundle('zfs'): + directories['/var/pleroma']['needs'] = { + 'zfs_dataset:tank/pleroma-data', + } + +actions = { + 'pleroma_download_release': { + 'command': \ + 'cd /opt/pleroma/ && '\ + f'wget -O/opt/pleroma/pleroma.zip https://git.pleroma.social/api/v4/projects/2/jobs/artifacts/release/{version}/download?job=amd64 && '\ + 'rm -rf release && '\ + 'unzip /opt/pleroma/pleroma.zip && '\ + 'chown -R pleroma:pleroma /opt/pleroma/release && '\ + f'echo -n "{version}" > /opt/pleroma/.bundlewrap_installed_version', + 'unless': f'[ "$(cat /opt/pleroma/.bundlewrap_installed_version)" = "{version}" ]', + 'needs': { + 'directory:/opt/pleroma', + }, + 'preceded_by': { + 'svc_systemd:pleroma:stop', + }, + 'triggers': { + 'action:pleroma_migrate_database', + 'svc_systemd:pleroma:restart', + }, + }, + 'pleroma_migrate_database': { + 'triggered': True, + 'command': \ + 'echo "CREATE EXTENSION IF NOT EXISTS citext;" | psql pleroma && '\ + 'echo "CREATE EXTENSION IF NOT EXISTS pg_trgm;" | psql pleroma && '\ + 'echo "CREATE EXTENSION IF NOT EXISTS \\\"uuid-ossp\\\";" | psql pleroma && '\ + 'sudo -u pleroma PLEROMA_CONFIG_PATH=/opt/pleroma/pleroma.config.exs /opt/pleroma/release/bin/pleroma_ctl create', + 'needs': { + 'postgres_db:pleroma', + }, + }, +} + +files = { + '/etc/systemd/system/pleroma.service': { + 'triggers': { + 'action:systemd-reload', + 'svc_systemd:pleroma:restart', + }, + }, + '/opt/pleroma/pleroma.config.exs': { + 'content_type': 'mako', + 'triggers': { + 'svc_systemd:pleroma:restart', + }, + }, +} + +svc_systemd = { + 'pleroma': { + 'needs': { + 'action:pleroma_download_release', + 'action:pleroma_migrate_database', + 'file:/etc/systemd/system/pleroma.service', + 'file:/opt/pleroma/pleroma.config.exs', + }, + }, +} diff --git a/bundles/pleroma/metadata.py b/bundles/pleroma/metadata.py new file mode 100644 index 0000000..44e7a3b --- /dev/null +++ b/bundles/pleroma/metadata.py @@ -0,0 +1,62 @@ +defaults = { + 'apt': { + 'packages': { + 'imagemagick': {}, + 'ffmpeg': {}, + 'libimage-exiftool-perl': {}, + }, + }, + 'backups': { + 'paths': { + '/var/pleroma', + }, + }, + 'zfs': { + 'datasets': { + 'tank/pleroma-data': { + 'mountpoint': '/var/pleroma', + 'needed_by': { + 'directory:/var/pleroma', + }, + }, + }, + }, + 'postgresql': { + 'roles': { + 'pleroma': { + 'password': repo.vault.password_for(f'{node.name} postgresql pleroma'), + }, + }, + 'databases': { + 'pleroma': { + 'owner': 'pleroma', + }, + }, + }, +} + + +@metadata_reactor.provides( + 'nginx/vhosts/pleroma', +) +def nginx(metadata): + if not node.has_bundle('nginx'): + raise DoNotRunAgain + + return { + 'nginx': { + 'vhosts': { + 'pleroma': { + 'domain': metadata.get('pleroma/url'), + 'locations': { + '/': { + 'target': 'http://127.0.0.1:21000', + 'websockets': True, + }, + }, + 'website_check_path': '/main/all', + 'website_check_string': 'use Pleroma', + }, + }, + }, + } diff --git a/bundles/postfix/files/arch-override.conf b/bundles/postfix/files/arch-override.conf new file mode 100644 index 0000000..3b3e46d --- /dev/null +++ b/bundles/postfix/files/arch-override.conf @@ -0,0 +1,6 @@ +[Service] +# arch postfix is not set up for chrooting by default +ExecStartPre=-/usr/sbin/mkdir -p /var/spool/postfix/etc +% for file in ['/etc/localtime', '/etc/nsswitch.conf', '/etc/resolv.conf', '/etc/services']: +ExecStartPre=-/usr/sbin/cp -p ${file} /var/spool/postfix${file} +% endfor diff --git a/bundles/postfix/files/blocked_recipients b/bundles/postfix/files/blocked_recipients deleted file mode 100644 index 4aff372..0000000 --- a/bundles/postfix/files/blocked_recipients +++ /dev/null @@ -1,5 +0,0 @@ -devnull@${node.metadata.get('postfix/myhostname')} DISCARD DEV-NULL - -% for address in sorted(blocked): -${address} REJECT -% endfor diff --git a/bundles/postfix/files/main.cf b/bundles/postfix/files/main.cf index 9d74175..bb647fc 100644 --- a/bundles/postfix/files/main.cf +++ b/bundles/postfix/files/main.cf @@ -3,7 +3,7 @@ biff = no append_dot_mydomain = no readme_directory = no compatibility_level = 2 -myhostname = ${node.metadata.get('postfix/myhostname')} +myhostname = ${node.metadata.get('postfix/myhostname', node.metadata['hostname'])} myorigin = /etc/mailname mydestination = $myhostname, localhost mynetworks = ${' '.join(sorted(mynetworks))} @@ -25,6 +25,7 @@ inet_interfaces = 127.0.0.1 % endif <%text> +smtp_use_tls = yes smtp_tls_loglevel = 1 smtp_tls_note_starttls_offer = yes smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache @@ -37,8 +38,8 @@ smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt % if node.has_bundle('postfixadmin'): -smtpd_tls_cert_file = /var/lib/dehydrated/certs/${node.metadata.get('postfix/myhostname')}/fullchain.pem -smtpd_tls_key_file = /var/lib/dehydrated/certs/${node.metadata.get('postfix/myhostname')}/privkey.pem +smtpd_tls_cert_file = /var/lib/dehydrated/certs/${node.metadata.get('postfix/myhostname', node.metadata['hostname'])}/fullchain.pem +smtpd_tls_key_file = /var/lib/dehydrated/certs/${node.metadata.get('postfix/myhostname', node.metadata['hostname'])}/privkey.pem <%text> smtpd_use_tls=yes smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache @@ -47,18 +48,17 @@ smtpd_client_restrictions = permit_mynetworks permit_sasl_authenticated smtpd_helo_required = yes smtpd_helo_restrictions = permit_mynetworks reject_invalid_helo_hostname smtpd_data_restrictions = reject_unauth_pipelining -smtpd_recipient_restrictions = check_recipient_access hash:/etc/postfix/blocked_recipients, permit_mynetworks -smtpd_relay_before_recipient_restrictions = yes -# https://ssl-config.mozilla.org/#server=postfix&version=3.7.10&config=intermediate&openssl=3.0.11&guideline=5.7 +# generated using mozilla ssl generator, using "old" configuration. +# we need this to support CentOS 7 systems, sadly ... +# https://ssl-config.mozilla.org/#server=postfix&version=3.5.13&config=old&openssl=1.1.1k&guideline=5.6 smtpd_tls_security_level = may smtpd_tls_auth_only = yes -smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1 -smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1 +smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3 +smtpd_tls_protocols = !SSLv2, !SSLv3 smtpd_tls_mandatory_ciphers = medium -smtpd_tls_dh1024_param_file = /etc/ssl/certs/dhparam.pem -tls_medium_cipherlist = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305 -tls_preempt_cipherlist = no +tls_medium_cipherlist = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA +tls_preempt_cipherlist = yes relay_domains = $mydestination, pgsql:/etc/postfix/pgsql/relay_domains.cf diff --git a/bundles/postfix/files/postfix-telegraf-queue b/bundles/postfix/files/postfix-telegraf-queue index 16b64e5..f5abfe7 100644 --- a/bundles/postfix/files/postfix-telegraf-queue +++ b/bundles/postfix/files/postfix-telegraf-queue @@ -4,6 +4,7 @@ from json import loads from subprocess import check_output + queue_counts = {} queue_json = check_output(['sudo', '/usr/sbin/postqueue', '-j']) diff --git a/bundles/postfix/items.py b/bundles/postfix/items.py index aeceed1..e66185f 100644 --- a/bundles/postfix/items.py +++ b/bundles/postfix/items.py @@ -21,13 +21,11 @@ for identifier in node.metadata.get('postfix/mynetworks', set()): netmask = '128' mynetworks.add(f'[{ip6}]/{netmask}') +my_package = 'pkg_pacman:postfix' if node.os == 'arch' else 'pkg_apt:postfix' files = { '/etc/mailname': { - 'content': node.metadata.get('postfix/myhostname'), - 'before': { - 'pkg_apt:postfix', - }, + 'content': node.metadata.get('postfix/myhostname', node.metadata['hostname']), 'triggers': { 'svc_systemd:postfix:restart', }, @@ -38,16 +36,6 @@ files = { 'action:postfix_newaliases', }, }, - '/etc/postfix/blocked_recipients': { - 'content_type': 'mako', - 'context': { - 'blocked': node.metadata.get('postfix/blocked_recipients', set()), - }, - 'triggers': { - 'action:postfix_postmap_blocked_recipients', - 'svc_systemd:postfix:restart', - }, - }, '/etc/postfix/master.cf': { 'content_type': 'mako', 'triggers': { @@ -81,20 +69,7 @@ actions = { 'command': 'newaliases', 'triggered': True, 'needs': { - 'pkg_apt:postfix', - }, - 'before': { - 'svc_systemd:postfix', - }, - }, - 'postfix_postmap_blocked_recipients': { - 'command': 'postmap hash:/etc/postfix/blocked_recipients', - 'triggered': True, - 'needs': { - 'pkg_apt:postfix', - }, - 'before': { - 'svc_systemd:postfix', + my_package, }, }, } @@ -104,7 +79,17 @@ svc_systemd = { 'needs': { 'file:/etc/postfix/master.cf', 'file:/etc/postfix/main.cf', - 'pkg_apt:postfix', + my_package, }, }, } + +if node.os == 'arch': + files['/etc/systemd/system/postfix.service.d/bundlewrap.conf'] = { + 'source': 'arch-override.conf', + 'content_type': 'mako', + 'triggers': { + 'action:systemd-reload', + 'svc_systemd:postfix:restart', + }, + } diff --git a/bundles/postfix/metadata.py b/bundles/postfix/metadata.py index f457b9b..e0dbe61 100644 --- a/bundles/postfix/metadata.py +++ b/bundles/postfix/metadata.py @@ -14,7 +14,7 @@ defaults = { 'postfix': { 'services': { 'POSTFIX PROCESS': { - 'command_on_monitored_host': '/usr/local/share/icinga/plugins/check_systemd_unit postfix' + ('' if node.os_version >= (13,) else '@-'), + 'command_on_monitored_host': '/usr/local/share/icinga/plugins/check_systemd_unit postfix' + ('' if node.os == 'arch' else '@-'), }, 'POSTFIX QUEUE': { 'command_on_monitored_host': 'sudo /usr/local/share/icinga/plugins/check_postfix_queue -w 20 -c 40 -d 50', @@ -22,6 +22,12 @@ defaults = { }, }, }, + 'pacman': { + 'packages': { + 'postfix': {}, + 's-nail': {}, + }, + }, } if node.has_bundle('postfixadmin'): @@ -81,7 +87,7 @@ def letsencrypt(metadata): } result['domains'] = { - metadata.get('postfix/myhostname'): set(), + metadata.get('postfix/myhostname', metadata.get('hostname')): set(), } return { @@ -90,10 +96,10 @@ def letsencrypt(metadata): @metadata_reactor.provides( - 'firewall/port_rules', - 'firewall/port_rules', - 'firewall/port_rules', - 'firewall/port_rules', + 'firewall/port_rules/25', + 'firewall/port_rules/465', + 'firewall/port_rules/587', + 'firewall/port_rules/2525', ) def firewall(metadata): if node.has_bundle('postfixadmin'): @@ -102,13 +108,13 @@ def firewall(metadata): default = metadata.get('postfix/mynetworks', set()) rules = { - '25/tcp': atomic(metadata.get('postfix/restrict-to', default)), - '465/tcp': atomic(metadata.get('postfix/restrict-to', default)), + '25': atomic(metadata.get('postfix/restrict-to', default)), + '465': atomic(metadata.get('postfix/restrict-to', default)), } if node.has_bundle('postfixadmin'): - rules['587/tcp'] = atomic(metadata.get('postfix/restrict-to', default)) - rules['2525/tcp'] = atomic(metadata.get('postfix/restrict-to', default)) + rules['587'] = atomic(metadata.get('postfix/restrict-to', default)) + rules['2525'] = atomic(metadata.get('postfix/restrict-to', default)) return { 'firewall': { @@ -142,14 +148,3 @@ def icinga2(metadata): }, }, } - - -@metadata_reactor.provides( - 'postfix/myhostname', -) -def myhostname(metadata): - return { - 'postfix': { - 'myhostname': metadata.get('hostname'), - }, - } diff --git a/bundles/postfixadmin/metadata.py b/bundles/postfixadmin/metadata.py index b9d6379..bed7ab6 100644 --- a/bundles/postfixadmin/metadata.py +++ b/bundles/postfixadmin/metadata.py @@ -60,23 +60,3 @@ def icinga_check_for_new_release(metadata): }, }, } - - -@metadata_reactor.provides( - 'nginx/vhosts/postfixadmin', -) -def nginx(metadata): - if not node.has_bundle('nginx'): - raise DoNotRunAgain - - return { - 'nginx': { - 'vhosts': { - 'postfixadmin': { - 'domain': metadata.get('postfixadmin/domain'), - 'webroot': '/opt/postfixadmin/public/', - 'php': True, - }, - }, - }, - } diff --git a/bundles/postgresql/files/postgresql.conf b/bundles/postgresql/files/postgresql.conf index 0996a13..56fa5af 100644 --- a/bundles/postgresql/files/postgresql.conf +++ b/bundles/postgresql/files/postgresql.conf @@ -9,7 +9,6 @@ max_connections = ${max_connections} autovacuum_max_workers = ${autovacuum_max_workers} maintenance_work_mem = ${maintenance_work_mem}MB work_mem = ${work_mem}MB -effective_cache_size = ${cache_size}MB shared_buffers = ${shared_buffers}MB temp_buffers = ${temp_buffers}MB log_destination = syslog @@ -27,5 +26,7 @@ log_min_duration_statement = -1 % endif effective_io_concurrency = ${effective_io_concurrency} max_worker_processes = ${max_worker_processes} +% if version_list >= [10]: max_parallel_workers = ${max_parallel_workers} +% endif max_parallel_workers_per_gather = ${max_parallel_workers_per_gather} diff --git a/bundles/postgresql/items.py b/bundles/postgresql/items.py index 0a1b09f..5f21b42 100644 --- a/bundles/postgresql/items.py +++ b/bundles/postgresql/items.py @@ -1,4 +1,4 @@ -postgresql_version = int(node.metadata.get('postgresql/version')) +postgresql_version = node.metadata['postgresql']['version'] pkg_apt = { 'postgresql-common': {}, @@ -44,7 +44,10 @@ files = { }, "/etc/postgresql/{}/main/postgresql.conf".format(postgresql_version): { 'content_type': 'mako', - 'context': node.metadata.get('postgresql'), + 'context': { + 'version_list': [int(i) for i in node.metadata['postgresql']['version'].split('.')], + **node.metadata['postgresql'], + }, 'owner': 'postgres', 'group': 'postgres', 'needs': { @@ -57,7 +60,7 @@ files = { }, } -if node.has_bundle('backup-client'): +if node.has_bundle('backup-client') and not node.has_bundle('zfs'): files['/etc/backup-pre-hooks.d/90-postgresql-dump-all'] = { 'source': 'backup-pre-hook', 'content_type': 'mako', @@ -67,6 +70,10 @@ if node.has_bundle('backup-client'): 'mode': '0700', } directories['/var/tmp/postgresdumps'] = {} +else: + files['/var/tmp/postgresdumps'] = { + 'delete': True, + } postgres_roles = { 'root': { diff --git a/bundles/postgresql/metadata.py b/bundles/postgresql/metadata.py index b624bae..fce9bb6 100644 --- a/bundles/postgresql/metadata.py +++ b/bundles/postgresql/metadata.py @@ -1,17 +1,7 @@ defaults = { - 'apt': { - 'repos': { - 'postgresql': { - 'items': { - 'deb https://apt.postgresql.org/pub/repos/apt/ {os_release}-pgdg main', - }, - }, - }, - }, 'backups': { 'paths': { '/var/lib/postgresql', - '/var/tmp/postgresdumps', }, }, 'bash_functions': { @@ -34,7 +24,6 @@ defaults = { 'shared_buffers': 128, 'temp_buffers': 8, 'slow_query_log_sec': 0, - 'cache_size': 256, }, } @@ -75,6 +64,36 @@ if node.has_bundle('zfs'): }, }, } +else: + defaults['backups']['paths'].add('/var/tmp/postgresdumps') + + +@metadata_reactor.provides( + 'apt/repos/postgresql', +) +def default_postgresql_version_for_debian(metadata): + # + versions_in_debian = { + '10': '11', # buster + '11': '13', # bullseye + } + os = str(node.os_version[0]) + version_to_be_installed = metadata.get('postgresql/version') + + if version_to_be_installed != versions_in_debian[os]: + return { + 'apt': { + 'repos': { + 'postgresql': { + 'items': { + 'deb https://apt.postgresql.org/pub/repos/apt/ {os_release}-pgdg main', + }, + }, + }, + }, + } + + return {} @metadata_reactor.provides( diff --git a/bundles/powerdns/files/named.conf b/bundles/powerdns/files/named.conf index 4154935..196e3f5 100644 --- a/bundles/powerdns/files/named.conf +++ b/bundles/powerdns/files/named.conf @@ -1,6 +1,6 @@ % for zone in sorted(zones): zone "${zone}" { file "/var/lib/powerdns/zones/${zone}"; - type master; + type native; }; % endfor diff --git a/bundles/powerdns/files/pdns.conf b/bundles/powerdns/files/pdns.conf index 7fcb1ca..1e2a5de 100644 --- a/bundles/powerdns/files/pdns.conf +++ b/bundles/powerdns/files/pdns.conf @@ -20,15 +20,12 @@ setgid=pdns allow-notify-from=${','.join(sorted(my_primary_servers))} slave=yes -% if node.os_version[0] > 10: -superslave=yes -% endif +# FIXME enable once debian stable has 4.1.9 +#superslave=yes % else: api=yes api-key=${api_key} webserver=yes -webserver-address=0.0.0.0 -webserver-allow-from=0.0.0.0/0 allow-notify-from= diff --git a/bundles/powerdns/files/schema.pgsql.sql b/bundles/powerdns/files/schema.pgsql.sql new file mode 100644 index 0000000..9635168 --- /dev/null +++ b/bundles/powerdns/files/schema.pgsql.sql @@ -0,0 +1,105 @@ +-- 4.3 schema, https://doc.powerdns.com/authoritative/backends/generic-postgresql.html + +CREATE TABLE domains ( + id SERIAL PRIMARY KEY, + name VARCHAR(255) NOT NULL, + master VARCHAR(128) DEFAULT NULL, + last_check INT DEFAULT NULL, + type VARCHAR(6) NOT NULL, + notified_serial BIGINT DEFAULT NULL, + account VARCHAR(40) DEFAULT NULL, + CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT))) +); + +CREATE UNIQUE INDEX name_index ON domains(name); + +ALTER TABLE domains OWNER TO ${user}; + +CREATE TABLE records ( + id BIGSERIAL PRIMARY KEY, + domain_id INT DEFAULT NULL, + name VARCHAR(255) DEFAULT NULL, + type VARCHAR(10) DEFAULT NULL, + content VARCHAR(65535) DEFAULT NULL, + ttl INT DEFAULT NULL, + prio INT DEFAULT NULL, + change_date INT DEFAULT NULL, + disabled BOOL DEFAULT 'f', + ordername VARCHAR(255), + auth BOOL DEFAULT 't', + CONSTRAINT domain_exists + FOREIGN KEY(domain_id) REFERENCES domains(id) + ON DELETE CASCADE, + CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT))) +); + +CREATE INDEX rec_name_index ON records(name); +CREATE INDEX nametype_index ON records(name,type); +CREATE INDEX domain_id ON records(domain_id); +CREATE INDEX recordorder ON records (domain_id, ordername text_pattern_ops); + +ALTER TABLE records OWNER TO ${user}; + +CREATE TABLE supermasters ( + ip INET NOT NULL, + nameserver VARCHAR(255) NOT NULL, + account VARCHAR(40) NOT NULL, + PRIMARY KEY(ip, nameserver) +); + +ALTER TABLE supermasters OWNER TO ${user}; + +CREATE TABLE comments ( + id SERIAL PRIMARY KEY, + domain_id INT NOT NULL, + name VARCHAR(255) NOT NULL, + type VARCHAR(10) NOT NULL, + modified_at INT NOT NULL, + account VARCHAR(40) DEFAULT NULL, + comment VARCHAR(65535) NOT NULL, + CONSTRAINT domain_exists + FOREIGN KEY(domain_id) REFERENCES domains(id) + ON DELETE CASCADE, + CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT))) +); + +CREATE INDEX comments_domain_id_idx ON comments (domain_id); +CREATE INDEX comments_name_type_idx ON comments (name, type); +CREATE INDEX comments_order_idx ON comments (domain_id, modified_at); + +ALTER TABLE comments OWNER TO ${user}; + +CREATE TABLE domainmetadata ( + id SERIAL PRIMARY KEY, + domain_id INT REFERENCES domains(id) ON DELETE CASCADE, + kind VARCHAR(32), + content TEXT +); + +CREATE INDEX domainidmetaindex ON domainmetadata(domain_id); + +ALTER TABLE domainmetadata OWNER TO ${user}; + +CREATE TABLE cryptokeys ( + id SERIAL PRIMARY KEY, + domain_id INT REFERENCES domains(id) ON DELETE CASCADE, + flags INT NOT NULL, + active BOOL, + content TEXT +); + +CREATE INDEX domainidindex ON cryptokeys(domain_id); +ALTER TABLE cryptokeys OWNER TO ${user}; + + +CREATE TABLE tsigkeys ( + id SERIAL PRIMARY KEY, + name VARCHAR(255), + algorithm VARCHAR(50), + secret VARCHAR(255), + CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT))) +); + +CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm); + +ALTER TABLE tsigkeys OWNER TO ${user}; diff --git a/bundles/powerdns/items.py b/bundles/powerdns/items.py index b6a5e8f..a6db93a 100644 --- a/bundles/powerdns/items.py +++ b/bundles/powerdns/items.py @@ -3,17 +3,28 @@ from os import listdir from os.path import isfile, join from subprocess import check_output -from bundlewrap.utils.ui import io - zone_path = join(repo.path, 'data', 'powerdns', 'files', 'bind-zones') -nameservers = set() -for rnode in sorted(repo.nodes_in_group('dns')): - nameservers.add(rnode.metadata.get('powerdns/my_hostname', rnode.metadata.get('hostname'))) +ZONE_HEADER = """ +; _ ____ _ _ _____ _ _ _ _ ____ +; / \\ / ___| | | |_ _| | | | \\ | |/ ___| +; / _ \\| | | |_| | | | | | | | \\| | | _ +; / ___ \\ |___| _ | | | | |_| | |\\ | |_| | +; /_/ \\_\\____|_| |_| |_| \\___/|_| \\_|\\____| +; +; --> Diese Datei wird von BundleWrap verwaltet! <-- -my_primary_servers = set() -for ips in node.metadata.get('powerdns/my_primary_servers', {}).values(): - my_primary_servers.update(ips) +$TTL 60 +@ IN SOA ns-1.kunbox.net. hostmaster.kunbox.net. ( + {serial} + 3600 + 600 + 86400 + 300 + ) +""" +for rnode in sorted(repo.nodes_in_group('dns')): + ZONE_HEADER += '@ IN NS {}.\n'.format(rnode.metadata.get('powerdns/my_hostname', rnode.metadata.get('hostname'))) directories = { '/etc/powerdns/pdns.d': { @@ -39,11 +50,11 @@ files = { '/etc/powerdns/pdns.conf': { 'content_type': 'mako', 'context': { - 'api_key': node.metadata.get('powerdns/api_key'), - 'my_hostname': node.metadata.get('powerdns/my_hostname', node.metadata.get('hostname')), - 'is_secondary': node.metadata.get('powerdns/is_secondary', False), - 'my_primary_servers': my_primary_servers, - 'my_secondary_servers': node.metadata.get('powerdns/my_secondary_servers', set()), + 'api_key': node.metadata['powerdns']['api_key'], + 'my_hostname': node.metadata['powerdns'].get('my_hostname', node.metadata.get('hostname')), + 'is_secondary': node.metadata['powerdns'].get('is_secondary', False), + 'my_primary_servers': node.metadata['powerdns'].get('my_primary_servers', set()), + 'my_secondary_servers': node.metadata['powerdns'].get('my_secondary_servers', set()), }, 'needs': { 'pkg_apt:pdns-server', @@ -67,8 +78,8 @@ svc_systemd = { actions = { 'powerdns_reload_zones': { 'triggered': True, - 'command': r'pdns_control rediscover; pdns_control reload; pdns_control notify \*', - 'after': { + 'command': 'pdns_control rediscover; pdns_control reload', + 'needs': { 'svc_systemd:pdns', }, }, @@ -81,10 +92,9 @@ if node.metadata.get('powerdns/features/bind', False): continue try: - output = check_output(['git', 'log', '-1', '--pretty=%ci']).decode('utf-8').strip() + output = check_output(['git', 'log', '-1', '--pretty=%ci', join(zone_path, zone)]).decode('utf-8').strip() serial = datetime.strptime(output, '%Y-%m-%d %H:%M:%S %z').strftime('%y%m%d%H%M') - except Exception as e: - io.stderr(f"Error while parsing commit time for {zone} serial: {e!r}") + except: serial = datetime.now().strftime('%y%m%d0000') primary_zones.add(zone) @@ -92,8 +102,7 @@ if node.metadata.get('powerdns/features/bind', False): files[f'/var/lib/powerdns/zones/{zone}'] = { 'content_type': 'mako', 'context': { - 'NAMESERVERS': '\n'.join(sorted({f'@ IN NS {ns}.' for ns in nameservers})), - 'SERIAL': serial, + 'header': ZONE_HEADER.format(serial=serial), 'metadata_records': node.metadata.get(f'powerdns/bind-zones/{zone}/records', []), }, 'source': f'bind-zones/{zone}', @@ -133,22 +142,12 @@ if node.metadata.get('powerdns/features/bind', False): 'action:powerdns_reload_zones', }, } -else: - files['/etc/powerdns/named.conf'] = { - 'delete': True, - 'needed_by': { - 'svc_systemd:pdns', - }, - 'triggers': { - 'action:powerdns_reload_zones', - }, - } -if node.metadata.get('powerdns/features/pgsql', node.has_bundle('postgresql')): +if node.metadata.get('powerdns/features/pgsql', False): files['/etc/powerdns/pdns.d/pgsql.conf'] = { 'content_type': 'mako', 'context': { - 'password': node.metadata.get('postgresql/roles/powerdns/password'), + 'password': node.metadata['postgresql']['roles']['powerdns']['password'], }, 'needs': { 'pkg_apt:pdns-backend-pgsql', @@ -161,45 +160,16 @@ if node.metadata.get('powerdns/features/pgsql', node.has_bundle('postgresql')): }, } + files['/etc/powerdns/schema.pgsql.sql'] = {} + actions['powerdns_load_pgsql_schema'] = { - 'command': node.metadata.get('postgresql/roles/powerdns/password').format_into('PGPASSWORD={} psql -h 127.0.0.1 -d powerdns -U powerdns -w < /usr/share/pdns-backend-pgsql/schema/schema.pgsql.sql'), - 'unless': r'sudo -u postgres psql -d powerdns -c "\dt" | grep domains 2>&1 >/dev/null', + 'command': node.metadata['postgresql']['roles']['powerdns']['password'].format_into('PGPASSWORD={} psql -h 127.0.0.1 -d powerdns -U powerdns -w < /etc/powerdns/schema.pgsql.sql'), + 'unless': 'sudo -u postgres psql -d powerdns -c "\dt" | grep domains 2>&1 >/dev/null', 'needs': { 'bundle:postgresql', - 'pkg_apt:pdns-backend-pgsql', + 'file:/etc/powerdns/schema.pgsql.sql', }, 'needed_by': { 'svc_systemd:pdns', }, } - - for hostname, ips in node.metadata.get('powerdns/my_primary_servers', {}).items(): - for ip in ips: - ip_name = ip.replace(':', '-') - - actions[f'powerdns_ensure_{ip_name}_in_autoprimaries'] = { - 'command': f'psql -c "INSERT INTO supermasters (ip, nameserver, account) VALUES (\'{ip}\', \'{hostname}\', \'admin\')" powerdns', - 'unless': f'test -n \"$(psql -tAqc "SELECT nameserver FROM supermasters WHERE ip = \'{ip}\'" powerdns)\"', - 'triggers': { - 'action:powerdns_fix_primaries', - }, - 'after': { - 'action:powerdns_load_pgsql_schema', - }, - } - - actions[f'powerdns_ensure_{hostname}_matches_{ip_name}_in_autoprimaries'] = { - 'command': f'psql -c "UPDATE supermasters SET nameserver = \'{hostname}\' WHERE ip = \'{ip}\'" powerdns', - 'unless': f'bash -c "[ \"$(psql -tAqc "SELECT nameserver FROM supermasters WHERE ip = \'{ip}\'" powerdns)\" == \"{hostname}\" ]"', - 'triggers': { - 'action:powerdns_fix_primaries', - }, - 'after': { - f'action:powerdns_ensure_{ip_name}_in_autoprimaries', - }, - } - - actions['powerdns_fix_primaries'] = { - 'command': f'psql -c "UPDATE domains SET master = \'{", ".join(sorted(my_primary_servers))}\'" powerdns', - 'triggered': True, - } diff --git a/bundles/powerdns/metadata.py b/bundles/powerdns/metadata.py index 5437657..57f46f5 100644 --- a/bundles/powerdns/metadata.py +++ b/bundles/powerdns/metadata.py @@ -1,4 +1,4 @@ -from ipaddress import IPv4Address, IPv6Address, ip_address +from ipaddress import ip_address, IPv4Address, IPv6Address from bundlewrap.metadata import atomic @@ -43,11 +43,7 @@ if node.has_bundle('telegraf'): defaults['telegraf'] = { 'input_plugins': { 'builtin': { - 'powerdns': [{ - 'unix_sockets': [ - '/var/run/pdns/pdns.controlsocket', - ], - }], + 'powerdns': [{}], }, }, 'additional_groups': { @@ -86,8 +82,6 @@ def get_ips_of_secondary_nameservers(metadata): ips = set() for rnode in repo.nodes_in_group('dns'): if rnode.metadata.get('powerdns/is_secondary', False): - if rnode.name == node.name: - raise BundleError(f'{node.name} cannot be its own secondary') for _, found_ips in repo.libs.tools.resolve_identifier(repo, rnode.name).items(): ips.update({str(ip) for ip in found_ips}) @@ -104,15 +98,11 @@ def get_ips_of_primary_nameservers(metadata): if not metadata.get('powerdns/is_secondary', False): return {} - ips = {} + ips = set() for rnode in repo.nodes_in_group('dns'): if not rnode.metadata.get('powerdns/is_secondary', False): - if rnode.name == node.name: - raise BundleError(f'{node.name} cannot be its own secondary') - hostname = rnode.metadata.get('hostname') - ips[hostname] = set() for _, found_ips in repo.libs.tools.resolve_identifier(repo, rnode.name).items(): - ips[hostname].update({str(ip) for ip in found_ips}) + ips.update({str(ip) for ip in found_ips}) return { 'powerdns': { @@ -134,7 +124,7 @@ def generate_dns_entries_for_nodes(metadata): ip4 = None ip6 = None - found_ips = repo.libs.tools.resolve_identifier(repo, rnode.name, only_physical=True) + found_ips = repo.libs.tools.resolve_identifier(repo, rnode.name) for ip in sorted(found_ips['ipv4']): if not ip4 and not ip.is_private: ip4 = ip @@ -143,14 +133,31 @@ def generate_dns_entries_for_nodes(metadata): if not ip6 and not ip.is_private: ip6 = ip - if not (ip4 or ip6) and (found_ips['ipv4'] or found_ips['ipv6']): - # do it again, but do not filter out private addresses - for ip in sorted(found_ips['ipv4']): - if not ip4: - ip4 = ip - for ip in sorted(found_ips['ipv6']): - if not ip6: - ip6 = ip + if not ip4 and found_ips['ipv4']: + # This node apparently does not have a public IPv4 address. + # We now manually iterate over that nodes interfaces to get + # a IPv4 address which is tied to a physical interface. + # Note we can't use resolve_identifier() here, because we + # only want physical interfaces. + for interface, config in rnode.metadata.get('interfaces', {}).items(): + if not ( + interface.startswith('bond') or + interface.startswith('br') or + interface.startswith('eno') or + interface.startswith('enp') or + interface.startswith('eth') or + interface == 'default' # dummy nodes use these + ): + continue + + for ip in sorted(config.get('ips', set())): + if '/' in ip: + addr = ip_address(ip.split('/')[0]) + else: + addr = ip_address(ip) + + if not ip4 and isinstance(addr, IPv4Address): + ip4 = addr if ip4: results.add('{} IN A {}'.format(dns_name, ip4)) @@ -179,16 +186,16 @@ def hosts_entries_for_all_dns_servers(metadata): if rnode.name == node.name: continue - found_ips = repo.libs.tools.resolve_identifier(repo, rnode.name) - for ip in sorted(found_ips['ipv4']): - if not ip.is_private: - entries[str(ip)] = { - rnode.metadata.get('hostname'), - rnode.name, - } + ip = rnode.metadata.get('external_ipv4') - if rnode.metadata.get('powerdns/my_hostname', None): - entries[str(ip)].add(rnode.metadata.get('powerdns/my_hostname')) + if ip: + entries[ip] = { + rnode.metadata.get('hostname'), + rnode.name, + } + + if rnode.metadata.get('powerdns/my_hostname', None): + entries[ip].add(rnode.metadata.get('powerdns/my_hostname')) return { 'hosts': { @@ -204,9 +211,8 @@ def firewall(metadata): return { 'firewall': { 'port_rules': { - '53/tcp': atomic(metadata.get('powerdns/restrict-to/dns', {'*'})), - '53/udp': atomic(metadata.get('powerdns/restrict-to/dns', {'*'})), - '8081/tcp': atomic(metadata.get('powerdns/restrict-to/api', set())), + '53': atomic(metadata.get('powerdns/restrict-to', {'*'})), + '53/udp': atomic(metadata.get('powerdns/restrict-to', {'*'})), }, }, } diff --git a/bundles/powerdnsadmin/files/powerdnsadmin.service b/bundles/powerdnsadmin/files/powerdnsadmin.service index 1153886..333cfe7 100644 --- a/bundles/powerdnsadmin/files/powerdnsadmin.service +++ b/bundles/powerdnsadmin/files/powerdnsadmin.service @@ -9,7 +9,7 @@ Group=powerdnsadmin Environment=FLASK_CONF=/opt/powerdnsadmin/config.py WorkingDirectory=/opt/powerdnsadmin/src ExecStartPre=-/bin/chown powerdnsadmin:powerdnsadmin /opt/powerdnsadmin/src/powerdnsadmin/static -ExecStart=/opt/powerdnsadmin/venv/bin/gunicorn 'powerdnsadmin:create_app()' --name powerdnsadmin --workers 4 --max-requests 1200 --max-requests-jitter 50 --log-level=info --bind=127.0.0.1:22100 +ExecStart=/opt/powerdnsadmin/venv/bin/gunicorn 'powerdnsadmin:create_app()' [Install] WantedBy=multi-user.target diff --git a/bundles/powerdnsadmin/items.py b/bundles/powerdnsadmin/items.py index 8398916..7cdf08c 100644 --- a/bundles/powerdnsadmin/items.py +++ b/bundles/powerdnsadmin/items.py @@ -21,14 +21,10 @@ git_deploy = { files = { '/opt/powerdnsadmin/config.py': { 'content_type': 'mako', - 'triggers': { - 'svc_systemd:powerdnsadmin:restart', - }, }, '/etc/systemd/system/powerdnsadmin.service': { 'triggers': { 'action:systemd-reload', - 'svc_systemd:powerdnsadmin:restart', }, }, } @@ -40,13 +36,10 @@ actions = { 'needs': { 'directory:/opt/powerdnsadmin', # provided by bundle:users }, - 'after': { - 'pkg_apt:', - }, }, 'powerdnsadmin_install_deps': { 'triggered': True, - 'command': '/opt/powerdnsadmin/venv/bin/pip install --upgrade psycopg2-binary -r /opt/powerdnsadmin/src/requirements.txt', + 'command': '/opt/powerdnsadmin/venv/bin/pip install -r /opt/powerdnsadmin/src/requirements.txt', 'needs': { 'action:powerdnsadmin_create_virtualenv', 'pkg_apt:', @@ -71,8 +64,8 @@ actions = { 'chown -R powerdnsadmin:powerdnsadmin /opt/powerdnsadmin/src/powerdnsadmin/static/', ]), 'needs': { + 'action:nodejs_install_yarn', 'action:powerdnsadmin_install_deps', - 'bundle:nodejs', 'pkg_apt:', }, }, diff --git a/bundles/powerdnsadmin/metadata.py b/bundles/powerdnsadmin/metadata.py index c2b2c1e..8389941 100644 --- a/bundles/powerdnsadmin/metadata.py +++ b/bundles/powerdnsadmin/metadata.py @@ -10,12 +10,10 @@ defaults = { 'libxmlsec1-dev': {}, 'libxslt1-dev': {}, 'pkg-config': {}, + 'python3-psycopg2': {}, 'python3-wheel': {}, }, }, - 'nodejs': { - 'version': 22, - }, 'users': { 'powerdnsadmin': { 'home': '/opt/powerdnsadmin', @@ -53,27 +51,3 @@ def icinga_check_for_new_release(metadata): }, }, } - - -@metadata_reactor.provides( - 'nginx/vhosts/powerdnsadmin', -) -def nginx(metadata): - if not node.has_bundle('nginx'): - raise DoNotRunAgain - - return { - 'nginx': { - 'vhosts': { - 'powerdnsadmin': { - 'locations': { - '/': { - 'target': 'http://127.0.0.1:22100', - }, - }, - 'website_check_path': '/login', - 'website_check_string': 'PowerDNS', - }, - }, - }, - } diff --git a/bundles/pppd/files/check_dyndns_update b/bundles/pppd/files/check_dyndns_update new file mode 100644 index 0000000..eaf8dfe --- /dev/null +++ b/bundles/pppd/files/check_dyndns_update @@ -0,0 +1,20 @@ +#!/bin/bash + +[[ -n "$DEBUG" ]] && set -x + +interface="$(ip link show | awk '/ ppp/ {print substr($2, 1, length($2)-1)}')" +addr="$(ip addr show dev "$interface" | awk '/inet / {print $2}')" +resolved="$(dig +short "${domain}" A)" + +if [[ -z "$addr" ]] || [[ -z "$resolved" ]] +then + echo "Address on '$interface' is '$addr' - resolved '$resolved'" + exit 3 +elif [[ "$addr" == "$resolved" ]] +then + echo "Resolved IP for ${domain} matches current ip on $interface" + exit 0 +else + echo "Resolved $resolved for ${domain}, but got $addr on $interface!" + exit 2 +fi diff --git a/bundles/pppd/files/dyndns b/bundles/pppd/files/dyndns index 633915f..a88d7c5 100644 --- a/bundles/pppd/files/dyndns +++ b/bundles/pppd/files/dyndns @@ -1,58 +1,23 @@ #!/usr/bin/env python3 -import logging -from ipaddress import ip_address -from json import loads -from subprocess import check_output +import requests +from sys import argv -from requests import get +INTERFACE = argv[1] +LOCAL_IP = argv[4] UPDATE_URL = '${url}' USERNAME = '${username}' PASSWORD = '${password}' -# <%text> -logging.basicConfig(level=logging.INFO) -LOG = logging.getLogger('DynDNS') -try: - ips = set() - - iproute = loads(check_output(['ip', '-json', 'address', 'show', 'scope', 'global'])) - - for iface in iproute: - if not iface['ifname'].startswith('ppp'): - LOG.debug(f'ignoring {iface["ifname"]}') - continue - - LOG.info(f'working on {iface["ifname"]}') - for ip in iface['addr_info']: - try: - addr = ip_address(ip['local']) - - LOG.info(f'{iface["ifname"]} has ip {addr.compressed}') - ips.add(addr.compressed) - except Exception: - continue - - if ips: - LOG.info('got some addresses!') - break - - url = UPDATE_URL.format( - ips=','.join(sorted(ips)) +r = requests.get( + UPDATE_URL.format( + ip=LOCAL_IP, + ), + auth=( + USERNAME, + PASSWORD, ) +) - LOG.info(url) - - r = get( - url, - auth=( - USERNAME, - PASSWORD, - ), - ) - r.raise_for_status() -except Exception as e: - logging.exception(e) - -# +print('got status {} when updating dns'.format(r.status_code)) diff --git a/bundles/pppd/files/dyndns_periodic b/bundles/pppd/files/dyndns_periodic index 353ee6d..3aebb47 100644 --- a/bundles/pppd/files/dyndns_periodic +++ b/bundles/pppd/files/dyndns_periodic @@ -1,51 +1,17 @@ -#!/usr/bin/env python3 +#!/bin/bash -import logging -from ipaddress import ip_address -from json import loads -from subprocess import check_output, run +[[ -n "$DEBUG" ]] && set -x -DOMAIN = '${domain}' +interface="$(ip link show | awk '/ ppp/ {print substr($2, 1, length($2)-1)}')" +addr="$(ip addr show dev "$interface" | awk '/inet / {print $2}')" +resolved="$(dig +short "${domain}" A)" -# <%text> -logging.basicConfig(level=logging.INFO) -LOG = logging.getLogger('DynDNS checker') -try: - iproute = loads(check_output(['ip', '-json', 'address', 'show', 'scope', 'global'])) - resolved_ipv4 = check_output(['dig', '+short', DOMAIN, 'A']).decode().strip() - resolved_ipv6 = check_output(['dig', '+short', DOMAIN, 'AAAA']).decode().strip() - - LOG.info(f'resolved ipv4 is "{resolved_ipv4}"') - LOG.info(f'resolved ipv6 is "{resolved_ipv6}"') - - needs_changing = False - - for iface in iproute: - if not iface['ifname'].startswith('ppp'): - LOG.debug(f'ignoring {iface["ifname"]}') - continue - - LOG.info(f'working on {iface["ifname"]}') - for ip in iface['addr_info']: - try: - addr = ip_address(ip['local']) - - LOG.info(f'{iface["ifname"]} has ip {addr.compressed}') - - if ( - (addr.version == 4 and addr.compressed != resolved_ipv4) - or (addr.version == 6 and addr.compressed != resolved_ipv6) - ): - needs_changing = True - except Exception: - continue - - if needs_changing: - LOG.warning('addresses have changed, calling update script!') - run(['/etc/ppp/ip-up.d/dyndns']) - else: - LOG.info('everything is fine') -except Exception as e: - logging.exception(e) - -# +if [[ -z "$addr" ]] || [[ -z "$resolved" ]] +then + echo "Something is wrong:" + echo "Address on '$interface' is '$addr'" + echo "Resolved DNS is '$resolved'" +elif [[ "$addr" != "$resolved" ]] +then + /etc/ppp/ip-up.d/dyndns "$interface" "doesnt" "matter" "$addr" +fi diff --git a/bundles/pppd/files/ip-up b/bundles/pppd/files/ip-up index 2ac4934..8eba2b9 100644 --- a/bundles/pppd/files/ip-up +++ b/bundles/pppd/files/ip-up @@ -2,7 +2,7 @@ INTERFACE=$1 -echo "add rule nat postrouting oifname $INTERFACE masquerade" > /etc/nftables-rules.d/90-pppd +echo "add rule nat postrouting oif $INTERFACE masquerade" > /etc/nftables-rules.d/90-pppd % for rule in sorted(nftables): echo "add rule ${rule}" >> /etc/nftables-rules.d/90-pppd % endfor diff --git a/bundles/pppd/items.py b/bundles/pppd/items.py index cf21a6f..8d94950 100644 --- a/bundles/pppd/items.py +++ b/bundles/pppd/items.py @@ -110,6 +110,11 @@ if node.metadata.get('pppd/dyndns', {}): 'context': node.metadata.get('pppd/dyndns'), 'mode': '0755', } + files['/usr/local/share/icinga/plugins/check_dyndns_update'] = { + 'content_type': 'mako', + 'context': node.metadata.get('pppd/dyndns'), + 'mode': '0755', + } files['/usr/local/bin/dyndns_periodic'] = { 'content_type': 'mako', 'context': node.metadata.get('pppd/dyndns'), diff --git a/bundles/pppd/metadata.py b/bundles/pppd/metadata.py index 75274a5..9d8792b 100644 --- a/bundles/pppd/metadata.py +++ b/bundles/pppd/metadata.py @@ -39,3 +39,24 @@ def ignore_interface(metadata): }, }, } + + +@metadata_reactor.provides( + 'icinga2_api/pppd/services', +) +def icinga_dyndns(metadata): + if not metadata.get('pppd/dyndns', {}): + return {} + + return { + 'icinga2_api': { + 'pppd': { + 'services': { + 'DYNDNS UPDATE': { + 'command_on_monitored_host': '/usr/local/share/icinga/plugins/check_dyndns_update', + 'vars.notification.mail': True, + }, + }, + }, + }, + } diff --git a/bundles/pretalx/files/pretalx-administrators-from-group b/bundles/pretalx/files/pretalx-administrators-from-group index 3253000..c1dcf80 100644 --- a/bundles/pretalx/files/pretalx-administrators-from-group +++ b/bundles/pretalx/files/pretalx-administrators-from-group @@ -1,10 +1,9 @@ #!/usr/bin/env python3 +import psycopg2 from configparser import ConfigParser from sys import argv, exit -import psycopg2 - def main(): try: diff --git a/bundles/pretalx/items.py b/bundles/pretalx/items.py index e6b22a4..e5b65d1 100644 --- a/bundles/pretalx/items.py +++ b/bundles/pretalx/items.py @@ -1,6 +1,3 @@ -assert node.has_bundle('redis'), f'{node.name}: pretalx needs redis' -assert node.has_bundle('nodejs'), f'{node.name}: pretalx needs nodejs for rebuild step' - actions = { 'pretalx_create_virtualenv': { 'command': '/usr/bin/python3 -m virtualenv -p python3 /opt/pretalx/venv/', @@ -11,20 +8,17 @@ actions = { }, }, 'pretalx_install': { - 'command': ' && '.join([ - 'cd /opt/pretalx/src', - '/opt/pretalx/venv/bin/pip install --upgrade pip wheel gunicorn psycopg2-binary', + 'command': + 'cd /opt/pretalx/src/src && ' + '/opt/pretalx/venv/bin/pip install --upgrade pip wheel gunicorn psycopg2-binary && ' '/opt/pretalx/venv/bin/pip install --upgrade -e .[redis]', - ]), 'needs': { 'action:pretalx_create_virtualenv', - 'pkg_apt:gcc', - 'pkg_apt:python3-dev', }, 'triggered': True, }, 'pretalx_migrate': { - 'command': '/usr/bin/sudo -Hu pretalx PRETALX_CONFIG_FILE=/opt/pretalx/pretalx.cfg /opt/pretalx/venv/bin/python -m pretalx migrate', + 'command': 'PRETALX_CONFIG_FILE=/opt/pretalx/pretalx.cfg /opt/pretalx/venv/bin/python -m pretalx migrate', 'needs': { 'action:pretalx_install', 'file:/opt/pretalx/pretalx.cfg', @@ -34,22 +28,24 @@ actions = { 'triggered': True, }, 'pretalx_rebuild': { - 'command': ' && '.join([ - 'cd /opt/pretalx/src/src/pretalx/frontend/schedule-editor/', - 'npm install', - 'PRETALX_CONFIG_FILE=/opt/pretalx/pretalx.cfg /opt/pretalx/venv/bin/python -m pretalx rebuild', - ]), + 'command': 'PRETALX_CONFIG_FILE=/opt/pretalx/pretalx.cfg /opt/pretalx/venv/bin/python -m pretalx rebuild', 'needs': { 'action:pretalx_install', 'action:pretalx_migrate', 'directory:/opt/pretalx/data', 'directory:/opt/pretalx/static', 'file:/opt/pretalx/pretalx.cfg', - 'bundle:nodejs', }, - 'triggers': { - # pretalx-web reads the manifest.json generated by this build-step upon startup - 'svc_systemd:pretalx-web:restart', + 'triggered': True, + }, + 'pretalx_regenerate-css': { + 'command': 'sudo -u pretalx PRETALX_CONFIG_FILE=/opt/pretalx/pretalx.cfg /opt/pretalx/venv/bin/python -m pretalx regenerate_css', + 'needs': { + 'action:pretalx_install', + 'action:pretalx_migrate', + 'directory:/opt/pretalx/data', + 'directory:/opt/pretalx/static', + 'file:/opt/pretalx/pretalx.cfg', }, 'triggered': True, }, @@ -74,17 +70,19 @@ directories = { git_deploy = { '/opt/pretalx/src': { 'repo': 'https://github.com/pretalx/pretalx.git', - 'rev': node.metadata.get('pretalx/version'), + 'rev': node.metadata['pretalx']['version'], 'triggers': { 'action:pretalx_install', 'action:pretalx_migrate', 'action:pretalx_rebuild', + 'action:pretalx_regenerate-css', 'svc_systemd:pretalx-web:restart', 'svc_systemd:pretalx-worker:restart', }, }, } + svc_systemd = { 'pretalx-runperiodic.timer': { 'needs': { @@ -109,6 +107,7 @@ svc_systemd = { 'action:pretalx_install', 'action:pretalx_migrate', 'action:pretalx_rebuild', + 'action:pretalx_regenerate-css', 'file:/etc/systemd/system/pretalx-web.service', 'file:/opt/pretalx/pretalx.cfg', }, @@ -117,7 +116,6 @@ svc_systemd = { 'needs': { 'action:pretalx_install', 'action:pretalx_migrate', - 'action:pretalx_rebuild', 'file:/etc/systemd/system/pretalx-worker.service', 'file:/opt/pretalx/pretalx.cfg', }, @@ -127,12 +125,15 @@ svc_systemd = { files = { '/opt/pretalx/pretalx.cfg': { 'content_type': 'mako', - 'context': node.metadata.get('pretalx'), + 'context': node.metadata['pretalx'], 'triggers': { 'svc_systemd:pretalx-web:restart', 'svc_systemd:pretalx-worker:restart', }, }, + '/opt/pretalx/pretalx-administrators-from-group': { + 'mode': '0755', + }, '/etc/systemd/system/pretalx-runperiodic.timer': { 'triggers': { 'action:systemd-reload', @@ -169,16 +170,24 @@ files = { }, } +if node.metadata.get('pretalx/administrators-from-group-id', None): + files['/etc/cron.d/pretalx-administrators-from-group'] = { + 'source': 'cron-pretalx-administrators-from-group', + 'content_type': 'mako', + } +else: + files['/etc/cron.d/pretalx-administrators-from-group'] = { + 'delete': True, + } + # run `pip install` one after another due to concurrency issues last_action = 'action:pretalx_install' for plugin_name, plugin_config in node.metadata.get('pretalx/plugins', {}).items(): - assert '-' not in plugin_name, f'{node.name} pretalx plugin {plugin_name} must not contain dashes' - directories[f'/opt/pretalx/plugin_{plugin_name}'] = {} git_deploy[f'/opt/pretalx/plugin_{plugin_name}'] = { 'repo': plugin_config['repo'], - 'rev': plugin_config.get('rev', 'master'), + 'rev': plugin_config['rev'], 'triggers': { f'action:pretalx_install_plugin_{plugin_name}', }, @@ -192,6 +201,7 @@ for plugin_name, plugin_config in node.metadata.get('pretalx/plugins', {}).items 'triggers': { 'action:pretalx_migrate', 'action:pretalx_rebuild', + 'action:pretalx_regenerate-css', 'svc_systemd:pretalx-web:restart', 'svc_systemd:pretalx-worker:restart', }, diff --git a/bundles/pretalx/metadata.py b/bundles/pretalx/metadata.py index 15b61e3..3c52e15 100644 --- a/bundles/pretalx/metadata.py +++ b/bundles/pretalx/metadata.py @@ -1,19 +1,17 @@ defaults = { 'apt': { 'packages': { - 'gcc': {}, # for compiling some python deps 'gettext': {}, - 'python3-dev': {}, }, }, - 'bash_aliases': { - 'pretalx': 'sudo /opt/pretalx/venv/bin/python -m pretalx', - }, 'backups': { 'paths': { '/opt/pretalx/data', }, }, + 'bash_aliases': { + 'pretalx': 'sudo /opt/pretalx/venv/bin/python -m pretalx', + }, 'icinga2_api': { 'pretalx': { 'services': { @@ -26,9 +24,6 @@ defaults = { }, }, }, - 'nodejs': { - 'version': 22, - }, 'pretalx': { 'database': { 'user': 'pretalx', diff --git a/bundles/proftpd/items.py b/bundles/proftpd/items.py deleted file mode 100644 index 506fb1b..0000000 --- a/bundles/proftpd/items.py +++ /dev/null @@ -1,13 +0,0 @@ -files['/etc/proftpd/proftpd.conf'] = { - 'source': f'{node.name}.conf', - 'triggers': { - 'svc_systemd:proftpd:restart', - }, -} - -svc_systemd['proftpd'] = { - 'needs': { - 'file:/etc/proftpd/proftpd.conf', - 'pkg_apt:proftpd-core', - }, -} diff --git a/bundles/proftpd/metadata.py b/bundles/proftpd/metadata.py deleted file mode 100644 index ad33bfb..0000000 --- a/bundles/proftpd/metadata.py +++ /dev/null @@ -1,26 +0,0 @@ -from bundlewrap.metadata import atomic - -defaults = { - 'apt': { - 'packages': { - 'proftpd-core': {}, - }, - }, -} - - -@metadata_reactor.provides( - 'firewall/port_rules', -) -def firewall(metadata): - sources = atomic(metadata.get('mosquitto/restrict-to', set())) - - return { - 'firewall': { - 'port_rules': { - '20/tcp': sources, - '21/tcp': sources, - '49152-50192/tcp': sources, - }, - }, - } diff --git a/bundles/pyenv/items.py b/bundles/pyenv/items.py deleted file mode 100644 index 97f1439..0000000 --- a/bundles/pyenv/items.py +++ /dev/null @@ -1,28 +0,0 @@ -from shlex import quote - -directories = { - '/opt/pyenv': {}, - '/opt/pyenv/install': {}, -} - -git_deploy = { - '/opt/pyenv/install': { - 'repo': 'https://github.com/pyenv/pyenv.git', - 'rev': node.metadata.get('pyenv/version'), - 'needs': { - 'directory:/opt/pyenv/install', - }, - }, -} - -for version in node.metadata.get('pyenv/python_versions', set()): - actions[f'pyenv_install_{version}'] = { - 'command': f'PYENV_ROOT=/opt/pyenv /opt/pyenv/install/bin/pyenv install {quote(version)}', - 'unless': f'PYENV_ROOT=/opt/pyenv /opt/pyenv/install/bin/pyenv versions --bare | grep -E "^{quote(version)}$"', - 'needs': { - 'git_deploy:/opt/pyenv/install', - }, - 'after': { - 'pkg_apt:', - }, - } diff --git a/bundles/pyenv/metadata.py b/bundles/pyenv/metadata.py deleted file mode 100644 index 177a2b3..0000000 --- a/bundles/pyenv/metadata.py +++ /dev/null @@ -1,20 +0,0 @@ -defaults = { - 'apt': { - 'packages': { - 'build-essential': {}, - 'curl': {}, - 'libbz2-dev': {}, - 'libffi-dev': {}, - 'liblzma-dev': {}, - 'libncurses-dev': {}, - 'libreadline-dev': {}, - 'libsqlite3-dev': {}, - 'libssl-dev': {}, - 'libxml2-dev': {}, - 'libxmlsec1-dev': {}, - 'tk-dev': {}, - 'xz-utils': {}, - 'zlib1g-dev': {}, - }, - }, -} diff --git a/bundles/radvd/files/radvd.conf b/bundles/radvd/files/radvd.conf index ee40111..10b7fc7 100644 --- a/bundles/radvd/files/radvd.conf +++ b/bundles/radvd/files/radvd.conf @@ -2,21 +2,19 @@ interface ${interface} { AdvSendAdvert on; - MinRtrAdvInterval 60; - MaxRtrAdvInterval 300; + MinRtrAdvInterval 10; + MaxRtrAdvInterval 30; MinDelayBetweenRAs 10; prefix ${config.get('prefix', '::/64')} { AdvOnLink on; AdvAutonomous on; AdvRouterAddr on; - AdvPreferredLifetime 600; - AdvValidLifetime 900; }; -% if config.get('rdnss'): +% if 'rdnss' in config: RDNSS ${' '.join(sorted(config['rdnss']))} { - AdvRDNSSLifetime 600; + AdvRDNSSLifetime 900; }; % endif }; diff --git a/bundles/raspberrypi/files/config.txt b/bundles/raspberrypi/files/config.txt index bf6751e..00079b2 100644 --- a/bundles/raspberrypi/files/config.txt +++ b/bundles/raspberrypi/files/config.txt @@ -1,30 +1,22 @@ disable_overscan=1 +hdmi_force_hotplug=1 +dtparam=spi=on dtparam=audio=on -dtoverlay=vc4-kms-v3d +dtoverlay=vc4-fkms-v3d max_framebuffers=2 +hdmi_drive=2 force_turbo=1 -gpu_mem=${node.metadata.get('raspberrypi/gpu_mem', 128)} - -% if node.metadata.get('raspberrypi/enable_display'): -display_auto_detect=1 -% else: -dtparam=i2c_arm=on -dtparam=i2s=on -dtparam=spi=on -hdmi_drive=2 -hdmi_force_hotplug=1 -% endif +gpu_mem=${node.metadata['raspberrypi'].get('gpu_mem', 128)} % if node.os == 'debian': arm_64bit=1 % endif -arm_boost=1 -% for item in sorted(node.metadata.get('raspberrypi/config.txt', set())): +% for item in sorted(node.metadata['raspberrypi'].get('config.txt', set())): ${item} % endfor -% if node.metadata.get('raspberrypi/enable_camera', False): -camera_auto_detect=1 +% if node.metadata['raspberrypi'].get('camera', False): +start_x=1 % endif diff --git a/bundles/raspberrypi/items.py b/bundles/raspberrypi/items.py index 41f5544..aab459a 100644 --- a/bundles/raspberrypi/items.py +++ b/bundles/raspberrypi/items.py @@ -15,11 +15,11 @@ actions = { } files = { - '/boot/firmware/cmdline.txt': { + '/boot/cmdline.txt': { 'content': ' '.join(sorted(node.metadata['raspberrypi']['cmdline'])), **file_perms, }, - '/boot/firmware/config.txt': { + '/boot/config.txt': { 'content_type': 'mako', 'context': node.metadata['raspberrypi'], **file_perms, diff --git a/bundles/raspberrypi/metadata.py b/bundles/raspberrypi/metadata.py index 80eac1a..a4c10c2 100644 --- a/bundles/raspberrypi/metadata.py +++ b/bundles/raspberrypi/metadata.py @@ -1,6 +1,5 @@ defaults = { 'apt': { - 'clean_old_kernels': False, 'packages': { 'dhcpcd5': { 'installed': False, @@ -15,16 +14,9 @@ defaults = { 'installed': False, }, }, - 'repos': { - 'raspi': { - 'install_gpg_key': False, - 'items': { - 'deb http://archive.raspberrypi.org/debian/ {os_release} main', - }, - }, - }, }, 'raspberrypi': { + 'default-target': 'multi-user.target', 'cmdline': { 'console=tty1', 'root=/dev/mmcblk0p2', @@ -36,8 +28,6 @@ defaults = { 'plymouth.ignore-serial-consoles', 'net.ifnames=0', }, - 'default-target': 'multi-user.target', - 'enable_display': False, }, 'systemd': { 'journal': { @@ -47,19 +37,3 @@ defaults = { }, }, } - - -@metadata_reactor.provides( - 'raspberrypi/cmdline', -) -def display(metadata): - if not metadata.get('raspberrypi/enable_display'): - return {} - - return { - 'raspberrypi': { - 'cmdline': { - 'video=DSI-1:800x480@60,rotate=180', - }, - }, - } diff --git a/bundles/redis/files/redis.conf b/bundles/redis/files/redis.conf index f636ddf..f479be2 100644 --- a/bundles/redis/files/redis.conf +++ b/bundles/redis/files/redis.conf @@ -48,4 +48,3 @@ tcp-keepalive 0 timeout 0 zset-max-ziplist-entries 128 zset-max-ziplist-value 64 -protected-mode no diff --git a/bundles/redis/metadata.py b/bundles/redis/metadata.py index db31a84..cf15c20 100644 --- a/bundles/redis/metadata.py +++ b/bundles/redis/metadata.py @@ -1,5 +1,3 @@ -from bundlewrap.metadata import atomic - defaults = { 'apt': { 'packages': { @@ -50,16 +48,3 @@ if node.has_bundle('telegraf'): }, }, } - - -@metadata_reactor.provides( - 'firewall/port_rules', -) -def firewall(metadata): - return { - 'firewall': { - 'port_rules': { - '6379/tcp': atomic(metadata.get('redis/restrict-to', set())), - }, - }, - } diff --git a/bundles/routeros/README.md b/bundles/routeros/README.md deleted file mode 100644 index 3b4ccf4..0000000 --- a/bundles/routeros/README.md +++ /dev/null @@ -1,9 +0,0 @@ -RouterOS -======== - -Pulls device configuration from netbox_dump.json and creates items accordingly. - -Notes ------ - -To add management IPs to a VLAN, you need to create a virtual interface in Netbox whose name matches the name of a VLAN. Then add the IP to that virtual interface. diff --git a/bundles/routeros/items.py b/bundles/routeros/items.py deleted file mode 100644 index cd1ec29..0000000 --- a/bundles/routeros/items.py +++ /dev/null @@ -1,172 +0,0 @@ -routeros['/ip/dns'] = { - 'servers': '8.8.8.8', -} - -for service in ( - 'api-ssl', # slow :( - 'ftp', # we can download files via HTTP - 'telnet', - 'www-ssl', # slow :( - 'winbox', -): - routeros[f'/ip/service?name={service}'] = { - 'disabled': True, - } - -for service in ( - 'api', - 'ssh', - 'www', -): - routeros[f'/ip/service?name={service}'] = { - 'disabled': False, - } - -LOGGING_TOPICS = ( - 'critical', - 'error', - 'info', - 'stp', - 'warning', -) - -for topic in LOGGING_TOPICS: - routeros[f'/system/logging?action=memory&topics={topic}'] = {} - -if node.metadata.get('routeros/syslog-server', None): - routeros['/system/logging/action?name=remote'] = { - 'target': 'remote', - 'remote': node.metadata.get('routeros/syslog-server'), - 'remote-port': 514, - } - for topic in LOGGING_TOPICS: - routeros[f'/system/logging?action=remote&topics={topic}'] = {} - -routeros['/snmp'] = { - 'enabled': True, -} -routeros['/snmp/community?name=public'] = { - 'addresses': '::/0', - 'disabled': False, - 'read-access': True, - 'write-access': False, -} - -routeros['/system/clock'] = { - 'time-zone-autodetect': False, - 'time-zone-name': 'UTC', -} - -routeros['/system/identity'] = { - 'name': node.name, - # doing this first gives us some chance to notice an IP mixup - 'before': {'routeros:'}, -} - -routeros['/system/ntp/client'] = { - 'enabled': True, - 'server-dns-names': 'de.pool.ntp.org', -} - -if node.metadata.get('routeros/gateway'): - routeros['/ip/route?dst-address=0.0.0.0/0'] = { - 'gateway': node.metadata.get('routeros/gateway'), - } - -routeros['/interface/bridge?name=bridge'] = { - 'priority': node.metadata.get('routeros/bridge_priority', '0x8000'), - 'protocol-mode': 'rstp', - 'vlan-filtering': True, -} - -# assign bridge ports -for port_name, port_conf in node.metadata.get('routeros/ports').items(): - if port_conf.get('delete'): - routeros[f'/interface/bridge/port?interface={port_name}'] = { - 'delete': True, - 'tags': {'routeros-port'}, - 'needs': {f'routeros:/interface?name={port_name}'}, - } - else: - pvid = port_conf.get('pvid') - if not pvid: - for vlan_name, vlan_conf in node.metadata.get('routeros/vlans').items(): - if port_name in vlan_conf.get('untagged', []): - if pvid: - raise ValueError( - f"{node.name}: port {port_name} untagged " - f"in VLANs {pvid} and {vlan_conf['id']}" - ) - else: - pvid = vlan_conf['id'] - - # Field must not be present of some port types. - if port_conf.get('hw'): - hw = {'hw': port_conf['hw']} - else: - hw = {} - - routeros[f'/interface/bridge/port?interface={port_name}'] = { - 'bridge': 'bridge', - '_comment': port_conf.get('description', ''), - 'disabled': False, - **hw, - 'pvid': pvid or '1', - 'tags': {'routeros-port'}, - 'needs': { - f'routeros:/interface?name={port_name}', - 'routeros:/interface/bridge?name=bridge', - 'tag:routeros-bridge-vlan', # or we end up with dynamic VLANs after setting pvid to an unknown VLAN - }, - } - - routeros[f'/interface?name={port_name}'] = { - '_comment': port_conf.get('description', ''), - 'disabled': port_conf.get('disabled', False) - and not port_conf.get('delete', False), - } - - -# create IPs -for ip, ip_conf in node.metadata.get('routeros/ips').items(): - routeros[f'/ip/address?address={ip}'] = { - 'interface': ip_conf['interface'], - 'tags': {'routeros-ip'}, - 'needs': { - 'tag:routeros-vlan', - }, - } - -for vlan, conf in node.metadata.get('routeros/vlans').items(): - if conf['delete']: - # delete old VLANs - routeros[f'/interface/vlan?name={vlan}'] = { - 'delete': True, - } - - routeros[f"/interface/bridge/vlan?vlan-ids={conf['id']}"] = { - 'delete': True, - } - else: - # create vlans - routeros[f'/interface/vlan?name={vlan}'] = { - 'vlan-id': conf['id'], - 'interface': 'bridge', - 'tags': {'routeros-vlan'}, - 'needs': { - 'routeros:/interface/bridge?name=bridge', - }, - } - - # assign ports to vlans - routeros[f"/interface/bridge/vlan?vlan-ids={conf['id']}"] = { - 'bridge': 'bridge', - 'untagged': sorted(conf['untagged']), - 'tagged': sorted(conf['tagged']), - '_comment': vlan, - 'tags': {'routeros-bridge-vlan'}, - 'needs': { - 'routeros:/interface/bridge?name=bridge', - 'tag:routeros-vlan', - }, - } diff --git a/bundles/routeros/metadata.py b/bundles/routeros/metadata.py deleted file mode 100644 index e987a4e..0000000 --- a/bundles/routeros/metadata.py +++ /dev/null @@ -1,115 +0,0 @@ -import re -from json import load -from os.path import join - -with open(join(repo.path, 'configs', 'netbox', f'{node.name}.json')) as f: - netbox = load(f) - -ips = {} -ports = {} -vlans = { - v['name']: { - 'id': v['vid'], - 'delete': False, - 'tagged': set(), - 'untagged': set(), - } - for v in netbox['vlans'] -} - -for port, conf in netbox['interfaces'].items(): - for ip in conf['ips']: - ips[ip] = {'interface': port} - - if conf['type'].lower() == 'virtual': - # these are VLAN interfaces (for management IPs) - if conf['ips']: - # this makes management services available in the VLAN - try: - vlans[port]['tagged'].add('bridge') - except KeyError: - raise ValueError( - f'name of virtual interface "{port}" on {node.name} ' - f'matches none of the known VLANs: {list(vlans.keys())} ' - '(you probably need to rename the interface in Netbox ' - 'and/or run netbox-dump)' - ) - # We do not create the actual VLAN interface here, that - # happens automatically in items.py. - continue - elif not conf['enabled'] or not conf['mode']: - # disable unconfigured ports - ports[port] = { - 'disabled': True, - 'description': conf.get('description', ''), - } - # dont add vlans for this port - continue - else: - ports[port] = { - 'disabled': False, - 'description': conf.get('description', ''), - } - if conf.get('ips', []): - ports[port]['ips'] = set(conf['ips']) - if conf['type'] in ( - '1000base-t', - '10gbase-x-sfpp', - 'A_1000BASE_T', - 'A_10GBASE_X_SFPP', - ): - ports[port]['hw'] = True - - if conf['untagged_vlan']: - vlans[conf['untagged_vlan']]['untagged'].add(port) - if conf['ips']: - # this makes management services available in the VLAN - vlans[conf['untagged_vlan']]['tagged'].add('bridge') - - # tagged - - if conf['mode'] in ('TAGGED_ALL', 'tagged-all'): - tagged = set(vlans.keys()) - {conf['untagged_vlan']} - else: - tagged = conf['tagged_vlans'] - - for vlan in tagged: - vlans[vlan]['tagged'].add(port) - - # this makes management services available in the VLAN - if conf['ips']: - vlans[vlan]['tagged'].add('bridge') - -defaults = { - 'icinga2_api': { - 'routeros': { - 'services': { - 'TEMPERATURE': { - 'check_command': 'snmp', - 'vars.snmp_oid': '1.3.6.1.4.1.14988.1.1.3.11.0', - 'vars.snmp_version': '2c', - 'vars.snmp_community': 'public', - 'vars.warn': '@750:799', # 1/10 °C - 'vars.crit': '@800:9999', - }, - }, - }, - }, - 'routeros': { - 'ips': ips, - 'ports': ports, - 'vlans': vlans, - }, -} - - -@metadata_reactor.provides('routeros/gateway') -def gateway(metadata): - ip_pattern = re.compile(r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.)\d{1,3}') - gateway = ip_pattern.match(node.hostname).group(1) + '1' - - return { - 'routeros': { - 'gateway': gateway, - }, - } diff --git a/bundles/rspamd/files/local.d/dmarc.conf b/bundles/rspamd/files/local.d/dmarc.conf index 195361e..fa42ec0 100644 --- a/bundles/rspamd/files/local.d/dmarc.conf +++ b/bundles/rspamd/files/local.d/dmarc.conf @@ -1,7 +1,7 @@ reporting { enabled = true; - email = 'devnull@${node.metadata.get('postfix/myhostname')}'; - domain = '${node.metadata.get('postfix/myhostname')}'; + email = 'dmarc+${node.name.replace('.', '-')}@kunbox.net'; + domain = '${node.metadata.get('hostname')}'; org_name = 'kunbox.net'; smtp = '127.0.0.1'; smtp_port = 25; diff --git a/bundles/rspamd/files/local.d/greylist.conf b/bundles/rspamd/files/local.d/greylist.conf deleted file mode 100644 index a6ee831..0000000 --- a/bundles/rspamd/files/local.d/greylist.conf +++ /dev/null @@ -1 +0,0 @@ -enabled = false; diff --git a/bundles/rspamd/files/telegraf-rspamd-plugin b/bundles/rspamd/files/telegraf-rspamd-plugin index 23e5ccb..9cb2c3d 100644 --- a/bundles/rspamd/files/telegraf-rspamd-plugin +++ b/bundles/rspamd/files/telegraf-rspamd-plugin @@ -1,8 +1,7 @@ #!/usr/bin/env python3 -from sys import argv, stderr - from requests import get +from sys import argv, stderr try: r = get('http://127.0.0.1:11334/stat') diff --git a/bundles/rspamd/items.py b/bundles/rspamd/items.py index 2f9aacb..8fa793c 100644 --- a/bundles/rspamd/items.py +++ b/bundles/rspamd/items.py @@ -96,12 +96,12 @@ if 'dkim' in node.metadata.get('rspamd', {}): }, } - dkim_key = repo.libs.faults.ensure_fault_or_none(node.metadata.get('rspamd/dkim')) + dkim_key = repo.libs.faults.ensure_fault_or_none(node.metadata['rspamd']['dkim']) actions = { 'rspamd_assure_dkim_key_permissions': { 'command': 'chown _rspamd:_rspamd /var/lib/rspamd/dkim/*.key', - 'unless': r'test -z "$(find /var/lib/rspamd/ -iname \"*.key\" \! -user _rspamd)"', + 'unless': 'test -z "$(find /var/lib/rspamd/ -iname \"*.key\" \! -user _rspamd)"', 'needs': { 'action:rspamd_generate_dkim_key', 'directory:/var/lib/rspamd/dkim', diff --git a/bundles/rsyslogd/files/logrotate.conf b/bundles/rsyslogd/files/logrotate.conf deleted file mode 100644 index 66c90fa..0000000 --- a/bundles/rsyslogd/files/logrotate.conf +++ /dev/null @@ -1,10 +0,0 @@ -/var/log/rsyslog/*/*.log -{ - rotate 30 - daily - missingok - notifempty - compress - delaycompress - copytruncate -} diff --git a/bundles/rsyslogd/files/rsyslog.conf b/bundles/rsyslogd/files/rsyslog.conf deleted file mode 100644 index b7ca916..0000000 --- a/bundles/rsyslogd/files/rsyslog.conf +++ /dev/null @@ -1,18 +0,0 @@ -# provides UDP syslog reception -module(load="imudp") -input(type="imudp" port="514") - -# provides TCP syslog reception -module(load="imtcp") -input(type="imtcp" port="514") - -$FileOwner root -$FileGroup adm -$FileCreateMode 0640 -$DirCreateMode 0755 -$Umask 0022 - -$WorkDirectory /var/spool/rsyslog - -$template remote-incoming-logs,"/var/log/rsyslog/%HOSTNAME%/%PROGRAMNAME%.log" -*.* ?remote-incoming-logs diff --git a/bundles/rsyslogd/items.py b/bundles/rsyslogd/items.py deleted file mode 100644 index 1ef2572..0000000 --- a/bundles/rsyslogd/items.py +++ /dev/null @@ -1,18 +0,0 @@ -files['/etc/logrotate.d/rsyslog'] = { - 'source': 'logrotate.conf', -} - -files['/etc/rsyslog.conf'] = { - 'triggers': { - 'svc_systemd:rsyslog:restart', - }, -} - -svc_systemd['rsyslog'] = { - 'needs': { - 'pkg_apt:rsyslog', - }, - 'after': { - 'file:/etc/rsyslog.conf', - }, -} diff --git a/bundles/rsyslogd/metadata.py b/bundles/rsyslogd/metadata.py deleted file mode 100644 index 877e93b..0000000 --- a/bundles/rsyslogd/metadata.py +++ /dev/null @@ -1,37 +0,0 @@ -from bundlewrap.metadata import atomic - -defaults = { - 'apt': { - 'packages': { - 'rsyslog': {}, - }, - }, - 'backups': { - 'paths': { - '/var/log/rsyslog', - }, - }, - 'icinga2_api': { - 'rsyslog': { - 'services': { - 'RSYSLOGD PROCESS': { - 'command_on_monitored_host': '/usr/local/share/icinga/plugins/check_systemd_unit rsyslog', - }, - }, - }, - }, -} - - -@metadata_reactor.provides( - 'firewall/port_rules', -) -def firewall(metadata): - return { - 'firewall': { - 'port_rules': { - '514/tcp': atomic(metadata.get('rsyslogd/restrict-to', set())), - '514/udp': atomic(metadata.get('rsyslogd/restrict-to', set())), - }, - }, - } diff --git a/bundles/samba/files/override.conf b/bundles/samba/files/override.conf deleted file mode 100644 index 35693b4..0000000 --- a/bundles/samba/files/override.conf +++ /dev/null @@ -1,3 +0,0 @@ -[Service] -RestartSec=10 -Restart=on-failure diff --git a/bundles/samba/files/smb.conf b/bundles/samba/files/smb.conf deleted file mode 100644 index 7c4ad0b..0000000 --- a/bundles/samba/files/smb.conf +++ /dev/null @@ -1,67 +0,0 @@ -[global] -workgroup = KUNBOX -server string = ${node.name} samba -dns proxy = no -max log size = 1000 -syslog = 1 -syslog only = 1 -panic action = /usr/share/samba/panic-action %d -encrypt passwords = true -passdb backend = tdbsam -obey pam restrictions = yes -map to guest = bad user -load printers = no -usershare allow guests = yes -allow insecure wide links = yes -min protocol = SMB2 -% if timemachine: -vfs objects = fruit -fruit:aapl = yes -fruit:copyfile = yes -fruit:model = MacSamba -% endif -% for name, opts in sorted(node.metadata.get('samba/shares', {}).items()): - -[${name}] -browseable = yes -comment = ${opts.get('comment', f'share of {opts["path"]}')} -fake oplocks = yes -force group = ${opts.get('force_group', 'nogroup')} -force user = ${opts.get('force_user', 'nobody')} -% if opts.get('guest_ok', True): -guest ok = yes -% else: -guest ok = no -% endif -locking = no -path = ${opts['path']} -printable = no -read only = no -vfs objects = catia fruit -writable = ${'yes' if opts.get('writable', False) else 'no'} -% if opts.get('follow_symlinks', True): -follow symlinks = yes -wide links = yes -% endif -% endfor -% for name in sorted(timemachine): - -[timemachine-${name}] -comment = Time Machine backup for ${name} -available = yes -browseable = yes -guest ok = no -read only = false -valid users = timemachine-${name} -path = /srv/timemachine/${name} -durable handles = yes -vfs objects = catia fruit streams_xattr - -fruit:delete_empty_adfiles = yes -fruit:metadata = stream -fruit:posix_rename = yes -fruit:time machine = yes -fruit:time machine max size = 2000G -fruit:veto_appledouble = no -fruit:wipe_intentionally_left_blank_rfork = yes -% endfor diff --git a/bundles/samba/files/timemachine.service b/bundles/samba/files/timemachine.service deleted file mode 100644 index d25e6e5..0000000 --- a/bundles/samba/files/timemachine.service +++ /dev/null @@ -1,21 +0,0 @@ - - - - %h - - _smb._tcp - 445 - - - _device-info._tcp - 0 - model=RackMac1,2 - - - _adisk._tcp -% for idx, share_name in enumerate(sorted(shares)): - dk${idx}=adVN=timemachine-${share_name},adVF=0x82 -% endfor - sys=waMa=0,adVF=0x100 - - diff --git a/bundles/samba/items.py b/bundles/samba/items.py deleted file mode 100644 index 2f5090e..0000000 --- a/bundles/samba/items.py +++ /dev/null @@ -1,91 +0,0 @@ -svc_systemd = { - 'nmbd': { - 'needs': { - 'pkg_apt:samba', - }, - }, - 'smbd': { - 'needs': { - 'pkg_apt:samba', - }, - }, -} - -timemachine_shares = node.metadata.get('samba/timemachine-shares', set()) - -files = { - '/etc/samba/smb.conf': { - 'content_type': 'mako', - 'context': { - 'timemachine': timemachine_shares, - }, - 'triggers': { - 'svc_systemd:nmbd:restart', - 'svc_systemd:smbd:restart', - }, - }, - '/etc/systemd/system/nmbd.service.d/bundlewrap.conf': { - 'source': 'override.conf', - 'triggers': { - 'action:systemd-reload', - 'svc_systemd:nmbd:restart', - }, - }, - '/etc/systemd/system/smbd.service.d/bundlewrap.conf': { - 'source': 'override.conf', - 'triggers': { - 'action:systemd-reload', - 'svc_systemd:smbd:restart', - }, - }, -} - -last_action = set() -for user, uconfig in node.metadata.get('users', {}).items(): - if ( - 'password' not in uconfig - or uconfig.get('delete') - or user in ('root',) - ): - continue - - actions[f'smbpasswd_for_user_{user}'] = { - 'command': f'smbpasswd -a -s {user}', - 'unless': f'pdbedit -L | grep -E "^{user}:"', - 'data_stdin': uconfig['password'] + '\n' + uconfig['password'], - 'needs': { - 'pkg_apt:samba', - f'user:{user}', - }, - 'after': last_action, - } - last_action = { - f'action:smbpasswd_for_user_{user}', - } - -if timemachine_shares: - assert node.has_bundle('avahi-daemon'), f'{node.name}: samba needs avahi-daemon to publish time machine shares' - - for share, share_config in node.metadata.get('samba/shares', {}).items(): - assert not share_config.get('guest_ok', True), f'{node.name} samba {share}: cannot have time machine shares and "guest ok" shares on the same machine' - - files['/etc/avahi/services/timemachine.service'] = { - 'content_type': 'mako', - 'context': { - 'shares': timemachine_shares, - }, - } - - for share_name in timemachine_shares: - users[f'timemachine-{share_name}'] = { - 'home': f'/srv/timemachine/{share_name}', - } - - directories[f'/srv/timemachine/{share_name}'] = { - 'owner': f'timemachine-{share_name}', - 'group': f'timemachine-{share_name}', - 'mode': '0700', - 'needs': { - f'zfs_dataset:tank/timemachine/{share_name}', - }, - } diff --git a/bundles/samba/metadata.py b/bundles/samba/metadata.py deleted file mode 100644 index c8243af..0000000 --- a/bundles/samba/metadata.py +++ /dev/null @@ -1,53 +0,0 @@ -from bundlewrap.metadata import atomic - -defaults = { - 'apt': { - 'packages': { - 'samba': {}, - 'samba-vfs-modules': {}, - } - } -} - - -@metadata_reactor.provides( - 'firewall/port_rules', -) -def firewall(metadata): - return { - 'firewall': { - 'port_rules': { - '137/udp': atomic(metadata.get('samba/restrict-to', set())), - '138/udp': atomic(metadata.get('samba/restrict-to', set())), - '139/tcp': atomic(metadata.get('samba/restrict-to', set())), - '445/tcp': atomic(metadata.get('samba/restrict-to', set())), - }, - }, - } - - -@metadata_reactor.provides( - 'zfs/datasets', -) -def timemachine_zfs(metadata): - shares = metadata.get('samba/timemachine-shares', set()) - - if not shares: - return {} - - assert node.has_bundle('zfs'), f'{node.name}: time machine backups require zfs' - - datasets = { - 'tank/timemachine': {}, - } - - for share_name in shares: - datasets[f'tank/timemachine/{share_name}'] = { - 'mountpoint': f'/srv/timemachine/{share_name}', - } - - return { - 'zfs': { - 'datasets': datasets, - }, - } diff --git a/bundles/scansnap/files/ocr.sh b/bundles/scansnap/files/ocr.sh new file mode 100644 index 0000000..04e98f9 --- /dev/null +++ b/bundles/scansnap/files/ocr.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +set -euo pipefail + +DATE=$(date +%F_%H-%M-%S) + +cd "$1" + +convert *.tiff no_ocr.pdf +ocrmypdf -l deu no_ocr.pdf has_ocr.pdf + +rm -f *.tiff +rm -f no_ocr.pdf + +chown nobody:nogroup has_ocr.pdf + +mv has_ocr.pdf "/srv/scansnap/${DATE}.pdf" + +cd / + +rm -r "$1" diff --git a/bundles/scansnap/files/scan.sh b/bundles/scansnap/files/scan.sh new file mode 100644 index 0000000..ab5800f --- /dev/null +++ b/bundles/scansnap/files/scan.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +set -euo pipefail + +OUTFILE=$(mktemp -d) + +scanimage --source 'ADF Duplex' --format tiff --mode Color --brightness 23 --resolution 300 --page-width 210 --page-height 297.3 -x 210 -y 297.3 --batch=${OUTFILE}/p%04d.tiff + +/etc/scanbd/scripts/ocr.sh "$OUTFILE" & diff --git a/bundles/scansnap/files/scanbd.conf b/bundles/scansnap/files/scanbd.conf new file mode 100644 index 0000000..f425338 --- /dev/null +++ b/bundles/scansnap/files/scanbd.conf @@ -0,0 +1,52 @@ +global { + debug = true + debug-level = 2 + + user = saned + group = scanner + + saned = "/usr/sbin/saned" + saned_opt = {} + saned_env = { "SANE_CONFIG_DIR=/etc/scanbd" } + + scriptdir = /etc/scanbd/scripts + + timeout = 500 + + pidfile = "/var/run/scanbd.pid" + + environment { + device = "SCANBD_DEVICE" + action = "SCANBD_ACTION" + } + + function function_knob { + filter = "^message.*" + desc = "The value of the function knob / wheel / selector" + env = "SCANBD_FUNCTION" + } + function function_mode { + filter = "^mode.*" + desc = "Color mode" + env = "SCANBD_FUNCTION_MODE" + } + + multiple_actions = false + action scan { + filter = "^scan.*" + numerical-trigger { + from-value = 0 + to-value = 1 + } + desc = "Scan to file" + script = "scan.sh" + } +} + +include(scanner.d/avision.conf) +include(scanner.d/fujitsu.conf) +include(scanner.d/hp.conf) +include(scanner.d/pixma.conf) +include(scanner.d/snapscan.conf) +include(scanner.d/canon.conf) +include(scanner.d/plustek.conf) diff --git a/bundles/scansnap/items.py b/bundles/scansnap/items.py new file mode 100644 index 0000000..23f9305 --- /dev/null +++ b/bundles/scansnap/items.py @@ -0,0 +1,39 @@ +directories = { + '/etc/scanbd/scripts': { + 'purge': True, + }, + '/srv/scansnap': { + 'owner': 'nobody', + 'group': 'nogroup', + }, +} + +files = { + '/etc/scanbd/scanbd.conf': { + 'triggers': { + 'svc_systemd:scanbd:restart', + }, + }, + '/etc/scanbd/scripts/ocr.sh': { + 'mode': '0755', + 'needs': { + 'directory:/srv/scansnap', + }, + }, + '/etc/scanbd/scripts/scan.sh': { + 'mode': '0755', + 'needs': { + 'directory:/srv/scansnap', + 'file:/etc/scanbd/scripts/ocr.sh', + }, + }, +} + +svc_systemd = { + 'scanbd': { + 'needs': { + 'file:/etc/scanbd/scanbd.conf', + 'pkg_apt:scanbd', + }, + }, +} diff --git a/bundles/scansnap/metadata.py b/bundles/scansnap/metadata.py new file mode 100644 index 0000000..b1d5535 --- /dev/null +++ b/bundles/scansnap/metadata.py @@ -0,0 +1,22 @@ +defaults = { + 'apt': { + 'packages': { + 'sane-utils': {}, + 'scanbd': {}, + 'imagemagick': {}, + 'ocrmypdf': {}, + 'tesseract-ocr-deu': {}, + }, + }, + 'backups': { + 'paths': { + '/srv/scansnap', + }, + }, + 'cron': { + 'jobs': { + # Automatically remove files which are older than 14 days + 'scansnap_cleanup': '00 00 * * * root /usr/bin/find /srv/scansnap/ -mindepth 1 -mtime +14 -delete', + }, + }, +} diff --git a/bundles/sdm630_mqtt/files/sdm630_printout.service b/bundles/sdm630_mqtt/files/sdm630_printout.service deleted file mode 100644 index 8ba5a23..0000000 --- a/bundles/sdm630_mqtt/files/sdm630_printout.service +++ /dev/null @@ -1,21 +0,0 @@ -[Unit] -Description=SDM630 stats printout -Conflicts=getty@tty1.service -After=systemd-user-sessions.service getty@tty1.service plymouth-quit.service - -[Service] -User=sdm630_mqtt -Group=sdm630_mqtt -ExecStart=/opt/sdm630_mqtt/venv/bin/python printout.py /opt/sdm630_mqtt/config.toml -WorkingDirectory=/opt/sdm630_mqtt/src -Restart=always -RestartSec=10 -StandardInput=tty -StandardOutput=tty -StandardError=journal -TTYPath=/dev/tty1 -TTYReset=yes -TTYVHangup=yes - -[Install] -WantedBy=multi-user.target diff --git a/bundles/sdm630_mqtt/files/sdm630_to_mqtt.service b/bundles/sdm630_mqtt/files/sdm630_to_mqtt.service deleted file mode 100644 index b1e67d7..0000000 --- a/bundles/sdm630_mqtt/files/sdm630_to_mqtt.service +++ /dev/null @@ -1,14 +0,0 @@ -[Unit] -Description=SDM630-to-MQTT bridge -After=network.target - -[Service] -User=sdm630_mqtt -Group=sdm630_mqtt -ExecStart=/opt/sdm630_mqtt/venv/bin/python sdm630_mqtt.py /opt/sdm630_mqtt/config.toml -WorkingDirectory=/opt/sdm630_mqtt/src -Restart=always -RestartSec=1 - -[Install] -WantedBy=multi-user.target diff --git a/bundles/sdm630_mqtt/items.py b/bundles/sdm630_mqtt/items.py deleted file mode 100644 index 6a691c9..0000000 --- a/bundles/sdm630_mqtt/items.py +++ /dev/null @@ -1,76 +0,0 @@ -directories['/opt/sdm630_mqtt/src'] = {} - -git_deploy['/opt/sdm630_mqtt/src'] = { - 'repo': 'https://git.franzi.business/kunsi/sdm630_mqtt.git', - 'rev': 'main', - 'triggers': { - 'action:sdm630_mqtt_install_deps', - }, -} - -actions['sdm630_mqtt_create_virtualenv'] = { - 'command': 'python3 -m virtualenv /opt/sdm630_mqtt/venv', - 'unless': 'test -x /opt/sdm630_mqtt/venv/bin/python3', - 'needs': { - 'directory:/opt/sdm630_mqtt/src', - }, -} - -actions['sdm630_mqtt_install_deps'] = { - 'command': 'cd /opt/sdm630_mqtt/src && /opt/sdm630_mqtt/venv/bin/pip install -r requirements.txt', - 'triggered': True, - 'needs': { - 'action:sdm630_mqtt_create_virtualenv', - }, -} - -users['sdm630_mqtt'] = { - 'home': '/opt/sdm630_mqtt', -} - -files['/opt/sdm630_mqtt/config.toml'] = { - 'content': repo.libs.faults.dict_as_toml(node.metadata.get('sdm630_mqtt/config')), - 'triggers': set(), -} - -if node.has_bundle('telegraf'): - files['/opt/sdm630_mqtt/config.toml']['triggers'].add('svc_systemd:telegraf:restart') - git_deploy['/opt/sdm630_mqtt/src']['triggers'].add('svc_systemd:telegraf:restart') - -if node.metadata.get('sdm630_mqtt/enable_stats_collection', True): - files['/usr/local/lib/systemd/system/sdm630_to_mqtt.service'] = { - 'triggers': { - 'action:systemd-reload', - 'svc_systemd:sdm630_to_mqtt:restart', - }, - } - - svc_systemd['sdm630_to_mqtt'] = { - 'needs': { - 'git_deploy:/opt/sdm630_mqtt/src', - 'action:sdm630_mqtt_install_deps', - 'file:/usr/local/lib/systemd/system/sdm630_to_mqtt.service', - }, - } - - files['/opt/sdm630_mqtt/config.toml']['triggers'].add('svc_systemd:sdm630_to_mqtt:restart') - git_deploy['/opt/sdm630_mqtt/src']['triggers'].add('svc_systemd:sdm630_to_mqtt:restart') - -if node.metadata.get('sdm630_mqtt/enable_local_printout', False): - files['/usr/local/lib/systemd/system/sdm630_printout.service'] = { - 'triggers': { - 'action:systemd-reload', - 'svc_systemd:sdm630_printout:restart', - }, - } - - svc_systemd['sdm630_printout'] = { - 'needs': { - 'git_deploy:/opt/sdm630_mqtt/src', - 'action:sdm630_mqtt_install_deps', - 'file:/usr/local/lib/systemd/system/sdm630_printout.service', - }, - } - - files['/opt/sdm630_mqtt/config.toml']['triggers'].add('svc_systemd:sdm630_printout:restart') - git_deploy['/opt/sdm630_mqtt/src']['triggers'].add('svc_systemd:sdm630_printout:restart') diff --git a/bundles/sdm630_mqtt/metadata.py b/bundles/sdm630_mqtt/metadata.py deleted file mode 100644 index 944b8b2..0000000 --- a/bundles/sdm630_mqtt/metadata.py +++ /dev/null @@ -1,38 +0,0 @@ -defaults = { - 'sdm630_mqtt': { - 'config': { - 'modbus': { - 'host': '127.0.0.1', - 'port': 501, - 'unit_id': 1, - }, - 'mqtt': { - 'prefix': 'sdm630', - 'host': '127.0.0.1', - 'port': 1883, - }, - 'printout': { - 'title': 'SDM630', - }, - 'telegraf': { - 'identifier': 'unknown', - }, - }, - }, - 'telegraf': { - 'input_plugins': { - 'execd': { - 'sdm630_mqtt': { - 'command': [ - '/opt/sdm630_mqtt/venv/bin/python', - '/opt/sdm630_mqtt/src/telegraf.py', - '/opt/sdm630_mqtt/config.toml', - ], - 'signal': 'none', - 'restart_delay': '1s', - 'data_format': 'influx', - }, - }, - }, - }, -} diff --git a/bundles/seafile/files/seafile.service b/bundles/seafile/files/seafile.service new file mode 100644 index 0000000..5b0a959 --- /dev/null +++ b/bundles/seafile/files/seafile.service @@ -0,0 +1,13 @@ +[Unit] +Description=Seafile +After=network.target mysql.service + +[Service] +Type=forking +ExecStart=/opt/seafile/seafile-server-latest/seafile.sh start +ExecStop=/opt/seafile/seafile-server-latest/seafile.sh stop +User=seafile +Group=seafile + +[Install] +WantedBy=multi-user.target diff --git a/bundles/seafile/files/seahub.service b/bundles/seafile/files/seahub.service new file mode 100644 index 0000000..b554599 --- /dev/null +++ b/bundles/seafile/files/seahub.service @@ -0,0 +1,13 @@ +[Unit] +Description=Seafile hub +After=network.target seafile.service + +[Service] +Type=forking +ExecStart=/opt/seafile/seafile-server-latest/seahub.sh start +ExecStop=/opt/seafile/seafile-server-latest/seahub.sh stop +User=seafile +Group=seafile + +[Install] +WantedBy=multi-user.target diff --git a/bundles/seafile/items.py b/bundles/seafile/items.py new file mode 100644 index 0000000..24c6c72 --- /dev/null +++ b/bundles/seafile/items.py @@ -0,0 +1,41 @@ +users = { + 'seafile': { + 'home': '/opt/seafile', + }, +} + +directories = { + '/opt/seafile': { + 'mode': '0755', + 'owner': 'seafile', + 'group': 'seafile', + }, +} + +files = { + '/etc/systemd/system/seafile.service': { + 'needed_by': { + 'svc_systemd:seafile', + }, + 'triggers': { + 'action:systemd-reload', + }, + }, + '/etc/systemd/system/seahub.service': { + 'needed_by': { + 'svc_systemd:seafile', + }, + 'triggers': { + 'action:systemd-reload', + }, + }, +} + +svc_systemd = { + 'seafile': {}, + 'seahub': { + 'needs': { + 'svc_systemd:seafile', + }, + }, +} diff --git a/bundles/seafile/metadata.py b/bundles/seafile/metadata.py new file mode 100644 index 0000000..66a586d --- /dev/null +++ b/bundles/seafile/metadata.py @@ -0,0 +1,27 @@ +defaults = { + 'apt': { + 'packages': { + 'mariadb-server': {}, + 'python3': {}, + 'python3-setuptools': {}, + 'python3-pip': {}, + }, + }, + 'backups': { + 'paths': { + '/opt/seafile', + }, + }, + 'icinga2_api': { + 'seafile': { + 'services': { + 'SEAFILE PROCESS': { + 'command_on_monitored_host': '/usr/local/share/icinga/plugins/check_systemd_unit seafile', + }, + 'SEAHUB PROCESS': { + 'command_on_monitored_host': '/usr/local/share/icinga/plugins/check_systemd_unit seahub', + }, + }, + }, + }, +} diff --git a/bundles/simple-icinga-dashboard/files/config.toml b/bundles/simple-icinga-dashboard/files/config.toml new file mode 100644 index 0000000..b72063a --- /dev/null +++ b/bundles/simple-icinga-dashboard/files/config.toml @@ -0,0 +1,4 @@ +<% + from tomlkit import dumps as toml_dumps + from bundlewrap.utils.text import toml_clean +%>${toml_clean(toml_dumps(repo.libs.faults.resolve_faults(node.metadata['simple-icinga-dashboard']), sort_keys=True))} diff --git a/bundles/simple-icinga-dashboard/items.py b/bundles/simple-icinga-dashboard/items.py index a2b6f47..74f05db 100644 --- a/bundles/simple-icinga-dashboard/items.py +++ b/bundles/simple-icinga-dashboard/items.py @@ -43,8 +43,18 @@ git_deploy = { } files = { + '/etc/systemd/system/simple-icinga-dashboard.service': { + 'triggers': { + 'action:systemd-reload', + }, + }, + '/etc/systemd/system/simple-icinga-dashboard.timer': { + 'triggers': { + 'action:systemd-reload', + }, + }, '/opt/simple-icinga-dashboard/config.toml': { - 'content': repo.libs.faults.dict_as_toml(node.metadata.get('simple-icinga-dashboard')), + 'content_type': 'mako', 'needs': { 'git_deploy:/opt/simple-icinga-dashboard/src', }, @@ -59,3 +69,13 @@ symlinks = { }, }, } + +svc_systemd = { + 'simple-icinga-dashboard.timer': { + 'needs': { + 'action:simple-icinga-dashboard_install_requirements', + 'file:/etc/systemd/system/simple-icinga-dashboard.service', + 'file:/etc/systemd/system/simple-icinga-dashboard.timer', + }, + }, +} diff --git a/bundles/simple-icinga-dashboard/metadata.py b/bundles/simple-icinga-dashboard/metadata.py index 91c5cf5..1d1b905 100644 --- a/bundles/simple-icinga-dashboard/metadata.py +++ b/bundles/simple-icinga-dashboard/metadata.py @@ -11,17 +11,4 @@ defaults = { 'filename': '/opt/simple-icinga-dashboard/out/index.html', }, }, - 'systemd-timers': { - 'timers': { - 'simple-icinga-dashboard': { - 'when': 'minutely', - 'command': '/opt/simple-icinga-dashboard/venv/bin/python /opt/simple-icinga-dashboard/src/service.py', - 'pwd': '/opt/simple-icinga-dashboard/src/', - 'user': 'icinga_dashboard', - 'environment': { - 'STATUSPAGE_CONFIG': '/opt/simple-icinga-dashboard/config.toml', - }, - }, - }, - }, } diff --git a/bundles/smartd/files/telegraf_plugin b/bundles/smartd/files/telegraf_plugin index 46144bf..5a7a1a5 100644 --- a/bundles/smartd/files/telegraf_plugin +++ b/bundles/smartd/files/telegraf_plugin @@ -1,7 +1,7 @@ #!/usr/bin/env python -from json import loads from subprocess import check_output +from json import loads from sys import stderr devices = check_output(['smartctl', '--scan']).decode().splitlines() @@ -29,16 +29,10 @@ for device in devices: if 'nvme_smart_health_information_log' in json: for k, v in json['nvme_smart_health_information_log'].items(): - if not str(v).isdigit(): - continue - telegraf_output.add(f'{k}={v}') if 'ata_smart_attributes' in json: for entry in json['ata_smart_attributes']['table']: - if not str(entry['raw']['value']).isdigit(): - continue - telegraf_output.add('{}={}'.format( entry['name'], entry['raw']['value'], diff --git a/bundles/smartd/items.py b/bundles/smartd/items.py index e18270f..540a6a9 100644 --- a/bundles/smartd/items.py +++ b/bundles/smartd/items.py @@ -2,7 +2,7 @@ files = { '/etc/smartd.conf': { 'content_type': 'mako', 'triggers': { - 'svc_systemd:smartmontools:reload', + 'svc_systemd:smartd:reload', }, }, '/usr/local/share/icinga/plugins/check_smart': { @@ -15,5 +15,7 @@ files = { } svc_systemd = { - 'smartmontools': {}, + 'smartd': { + 'enabled': None, # FIXME this is symlinked to smartmontools.service on bullseye + }, } diff --git a/bundles/smartd/metadata.py b/bundles/smartd/metadata.py index 5202068..63af59a 100644 --- a/bundles/smartd/metadata.py +++ b/bundles/smartd/metadata.py @@ -1,16 +1,14 @@ -from re import search - defaults = { 'apt': { 'packages': { 'smartmontools': { 'needed_by': { - 'svc_systemd:smartmontools', + 'svc_systemd:smartd', }, }, 'nvme-cli': { 'needed_by': { - 'svc_systemd:smartmontools', + 'svc_systemd:smartd', }, }, }, @@ -19,7 +17,7 @@ defaults = { 'smartd': { 'services': { 'SMARTD PROCESS': { - 'command_on_monitored_host': '/usr/local/share/icinga/plugins/check_systemd_unit smartmontools', + 'command_on_monitored_host': '/usr/local/share/icinga/plugins/check_systemd_unit smartd', }, }, }, @@ -43,6 +41,27 @@ if node.has_bundle('telegraf'): } +@metadata_reactor.provides( + 'smartd/disks', +) +def zfs_disks_to_metadata(metadata): + disks = set() + + for config in metadata.get('zfs/pools', {}).values(): + for option in config['when_creating']['config']: + if option.get('type', '') in {'log', 'cache'}: + continue + + for disk in option['devices']: + disks.add(disk) + + return { + 'smartd': { + 'disks': disks, + }, + } + + @metadata_reactor.provides( 'icinga2_api/smartd/services', ) @@ -65,19 +84,21 @@ def icinga(metadata): @metadata_reactor.provides( - 'systemd-timers/timers', + 'cron/jobs/smartd', ) def monthly_long_test(metadata): - timers = {} + lines = set() - for day, disk in enumerate(sorted(metadata.get('smartd/disks', set())), start=1): - timers[f'smartd{disk.replace("/", "-")}'] = { - 'command': f'/usr/sbin/smartctl --test=long {disk}', - 'when': f'*-*-{day} 03:00:00 UTC', - } + for number, disk in enumerate(sorted(metadata.get('smartd/disks', set()))): + lines.add('0 3 {} * * root /usr/sbin/smartctl --test=long {} >/dev/null'.format( + number+1, # enumerate() starts at 0 + disk, + )) return { - 'systemd-timers': { - 'timers': timers, + 'cron': { + 'jobs': { + 'smartd': '\n'.join(sorted(lines)), + }, }, } diff --git a/bundles/sshmon/files/check_cpu_stats b/bundles/sshmon/files/check_cpu_stats index f0c3a35..36e5ae3 100644 --- a/bundles/sshmon/files/check_cpu_stats +++ b/bundles/sshmon/files/check_cpu_stats @@ -4,30 +4,27 @@ from re import findall from subprocess import check_output from sys import exit -ITERATIONS = 10 - try: top_output = None - top_output = check_output(rf"top -b -n{ITERATIONS} -d1 | grep -i '^%cpu'", shell=True).decode('UTF-8') + for line in check_output(['top', '-b', '-n1', '-d1']).decode('UTF-8').splitlines(): + if line.lower().strip().startswith('%cpu'): + top_output = line.lower().split(':', 2)[1] + break + + if not top_output: + print('%cpu not found in top output') + exit(3) cpu_usage = {} - for value, identifier in findall(r'([0-9\.\,]{3,5}) ([a-z]{2})', top_output): - if identifier not in cpu_usage: - cpu_usage[identifier] = 0.0 - cpu_usage[identifier] += float(value.replace(',', '.')) - - output = [] - for identifier, value_added in cpu_usage.items(): - value = value_added / ITERATIONS - output.append(f"{value:.2f} {identifier}") - cpu_usage[identifier] = value - - print(f"Average over {ITERATIONS} seconds: " + ", ".join(output)) + for value, identifier in findall('([0-9\.\,]{3,5}) ([a-z]{2})', top_output): + cpu_usage[identifier] = float(value.replace(',', '.')) warn = set() crit = set() + print(top_output) + # steal if cpu_usage['st'] > 10: crit.add('CPU steal is {}% (>10%)'.format(cpu_usage['st'])) diff --git a/bundles/sshmon/files/check_forgejo_for_new_release b/bundles/sshmon/files/check_forgejo_for_new_release index 99dcd30..99fb18d 100644 --- a/bundles/sshmon/files/check_forgejo_for_new_release +++ b/bundles/sshmon/files/check_forgejo_for_new_release @@ -38,10 +38,10 @@ try: for i in releases: if i["tag_name"].startswith(tag_prefix): - if not (i["prerelease"] or i["draft"]) and ( + if ( newest_release is None or parse(i["tag_name"]) > parse(newest_release["tag_name"]) - ): + ) and not (i["prerelease"] or i["draft"]): newest_release = i assert newest_release is not None, "Could not determine latest release" @@ -55,9 +55,8 @@ try: exit(2) else: print( - "Currently installed version {} matches newest release on {}".format( - current_version, - host, + "Currently installed version {} matches newest release on github".format( + current_version ) ) exit(0) diff --git a/bundles/sshmon/files/check_github_for_new_release b/bundles/sshmon/files/check_github_for_new_release index ec510de..3a50d94 100644 --- a/bundles/sshmon/files/check_github_for_new_release +++ b/bundles/sshmon/files/check_github_for_new_release @@ -37,10 +37,10 @@ try: for i in releases: if i["tag_name"].startswith(tag_prefix): - if not (i["prerelease"] or i["draft"]) and ( + if ( newest_release is None or parse(i["tag_name"]) > parse(newest_release["tag_name"]) - ): + ) and not (i["prerelease"] or i["draft"]): newest_release = i assert newest_release is not None, "Could not determine latest release" diff --git a/bundles/sshmon/files/check_http_wget b/bundles/sshmon/files/check_http_wget index c259871..ade5dbe 100644 --- a/bundles/sshmon/files/check_http_wget +++ b/bundles/sshmon/files/check_http_wget @@ -2,8 +2,8 @@ #this is actually a python https requests query, its called check_http_wget cause it got replaced -from argparse import ArgumentParser from sys import exit +from argparse import ArgumentParser import requests diff --git a/bundles/sshmon/files/check_https_certificate_at_url b/bundles/sshmon/files/check_https_certificate_at_url index ce0f0ba..7c22cfe 100644 --- a/bundles/sshmon/files/check_https_certificate_at_url +++ b/bundles/sshmon/files/check_https_certificate_at_url @@ -19,11 +19,7 @@ crit_days=30 case "$issuer_hash" in # 4f06f81d: issuer=C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3 # 8d33f237: issuer=C = US, O = Let's Encrypt, CN = R3 - # 462422cf: issuer=C = US, O = Let's Encrypt, CN = E5 - # 9aad238c: issuer=C = US, O = Let's Encrypt, CN = E6 - # 31dfb39d: issuer=C = US, O = Let's Encrypt, CN = R11 - # aa578057: issuer=C = US, O = Let's Encrypt, CN = R10 - 4f06f81d|8d33f237|462422cf|9aad238c|31dfb39d|aa578057) + 4f06f81d|8d33f237) warn_days=10 crit_days=3 ;; diff --git a/bundles/sshmon/files/check_mounts b/bundles/sshmon/files/check_mounts index bc2fc4b..f387ce4 100644 --- a/bundles/sshmon/files/check_mounts +++ b/bundles/sshmon/files/check_mounts @@ -5,6 +5,7 @@ from argparse import ArgumentParser from subprocess import check_output from tempfile import TemporaryFile + check_filesystem_types = { 'ext2', 'ext3', diff --git a/bundles/sshmon/items.py b/bundles/sshmon/items.py index be9a9a4..1361eb2 100644 --- a/bundles/sshmon/items.py +++ b/bundles/sshmon/items.py @@ -50,7 +50,6 @@ files = { for check in { 'cpu_stats', - 'forgejo_for_new_release', 'github_for_new_release', 'http_url_for_string', 'http_wget', @@ -64,3 +63,12 @@ for check in { files["/usr/local/share/icinga/plugins/check_{}".format(check)] = { 'mode': "0755", } + + +if node.has_bundle('pacman'): + symlinks['/usr/lib/nagios/plugins'] = { + 'target': '/usr/lib/monitoring-plugins', + 'needs': { + 'pkg_pacman:monitoring-plugins', + }, + } diff --git a/bundles/sshmon/metadata.py b/bundles/sshmon/metadata.py index 3026479..4fc3df2 100644 --- a/bundles/sshmon/metadata.py +++ b/bundles/sshmon/metadata.py @@ -8,10 +8,7 @@ defaults = { 'monitoring-plugins': {}, 'python3-requests': {}, 'python3-setuptools': {}, # needed by check_github_for_new_release - 'sysstat': { - # legacy - 'installed': False, - }, + 'sysstat': {}, # needed by check_cpu_stats }, }, 'icinga2_api': { @@ -19,8 +16,6 @@ defaults = { 'services': { 'CPU': { 'command_on_monitored_host': '/usr/local/share/icinga/plugins/check_cpu_stats', - # takes samples over 10 seconds - 'vars.sshmon_timeout': 20 }, 'LOAD': { 'command_on_monitored_host': '/usr/lib/nagios/plugins/check_load -r -w 4,2,1 -c 8,4,2', @@ -36,6 +31,15 @@ defaults = { 'sshmon', }, }, + 'pacman': { + 'packages': { + 'gawk': {}, + 'perl-libwww': {}, + 'monitoring-plugins': {}, + 'python-requests': {}, + 'sysstat': {}, + }, + }, } diff --git a/bundles/sudo/files/bwusers b/bundles/sudo/files/bwusers index 00dfafa..6c47ecd 100644 --- a/bundles/sudo/files/bwusers +++ b/bundles/sudo/files/bwusers @@ -1,5 +1,9 @@ % for user, config in sorted(node.metadata['users'].items()): -% for p in sorted(config.get('sudo_commands', [])): +% if config.get('is_admin', False): +${user} ALL=(ALL) NOPASSWD:ALL +% else: +% for p in sorted(config.get('sudo_commands', [])): ${user} ALL=(ALL) NOPASSWD:${p} -% endfor +% endfor +% endif % endfor diff --git a/bundles/sudo/metadata.py b/bundles/sudo/metadata.py index e76edaf..82b007d 100644 --- a/bundles/sudo/metadata.py +++ b/bundles/sudo/metadata.py @@ -4,4 +4,9 @@ defaults = { 'sudo': {}, }, }, + 'pacman': { + 'packages': { + 'sudo': {}, + }, + }, } diff --git a/bundles/sysctl/items.py b/bundles/sysctl/items.py index 99860e1..c4c448c 100644 --- a/bundles/sysctl/items.py +++ b/bundles/sysctl/items.py @@ -20,14 +20,6 @@ files = { }, } -if node.os == 'debian': - # debian insists on creating that file during almost every - # unattended-upgrades run. Make it known to bundlewrap, so - # it does not get removed during applies. - symlinks['/etc/sysctl.d/99-sysctl.conf'] = { - 'target': '../sysctl.conf', - } - directories = { '/etc/sysctl.d': { 'purge': True, diff --git a/bundles/systemd-boot/files/entry b/bundles/systemd-boot/files/entry new file mode 100755 index 0000000..00d3d8f --- /dev/null +++ b/bundles/systemd-boot/files/entry @@ -0,0 +1,13 @@ +title ${config['title']} + +% if 'linux' in config: +linux ${config['linux']} +% for line in config['initrd']: +initrd ${line} +% endfor +% if config.get('options', set()): +options ${' '.join(sorted(config['options']))} +% endif +% else: +efi ${config['efi']} +% endif diff --git a/bundles/systemd-boot/files/loader.conf b/bundles/systemd-boot/files/loader.conf new file mode 100755 index 0000000..b30de61 --- /dev/null +++ b/bundles/systemd-boot/files/loader.conf @@ -0,0 +1,5 @@ +auto-entries no +auto-firmware yes +console-mode keep +default ${config['default']} +timeout ${config.get('timeout', 5)} diff --git a/bundles/systemd-boot/files/pacman_hook b/bundles/systemd-boot/files/pacman_hook new file mode 100644 index 0000000..d65c027 --- /dev/null +++ b/bundles/systemd-boot/files/pacman_hook @@ -0,0 +1,9 @@ +[Trigger] +Type = Package +Operation = Upgrade +Target = systemd + +[Action] +Description = Gracefully upgrading systemd-boot... +When = PostTransaction +Exec = /usr/bin/systemctl restart systemd-boot-update.service diff --git a/bundles/systemd-boot/items.py b/bundles/systemd-boot/items.py new file mode 100644 index 0000000..0f26d00 --- /dev/null +++ b/bundles/systemd-boot/items.py @@ -0,0 +1,32 @@ +assert node.os == 'arch' +assert node.metadata.get('systemd-boot/default') in node.metadata.get('systemd-boot/entries') + +files = { + '/etc/pacman.d/hooks/99-systemd-boot-update': { + 'source': 'pacman_hook', + }, + '/boot/loader/loader.conf': { + 'content_type': 'mako', + 'context': { + 'config': node.metadata.get('systemd-boot'), + }, + 'mode': None, + }, +} + +directories = { + '/boot/loader/entries': { + 'purge': True, + }, +} + +for entry, config in node.metadata.get('systemd-boot/entries').items(): + files[f'/boot/loader/entries/{entry}.conf'] = { + 'source': 'entry', + 'content_type': 'mako', + 'context': { + 'entry': entry, + 'config': config, + }, + 'mode': None, + } diff --git a/bundles/systemd-networkd/files/template-bridge.network b/bundles/systemd-networkd/files/template-bridge.network index d7ea47c..0487f79 100644 --- a/bundles/systemd-networkd/files/template-bridge.network +++ b/bundles/systemd-networkd/files/template-bridge.network @@ -3,6 +3,3 @@ Name=${' '.join(sorted(match))} [Network] Bridge=${bridge} - -[Link] -ActivationPolicy=always-up diff --git a/bundles/systemd-networkd/files/template-iface-dhcp.network b/bundles/systemd-networkd/files/template-iface-dhcp.network new file mode 100644 index 0000000..19fd0d8 --- /dev/null +++ b/bundles/systemd-networkd/files/template-iface-dhcp.network @@ -0,0 +1,27 @@ +<% + from ipaddress import ip_network +%>\ +[Match] +Name=${interface} + +[Network] +DHCP=yes +IPv6AcceptRA=yes + +[DHCPv4] +UseDomains=${str(config.get('use_dhcp_domains', False)).lower()} +UseHostname=no +UseMTU=${str(config.get('use_dhcp_mtu', True)).lower()} +UseNTP=${str(config.get('use_dhcp_ntp', False)).lower()} +UseTimezone=no + +% if config.get('send_hostname', True): +SendHostname=yes +Hostname=${node.name.split('.')[-1]} +% else: +SendHostname=no +% endif + +% if config.get('forwarding', False): +IPForward=yes +%endif diff --git a/bundles/systemd-networkd/files/template-iface.network b/bundles/systemd-networkd/files/template-iface-nodhcp.network similarity index 62% rename from bundles/systemd-networkd/files/template-iface.network rename to bundles/systemd-networkd/files/template-iface-nodhcp.network index cbb10b6..59c2d91 100644 --- a/bundles/systemd-networkd/files/template-iface.network +++ b/bundles/systemd-networkd/files/template-iface-nodhcp.network @@ -25,47 +25,30 @@ Destination=${route} GatewayOnlink=yes % endfor -% if not config.get('dhcp', False): -% if 'gateway4' in config: +% if 'gateway4' in config: [Route] Gateway=${config['gateway4']} GatewayOnlink=yes -% endif -% if 'gateway6' in config: +% endif +% if 'gateway6' in config: [Route] Gateway=${config['gateway6']} GatewayOnlink=yes -% endif % endif [Network] -% if config.get('ipv6_accept_ra', False) or config.get('dhcp', False): +DHCP=no +% if config.get('ipv6_accept_ra', False): IPv6AcceptRA=yes % else: IPv6AcceptRA=no % endif -% if config.get('dhcp', False): -DHCP=yes -IPv6AcceptRA=yes -[DHCPv4] -UseDomains=false -UseHostname=no -UseMTU=true -UseNTP=false -UseTimezone=no - -SendHostname=no -% else: -DHCP=no -% endif +% if config.get('forwarding', False): +IPForward=yes +%endif % for vlan in sorted(config.get('vlans', set())): VLAN=${interface}.${vlan} % endfor -% if 'activation_policy' in config: - -[Link] -ActivationPolicy=${config['activation_policy']} -% endif diff --git a/bundles/systemd-networkd/items.py b/bundles/systemd-networkd/items.py index 7bd0808..969c3e2 100644 --- a/bundles/systemd-networkd/items.py +++ b/bundles/systemd-networkd/items.py @@ -40,7 +40,9 @@ for interface, config in node.metadata.get('interfaces').items(): if config.get('dhcp', False): if 'vlans' in config: raise BundleError(f'{node.name} interface {interface} cannot use vlans and dhcp!') + template = 'template-iface-dhcp.network' else: + template = 'template-iface-nodhcp.network' all_interfaces_use_dhcp = False if '.' in interface: @@ -78,7 +80,7 @@ for interface, config in node.metadata.get('interfaces').items(): if not config.get('ignore', False): files[f'/etc/systemd/network/{interface}.network'] = { - 'source': 'template-iface.network', + 'source': template, 'content_type': 'mako', 'context': { 'interface': interface, diff --git a/bundles/systemd-networkd/metadata.py b/bundles/systemd-networkd/metadata.py index 6e67af9..303e0f3 100644 --- a/bundles/systemd-networkd/metadata.py +++ b/bundles/systemd-networkd/metadata.py @@ -1,12 +1,6 @@ defaults = { 'apt': { 'packages': { - 'isc-dhcp-client': { - 'installed': False, - }, - 'network-manager': { - 'installed': False, - }, 'resolvconf': { 'installed': False, }, diff --git a/bundles/systemd-timers/files/template.service b/bundles/systemd-timers/files/template.service index 271b756..6f7c444 100644 --- a/bundles/systemd-timers/files/template.service +++ b/bundles/systemd-timers/files/template.service @@ -1,17 +1,8 @@ -<% - if config.get('exclude_from_monitoring', False): - monitored = '' - else: - monitored = f'/usr/local/sbin/systemd-timer-monitored {timer} ' -%>\ [Unit] Description=Service for Timer ${timer} After=network.target -% if config.get('requires', set()): -Requires=${' '.join(sorted(config['requires']))} -% endif -% if config.get('requisite', set()): -Requisite=${' '.join(sorted(config['requisite']))} +% if config.get('requires', ''): +Requires=${config['requires']} % endif [Service] @@ -24,8 +15,8 @@ WorkingDirectory=${config.get('pwd', '/')} Type=oneshot % if isinstance(config['command'], list): % for command in config['command']: -ExecStart=${monitored}${command} +ExecStart=/usr/local/sbin/systemd-timer-monitored ${timer} ${command} % endfor % else: -ExecStart=${monitored}${config['command']} +ExecStart=/usr/local/sbin/systemd-timer-monitored ${timer} ${config['command']} % endif diff --git a/bundles/systemd-timers/metadata.py b/bundles/systemd-timers/metadata.py index 9aaf573..23f87ff 100644 --- a/bundles/systemd-timers/metadata.py +++ b/bundles/systemd-timers/metadata.py @@ -5,10 +5,7 @@ def monitoring(metadata): services = {} for timer, config in node.metadata.get('systemd-timers/timers', {}).items(): - if ( - config.get('delete', False) - or config.get('exclude_from_monitoring', False) - ): + if config.get('delete', False): continue services[f'SYSTEMD-TIMER {timer}'] = { diff --git a/bundles/systemd/files/journald.conf b/bundles/systemd/files/journald.conf index 1ccdb9c..a062649 100644 --- a/bundles/systemd/files/journald.conf +++ b/bundles/systemd/files/journald.conf @@ -15,10 +15,5 @@ RuntimeKeepFree=${journal.get('keepfree', '2G')} RuntimeMaxFileSize=100M MaxFileSec=1d -ForwardToSyslog=no -ForwardToKMsg=no -ForwardToConsole=no -ForwardToWall=yes - # Disable auditing Audit=no diff --git a/bundles/systemd/items.py b/bundles/systemd/items.py index 005696e..c8ecbd9 100644 --- a/bundles/systemd/items.py +++ b/bundles/systemd/items.py @@ -1,4 +1,4 @@ -timezone = node.metadata.get('timezone') +timezone = node.metadata.get('timezone', 'UTC') actions['systemd-reload'] = { 'command': 'systemctl daemon-reload', diff --git a/bundles/systemd/metadata.py b/bundles/systemd/metadata.py index 76f2016..f8a8ba4 100644 --- a/bundles/systemd/metadata.py +++ b/bundles/systemd/metadata.py @@ -21,14 +21,8 @@ defaults = { }, }, }, - 'timezone': 'UTC', } -if not node.has_bundle('rsyslogd'): - defaults['apt']['packages']['rsyslog'] = { - 'installed': False, - } - if node.has_bundle('apt') and node.os_version[0] > 10: defaults['apt']['packages']['systemd-timesyncd'] = { 'after': { @@ -37,6 +31,5 @@ if node.has_bundle('apt') and node.os_version[0] > 10: }, 'needed_by': { 'action:systemd-enable-ntp', - 'svc_systemd:systemd-timesyncd', }, } diff --git a/bundles/telegraf-monitors-mikrotik/files/telegraf-plugin-snmp-mikrotik b/bundles/telegraf-monitors-mikrotik/files/telegraf-plugin-snmp-mikrotik deleted file mode 100644 index dbcefd8..0000000 --- a/bundles/telegraf-monitors-mikrotik/files/telegraf-plugin-snmp-mikrotik +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env python3 -from sys import argv - -from hnmp import SNMP - -snmp = SNMP(argv[2], community=argv[3]) - -single_value_metrics_int_oids = { - 'cpu-load': '1.3.6.1.2.1.25.3.3.1.2.1', - 'cpu-temperature': '1.3.6.1.4.1.14988.1.1.3.11.0', - 'fan1-speed': '1.3.6.1.4.1.14988.1.1.3.17.0', - 'fan2-speed': '1.3.6.1.4.1.14988.1.1.3.18.0', - 'power-consumption': '1.3.6.1.4.1.14988.1.1.3.12.0', - #'psu1-state': '1.3.6.1.4.1.14988.1.1.3.15.0', - 'temperature': '1.3.6.1.4.1.14988.1.1.3.10.0', -} - -single_value_metrics_int_values = { - key: snmp.get(oid) - for key, oid in single_value_metrics_int_oids.items() -} - -formatted_values = sorted([ - f"{key}={value}i" - for key, value in single_value_metrics_int_values.items() - if value -]) - -print("mikrotik,host={host} {values}".format( - host=argv[1], - values=",".join(formatted_values), -)) - - -table = snmp.table( - "1.3.6.1.4.1.14988.1.1.15.1.1", - columns={ - 2: "interface", - #3: "status", - 4: "voltage", - 5: "current", - 6: "power", - }, - fetch_all_columns=False, -) - -for row in table.rows: - print(row) - interface_name = row['interface'] - values = [] - for column, value in row.items(): - if column == "interface" or not value: - continue - values.append("{}={}i".format(column, value)) - - print("mikrotik,interface={interface},host={host} {values}".format( - host=argv[1], - interface=interface_name, - values=",".join(values), - )) diff --git a/bundles/telegraf-monitors-mikrotik/items.py b/bundles/telegraf-monitors-mikrotik/items.py deleted file mode 100644 index 410e563..0000000 --- a/bundles/telegraf-monitors-mikrotik/items.py +++ /dev/null @@ -1,9 +0,0 @@ -files['/usr/local/bin/telegraf-plugin-snmp-mikrotik'] = { - 'mode': '0755', -} - -pkg_pip['hnmp'] = { - 'before': { - 'svc_systemd:telegraf', - }, -} diff --git a/bundles/telegraf-monitors-mikrotik/metadata.py b/bundles/telegraf-monitors-mikrotik/metadata.py deleted file mode 100644 index 29d5c08..0000000 --- a/bundles/telegraf-monitors-mikrotik/metadata.py +++ /dev/null @@ -1,22 +0,0 @@ -@metadata_reactor.provides( - 'telegraf/input_plugins/exec', -) -def collect_nodes(metadata): - execs = {} - - for rnode in repo.nodes_in_group('switches-mikrotik'): - snmp_pw = rnode.metadata.get('routeros/snmp/community', 'public') - - execs[f'snmp_mikrotik_{rnode.name}'] = { - 'commands': [f'/usr/local/bin/telegraf-plugin-snmp-mikrotik {rnode.name} {rnode.hostname} {snmp_pw}'], - 'data_format': 'influx', - 'timeout': '30s', - } - - return { - 'telegraf': { - 'input_plugins': { - 'exec': execs, - }, - }, - } diff --git a/bundles/telegraf/files/telegraf.conf b/bundles/telegraf/files/telegraf.conf new file mode 100644 index 0000000..12dcdb7 --- /dev/null +++ b/bundles/telegraf/files/telegraf.conf @@ -0,0 +1,4 @@ +<% + from tomlkit import dumps as toml_dumps + from bundlewrap.utils.text import toml_clean +%>${toml_clean(toml_dumps(repo.libs.faults.resolve_faults(config), sort_keys=True))} diff --git a/bundles/telegraf/items.py b/bundles/telegraf/items.py index 4ee5ef2..8577cbb 100644 --- a/bundles/telegraf/items.py +++ b/bundles/telegraf/items.py @@ -11,19 +11,7 @@ telegraf_config = { 'quiet': False, 'round_interval': False, }, - 'outputs': { - 'influxdb_v2': [{ - 'urls': [node.metadata.get('telegraf/influxdb_url', repo.libs.defaults.influxdb_url)], - 'token': node.metadata.get('telegraf/influxdb_token', repo.vault.decrypt(repo.libs.defaults.influxdb_token)), - 'organization': node.metadata.get('telegraf/influxdb_org', repo.vault.decrypt(repo.libs.defaults.influxdb_org)), - 'bucket': node.metadata.get('telegraf/influxdb_bucket', repo.vault.decrypt(repo.libs.defaults.influxdb_bucket)), - }], - }, - 'inputs': {}, -} - -if node.metadata.get('telegraf/collect_default_metrics', True): - telegraf_config['inputs'] = { + 'inputs': { 'cpu': [{ 'percpu': False, 'totalcpu': True, @@ -55,9 +43,17 @@ if node.metadata.get('telegraf/collect_default_metrics', True): 'nstat': [{}], 'processes': [{}], 'system': [{}], - } - -telegraf_config['inputs'].update(node.metadata.get('telegraf/input_plugins/builtin', {})) + **node.metadata.get('telegraf/input_plugins/builtin', {}), + }, + 'outputs': { + 'influxdb_v2': [{ + 'urls': [node.metadata.get('telegraf/influxdb_url', repo.libs.defaults.influxdb_url)], + 'token': node.metadata.get('telegraf/influxdb_token', repo.vault.decrypt(repo.libs.defaults.influxdb_token)), + 'organization': node.metadata.get('telegraf/influxdb_org', repo.vault.decrypt(repo.libs.defaults.influxdb_org)), + 'bucket': node.metadata.get('telegraf/influxdb_bucket', repo.vault.decrypt(repo.libs.defaults.influxdb_bucket)), + }], + }, +} # Bundlewrap can't merge lists. To work around this, telegraf/input_plugins/exec(d) # is a dict, of which we only use the value of it. This also allows us @@ -97,7 +93,10 @@ for name, config in sorted(node.metadata.get('telegraf/input_plugins/prometheus' files = { '/etc/telegraf/telegraf.conf': { - 'content': repo.libs.faults.dict_as_toml(telegraf_config), + 'content_type': 'mako', + 'context': { + 'config': telegraf_config, + }, 'triggers': { 'svc_systemd:telegraf:restart', }, diff --git a/bundles/telegraf/metadata.py b/bundles/telegraf/metadata.py index 4af8190..50a588e 100644 --- a/bundles/telegraf/metadata.py +++ b/bundles/telegraf/metadata.py @@ -11,7 +11,7 @@ defaults = { 'repos': { 'influxdb': { 'items': { - 'deb https://repos.influxdata.com/{os} stable main', + 'deb https://repos.influxdata.com/{os} {os_release} stable', }, }, }, @@ -25,4 +25,14 @@ defaults = { }, }, }, + 'pacman': { + 'packages': { + 'telegraf-bin': { + 'needed_by': { + 'svc_systemd:telegraf', + 'user:telegraf', + }, + }, + }, + }, } diff --git a/bundles/telegraf_airgradient/files/airgradient_telegraf b/bundles/telegraf_airgradient/files/airgradient_telegraf deleted file mode 100644 index 3ada3e8..0000000 --- a/bundles/telegraf_airgradient/files/airgradient_telegraf +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/python3 - -from logging import basicConfig, getLogger -from sys import argv - -from requests import get - -basicConfig(level="INFO") -L = getLogger(__name__) - - -def out(keys, values): - print( - "airgradient,{} {}".format( - ",".join([f"{k}={v}" for k, v in keys.items()]), - ",".join([f"{k}={v}" for k, v in values.items()]), - ), - flush=True, - ) - - -try: - r = get( - f"https://api.airgradient.com/public/api/v1/locations/measures/current?token={argv[2]}" - ) - L.debug(r.status_code) - L.info(r.text) - r.raise_for_status() - for location in r.json(): - L.debug(location) - out( - { - "place": argv[1], - "location": location["locationName"], - }, - { - k: location[k] - for k in ( - "atmp", - "noxIndex", - "pm003Count", - "pm01", - "pm02", - "pm10", - "rco2", - "rhum", - "tvoc", - "tvocIndex", - "wifi", - ) - }, - ) -except Exception: - L.exception("fail!") diff --git a/bundles/telegraf_airgradient/items.py b/bundles/telegraf_airgradient/items.py deleted file mode 100644 index 702d22f..0000000 --- a/bundles/telegraf_airgradient/items.py +++ /dev/null @@ -1,3 +0,0 @@ -files['/usr/local/bin/airgradient_telegraf'] = { - 'mode': '0755', -} diff --git a/bundles/telegraf_airgradient/metadata.py b/bundles/telegraf_airgradient/metadata.py deleted file mode 100644 index f64fb28..0000000 --- a/bundles/telegraf_airgradient/metadata.py +++ /dev/null @@ -1,19 +0,0 @@ -@metadata_reactor.provides( - 'telegraf/input_plugins/exec', -) -def telegraf(metadata): - result = {} - for location, api_key in metadata.get('telegraf_airgradient', {}).items(): - result[f'airgradient_{location}'] = { - 'commands': [f'/usr/local/bin/airgradient_telegraf {location} {api_key}'], - 'data_format': 'influx', - 'timeout': '10s', - } - - return { - 'telegraf': { - 'input_plugins': { - 'exec': result, - }, - }, - } diff --git a/bundles/transmission/metadata.py b/bundles/transmission/metadata.py index da2a09e..5f5c682 100644 --- a/bundles/transmission/metadata.py +++ b/bundles/transmission/metadata.py @@ -4,6 +4,7 @@ defaults = { 'apt': { 'packages': { 'transmission-daemon': {}, + 'transmission-remote-cli': {}, }, }, 'icinga2_api': { @@ -55,9 +56,9 @@ def firewall(metadata): return { 'firewall': { 'port_rules': { - f"{metadata.get('transmission/config/peer-port')}/tcp": atomic({'*'}), - f"{metadata.get('transmission/config/peer-port')}/udp": atomic({'*'}), - f"{metadata.get('transmission/config/rpc-port')}/tcp": atomic(metadata.get('transmission/restrict-to', {'*'})), + str(metadata.get('transmission/config/peer-port')): atomic({'*'}), + str(metadata.get('transmission/config/peer-port')) + '/udp': atomic({'*'}), + str(metadata.get('transmission/config/rpc-port')): atomic(metadata.get('transmission/restrict-to', {'*'})), }, }, } diff --git a/bundles/travelynx/files/travelynx.conf b/bundles/travelynx/files/travelynx.conf index 46883cf..bc8e128 100644 --- a/bundles/travelynx/files/travelynx.conf +++ b/bundles/travelynx/files/travelynx.conf @@ -5,13 +5,15 @@ # 'localhost'. { - base_url => Mojo::URL->new('https://${domain}'), - + # Cache directories for schedule and realtime data. Mandatory. The parent + # directory ('/var/cache/travelynx' in this case) must already exist. cache => { schedule => '/var/cache/travelynx/iris', realtime => '/var/cache/travelynx/iris-rt', }, + # Database configuration. host and port are optional + # (defaulting to localhost:5432), the rest is mandatory. db => { host => '${database.get('host', 'localhost')}', port => 5432, @@ -20,6 +22,8 @@ password => '${database['password']}', }, + # See the Mojo::Server::Hypnotoad manual for details on the following + # settings. hypnotoad => { accepts => 100, clients => 10, @@ -30,19 +34,23 @@ }, mail => { + # If you want to disable outgoing mail for development purposes, + # uncomment the following line. Mails will instead be logged as + # Mojolicious "info" messages, causing their content to be printed on + # stdout. + ## disabled => 1, + + # Otherwise, specify the sender ("From" field) for mail sent by travelynx + # here. E.g. 'Travelynx ' from => '${mail_from}', }, - ref => { - issues => 'https://github.com/derf/travelynx/issues', - source => 'https://github.com/derf/travelynx', - }, - + # Secrets used for cookie signing and verification. Must contain at least + # one random string. If you specify several strings, the first one will + # be used for signing new cookies, and the remaining ones will still be + # accepted for cookie validation. secrets => [ '${cookie_secret}', -% for i in sorted(additional_cookie_secrets): - '${i}', -% endfor ], version => '${version}', diff --git a/bundles/travelynx/files/travelynx.service b/bundles/travelynx/files/travelynx.service index 53aec53..6c7b4f2 100644 --- a/bundles/travelynx/files/travelynx.service +++ b/bundles/travelynx/files/travelynx.service @@ -8,9 +8,9 @@ Type=simple RemainAfterExit=yes PIDFile=/var/cache/travelynx/travelynx.pid -ExecStart=/usr/bin/hypnotoad -f index.pl -ExecStop=/usr/bin/hypnotoad -s index.pl -ExecReload=/usr/bin/hypnotoad index.pl +ExecStart=/usr/local/bin/hypnotoad -f index.pl +ExecStop=/usr/local/bin/hypnotoad -s index.pl +ExecReload=/usr/local/bin/hypnotoad index.pl User=travelynx WorkingDirectory=/opt/travelynx diff --git a/bundles/travelynx/items.py b/bundles/travelynx/items.py index 9a03785..dda92cf 100644 --- a/bundles/travelynx/items.py +++ b/bundles/travelynx/items.py @@ -20,14 +20,14 @@ directories = { } files = { - '/usr/local/lib/systemd/system/travelynx.service': { + '/etc/systemd/system/travelynx.service': { 'triggers': { 'action:systemd-reload', 'svc_systemd:travelynx:restart', 'svc_systemd:travelynx-worker:restart', }, }, - '/usr/local/lib/systemd/system/travelynx-worker.service': { + '/etc/systemd/system/travelynx-worker.service': { 'triggers': { 'action:systemd-reload', 'svc_systemd:travelynx:restart', @@ -36,7 +36,7 @@ files = { }, '/opt/travelynx/travelynx.conf': { 'content_type': 'mako', - 'context': node.metadata.get('travelynx'), + 'context': node.metadata['travelynx'], 'needs': { 'git_deploy:/opt/travelynx', }, @@ -61,7 +61,7 @@ if isfile(join(repo.path, 'data', 'travelynx', 'files', 'imprint', node.name)): git_deploy = { '/opt/travelynx': { 'repo': 'https://github.com/derf/travelynx.git', - 'rev': node.metadata.get('travelynx/version'), + 'rev': node.metadata['travelynx']['version'], 'needs': { 'directory:/opt/travelynx', }, @@ -84,7 +84,7 @@ actions = { 'triggered': True, }, 'travelynx_database_migrate': { - 'command': 'export PERL5LIB=/opt/travelynx/local/lib/perl5; cd /opt/travelynx && perl index.pl database migrate', + 'command': 'cd /opt/travelynx && perl index.pl database migrate', # Because git_deploy does not put .git onto the server, the script # will complain on STDERR about not finding a git repository. # That's why we need to redirect stderr to /dev/null. @@ -102,15 +102,14 @@ actions = { svc_systemd = { 'travelynx': { 'needs': { - 'file:/usr/local/lib/systemd/system/travelynx.service', + 'file:/etc/systemd/system/travelynx.service', 'action:travelynx_database_migrate', 'directory:/var/cache/travelynx', - 'pkg_apt:libmojolicious-perl', }, }, 'travelynx-worker': { 'needs': { - 'file:/usr/local/lib/systemd/system/travelynx-worker.service', + 'file:/etc/systemd/system/travelynx-worker.service', 'svc_systemd:travelynx', }, }, diff --git a/bundles/travelynx/metadata.py b/bundles/travelynx/metadata.py index b7dadd6..969b0cd 100644 --- a/bundles/travelynx/metadata.py +++ b/bundles/travelynx/metadata.py @@ -1,9 +1,4 @@ defaults = { - 'apt': { - 'packages': { - 'libmojolicious-perl': {}, - }, - }, 'travelynx': { 'database': { 'username': 'travelynx', @@ -14,7 +9,6 @@ defaults = { 'spare_workers': 2, 'mail_from': 'travelynx@{}'.format(node.hostname), 'cookie_secret': repo.vault.password_for('{} travelynx cookie_secret'.format(node.name)), - 'additional_cookie_secrets': set(), }, 'postgresql': { 'roles': { diff --git a/bundles/unbound/files/unbound.conf b/bundles/unbound/files/unbound.conf index c25e0a3..247768a 100644 --- a/bundles/unbound/files/unbound.conf +++ b/bundles/unbound/files/unbound.conf @@ -1,11 +1,6 @@ server: # provided by pkg_apt:unbound-anchor auto-trust-anchor-file: "/var/lib/unbound/root.key" -% if node.metadata.get('unbound/dns64', node.has_bundle('jool')): - module-config: "dns64 validator iterator" -% else: - module-config: "validator iterator" -% endif verbosity: 0 @@ -28,6 +23,10 @@ server: access-control: ::1 allow % endif +% if node.has_bundle('pppd'): + prefer-ip4: yes +% endif + msg-cache-size: ${cache_size} msg-cache-slabs: ${cache_slabs} rrset-cache-size: ${cache_size} diff --git a/bundles/unbound/items.py b/bundles/unbound/items.py index 89bce8a..519b811 100644 --- a/bundles/unbound/items.py +++ b/bundles/unbound/items.py @@ -41,13 +41,6 @@ svc_systemd = { }, } -directories['/usr/share/dns'] = { - 'before': { - 'pkg_apt:unbound', - 'pkg_apt:unbound-anchor', - }, -} - if node.has_bundle('systemd-networkd'): svc_systemd['unbound']['needed_by'] = { 'file:/etc/resolv.conf', diff --git a/bundles/unbound/metadata.py b/bundles/unbound/metadata.py index 70a3511..b08df0b 100644 --- a/bundles/unbound/metadata.py +++ b/bundles/unbound/metadata.py @@ -70,7 +70,7 @@ def firewall(metadata): return { 'firewall': { 'port_rules': { - '53/tcp': atomic(metadata.get('unbound/restrict-to', set())), + '53': atomic(metadata.get('unbound/restrict-to', set())), '53/udp': atomic(metadata.get('unbound/restrict-to', set())), }, }, diff --git a/bundles/users/files/bashrc b/bundles/users/files/bashrc index 02a9c02..0a21add 100644 --- a/bundles/users/files/bashrc +++ b/bundles/users/files/bashrc @@ -19,9 +19,7 @@ then fi uptime -echo -last | head -n5 -echo +last | grep 'still logged in' export HISTCONTROL=ignoredups export HISTSIZE=50000 @@ -38,7 +36,6 @@ export EDITOR=vim export VISUAL=vim alias ipb='ip -brief --color=auto' -alias ipa='ip -brief --color=always addr show; echo; ip --color=always route show; ip -6 --color=always route show' alias l='ls -lAh' alias s='sudo -i' alias v='vim -p' @@ -64,8 +61,3 @@ ${k}() { ${v} } % endfor - -if [[ -f "/etc/bashrc_bundlewrap/$(logname)" ]] -then - source "/etc/bashrc_bundlewrap/$(logname)" -fi diff --git a/bundles/users/items.py b/bundles/users/items.py index 79590dc..457c46a 100644 --- a/bundles/users/items.py +++ b/bundles/users/items.py @@ -1,8 +1,4 @@ -from os.path import exists, join - -directories['/etc/bashrc_bundlewrap'] = { - 'purge': True, -} +from os.path import join, exists files = { '/etc/bash.bashrc': { @@ -68,13 +64,14 @@ for username, attrs in node.metadata['users'].items(): } if exists(join(repo.path, 'data', 'users', 'files', 'bash', '{}.bashrc'.format(username))): - files[f'/etc/bashrc_bundlewrap/{username}'] = { + files[home + '/.bashrc'] = { 'content_type': 'mako', 'source': 'bash/{}.bashrc'.format(username), } - files[f"{home}/.bashrc"] = { - 'delete': True, - } + else: + files[home + '/.bashrc'] = { + 'delete': True, + } if attrs.get('enable_linger', False): linger_test = '' diff --git a/bundles/users/metadata.py b/bundles/users/metadata.py index e6f3498..fc3cb0c 100644 --- a/bundles/users/metadata.py +++ b/bundles/users/metadata.py @@ -7,6 +7,11 @@ defaults = { 'kitty-terminfo': {}, }, }, + 'pacman': { + 'packages': { + 'kitty-terminfo': {}, + }, + }, 'users': { 'root': { 'home': '/root', @@ -31,7 +36,7 @@ def add_users_from_json(metadata): if config.get('is_admin', False) or uname in metadata_users: users[uname] = { 'ssh_pubkey': set(config['ssh_pubkey']), - 'sudo_commands': ['ALL'], + 'is_admin': config.get('is_admin', False), } # Then, run again to get all 'to be deleted' users diff --git a/bundles/vmhost/items.py b/bundles/vmhost/items.py index 402e8ec..e432a40 100644 --- a/bundles/vmhost/items.py +++ b/bundles/vmhost/items.py @@ -24,3 +24,12 @@ if node.has_bundle('nftables') and node.has_bundle('apt'): 'svc_systemd:nftables:reload', }, } + +if node.has_bundle('pacman'): + svc_systemd['libvirtd'] = { + 'running': None, # triggered via .socket + } + svc_systemd['virtlogd'] = { + 'running': None, # triggered via .socket + 'enabled': None, # triggered via .socket + } diff --git a/bundles/vmhost/metadata.py b/bundles/vmhost/metadata.py index 79f9d8a..36eb53b 100644 --- a/bundles/vmhost/metadata.py +++ b/bundles/vmhost/metadata.py @@ -21,6 +21,13 @@ defaults = { }, }, }, + 'pacman': { + 'packages': { + 'edk2-ovmf': {}, + 'libvirt': {}, + 'qemu-headless': {}, + }, + }, } if node.os == 'debian' and node.os_version[0] < 11: @@ -36,6 +43,9 @@ if node.has_bundle('nftables'): }, } +if node.has_bundle('arch-with-gui'): + defaults['pacman']['packages']['virt-manager'] = {} + @metadata_reactor.provides( 'users', @@ -43,7 +53,7 @@ if node.has_bundle('nftables'): def libvirt_group_for_admins(metadata): result = {} for user, config in metadata.get('users', {}).items(): - if 'ALL' in config.get('sudo_commands', set()): + if config.get('is_admin', False): result[user] = { 'groups': { 'libvirt', diff --git a/bundles/voc-tracker-worker/files/crs-runner.service b/bundles/voc-tracker-worker/files/crs-runner.service new file mode 100644 index 0000000..72665cb --- /dev/null +++ b/bundles/voc-tracker-worker/files/crs-runner.service @@ -0,0 +1,15 @@ +[Unit] +Description=CRS runner for ${script} +After=network.target + +[Service] +User=voc +Group=voc +ExecStart=/opt/crs-scripts/bin/crs_run ${script} +WorkingDirectory=/opt/crs-scripts +Restart=on-failure +RestartSec=10 +SyslogIdentifier=crs-${worker} + +[Install] +WantedBy=crs-worker.target diff --git a/bundles/voc-tracker-worker/files/environment b/bundles/voc-tracker-worker/files/environment new file mode 100644 index 0000000..87e4333 --- /dev/null +++ b/bundles/voc-tracker-worker/files/environment @@ -0,0 +1,6 @@ +export CRS_TRACKER="${url}" +export CRS_TOKEN="${token}" +export CRS_SECRET="${secret}" +% if use_vaapi: +export CRS_USE_VAAPI="yes" +% endif diff --git a/bundles/voc-tracker-worker/items.py b/bundles/voc-tracker-worker/items.py new file mode 100644 index 0000000..6f28a8b --- /dev/null +++ b/bundles/voc-tracker-worker/items.py @@ -0,0 +1,56 @@ +paths = { # subpaths of /video + 'capture', + 'encoded', + 'fuse', + 'intros', + 'repair', + 'tmp', +} + +directories = { + '/opt/crs-scripts': {}, +} + +for path in paths: + directories[f'/video/{path}'] = { + 'owner': 'voc', + 'group': 'voc', + } + +git_deploy = { + '/opt/crs-scripts': { + 'repo': 'https://github.com/crs-tools/crs-scripts.git', + 'rev': 'master', + }, +} + +files = { + '/etc/default/crs-worker': { + 'content_type': 'mako', + 'source': 'environment', + 'context': node.metadata.get('voc-tracker-worker'), + }, +} + +for worker, script in { + 'recording-scheduler': 'script-A-recording-scheduler.pl', + 'mount4cut': 'script-B-mount4cut.pl', + 'cut-postprocessor': 'script-C-cut-postprocessor.pl', + 'encoding': 'script-D-encoding.pl', + 'postencoding': 'script-E-postencoding-auphonic.pl', + 'postprocessing': 'script-F-postprocessing-upload.pl', +}.items(): + files[f'/etc/systemd/system/crs-{worker}.service'] = { + 'content_type': 'mako', + 'source': 'crs-runner.service', + 'context': { + 'worker': worker, + 'script': script, + }, + 'needs': { + 'file:/etc/default/crs-worker', + }, + 'triggers': { + 'action:systemd-reload', + }, + } diff --git a/bundles/voc-tracker-worker/metadata.py b/bundles/voc-tracker-worker/metadata.py new file mode 100644 index 0000000..3a741a8 --- /dev/null +++ b/bundles/voc-tracker-worker/metadata.py @@ -0,0 +1,52 @@ +defaults = { + 'apt': { + 'packages': { + 'ffmpeg': {}, + 'fuse': {}, + 'fuse-ts': {}, + 'libboolean-perl': {}, + 'libconfig-inifiles-perl': {}, + 'libdatetime-perl': {}, + 'libfile-which-perl': {}, + 'libipc-run3-perl': {}, + 'libjson-perl': {}, + 'libmath-round-perl': {}, + 'libproc-processtable-perl': {}, + 'libwww-curl-perl': {}, + 'libxml-rpc-fast-perl': {}, + 'libxml-simple-perl': {}, + }, + }, + 'voc-tracker-worker': { + 'use_vaapi': False, + }, + 'users': { + 'voc': { + 'home': '/opt/voc', + }, + }, + 'pacman': { + 'packages': { + 'ffmpeg': {}, + 'fuse2': {}, + 'fuse3': {}, + # fuse-ts missing + 'perl-boolean': {}, # from aurto + 'perl-config-inifiles': {}, + 'perl-datetime': {}, + 'perl-file-which': {}, + 'perl-ipc-run3': {}, + 'perl-json': {}, + 'perl-math-round': {}, + 'perl-proc-processtable': {}, + 'perl-www-curl': {}, # from aurto + 'perl-xml-simple': {}, + }, + }, +} + +# Install manually from CPAN: +# IO::Socket::SSL +# LWP::Protocol::https +# Types::Serialiser::Error +# XML::RPC::Fast diff --git a/bundles/weechat/metadata.py b/bundles/weechat/metadata.py deleted file mode 100644 index 034ecfb..0000000 --- a/bundles/weechat/metadata.py +++ /dev/null @@ -1,102 +0,0 @@ -defaults = { - 'apt': { - 'packages': { - 'libpod-parser-perl': {}, - 'mosh': {}, - 'weechat': {}, - 'weechat-core': {}, - 'weechat-curses': {}, - 'weechat-perl': {}, - 'weechat-plugins': {}, - 'weechat-python': {}, - 'weechat-ruby': {}, - }, - 'repos': { - 'weechat': { - 'items': { - 'deb https://weechat.org/{os} {os_release} main', - }, - }, - }, - }, - 'nftables': { - 'input': { - '10-weechat': { - 'udp dport { 60000-61000 } accept', - }, - }, - }, -} - - -@metadata_reactor.provides( - 'backup-client/pre-hooks', - 'backups/paths', - 'users', - 'zfs/datasets', -) -def paths(metadata): - user = metadata.get('weechat/user') - - return { - 'backup-client': { - 'pre-hooks': { - 'weechat': f""" - echo 'core.weechat */layout store' >> /home/{user}/.weechat/weechat_fifo - echo 'core.weechat */save' >> /home/{user}/.weechat/weechat_fifo - """, - }, - }, - 'backups': { - 'paths': { - f'/home/{user}/.weechat', - }, - }, - 'users': { - user: { - 'enable_linger': True, - }, - }, - 'zfs': { - 'datasets': { - f'tank/{user}': {}, - f'tank/{user}/weechat': { - 'mountpoint': f'/home/{user}/.weechat', - 'compression': 'on', - }, - }, - }, - } - - -@metadata_reactor.provides( - 'nginx/vhosts', -) -def relay_vhost(metadata): - if not node.has_bundle('nginx'): - raise DoNotRunAgain - - relay_domain = metadata.get('weechat/relay_domain', None) - if relay_domain is None: - return {} - - return { - 'nginx': { - 'vhosts': { - 'weechat': { - 'domain': relay_domain, - # This only does websockets connections, which stay - # open for a very long time. This only generates - # useless metrics. - 'timing_log': False, - 'locations': { - '/weechat': { - 'proxy_read_timeout': '12h', - 'target': 'http://[::1]:9000', - 'websockets': True, - }, - }, - }, - }, - }, - } diff --git a/bundles/wide-dhcp6c/files/ip-down b/bundles/wide-dhcp6c/files/ip-down index edc84de..ec060ee 100644 --- a/bundles/wide-dhcp6c/files/ip-down +++ b/bundles/wide-dhcp6c/files/ip-down @@ -3,5 +3,8 @@ systemctl stop wide-dhcpv6-client % for interface, subnet_id in sorted(targets.items()): -ip -6 addr flush dev ${interface} scope global +for IP in $(ip -6 addr show dev ${interface} | grep inet6 | awk '{print $2}' | grep -vF 'fe80::') +do + ip -6 addr del $IP dev ${interface} +done % endfor diff --git a/bundles/wide-dhcp6c/files/ip-up b/bundles/wide-dhcp6c/files/ip-up index da0ac8d..d6624a8 100644 --- a/bundles/wide-dhcp6c/files/ip-up +++ b/bundles/wide-dhcp6c/files/ip-up @@ -12,7 +12,7 @@ if systemctl is-active wide-dhcpv6-client; then systemctl stop wide-dhcpv6-client sleep 1 - systemctl start wide-dhcpv6-client + systemctl sart wide-dhcpv6-client else systemctl start wide-dhcpv6-client fi diff --git a/bundles/wide-dhcp6c/items.py b/bundles/wide-dhcp6c/items.py index 53fc656..fb04b49 100644 --- a/bundles/wide-dhcp6c/items.py +++ b/bundles/wide-dhcp6c/items.py @@ -2,21 +2,18 @@ if node.has_bundle('pppd'): files['/etc/ppp/ip-up.d/wide-dhcp6c'] = { 'source': 'ip-up', 'content_type': 'mako', - 'context': node.metadata.get('wide-dhcp6c'), - 'mode': '0755', - 'triggers': { - 'svc_systemd:wide-dhcpv6-client:restart', + 'context': { + 'source': node.metadata['wide-dhcp6c']['source'], }, + 'mode': '0755', } - files['/etc/ppp/ip-down.d/wide-dhcp6c'] = { 'source': 'ip-down', 'content_type': 'mako', - 'context': node.metadata.get('wide-dhcp6c'), - 'mode': '0755', - 'triggers': { - 'svc_systemd:wide-dhcpv6-client:restart', + 'context': { + 'targets': node.metadata['wide-dhcp6c']['targets'], }, + 'mode': '0755', } # Will be started and stopped by pppd. @@ -28,7 +25,11 @@ else: files['/etc/wide-dhcpv6/dhcp6c.conf'] = { 'content_type': 'mako', - 'context': node.metadata.get('wide-dhcp6c'), + 'context': { + 'source': node.metadata['wide-dhcp6c']['source'], + 'targets': node.metadata['wide-dhcp6c']['targets'], + 'subnet_len': node.metadata['wide-dhcp6c']['subnet_len'], + }, 'triggers': { 'svc_systemd:wide-dhcpv6-client:restart', }, @@ -36,7 +37,9 @@ files['/etc/wide-dhcpv6/dhcp6c.conf'] = { files['/etc/systemd/system/wide-dhcpv6-client.service'] = { 'content_type': 'mako', - 'context': node.metadata.get('wide-dhcp6c'), + 'context': { + 'source': node.metadata['wide-dhcp6c']['source'], + }, 'triggers': { 'action:systemd-reload', 'svc_systemd:wide-dhcpv6-client:restart', diff --git a/bundles/wide-dhcp6c/metadata.py b/bundles/wide-dhcp6c/metadata.py index 050e690..7ac556b 100644 --- a/bundles/wide-dhcp6c/metadata.py +++ b/bundles/wide-dhcp6c/metadata.py @@ -5,10 +5,10 @@ defaults = { }, }, 'nftables': { - 'input': { + 'rules': { '10-wide-dhcp6c': [ - 'udp dport { 546, 547 } ip6 saddr ff00::/12 accept', - 'udp dport { 546, 547 } ip6 saddr fe80::/10 accept', + 'inet filter input udp dport { 546, 547 } ip6 saddr ff00::/12 accept', + 'inet filter input udp dport { 546, 547 } ip6 saddr fe80::/10 accept', ], }, }, diff --git a/bundles/wireguard/files/pppd-ip-up b/bundles/wireguard/files/pppd-ip-up new file mode 100644 index 0000000..5e5d200 --- /dev/null +++ b/bundles/wireguard/files/pppd-ip-up @@ -0,0 +1,10 @@ +#!/bin/bash + +# We need to send some traffic over the wireguard tunnel to make sure +# it gets connected. Easiest way is to simply send some pings to the +# other side. + +% for peer, config in sorted(node.metadata.get('wireguard/peers', {}).items()): +# refresh connection to ${peer} +/usr/bin/ping -c 4 ${config['their_ip']} +% endfor diff --git a/bundles/wireguard/files/wg.netdev b/bundles/wireguard/files/wg.netdev index c6abf78..de9af7f 100644 --- a/bundles/wireguard/files/wg.netdev +++ b/bundles/wireguard/files/wg.netdev @@ -1,5 +1,5 @@ [NetDev] -Name=wg_${iface} +Name=wg${number} Kind=wireguard Description=WireGuard connection to ${peer} @@ -10,12 +10,8 @@ ListenPort=${port} [WireGuardPeer] PublicKey=${pubkey} AllowedIPs=0.0.0.0/0 -% if psk: PresharedKey=${psk} -% endif % if endpoint: Endpoint=${endpoint} % endif -% if specials.get('persistent_keepalive', True): PersistentKeepalive=30 -% endif diff --git a/bundles/wireguard/files/wg_health_check b/bundles/wireguard/files/wg_health_check new file mode 100644 index 0000000..976e112 --- /dev/null +++ b/bundles/wireguard/files/wg_health_check @@ -0,0 +1,46 @@ +#!/bin/bash + +if [[ -e "/var/lib/bundlewrap/hard-${node.name}/info" ]] +then + # make sure we're not restarting during bw apply + echo "bw apply running" + exit 0 +fi + +now="$(date +%s)" + +everything_up=1 + +% for peer, ip in sorted(peers.items()): +# ${peer} +if ! /usr/bin/ping -c 4 ${ip} >/dev/null 2>&1 +then + echo "${peer} was not reachable!" + everything_up=0 +fi + +% endfor +if [[ "$everything_up" -eq 1 ]] +then + echo "Everything is up as expected" + echo "$now" > /var/tmp/wg_all_reached + exit 0 +fi + +five_min_ago="$(expr $now - 300)" +last_reached="$(cat /var/tmp/wg_all_reached)" + +if [[ "$last_reached" -lt "$five_min_ago" ]] +then + echo "RESTART" + + systemctl restart systemd-networkd + + # only restart once an hour + echo "$(expr $now + 3300)" > /var/tmp/wg_all_reached +elif [[ "$last_reached" -gt "$now" ]] +then + echo "Something's broken, but we have recently restarted" +else + echo "Something's broken, but still in grace time" +fi diff --git a/bundles/wireguard/items.py b/bundles/wireguard/items.py index 0d8d13d..37d018b 100644 --- a/bundles/wireguard/items.py +++ b/bundles/wireguard/items.py @@ -13,24 +13,46 @@ deps = set() if node.has_bundle('apt'): deps.add('pkg_apt:wireguard') -for peer, config in sorted(node.metadata.get('wireguard/peers', {}).items()): - files[f'/etc/systemd/network/wg_{config["iface"]}.netdev'] = { +health_checks = {} +for number, (peer, config) in enumerate(sorted(node.metadata.get('wireguard/peers', {}).items())): + files[f'/etc/systemd/network/wg{number}.netdev'] = { 'content_type': 'mako', 'source': 'wg.netdev', 'owner': 'systemd-network', 'mode': '0600', 'context': { 'endpoint': config.get('endpoint'), - 'iface': config['iface'], + 'number': number, 'peer': peer, 'port': config['my_port'], 'privatekey': node.metadata.get('wireguard/privatekey'), - 'psk': config.get('psk'), + 'psk': config['psk'], 'pubkey': config['pubkey'], - 'specials': repo.libs.s2s.WG_AUTOGEN_SETTINGS.get(peer, {}), }, 'needs': deps, 'triggers': { 'svc_systemd:systemd-networkd:restart', }, } + + if config.get('health_check', False): + health_checks[peer] = config['their_ip'] + +if health_checks: + files['/usr/local/bin/wg_health_check'] = { + 'content_type': 'mako', + 'context': { + 'peers': health_checks, + }, + 'mode': '0755', + } + files['/etc/cron.d/wg_health_check'] = { + 'content': '* * * * * root /usr/local/bin/wg_health_check | logger -t wg_health_check\n', + } + +if node.has_bundle('pppd'): + files['/etc/ppp/ip-up.d/reconnect-wireguard'] = { + 'source': 'pppd-ip-up', + 'content_type': 'mako', + 'mode': '0755', + } diff --git a/bundles/wireguard/metadata.py b/bundles/wireguard/metadata.py index 267be6a..21e9b8f 100644 --- a/bundles/wireguard/metadata.py +++ b/bundles/wireguard/metadata.py @@ -1,34 +1,28 @@ from ipaddress import ip_network -from re import sub from bundlewrap.exceptions import NoSuchNode from bundlewrap.metadata import atomic + defaults = { 'apt': { 'packages': { 'wireguard': {}, }, + 'repos': { + 'backports': { + 'install_gpg_key': False, # default debian signing key + 'items': { + 'deb http://deb.debian.org/debian {os_release}-backports main', + }, + }, + }, }, 'wireguard': { 'privatekey': repo.libs.keys.gen_privkey(repo, f'{node.name} wireguard privatekey'), }, } -if node.os_version <= (11,): - defaults['apt']['repos'] = { - 'backports': { - 'install_gpg_key': False, # default debian signing key - 'items': { - 'deb http://deb.debian.org/debian {os_release}-backports main', - }, - }, - } -else: - defaults['apt']['packages']['wireguard-dkms'] = { - 'installed': False, - } - if node.has_bundle('telegraf'): defaults['telegraf'] = { 'input_plugins': { @@ -42,35 +36,6 @@ if node.has_bundle('telegraf'): } -@metadata_reactor.provides( - 'wireguard/peers', -) -def peers_auto_full_mesh(metadata): - peers = {} - - if node.name not in repo.libs.s2s.WG_AUTOGEN_NODES: - return {} - - for rnode in repo.libs.s2s.WG_AUTOGEN_NODES: - if rnode is None or rnode == node.name: - continue - - try: - rnode = repo.get_node(rnode) - except NoSuchNode: - continue - - if rnode.dummy: - continue - - peers[rnode.name] = {} - - return { - 'wireguard': { - 'peers': peers, - }, - } - @metadata_reactor.provides( 'wireguard/peers', @@ -79,19 +44,16 @@ def peer_psks(metadata): peers = {} for peer_name in metadata.get('wireguard/peers', {}): - peers[peer_name] = { - 'iface': sub('[^a-z0-9-_]+', '_', peer_name)[:12], - } + peers[peer_name] = {} - try: - repo.get_node(peer_name) - - if node.name < peer_name: - peers[peer_name]['psk'] = repo.vault.random_bytes_as_base64_for(f'{node.name} wireguard {peer_name}') - else: - peers[peer_name]['psk'] = repo.vault.random_bytes_as_base64_for(f'{peer_name} wireguard {node.name}') - except NoSuchNode: - pass + if node.name < peer_name: + peers[peer_name] = { + 'psk': repo.vault.random_bytes_as_base64_for(f'{node.name} wireguard {peer_name}'), + } + else: + peers[peer_name] = { + 'psk': repo.vault.random_bytes_as_base64_for(f'{peer_name} wireguard {node.name}'), + } return { 'wireguard': { @@ -131,9 +93,6 @@ def peer_pubkeys(metadata): 'wireguard/peers', ) def peer_ips_and_ports(metadata): - if node.name not in repo.libs.s2s.WG_AUTOGEN_NODES: - raise DoNotRunAgain - peers = {} base_port = 51820 @@ -143,9 +102,6 @@ def peer_ips_and_ports(metadata): except NoSuchNode: continue - if rnode.name not in repo.libs.s2s.WG_AUTOGEN_NODES: - continue - ip_a, ip_b = repo.libs.s2s.get_subnet_for_connection(repo, *sorted({node.name, peer_name})) if peer_name < node.name: @@ -157,7 +113,7 @@ def peer_ips_and_ports(metadata): peers[rnode.name] = { 'my_ip': str(my_ip), - 'my_port': base_port + repo.libs.s2s.WG_AUTOGEN_NODES.index(rnode.name), + 'my_port': base_port + number, 'their_ip': str(their_ip) } @@ -180,13 +136,11 @@ def peer_endpoints(metadata): except NoSuchNode: continue - if repo.libs.s2s.WG_AUTOGEN_SETTINGS.get(name, {}).get('no_autoconnect'): - continue peers[rnode.name] = { 'endpoint': '{}:{}'.format( - rnode.hostname, - rnode.metadata.get(f'wireguard/peers/{node.name}/my_port'), + rnode.metadata.get('wireguard/external_hostname', rnode.hostname), + rnode.metadata.get(f'wireguard/peers/{node.name}/my_port', 51820), ), } @@ -203,12 +157,12 @@ def peer_endpoints(metadata): def icinga2(metadata): services = {} - for peer, config in sorted(metadata.get('wireguard/peers', {}).items()): + for number, (peer, config) in enumerate(sorted(metadata.get('wireguard/peers', {}).items())): if config.get('exclude_from_monitoring', False): continue services[f'WIREGUARD CONNECTION {peer}'] = { - 'command_on_monitored_host': config['pubkey'].format_into(f'sudo /usr/local/share/icinga/plugins/check_wireguard_connected wg_{config["iface"]} {{}}'), + 'command_on_monitored_host': config['pubkey'].format_into(f'sudo /usr/local/share/icinga/plugins/check_wireguard_connected wg{number} {{}}'), } return { @@ -231,9 +185,7 @@ def firewall(metadata): except NoSuchNode: # roadwarrior ports['{}/udp'.format(config['my_port'])] = atomic(set(metadata.get('wireguard/restrict-to', set()))) else: - ports['{}/udp'.format(config['my_port'])] = atomic( - set(repo.libs.s2s.WG_AUTOGEN_SETTINGS.get(name, {}).get('firewall', set())) | {name} - ) + ports['{}/udp'.format(config['my_port'])] = atomic({name}) return { 'firewall': { @@ -247,31 +199,15 @@ def firewall(metadata): ) def interface_ips(metadata): interfaces = {} - snat_ip = metadata.get('wireguard/snat_ip', None) - - for peer, config in sorted(metadata.get('wireguard/peers', {}).items()): - routes = {} - + for number, (peer, config) in enumerate(sorted(metadata.get('wireguard/peers', {}).items())): if '/' in config['my_ip']: my_ip = config['my_ip'] else: my_ip = '{}/31'.format(config['my_ip']) - - ips = {my_ip} - if snat_ip and peer in repo.libs.s2s.WG_AUTOGEN_NODES: - ips.add(snat_ip) - - their_ip = config['their_ip'] - if '/' in their_ip: - their_ip = their_ip.split('/')[0] - - for route in config.get('routes', set()): - routes[route] = {'via': their_ip} - - interfaces[f'wg_{config["iface"]}'] = { - 'activation_policy': 'up' if config.get('auto_connection', True) else 'manual', - 'ips': ips, - 'routes': routes, + interfaces[f'wg{number}'] = { + 'ips': { + my_ip, + }, } return { 'interfaces': interfaces, @@ -279,37 +215,28 @@ def interface_ips(metadata): @metadata_reactor.provides( - 'nftables/forward/10-wireguard', - 'nftables/postrouting/10-wireguard', + 'nftables/rules/10-wireguard', ) def snat(metadata): - if not node.has_bundle('nftables'): + if not node.has_bundle('nftables') or node.os == 'arch': raise DoNotRunAgain - snat_ip = metadata.get('wireguard/snat_ip', None) + rules = set() + for number, (peer, config) in enumerate(sorted(metadata.get('wireguard/peers', {}).items())): + rules.add(f'inet filter forward iifname wg{number} accept') + rules.add(f'inet filter forward oifname wg{number} accept') - forward = set() - postrouting = set() - for peer, config in sorted(metadata.get('wireguard/peers', {}).items()): - forward.add(f'iifname wg_{config["iface"]} accept') - forward.add(f'oifname wg_{config["iface"]} accept') - - if snat_ip and peer in repo.libs.s2s.WG_AUTOGEN_NODES: - postrouting.add('ip saddr {} ip daddr != {} snat to {}'.format( + if 'snat_to' in config: + rules.add('nat postrouting ip saddr {} ip daddr != {} snat to {}'.format( config['my_ip'], config['their_ip'], - snat_ip, + config['snat_to'], )) - elif config.get('masquerade', False): - postrouting.add(f'oifname wg_{peer} masquerade') return { 'nftables': { - 'forward': { - '10-wireguard': sorted(forward), - }, - 'postrouting': { - '10-wireguard': sorted(postrouting), + 'rules': { + '10-wireguard': sorted(rules), }, }, } diff --git a/bundles/zfs/files/check_zpool_online b/bundles/zfs/files/check_zpool_online index 0e7c16c..9fb0cae 100644 --- a/bundles/zfs/files/check_zpool_online +++ b/bundles/zfs/files/check_zpool_online @@ -5,14 +5,11 @@ if [ $# -eq 0 ] ; then exit 3 fi -status="$(zpool status "$1")" - -if [ "$(echo "$status" | grep '^ state:')" = ' state: ONLINE' ] +if [ "$(zpool status "$1" | grep '^ state:')" = ' state: ONLINE' ] then echo "OK - Pool '$1' is online" exit 0 else echo "CRITICAL - Pool '$1' is FAULTY or NOT ONLINE" - echo "$status" exit 2 fi diff --git a/bundles/zfs/files/check_zpool_space b/bundles/zfs/files/check_zpool_space index abb533e..ff4b9bb 100644 --- a/bundles/zfs/files/check_zpool_space +++ b/bundles/zfs/files/check_zpool_space @@ -1,9 +1,9 @@ #!/usr/bin/env python3 -import re from subprocess import check_output from sys import argv, exit +import re def to_bytes(size): diff --git a/bundles/zfs/files/zfs-auto-snapshot b/bundles/zfs/files/zfs-auto-snapshot index 8e38cf7..4f1c919 100644 --- a/bundles/zfs/files/zfs-auto-snapshot +++ b/bundles/zfs/files/zfs-auto-snapshot @@ -2,6 +2,7 @@ import re + from datetime import datetime from json import loads from subprocess import check_call, check_output diff --git a/bundles/zfs/files/zfs-import-scan-override.service b/bundles/zfs/files/zfs-import-scan-override.service index 9004ee2..3853425 100644 --- a/bundles/zfs/files/zfs-import-scan-override.service +++ b/bundles/zfs/files/zfs-import-scan-override.service @@ -3,4 +3,8 @@ ConditionPathExists= [Service] ExecStart= +% if node.os == 'arch': +ExecStart=/usr/bin/zpool import -aN -o cachefile=none +% else: ExecStart=/usr/sbin/zpool import -aN -o cachefile=none +% endif diff --git a/bundles/zfs/items.py b/bundles/zfs/items.py index 530d27f..8dda658 100644 --- a/bundles/zfs/items.py +++ b/bundles/zfs/items.py @@ -1,7 +1,29 @@ from json import dumps +#from os.path import join from bundlewrap.metadata import MetadataJSONEncoder +if node.os == 'debian': + actions = { + # For some reason, this module doesn't get auto-loaded on debian, + # even if installation of zfsutils-linux tries to start + # zfs-mount.service. We have no choice but to do it manually. + 'modprobe_zfs': { + 'command': 'modprobe zfs', + 'unless': 'lsmod | grep ^zfs', + 'needs': { + 'pkg_apt:zfs-dkms', + }, + 'needed_by': { + 'pkg_apt:zfs-zed', + 'pkg_apt:zfsutils-linux', + 'zfs_dataset:', + 'zfs_pool:', + }, + 'comment': 'If this fails, do a dist-upgrade, reinstall zfs-dkms, reboot', + }, + } + files = { '/etc/modprobe.d/zfs.conf': { 'source': 'zfs-modprobe.conf', @@ -66,10 +88,6 @@ svc_systemd = { 'needs': { 'file:/etc/systemd/system/zfs-import-scan.service.d/bundlewrap.conf', }, - 'after': { - 'bundle:dm-crypt', # might unlock disks - 'pkg_apt:', - }, 'before': { 'svc_systemd:zfs-import-cache.service', }, @@ -78,32 +96,14 @@ svc_systemd = { 'running': None, 'enabled': False, 'masked': True, - 'after': { - 'pkg_apt:', - }, - }, - 'zfs-mount.service': { - 'after': { - 'bundle:dm-crypt', # might unlock disks - 'pkg_apt:', - }, - }, - 'zfs-zed': { - 'after': { - 'pkg_apt:', - }, }, + 'zfs-mount.service': {}, + 'zfs-zed': {}, 'zfs.target': { 'running': None, - 'after': { - 'pkg_apt:', - }, }, 'zfs-import.target': { 'running': None, - 'after': { - 'pkg_apt:', - }, }, } diff --git a/bundles/zfs/metadata.py b/bundles/zfs/metadata.py index 3b63e0b..624e2a6 100644 --- a/bundles/zfs/metadata.py +++ b/bundles/zfs/metadata.py @@ -3,6 +3,11 @@ defaults = { 'apt': { 'packages': { + 'linux-headers-amd64': { + 'needed_by': { + 'pkg_apt:zfs-dkms', + }, + }, 'zfs-dkms': { 'needed_by': { 'pkg_apt:zfs-zed', @@ -43,6 +48,18 @@ defaults = { }, }, }, + 'pacman': { + 'no_extract': { + 'etc/sudoers.d/zfs', + }, + 'packages': { + 'zfs-utils': { + 'needed_by': { + 'svc_systemd:zfs-zed', + }, + }, + }, + }, 'systemd-timers': { 'timers': { 'zfs-auto-snapshot-daily': { @@ -110,17 +127,20 @@ if node.has_bundle('telegraf'): @metadata_reactor.provides( - 'apt/packages', + 'pacman/packages', ) -def linux_headers(metadata): - cpu_arch = metadata.get('cpu_arch', 'amd64') - +def packages(metadata): + if node.metadata.get('pacman/linux-lts', False): + pkgname = 'zfs-linux-lts' + else: + pkgname = 'zfs-linux' return { - 'apt': { + 'pacman': { 'packages': { - f'linux-headers-{cpu_arch}': { + pkgname: { 'needed_by': { - 'pkg_apt:zfs-dkms', + 'zfs_dataset:', + 'zfs_pool:', }, }, }, @@ -137,7 +157,7 @@ def scrub_timer(metadata): 'systemd-timers': { 'timers': { 'zfs-scrub': { - 'when': metadata.get('zfs/scrub_when', 'Sun 02:00:00 UTC'), + 'when': 'Sun 02:00:00 UTC', 'command': scrubs, }, }, diff --git a/configs/as3320.txt b/configs/as3320.txt index 0ac3052..4eb09e7 100644 --- a/configs/as3320.txt +++ b/configs/as3320.txt @@ -1,8 +1,10 @@ -109.203.176.0/21 +109.160.36.0/24 +109.160.37.0/24 +109.160.38.0/24 +109.160.39.0/24 +109.160.40.0/24 +109.160.41.0/24 109.237.176.0/20 -109.72.116.0/24 -116.50.16.0/21 -128.65.164.0/22 129.181.208.0/21 129.181.216.0/22 137.170.112.0/24 @@ -16,13 +18,22 @@ 139.12.255.0/24 139.12.3.0/24 139.12.4.0/24 +141.11.17.0/24 +141.11.18.0/24 +141.11.247.0/24 141.169.240.0/20 141.77.0.0/16 -143.99.213.0/24 +141.98.44.0/24 +145.225.1.0/24 +145.225.148.0/22 +145.225.152.0/24 145.225.16.0/23 +145.225.2.0/24 +147.136.68.0/22 +147.136.76.0/22 +147.136.84.0/22 147.161.22.0/24 147.78.17.0/24 -147.79.8.0/21 149.208.250.0/23 149.208.252.0/24 149.208.253.0/24 @@ -31,14 +42,10 @@ 149.237.203.0/24 149.237.250.0/24 149.237.251.0/24 -149.237.254.0/24 149.243.232.0/22 149.249.244.0/22 149.249.244.0/23 149.249.246.0/23 -151.243.168.0/24 -151.243.173.0/24 -153.17.244.8/29 153.17.249.0/24 153.17.250.0/24 153.17.251.0/24 @@ -48,15 +55,8 @@ 153.17.255.0/24 153.96.218.0/24 153.96.22.0/24 -153.97.32.0/24 -153.97.34.0/24 158.116.231.0/24 -163.5.156.0/24 -163.5.170.0/24 -163.5.186.0/24 -163.5.220.0/24 -163.5.47.0/24 -163.5.66.0/24 +160.211.126.0/24 164.133.10.0/24 164.133.11.0/24 164.133.150.0/24 @@ -65,42 +65,46 @@ 164.133.91.0/24 164.133.98.0/24 164.133.99.0/24 -168.199.128.0/22 -168.199.160.0/22 -168.199.192.0/22 -168.199.212.0/22 +164.18.96.0/21 170.237.92.0/23 +171.25.178.0/24 +176.221.24.0/24 +176.221.25.0/24 176.53.136.0/24 176.53.137.0/24 -176.57.59.0/24 +179.61.160.0/22 185.100.160.0/22 -185.101.244.0/23 -185.101.246.0/23 185.101.4.0/22 185.109.108.0/22 +185.112.249.0/24 185.114.200.0/22 185.124.48.0/24 185.126.168.0/22 185.131.239.0/24 185.133.12.0/22 185.136.115.0/24 +185.149.25.0/24 +185.149.26.0/24 +185.149.27.0/24 185.149.52.0/24 185.157.101.0/24 185.161.176.0/22 +185.162.72.0/23 185.163.76.0/24 185.163.77.0/24 185.163.78.0/24 185.163.79.0/24 +185.172.38.0/24 +185.172.39.0/24 185.180.224.0/24 -185.183.212.0/23 -185.183.214.0/23 185.188.64.0/24 -185.195.239.0/24 185.198.13.0/24 185.202.32.0/21 +185.203.148.0/22 +185.206.69.0/24 185.207.46.0/24 -185.21.247.0/24 -185.224.0.0/24 +185.215.183.0/24 +185.230.136.0/24 185.237.0.0/24 185.237.1.0/24 185.237.2.0/24 @@ -113,16 +117,14 @@ 185.28.208.0/22 185.39.12.0/22 185.48.0.0/22 -185.57.24.0/24 185.82.160.0/23 -185.97.227.0/24 -188.208.124.0/24 -188.208.125.0/24 -188.209.223.0/24 -188.214.136.0/24 -188.214.137.0/24 -188.214.138.0/24 -188.214.139.0/24 +185.91.204.0/22 +185.95.156.0/24 +185.95.157.0/24 +185.95.158.0/24 +185.95.159.0/24 +188.208.103.0/24 +192.109.121.0/24 192.109.122.0/24 192.109.124.0/24 192.109.129.0/24 @@ -139,8 +141,10 @@ 192.109.209.0/24 192.109.54.0/24 192.109.96.0/24 +192.124.252.0/24 192.129.58.0/24 192.145.8.0/22 +192.166.146.0/23 192.166.253.0/24 192.166.49.0/24 192.166.52.0/24 @@ -148,6 +152,7 @@ 192.31.102.0/24 192.54.39.0/24 192.54.48.0/24 +192.54.66.0/24 192.54.73.0/24 192.54.79.0/24 192.67.167.0/24 @@ -163,6 +168,7 @@ 193.100.248.0/22 193.100.252.0/24 193.100.3.0/24 +193.101.12.0/22 193.101.128.0/22 193.101.139.0/24 193.101.162.0/23 @@ -187,15 +193,14 @@ 193.141.180.0/23 193.141.91.0/24 193.143.24.0/22 -193.151.248.0/22 193.158.0.0/15 193.16.184.0/23 193.16.235.0/24 -193.163.15.0/24 193.168.0.0/24 193.168.232.0/22 193.168.234.0/23 193.169.204.0/23 +193.178.226.0/23 193.188.196.0/24 193.201.170.0/24 193.201.206.0/24 @@ -203,7 +208,6 @@ 193.22.110.0/24 193.22.111.0/24 193.22.16.0/22 -193.22.164.0/24 193.22.174.0/24 193.22.205.0/24 193.22.29.0/24 @@ -229,10 +233,12 @@ 193.28.34.0/23 193.28.48.0/23 193.28.50.0/24 +193.28.64.0/21 193.29.112.0/24 193.29.115.0/24 193.29.116.0/24 193.29.126.0/24 +193.29.152.0/21 193.29.158.0/24 193.3.240.0/24 193.30.136.0/22 @@ -250,14 +256,12 @@ 193.53.93.0/24 193.58.253.0/24 193.84.136.0/22 -193.96.230.0/24 193.96.232.0/23 193.97.238.0/24 193.98.181.0/24 193.98.224.0/24 193.99.96.0/20 194.0.151.0/24 -194.0.232.0/24 194.110.133.0/24 194.113.160.0/22 194.113.20.0/23 @@ -268,8 +272,6 @@ 194.115.120.0/24 194.115.163.0/24 194.115.182.0/23 -194.115.182.0/24 -194.115.183.0/24 194.115.52.0/24 194.115.66.0/24 194.115.88.0/21 @@ -291,23 +293,13 @@ 194.127.182.0/24 194.127.195.0/24 194.127.208.0/22 -194.127.242.0/23 194.127.254.0/24 194.145.252.0/24 -194.147.171.0/24 194.15.194.0/24 194.15.60.0/24 194.15.61.0/24 194.15.64.0/21 194.15.72.0/22 -194.150.228.0/23 -194.152.128.0/24 -194.152.129.0/24 -194.152.132.0/24 -194.152.141.0/24 -194.152.142.0/24 -194.152.154.0/24 -194.152.155.0/24 194.153.86.0/24 194.156.128.0/22 194.156.148.0/24 @@ -329,7 +321,7 @@ 194.180.64.0/20 194.25.0.0/16 194.25.1.5/32 -194.31.142.0/24 +194.26.191.0/24 194.31.208.0/24 194.31.209.0/24 194.31.210.0/24 @@ -339,29 +331,27 @@ 194.33.115.0/24 194.33.120.0/24 194.33.121.0/24 -194.33.50.0/24 -194.38.48.0/24 -194.38.49.0/24 -194.38.50.0/24 -194.38.51.0/24 194.39.175.0/24 194.39.189.0/24 194.39.48.0/20 194.39.48.0/21 194.39.56.0/21 -194.39.61.0/24 194.39.62.0/24 194.39.63.0/24 194.39.88.0/21 194.39.97.0/24 +194.45.144.0/21 +194.49.110.0/24 194.49.117.0/24 194.49.118.0/23 194.49.125.0/24 194.49.48.0/24 194.49.54.0/24 +194.49.72.0/24 194.49.73.0/24 194.49.74.0/23 194.49.85.0/24 +194.55.158.0/24 194.55.180.0/24 194.55.183.0/24 194.55.192.0/19 @@ -402,17 +392,17 @@ 194.99.76.0/23 194.99.83.0/24 194.99.92.0/22 -195.133.7.0/24 195.137.216.0/23 195.138.223.0/24 195.144.15.0/24 195.145.0.0/16 195.149.79.0/24 195.160.248.0/22 +195.178.132.0/22 195.190.2.0/24 195.192.254.0/24 +195.20.114.0/23 195.200.207.0/24 -195.226.200.0/24 195.230.116.0/24 195.234.133.0/24 195.243.0.0/16 @@ -421,13 +411,13 @@ 195.248.140.0/23 195.248.144.0/23 195.248.89.0/24 +195.250.48.0/24 195.250.50.0/24 195.250.57.0/24 195.36.64.0/18 195.36.81.0/24 195.36.90.0/24 195.36.91.0/24 -195.66.83.0/24 195.68.204.0/23 195.74.94.0/24 195.78.249.0/24 @@ -435,26 +425,14 @@ 198.40.90.0/24 198.57.10.0/24 2.160.0.0/12 -2.58.100.0/24 -2.58.102.0/24 -204.52.120.0/24 -204.52.121.0/24 204.69.32.0/24 205.142.63.0/24 +212.102.107.0/24 212.184.0.0/15 212.185.0.0/16 -212.68.172.0/22 -212.68.176.0/22 -212.68.180.0/22 -213.145.90.0/23 -213.145.92.0/23 213.173.0.0/19 -213.209.136.0/24 -213.209.149.0/24 -213.209.156.0/24 217.0.0.0/13 217.117.96.0/24 -217.177.33.0/24 217.224.0.0/11 217.24.32.0/20 217.24.33.0/24 @@ -462,49 +440,42 @@ 217.80.0.0/12 31.212.0.0/15 31.224.0.0/11 -31.6.56.0/23 -37.143.0.0/22 -37.230.61.0/24 +31.6.52.0/22 37.46.11.0/24 37.50.0.0/15 37.80.0.0/12 -45.112.192.0/24 -45.129.165.0/24 +45.10.157.0/24 +45.128.158.0/23 45.132.80.0/22 -45.141.54.0/24 -45.145.16.0/24 -45.147.227.0/24 -45.149.7.0/24 -45.155.77.0/24 -45.81.255.0/24 -45.83.136.0/22 -45.93.186.0/23 -46.202.0.0/24 -46.250.224.0/21 -46.250.232.0/21 +45.140.8.0/23 +45.141.232.0/24 +45.141.62.0/23 +45.151.112.0/23 +45.151.114.0/23 +45.154.238.0/23 +45.157.202.0/23 +45.157.32.0/23 +45.90.184.0/22 46.78.0.0/15 46.80.0.0/12 +5.10.208.0/24 +5.10.209.0/24 +5.10.220.0/24 5.133.112.0/24 -5.249.188.0/22 -5.35.192.0/21 62.153.0.0/16 62.154.0.0/15 62.155.0.0/16 62.156.0.0/14 62.156.153.0/24 62.156.168.0/24 +62.192.152.0/24 62.224.0.0/14 62.56.208.0/21 -62.68.73.0/24 -62.72.172.0/24 -64.137.119.0/24 -64.137.125.0/24 -64.137.127.0/24 +62.76.229.0/24 77.47.152.0/22 77.83.136.0/23 77.83.138.0/23 -77.90.156.0/24 -77.90.184.0/24 +78.159.131.0/24 79.192.0.0/10 80.128.0.0/11 80.128.0.0/12 @@ -516,97 +487,43 @@ 80.157.8.0/21 80.187.0.0/16 80.187.160.0/20 -80.244.13.0/24 80.64.240.0/22 -80.71.231.0/24 -80.71.233.0/24 -80.71.235.0/24 -80.71.236.0/24 -80.71.238.0/24 -80.83.80.0/21 81.201.32.0/20 -81.31.210.0/23 -82.163.104.0/21 -82.163.60.0/22 -82.206.32.0/21 -82.206.40.0/21 -82.206.48.0/21 -82.215.70.0/24 +81.30.96.0/20 +83.136.208.0/22 +83.147.40.0/22 83.243.48.0/21 +83.243.55.0/24 84.128.0.0/10 84.246.108.0/24 -84.32.108.0/22 +84.32.20.0/22 84.32.48.0/22 -84.55.0.0/24 -84.55.1.0/24 -84.55.17.0/24 -84.55.2.0/24 -84.55.22.0/24 -84.55.3.0/24 -84.55.4.0/24 -84.55.5.0/24 -84.55.6.0/24 -84.55.7.0/24 -85.116.28.0/24 -85.116.29.0/24 -85.116.30.0/24 -85.116.31.0/24 +84.32.56.0/22 +84.46.240.0/20 85.119.160.0/23 -85.133.193.0/24 -85.133.208.0/24 -85.133.214.0/24 -85.133.254.0/24 -85.204.181.0/24 85.208.248.0/24 85.208.249.0/24 85.208.250.0/24 85.208.251.0/24 -86.105.211.0/24 -86.105.58.0/24 -86.107.164.0/24 -86.110.57.0/24 +85.239.148.0/24 +85.239.149.0/24 +85.239.150.0/24 +85.239.151.0/24 +86.38.156.0/24 86.38.248.0/21 86.38.37.0/24 87.128.0.0/10 87.128.0.0/11 87.237.240.0/21 88.128.0.0/16 -88.135.96.0/20 -88.216.60.0/22 +88.216.208.0/24 +89.116.248.0/24 89.116.64.0/22 -89.213.186.0/23 -89.39.97.0/24 +89.117.172.0/22 +89.35.127.0/24 +89.35.72.0/24 91.0.0.0/10 91.103.240.0/21 -91.124.135.0/24 -91.124.19.0/24 -91.124.20.0/24 -91.124.21.0/24 -91.124.22.0/24 -91.124.23.0/24 -91.124.24.0/24 -91.124.26.0/24 -91.124.27.0/24 -91.124.28.0/24 -91.124.31.0/24 -91.124.33.0/24 -91.124.34.0/24 -91.124.36.0/24 -91.124.37.0/24 -91.124.38.0/24 -91.124.39.0/24 -91.124.40.0/24 -91.124.41.0/24 -91.124.42.0/24 -91.124.43.0/24 -91.124.44.0/24 -91.124.45.0/24 -91.124.46.0/24 -91.124.47.0/24 -91.124.50.0/24 -91.124.51.0/24 -91.124.6.0/24 -91.124.7.0/24 91.189.192.0/21 91.194.232.0/23 91.198.113.0/24 @@ -626,52 +543,44 @@ 91.212.130.0/24 91.212.243.0/24 91.213.116.0/24 -91.214.10.0/24 91.215.116.0/22 91.216.242.0/24 91.216.45.0/24 91.217.214.0/24 -91.221.12.0/23 91.222.232.0/22 91.227.98.0/23 91.232.54.0/24 -91.246.176.0/21 -92.112.10.0/24 -92.112.158.0/24 -92.112.16.0/22 -92.112.20.0/22 -92.112.48.0/24 -92.112.6.0/24 -92.112.7.0/24 -92.112.8.0/24 -92.114.44.0/22 -92.119.164.0/22 +91.92.33.0/24 +91.92.34.0/24 +91.92.35.0/24 +91.92.49.0/24 +92.118.161.0/24 92.119.208.0/24 92.119.209.0/24 92.119.210.0/24 92.119.211.0/24 -93.113.70.0/24 -93.119.201.0/24 -93.119.232.0/24 +93.152.205.0/24 +93.152.207.0/24 +93.152.209.0/24 +93.152.215.0/24 +93.152.219.0/24 +93.152.221.0/24 +93.152.223.0/24 +93.152.224.0/24 +93.152.225.0/24 93.192.0.0/10 94.126.98.0/24 -94.176.72.0/24 -94.176.74.0/24 -94.176.79.0/24 -94.26.110.0/23 -94.26.64.0/23 -95.178.8.0/21 +94.26.90.0/24 2001:650:cc02::/48 2001:678:184::/48 2001:678:36c::/48 2001:678:480::/48 -2001:678:5b0::/48 2001:678:5d4::/48 2001:678:a04::/48 2001:678:adc::/48 2001:678:b38::/48 -2001:678:bdc::/48 2001:678:d4c::/48 +2001:678:e9c::/48 2001:678:ff0::/48 2001:67c:11a4::/48 2001:67c:14c4::/48 @@ -689,34 +598,13 @@ 2001:67c:764::/48 2001:67c:94c::/48 2001:67c:a34::/48 -2001:67c:b80::/48 -2001:67c:c84::/48 -2001:67c:c9c::/48 -2001:67c:ec0::/48 2003:3c0::/28 2003:3e0::/28 2003:8:1800::/48 2003:8:1803::/48 -2003:8:f400::/48 -2003:8:f401::/48 -2003:8:f402::/48 -2003:8:f403::/48 -2003:8:f404::/48 -2003:8:f405::/48 -2003:8:f406::/48 -2003:8:f407::/48 -2003:8:f408::/48 -2003:8:f409::/48 -2003:8:f40a::/48 -2003:8:f40b::/48 -2003:8:f40c::/48 -2003:8:f40d::/48 -2003:8:f40e::/48 2003::/19 2003::/20 2003::/23 -2a00:5c60:3::/48 -2a00:5c60:a::/48 2a00:6680::/46 2a01:598::/29 2a01:8fa0::/32 @@ -730,10 +618,12 @@ 2a06:1800::/29 2a06:1a80::/29 2a06:7180::/29 +2a07:b982:c000::/48 2a09:6f80::/29 2a09:8180::/30 2a0a:5340:ffff::/48 2a0a:a3c0:b0::/44 +2a0b:3c41:1::/48 2a0b:3c41:2::/48 2a0c:9e02:1000::/40 2a0c:9e02:100::/40 @@ -748,12 +638,6 @@ 2a0d:480::/29 2a0d:480::/30 2a0d:484::/30 -2a0e:cbc4::/32 -2a0e:cbc5::/32 -2a0e:cbc6::/32 -2a0e:cbc7::/32 2a0e:eb40::/32 2a10:cd80::/29 2a11:7400:d1::/48 -2a12:6900:1000::/40 -2a13:9500:2::/48 diff --git a/configs/as8881.txt b/configs/as8881.txt index aa354f9..9420d5f 100644 --- a/configs/as8881.txt +++ b/configs/as8881.txt @@ -1,14 +1,20 @@ 104.151.0.0/17 109.250.0.0/16 -109.250.0.0/18 +109.250.0.0/20 109.250.128.0/19 +109.250.16.0/20 109.250.160.0/19 109.250.192.0/19 109.250.224.0/19 -109.250.64.0/18 -109.72.113.0/24 +109.250.32.0/20 +109.250.48.0/20 +109.250.64.0/19 +109.250.80.0/22 +109.250.84.0/22 +109.250.88.0/22 +109.250.92.0/22 +109.250.96.0/19 134.101.0.0/21 -14.102.90.0/24 143.58.64.0/18 149.233.32.0/19 153.94.0.0/20 @@ -30,7 +36,6 @@ 185.151.201.0/24 185.151.203.0/24 185.158.48.0/22 -185.187.122.0/24 185.199.205.0/24 185.235.232.0/22 185.8.230.0/23 @@ -41,13 +46,13 @@ 192.166.84.0/22 192.166.87.0/24 192.166.88.0/21 -192.189.14.0/24 193.101.4.0/23 -193.102.10.0/24 +193.101.5.0/24 193.111.212.0/22 193.111.212.0/24 193.163.13.0/24 -193.17.225.0/24 +193.163.13.0/25 +193.163.13.128/25 193.219.15.0/24 193.22.120.0/21 193.22.120.0/24 @@ -62,22 +67,16 @@ 193.22.3.0/24 193.28.72.0/21 193.29.240.0/24 -193.29.241.0/24 -193.29.242.0/24 193.29.243.0/24 -193.29.244.0/24 -193.29.245.0/24 193.29.246.0/24 -193.29.247.0/24 193.30.132.0/24 193.30.140.0/24 193.96.238.0/24 193.98.229.0/24 193.98.40.0/22 193.99.160.0/21 -194.115.182.0/23 -194.115.182.0/24 -194.115.183.0/24 +194.113.252.0/23 +194.113.253.0/24 194.115.26.0/24 194.120.182.0/23 194.120.182.0/24 @@ -88,16 +87,14 @@ 194.127.144.0/21 194.127.203.0/24 194.139.55.0/24 -194.145.218.0/23 +194.145.230.0/24 194.156.216.0/21 194.156.232.0/23 194.156.233.0/24 194.174.168.0/22 -194.180.18.0/24 194.180.53.0/24 194.180.64.0/20 194.187.112.0/24 -194.30.180.0/24 194.31.92.0/24 194.39.185.0/24 194.39.87.0/24 @@ -109,26 +106,27 @@ 194.88.25.0/24 194.9.190.0/24 194.99.0.0/21 +194.99.113.0/24 195.149.80.0/23 195.167.208.0/20 +195.191.20.0/23 195.202.32.0/19 195.226.160.0/19 195.226.96.0/19 195.234.139.0/24 195.238.233.0/24 -195.238.238.0/24 +195.244.10.0/23 195.64.176.0/23 195.93.158.0/23 202.71.128.0/20 -202.71.141.0/24 212.204.0.0/19 -212.23.205.0/24 212.7.128.0/19 212.8.0.0/19 212.80.224.0/19 +212.80.224.0/20 +212.80.240.0/20 212.93.0.0/19 213.138.32.0/19 -213.138.35.0/24 213.139.128.0/19 213.182.128.0/19 213.30.192.0/18 @@ -145,161 +143,322 @@ 45.13.15.0/24 46.142.0.0/16 46.142.0.0/19 +46.142.112.0/20 46.142.128.0/19 46.142.160.0/19 +46.142.194.0/24 46.142.214.0/24 46.142.224.0/19 -46.142.32.0/19 +46.142.32.0/20 +46.142.48.0/20 46.142.64.0/19 -46.142.96.0/19 46.142.96.0/20 46.189.0.0/17 -46.203.156.0/24 -46.203.227.0/24 +46.189.116.0/24 61.8.128.0/19 -61.8.128.0/22 -61.8.132.0/22 -61.8.136.0/22 -61.8.144.0/22 -61.8.152.0/22 -61.8.156.0/24 -61.8.157.0/24 62.214.0.0/16 +62.214.213.0/24 62.214.224.0/19 62.217.32.0/19 62.220.0.0/19 -62.220.1.0/24 62.68.82.0/24 62.72.64.0/19 -62.72.70.0/24 +62.72.88.0/22 +62.72.92.0/23 +62.72.94.0/24 77.74.136.0/21 77.87.190.0/24 -80.241.192.0/20 80.242.160.0/19 82.119.160.0/19 82.140.0.0/18 -82.140.48.0/20 +82.140.2.0/23 +82.140.2.0/24 +82.140.3.0/24 +82.140.48.0/21 82.144.32.0/19 +82.144.34.0/24 +82.144.35.0/24 +82.144.36.0/24 +82.144.37.0/24 82.145.0.0/19 82.194.96.0/19 82.207.128.0/17 82.207.192.0/19 +82.207.224.0/21 +82.207.232.0/22 +82.207.236.0/24 +82.207.240.0/20 +82.207.244.0/24 +82.207.245.0/24 +82.207.246.0/24 +82.207.247.0/24 +82.207.248.0/24 +82.207.249.0/24 +82.207.250.0/24 +82.207.251.0/24 +82.207.252.0/24 +82.207.253.0/24 +82.207.254.0/24 +82.207.255.0/24 83.135.0.0/16 -83.135.0.0/20 +83.135.0.0/22 83.135.112.0/20 -83.135.128.0/19 +83.135.128.0/20 +83.135.144.0/20 +83.135.16.0/22 83.135.160.0/21 +83.135.164.0/22 83.135.168.0/21 83.135.176.0/22 +83.135.180.0/22 83.135.184.0/21 83.135.192.0/20 +83.135.20.0/24 83.135.208.0/20 +83.135.21.0/24 +83.135.22.0/24 83.135.224.0/22 +83.135.23.0/24 +83.135.230.0/23 83.135.232.0/21 +83.135.24.0/24 83.135.240.0/22 +83.135.244.0/24 +83.135.245.0/24 +83.135.248.0/24 +83.135.249.0/24 +83.135.25.0/24 +83.135.250.0/24 +83.135.251.0/24 +83.135.252.0/24 +83.135.253.0/24 +83.135.254.0/24 +83.135.255.0/24 +83.135.26.0/24 +83.135.27.0/24 +83.135.28.0/24 +83.135.29.0/24 +83.135.30.0/24 +83.135.31.0/24 +83.135.32.0/19 +83.135.4.0/22 83.135.64.0/19 +83.135.8.0/21 83.135.96.0/20 +83.243.48.0/21 +83.243.48.0/22 +83.243.52.0/22 84.19.192.0/19 +84.19.192.0/20 +84.19.208.0/20 87.122.0.0/15 +87.122.0.0/16 87.122.0.0/20 87.122.128.0/21 +87.122.136.0/22 87.122.144.0/20 -87.122.16.0/20 +87.122.16.0/22 87.122.160.0/20 87.122.176.0/21 -87.122.192.0/19 +87.122.184.0/24 +87.122.185.0/24 +87.122.186.0/24 +87.122.187.0/24 +87.122.188.0/24 +87.122.189.0/24 +87.122.190.0/24 +87.122.191.0/24 +87.122.192.0/20 +87.122.20.0/22 +87.122.208.0/20 87.122.224.0/19 +87.122.24.0/21 87.122.32.0/19 -87.122.64.0/19 +87.122.64.0/20 +87.122.80.0/20 87.122.96.0/19 -87.123.0.0/19 -87.123.128.0/19 +87.123.0.0/16 +87.123.0.0/20 +87.123.112.0/20 +87.123.128.0/20 +87.123.144.0/20 +87.123.16.0/20 87.123.160.0/20 87.123.176.0/20 -87.123.194.0/24 -87.123.196.0/24 -87.123.203.0/24 +87.123.192.0/20 +87.123.208.0/22 87.123.216.0/21 87.123.224.0/20 -87.123.240.0/21 -87.123.32.0/19 +87.123.240.0/22 +87.123.244.0/22 +87.123.248.0/22 +87.123.252.0/24 +87.123.253.0/24 +87.123.254.0/24 +87.123.255.0/24 +87.123.48.0/20 87.123.64.0/20 87.123.80.0/20 -87.123.96.0/19 +87.123.96.0/20 88.130.0.0/16 +88.130.0.0/19 +88.130.112.0/20 +88.130.130.0/23 +88.130.132.0/22 88.130.136.0/21 -88.130.144.0/20 +88.130.144.0/21 +88.130.152.0/24 +88.130.153.0/24 +88.130.154.0/24 +88.130.155.0/24 +88.130.156.0/22 +88.130.156.0/24 +88.130.157.0/24 +88.130.158.0/24 +88.130.159.0/24 +88.130.160.0/21 88.130.172.0/22 88.130.176.0/21 -88.130.192.0/23 -88.130.194.0/23 +88.130.180.0/24 +88.130.181.0/24 +88.130.182.0/24 +88.130.183.0/24 +88.130.184.0/24 +88.130.185.0/24 +88.130.186.0/24 +88.130.187.0/24 +88.130.188.0/24 +88.130.189.0/24 +88.130.190.0/24 +88.130.191.0/24 +88.130.192.0/21 +88.130.200.0/21 +88.130.208.0/21 88.130.216.0/21 +88.130.216.0/22 +88.130.220.0/24 +88.130.221.0/24 +88.130.222.0/24 +88.130.223.0/24 +88.130.32.0/20 88.130.48.0/24 88.130.49.0/24 88.130.50.0/24 +88.130.51.0/24 88.130.52.0/24 88.130.53.0/24 -88.130.54.0/23 +88.130.54.0/24 +88.130.55.0/24 88.130.56.0/24 88.130.57.0/24 88.130.58.0/24 88.130.59.0/24 +88.130.60.0/24 88.130.61.0/24 +88.130.62.0/24 88.130.63.0/24 88.130.64.0/19 -88.130.96.0/19 -89.187.24.0/24 -89.187.26.0/24 -89.207.200.0/21 +88.130.96.0/20 89.244.0.0/14 +89.244.0.0/16 +89.244.112.0/21 89.244.120.0/21 -89.244.160.0/21 +89.244.120.0/22 +89.244.124.0/24 +89.244.125.0/24 +89.244.126.0/24 +89.244.127.0/24 +89.244.160.0/20 +89.244.164.0/22 +89.244.168.0/21 89.244.176.0/20 89.244.192.0/19 -89.244.224.0/19 +89.244.224.0/20 +89.244.240.0/20 +89.244.64.0/21 +89.244.72.0/22 89.244.76.0/22 -89.244.78.0/23 89.244.80.0/20 -89.244.96.0/22 +89.244.96.0/20 +89.245.0.0/16 89.245.0.0/20 -89.245.112.0/20 -89.245.158.0/24 -89.245.159.0/24 89.245.16.0/20 89.245.160.0/20 89.245.176.0/21 +89.245.184.0/24 +89.245.185.0/24 +89.245.186.0/24 +89.245.187.0/24 +89.245.188.0/24 +89.245.189.0/24 +89.245.190.0/24 +89.245.191.0/24 89.245.192.0/19 89.245.224.0/19 -89.245.32.0/19 -89.245.64.0/19 +89.245.32.0/20 +89.245.48.0/20 +89.245.64.0/20 +89.245.80.0/20 89.245.96.0/20 -89.246.0.0/19 +89.246.0.0/16 +89.246.0.0/20 +89.246.104.0/23 +89.246.106.0/24 +89.246.107.0/24 +89.246.108.0/24 +89.246.109.0/24 +89.246.110.0/24 +89.246.111.0/24 +89.246.112.0/22 +89.246.116.0/22 +89.246.120.0/24 +89.246.121.0/24 89.246.122.0/24 +89.246.123.0/24 89.246.124.0/22 -89.246.160.0/21 +89.246.16.0/20 +89.246.160.0/20 +89.246.176.0/22 +89.246.180.0/22 89.246.184.0/21 89.246.192.0/19 -89.246.32.0/19 +89.246.32.0/20 +89.246.48.0/21 +89.246.56.0/21 89.246.96.0/21 -89.247.0.0/19 +89.247.0.0/16 +89.247.0.0/20 89.247.112.0/21 -89.247.112.0/22 89.247.120.0/22 -89.247.144.0/20 +89.247.124.0/24 +89.247.125.0/24 +89.247.126.0/24 +89.247.127.0/24 +89.247.144.0/22 +89.247.152.0/21 +89.247.16.0/20 89.247.160.0/20 -89.247.179.0/24 89.247.192.0/20 +89.247.208.0/21 89.247.216.0/22 -89.247.228.0/22 -89.247.232.0/21 +89.247.224.0/21 +89.247.232.0/22 89.247.236.0/22 -89.247.252.0/22 -89.247.32.0/19 +89.247.240.0/21 +89.247.240.0/22 +89.247.252.0/24 +89.247.253.0/24 +89.247.254.0/24 +89.247.255.0/24 89.247.32.0/20 +89.247.48.0/20 89.247.64.0/20 89.247.80.0/20 +89.247.96.0/20 89.27.128.0/17 +89.27.153.0/24 91.194.180.0/23 +91.195.104.0/23 91.198.67.0/24 91.199.158.0/24 91.201.128.0/22 @@ -310,6 +469,8 @@ 91.208.212.0/24 91.217.145.0/24 91.220.125.0/24 +91.223.2.0/24 +91.223.41.0/24 91.229.3.0/24 92.116.0.0/15 92.116.0.0/20 @@ -317,8 +478,11 @@ 92.116.120.0/21 92.116.128.0/18 92.116.16.0/20 -92.116.192.0/18 -92.116.32.0/19 +92.116.192.0/19 +92.116.224.0/20 +92.116.240.0/20 +92.116.32.0/20 +92.116.48.0/20 92.116.64.0/18 92.116.96.0/19 92.117.0.0/19 @@ -331,44 +495,75 @@ 92.117.240.0/21 92.117.248.0/21 92.117.64.0/19 -92.117.96.0/19 -93.114.90.0/24 -93.114.91.0/24 94.134.0.0/15 94.134.0.0/18 -94.134.112.0/22 -94.134.144.0/20 +94.134.100.0/22 +94.134.104.0/21 +94.134.112.0/21 +94.134.120.0/24 +94.134.121.0/24 +94.134.122.0/24 +94.134.123.0/24 +94.134.124.0/24 +94.134.125.0/24 +94.134.126.0/24 +94.134.127.0/24 +94.134.128.0/20 +94.134.144.0/22 +94.134.148.0/22 +94.134.152.0/21 94.134.160.0/21 94.134.168.0/22 94.134.172.0/22 +94.134.176.0/20 94.134.176.0/21 -94.134.192.0/22 +94.134.192.0/20 +94.134.208.0/21 94.134.216.0/21 -94.134.64.0/22 -94.134.68.0/22 +94.134.224.0/19 +94.134.64.0/20 94.134.80.0/22 -94.134.88.0/22 -94.134.94.0/23 -94.134.96.0/20 +94.134.84.0/24 +94.134.85.0/24 +94.134.86.0/24 +94.134.87.0/24 +94.134.88.0/24 +94.134.89.0/24 +94.134.90.0/24 +94.134.91.0/24 +94.134.92.0/24 +94.134.93.0/24 +94.134.94.0/24 +94.134.95.0/24 +94.134.96.0/22 2001:1438:1000::/36 -2001:1438:1:100::/56 -2001:1438:1:200::/56 -2001:1438:1:300::/56 -2001:1438:1:400::/56 -2001:1438:1:900::/56 -2001:1438:1:a00::/56 2001:1438:2000::/36 2001:1438:3000::/36 -2001:1438:300::/56 2001:1438:4000::/36 2001:1438::/32 +2001:1438:f000::/36 +2001:1438:fff:10::/64 +2001:1438:fff:11::/64 +2001:1438:fff:12::/64 +2001:1438:fff:3::/64 +2001:1438:fff:4::/64 +2001:1438:fff:5::/64 +2001:1438:fff:6::/64 +2001:1438:fff:7::/64 +2001:1438:fff:8::/64 +2001:1438:fff:9::/64 +2001:1438:fff:a::/64 +2001:1438:fff:b::/64 +2001:1438:fff:c::/64 +2001:1438:fff:d::/64 +2001:1438:fff:e::/64 +2001:1438:fff:f::/64 2001:16b8:1000::/40 2001:16b8:100::/40 2001:16b8:1100::/40 2001:16b8:1200::/40 2001:16b8:1300::/40 2001:16b8:1400::/40 -2001:16b8:2000::/35 2001:16b8:2000::/40 2001:16b8:200::/40 2001:16b8:2100::/40 @@ -386,10 +581,14 @@ 2001:16b8:2d00::/40 2001:16b8:2e00::/40 2001:16b8:300::/40 -2001:16b8:4000::/35 +2001:16b8:4000::/40 2001:16b8:400::/40 +2001:16b8:4100::/40 +2001:16b8:4200::/40 +2001:16b8:4300::/40 +2001:16b8:4500::/40 +2001:16b8:4600::/40 2001:16b8:500::/40 -2001:16b8:6000::/35 2001:16b8:6000::/40 2001:16b8:600::/40 2001:16b8:6100::/40 @@ -401,24 +600,19 @@ 2001:16b8:6700::/40 2001:16b8:6800::/40 2001:16b8:700::/40 -2001:16b8:8000::/36 2001:16b8:800::/40 -2001:16b8:9000::/36 2001:16b8:900::/40 2001:16b8::/32 -2001:16b8::/35 2001:16b8::/40 -2001:16b8:a000::/35 2001:16b8:a00::/40 2001:16b8:b00::/40 -2001:16b8:c000::/35 +2001:678:274::/48 2001:678:c74::/48 2001:67c:27ac::/48 2001:67c:2878::/48 2001:67c:2e8c::/48 2001:67c:660::/48 2001:67c:888::/48 -2001:67c:ed8::/48 2001:7b0::/32 2001:9e8:2000::/35 2001:9e8:4000::/35 @@ -435,11 +629,10 @@ 2a00:fb8:4000::/35 2a00:fb8:6000::/35 2a00:fb8::/29 +2a00:fb8::/32 2a00:fb8::/35 2a03:3fc0:2000::/48 2a07:9400::/29 2a0a:ed40::/29 -2a0b:9e80:1000::/36 2a0d:240::/29 2a0d:ad00::/29 -2a11:d00::/32 diff --git a/configs/junos-template.conf b/configs/junos-template.conf new file mode 100644 index 0000000..0f4012e --- /dev/null +++ b/configs/junos-template.conf @@ -0,0 +1,141 @@ +version ${'.'.join(node.metadata.get('junos/version'))}; +system { + host-name ${node.name.split('.')[-1]}; + time-zone GMT; + root-authentication { + encrypted-password "$5$1hGrR8Kk$lx3CIdxqvesBrZUtDftROEoyXQuMENEu62JVtHw6WGD"; ## SECRET-DATA + } + name-server { +% for srv in repo.libs.defaults.nameservers_ipv4: + ${srv}; +% endfor + } + login { +% for uid, (uname, uconfig) in enumerate(sorted(users.items())): + user ${uname} { + full-name ${uname}; + uid ${1000+uid}; + class super-user; + authentication { +% for pubkey in sorted(uconfig['ssh_pubkey']): + ${pubkey.split(' ', 1)[0]} "${pubkey}"; +% endfor + } + } +% endfor + } + services { + ssh { + protocol-version v2; + } + netconf { + ssh; + } +# web-management { +# http; +# } + } + syslog { + user * { + any emergency; + } + file messages { + any notice; + authorization info; + } + file interactive-commands { + interactive-commands any; + } + } + ntp { +% for srv in sorted(ntp_servers): + server ${srv}; +% endfor; + } +} +interfaces { +% for iface, config in sorted(interfaces.items()): + ${iface} { + unit 0 { +% if not config['enabled']: + disable; +% endif +% if config['mode'] == 'trunk': + family ethernet-switching { + port-mode trunk; + vlan { + members [ ${' '.join(sorted(config['tagged_vlans']))} ]; + } +% if config['untagged_vlan']: + native-vlan-id ${config['untagged_vlan']}; +% endif + } +% else: + family ethernet-switching; +% endif + } + } +% endfor + vlan { +% for idx, (vlan, vconfig) in enumerate(sorted(vlans.items())): +% if vconfig['ip_address']: + unit ${idx} { + family inet { + address ${vconfig['ip_address']}; + } + } +% endif +% endfor + } +} +snmp { + contact "${repo.libs.defaults.hostmaster_email}"; + community public { + authorization read-only; + } +} +routing-options { + static { + route 0.0.0.0/0 next-hop ${gateway}; + } +} +protocols { + igmp-snooping { + vlan all; + } + rstp; + lldp { + interface all; + } + lldp-med { + interface all; + } +} +ethernet-switching-options { + voip; + storm-control { + interface all; + } +} +vlans { +% for idx, (vlan, vconfig) in enumerate(sorted(vlans.items())): + ${vlan} { +% if vconfig['id']: + vlan-id ${vconfig['id']}; +% endif + interface { +% for iface, iconfig in sorted(interfaces.items()): +% if iconfig['untagged_vlan'] == vlan: + ${iface}.0; +% endif +% endfor + } +% if vconfig['ip_address']: + l3-interface vlan.${idx}; +% endif + } +% endfor +} +poe { + interface all; +} diff --git a/configs/netbox/home.switch-rack.json b/configs/netbox/home.switch-rack.json deleted file mode 100644 index 1792a8b..0000000 --- a/configs/netbox/home.switch-rack.json +++ /dev/null @@ -1,284 +0,0 @@ -{ - "interfaces": { - "ether1": { - "description": "home.router (enp1s0)", - "enabled": true, - "ips": [], - "mode": "tagged-all", - "tagged_vlans": [], - "type": "1000base-t", - "untagged_vlan": null - }, - "ether10": { - "description": "home.mitel-rfp35 (LAN)", - "enabled": true, - "ips": [], - "mode": "access", - "tagged_vlans": [], - "type": "1000base-t", - "untagged_vlan": "home.clients" - }, - "ether11": { - "description": "home.usv01 (LAN)", - "enabled": true, - "ips": [], - "mode": "access", - "tagged_vlans": [], - "type": "1000base-t", - "untagged_vlan": "home.clients" - }, - "ether12": { - "description": "", - "enabled": true, - "ips": [], - "mode": "access", - "tagged_vlans": [], - "type": "1000base-t", - "untagged_vlan": "home.clients" - }, - "ether13": { - "description": "", - "enabled": true, - "ips": [], - "mode": "access", - "tagged_vlans": [], - "type": "1000base-t", - "untagged_vlan": "home.clients" - }, - "ether14": { - "description": "", - "enabled": true, - "ips": [], - "mode": "access", - "tagged_vlans": [], - "type": "1000base-t", - "untagged_vlan": "home.clients" - }, - "ether15": { - "description": "", - "enabled": true, - "ips": [], - "mode": "access", - "tagged_vlans": [], - "type": "1000base-t", - "untagged_vlan": "home.clients" - }, - "ether16": { - "description": "", - "enabled": true, - "ips": [], - "mode": "access", - "tagged_vlans": [], - "type": "1000base-t", - "untagged_vlan": "home.clients" - }, - "ether17": { - "description": "", - "enabled": true, - "ips": [], - "mode": "access", - "tagged_vlans": [], - "type": "1000base-t", - "untagged_vlan": "home.clients" - }, - "ether18": { - "description": "", - "enabled": true, - "ips": [], - "mode": "access", - "tagged_vlans": [], - "type": "1000base-t", - "untagged_vlan": "home.clients" - }, - "ether19": { - "description": "home.lgtv-wohnzimmer", - "enabled": true, - "ips": [], - "mode": "access", - "tagged_vlans": [], - "type": "1000base-t", - "untagged_vlan": "home.clients" - }, - "ether2": { - "description": "Fritz!Box (LAN1)", - "enabled": true, - "ips": [], - "mode": "access", - "tagged_vlans": [], - "type": "1000base-t", - "untagged_vlan": "home.wan" - }, - "ether20": { - "description": "Franzi Laptop", - "enabled": true, - "ips": [], - "mode": "access", - "tagged_vlans": [], - "type": "1000base-t", - "untagged_vlan": "home.clients" - }, - "ether21": { - "description": "", - "enabled": true, - "ips": [], - "mode": "access", - "tagged_vlans": [], - "type": "1000base-t", - "untagged_vlan": "home.clients" - }, - "ether22": { - "description": "Arbeitsplatz Regal", - "enabled": true, - "ips": [], - "mode": "access", - "tagged_vlans": [], - "type": "1000base-t", - "untagged_vlan": "home.clients" - }, - "ether23": { - "description": "Wohnzimmer Kabel", - "enabled": true, - "ips": [], - "mode": "access", - "tagged_vlans": [], - "type": "1000base-t", - "untagged_vlan": "home.clients" - }, - "ether24": { - "description": "home.snom-wohnzimmer", - "enabled": true, - "ips": [], - "mode": "access", - "tagged_vlans": [], - "type": "1000base-t", - "untagged_vlan": "home.clients" - }, - "ether3": { - "description": "home.aruba325-schlafzimmer", - "enabled": true, - "ips": [], - "mode": "tagged", - "tagged_vlans": [ - "ffwi.client", - "home.v6only" - ], - "type": "1000base-t", - "untagged_vlan": "home.clients" - }, - "ether4": { - "description": "home.aruba325-wohnzimmer", - "enabled": true, - "ips": [], - "mode": "tagged", - "tagged_vlans": [ - "ffwi.client", - "home.v6only" - ], - "type": "1000base-t", - "untagged_vlan": "home.clients" - }, - "ether5": { - "description": "home.nas (eno1)", - "enabled": true, - "ips": [], - "mode": "tagged-all", - "tagged_vlans": [], - "type": "1000base-t", - "untagged_vlan": null - }, - "ether6": { - "description": "home.aruba325-office", - "enabled": true, - "ips": [], - "mode": "tagged", - "tagged_vlans": [ - "ffwi.client", - "home.v6only" - ], - "type": "1000base-t", - "untagged_vlan": "home.clients" - }, - "ether7": { - "description": "RIPE-Probe #28280 (LAN)", - "enabled": true, - "ips": [], - "mode": "access", - "tagged_vlans": [], - "type": "1000base-t", - "untagged_vlan": "home.dmz" - }, - "ether8": { - "description": "home.drucker-franzi", - "enabled": true, - "ips": [], - "mode": "access", - "tagged_vlans": [], - "type": "1000base-t", - "untagged_vlan": "home.clients" - }, - "ether9": { - "description": "info-beamer 12199 (LAN)", - "enabled": true, - "ips": [], - "mode": "access", - "tagged_vlans": [], - "type": "1000base-t", - "untagged_vlan": "home.clients" - }, - "home.clients": { - "description": "", - "enabled": true, - "ips": [ - "172.19.138.4/24" - ], - "mode": "", - "tagged_vlans": [], - "type": "virtual", - "untagged_vlan": null - }, - "sfp-sfpplus1": { - "description": "", - "enabled": true, - "ips": [], - "mode": "", - "tagged_vlans": [], - "type": "10gbase-x-sfpp", - "untagged_vlan": null - }, - "sfp-sfpplus2": { - "description": "", - "enabled": true, - "ips": [], - "mode": "", - "tagged_vlans": [], - "type": "10gbase-x-sfpp", - "untagged_vlan": null - } - }, - "vlans": [ - { - "name": "home.wan", - "vid": 7 - }, - { - "name": "home.clients", - "vid": 1138 - }, - { - "name": "home.dmz", - "vid": 1139 - }, - { - "name": "home.v6only", - "vid": 2000 - }, - { - "name": "ffwi.mesh", - "vid": 3000 - }, - { - "name": "ffwi.client", - "vid": 3001 - } - ] -} \ No newline at end of file diff --git a/data/apt/files/gpg-keys/docker.asc b/data/apt/files/gpg-keys/docker.asc deleted file mode 100644 index ee7872e..0000000 --- a/data/apt/files/gpg-keys/docker.asc +++ /dev/null @@ -1,62 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- - -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 -YT90qFF93M3v01BbxP+EIY2/9tiIPbrd -=0YYh ------END PGP PUBLIC KEY BLOCK----- diff --git a/data/apt/files/gpg-keys/grafana.asc b/data/apt/files/gpg-keys/grafana.asc index 074cc78..c74f292 100644 --- a/data/apt/files/gpg-keys/grafana.asc +++ b/data/apt/files/gpg-keys/grafana.asc @@ -28,112 +28,3 @@ ymdQ1sqe5nKvwG5GvcncPc3O7LMevDBWnpNNkgERnVxCqpm90TuE3ONbirnU4+/S tUsVU1DERc1fjOCnAm4pKIlNYphISIE7OQ== =0pMC -----END PGP PUBLIC KEY BLOCK----- ------BEGIN PGP PUBLIC KEY BLOCK----- -Comment: This is a revocation certificate - -iQE2BCABCgAgFiEETkDd9tduKEpKZ4DkjIw0xSQJjLYFAmO9q0cCHQIACgkQjIw0 -xSQJjLarJAf+JJU0CHTMSSs5WH6ohVy54HN+ev7p7vfcgvvFBAWZLTLrG5+eFUH0 -w0m9KegxAs+H/H/68ld1jY/P62fvkOR7WCWQ7HH+8ClKLwuWS4DpOHK9IOkHDK0w -0pVJ6NBiwhv8/B7EmiBf9zndjMtYa/wf8JZYVOXb0XE0L+Ec0WZSRZH+/WGA1E1s -MSgPwqDF7RKXDCJ65elYxi9CPZvXhj6RVldn/aRuHf5/SCDE/HmnDB9+v6ReEsWV -r/Xis2J0pWphpF/xtYxGf+Iy5fAHwDd4z9uKs9mBHSR0aDisuAW/eHF6KvBzQ7y0 -Yf3KxEyDvLwuAA5NBi7Xsd2wSKdfBGUGcQ== -=KTb+ ------END PGP PUBLIC KEY BLOCK----- ------BEGIN PGP PUBLIC KEY BLOCK----- - -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 -=lSMJ ------END PGP PUBLIC KEY BLOCK----- ------BEGIN PGP PUBLIC KEY BLOCK----- -Comment: This is a revocation certificate - -iQG2BCABCAAgFiEEDiLriOOeEid6d2CunkObECzzwMYFAmO4amECHQAACgkQnkOb -ECzzwMYiDQv/bbRnEhrFhr5XyA2vnu6nTZezbMwArC/ZwtFxtnj2iAwGZYY/pbPx -L8cHTpvK99I6J02SBHpmzthwHSindddPjuuQENdqH/TDlGvPH/mECJVTN9/kpjlg -HtO0MVKAKyXGbij7fR8prfPMRqOFbo4Rn9nQZZ/eY9KwkKVKxKHymppNbUbvv1qQ -NGfOi2QWkF+T8dbihbJHJgYpPb7uEmJ2EOX0KHu9nlYGX4jxtql+M3yeOi3juaXH -hLFWqVn3FkQW7N4IV+bVTkYcxQg01rWqY/h7BvL88AiMoiUXhOvE5iAS4sJe+EVB -bDfRaLr1Ju1CXYm5B+Q9b2pU0SWAbBNlVxYGs+NOeBh9YzwdGTFW2l/S/VLLv0bE -hBYuLwOIs0BqrL4TWwlB1ucEikg+r3O7OZL8Dnw0mnBVBmQxKhl1p8dLcYtylG3B -aEIbN6wHQe03xYvAmaHDdG0kjPiwhOlpZ+YU3ux8F2YnENXm9J+25GMyTXqybKQl -ltTE4hHgRH2v -=n71X ------END PGP PUBLIC KEY BLOCK----- ------BEGIN PGP PUBLIC KEY BLOCK----- - -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 -=J9CI ------END PGP PUBLIC KEY BLOCK----- diff --git a/data/apt/files/gpg-keys/icinga2.asc b/data/apt/files/gpg-keys/icinga2.asc index 165344f..901c78c 100644 --- a/data/apt/files/gpg-keys/icinga2.asc +++ b/data/apt/files/gpg-keys/icinga2.asc @@ -1,29 +1,30 @@ -----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v2.0.19 (GNU/Linux) -mQINBGZMb30BEAC6c5P5lo5cLN2wX9+jA7TEEJ/NiiOM9VxBwB/c2PFd6AjdGBbe -28VcXWmFdETg1N3Woq08yNVXdxS1tMslyl9apmmyCiSC2OPMmTOveLzZ196IljYR -DeZMF8C+rdzNKXZzn7+nEp9xRy34QUZRfx6pEnugMd0VK0d/ZKgMbcq2IvcRQwap -60+9t8ppesXhgaRBsAzvrj1twngqXP90JwzKGaR+iaGzrvvJn6cgXkw3MyXhskKY -4J0c7TV6DmTOIfL6RmBp8+SSco8xXD/O/YIpG8LWe+sbMqSaq7jFvKCINWgK4RAt -7mBRHvx81Y8IwV6B2wch/lSyYxKXTbE7uMefy3vyP9A9IFhMbFpc0EJA/4tHYEL4 -qPZyR44mizsxa+1h6AXO258ERtzL+FoksXnWTcQqBKjd6SHhLwN4BLsjrlWsJ6lD -VaSKsekEwMFTLvZiLxYXBLPU04dvGNgX7nbkFMEK6RxHqfMu+m6+0jPXzQ+ejuae -xoBBT61O7v5PPTqbZFBKnVzQPf7fBIHW5/AGAc+qAI459viwcCSlJ21RCzirFYc0 -/KDuSoo61yyNcq4G271lbT5SNeMZNlDxKkiHjbCpIU6iEF7uK828F1ZGKOMRztok -bzE7j1IDIfDQ3P/zfq73Rr2S9FfHlXvEmLIuj5G4PO7p0IwUlCD1a9oY+QARAQAB -tCxJY2luZ2EgR21iSCAoQnVpbGQgc2VydmVyKSA8aW5mb0BpY2luZ2EuY29tPokC -TgQTAQoAOBYhBN069hmO0AC0wLc5VswRb1WqfyOCBQJmTG99AhsDBQsJCAcCBhUK -CQgLAgQWAgMBAh4BAheAAAoJEMwRb1WqfyOCGrIP/i/4fYEkdCi4nhQGMzSP0Eyh -UhJjsUP9mEqSQRqOAplvjYa1yBbrSPLfkRE0oAL/o+4eUKcAQFeDQtDXJ/D4xl3Q -J5MehRJYzklrSs5XkEscb73HoDBUfFSgCVM2zK+JkCX0CPJ4ZLWtZGJ+8pCLpnkH -nCPonbGc6sS+m2JsPRwxyxAhdXxWSAesXd8dUSW3MOQz9JlC4/idQcCFs03fdhuZ -4jGMry08OihWVudTDK8nkwRZLzNoOivAQ3mIeaTcRMmgPJfYN4k0o90lXJWAbG+2 -j8p7Pyjv71OctI8KUbS4+f2H8i6r5Pc4M4hlUQh6QAN9o1oPJrXxurdp0EXgQXSy -rVH2MeguqprFJxGjdlTCSTYgQEmEXMixRAGzteEgCf/Qk9mPXoxFTNyNg4/Lkglb -Nj6dY6or6w+IsbdrcePqDAs+j9t5B97vU7Ldquloj85myQjkWPP8kjlsOlsXBkQ/ -C+mD+5iW2AiWh+yCasf6mOZwUfINZF+VDpmfIsZZbWpcMgp1f32fpRFZ3ietnsnR -+luNb19hUHKyyDDHMe/YM7H9P5vtX9BGz6O9kNpo1LAnigkSQSFBZlK3Po3Yk9eg -XPbDT5HsU3TMyS5ZnSDRRPPJwsyGPXz+0pCADae9H9hCc2C2LZIrrtwlOFPWuViA -ifY/dQmUP37n5XgMADRc -=O0zm +mQGiBFKHzk4RBACSHMIFTtfw4ZsNKAA03Gf5t7ovsKWnS7kcMYleAidypqhOmkGg +0petiYsMPYT+MOepCJFGNzwQwJhZrdLUxxMSWay4Xj0ArgpD9vbvU+gj8Tb02l+x +SqNGP8jXMV5UnK4gZsrYGLUPvx47uNNYRIRJAGOPYTvohhnFJiG402dzlwCg4u5I +1RdFplkp9JM6vNM9VBIAmcED/2jr7UQGsPs8YOiPkskGHLh/zXgO8SvcNAxCLgbp +BjGcF4Iso/A2TAI/2KGJW6kBW/Paf722ltU6s/6mutdXJppgNAz5nfpEt4uZKZyu +oSWf77179B2B/Wl1BsX/Oc3chscAgQb2pD/qPF/VYRJU+hvdQkq1zfi6cVsxyREV +k+IwA/46nXh51CQxE29ayuy1BoIOxezvuXFUXZ8rP6aCh4KaiN9AJoy7pBieCzsq +d7rPEeGIzBjI+yhEu8p92W6KWzL0xduWfYg9I7a2GTk8CaLX2OCLuwnKd7RVDyyZ +yzRjWs0T5U7SRAWspLStYxMdKert9lLyQiRHtLwmlgBPqa0gh7Q+SWNpbmdhIE9w +ZW4gU291cmNlIE1vbml0b3JpbmcgKEJ1aWxkIHNlcnZlcikgPGluZm9AaWNpbmdh +Lm9yZz6IYAQTEQIAIAUCUofOTgIbAwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJ +EMbjGcM0QQaCgSQAnRjXdbsyqziqhmxfAKffNJYuMPwdAKCS/IRCVyQzApFBtIBQ +1xuoym/4C7kCDQRSh85OEAgAvPwjlURCi8z6+7i60no4n16dNcSzd6AT8Kizpv2r +9BmNBff/GNYGnHyob/DMtmO2esEuVG8w62rO9m1wzzXzjbtmtU7NZ1Tg+C+reU2I +GNVu3SYtEVK/UTJHAhLcgry9yD99610tYPN2Fx33Efse94mXOreBfCvDsmFGSc7j +GVNCWXpMR3jTYyGj1igYd5ztOzG63D8gPyOucTTl+RWN/G9EoGBv6sWqk5eCd1Fs +JlWyQX4BJn3YsCZx3uj1DWL0dAl2zqcn6m1M4oj1ozW47MqM/efKOcV6VvCs9SL8 +F/NFvZcH4LKzeupCQ5jEONqcTlVlnLlIqId95Z4DI4AV9wADBQf/S6sKA4oH49tD +Yb5xAfUyEp5ben05TzUJbXs0Z7hfRQzy9+vQbWGamWLgg3QRUVPx1e4IT+W5vEm5 +dggNTMEwlLMI7izCPDcD32B5oxNVxlfj428KGllYWCFj+edY+xKTvw/PHnn+drKs +LE65Gwx4BPHm9EqWHIBX6aPzbgbJZZ06f6jWVBi/N7e/5n8lkxXqS23DBKemapyu +S1i56sH7mQSMaRZP/iiOroAJemPNxv1IQkykxw2woWMmTLKLMCD/i+4DxejE50tK +dxaOLTc4HDCsattw/RVJO6fwE414IXHMv330z4HKWJevMQ+CmQGfswvCwgeBP9n8 +PItLjBQAXIhJBBgRAgAJBQJSh85OAhsMAAoJEMbjGcM0QQaCzpAAmwUNoRyySf9p +5G3/2UD1PMueIwOtAKDVVDXEq5LJPVg4iafNu0SRMwgP0Q== +=icbY -----END PGP PUBLIC KEY BLOCK----- diff --git a/data/apt/files/gpg-keys/influxdb.asc b/data/apt/files/gpg-keys/influxdb.asc index 60aeaf6..c97d593 100644 --- a/data/apt/files/gpg-keys/influxdb.asc +++ b/data/apt/files/gpg-keys/influxdb.asc @@ -1,29 +1,52 @@ -----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 -mQINBGPIEycBEACpG4qSjhxA6fh4QJVJxFVBvCFt9tVx/hDbKH0Ryy9iilyMeReC -AS1/CZnSv/fhDNKmVPckf6on72z/ODwZcVfMV6DHkxmZ6x/tQrS6CWfKkupsON2H -KS3t4HUivahwHPlWtbfDqsWNwTAsZqklKpJQWY2ADPwurkbCmtYSjsgbLuWe23Pd -nJpLTHtlChM0ntW/l7Le1zYjGPUGoxMJgjg1YG8fi2l/zS0Of8bdQ26ps+WRvrSQ -RKhfAkfIgUiCXxBpDlN1spN73ZlAkaSb+myTfEKyJR55Yt9pHfkDdJh26RVgE1+N -GuLmm6oidaD9lTlNJ9P8wlLzoof3xJXYprgLLz/HmgtawnJ+DxFIXoXNNpUmhORJ -6Hb2Z5IKIyGIwXhQVe2Lw7B8awBNV99zUw517Wuax3RYx7Hwhntz9gFxS4GRxaCo -uLCFQ0AgDCkMHyEHufQo1XdjIB7fz6U551y5GMQw6/rjMnUM9ZI68SQ/FWou2cQf -533PyayvWOYQM4pP7ZmbzyCd393XlMaPWA5dyUOqv7Vcmv0IsAbncX6/KJmZAhKG -qu19xb6rv3ab2RbcU422guK3C/h/URPZJbSjf2w4jUV5UDe2veZg6BEVn7Sk5bW0 -ceX8n0GVbPNG7CvRduJPjXNzsz3FzmUS8QFFde3H5gl1T0f6GcfhmKgKEQARAQAB -tDdJbmZsdXhEYXRhIFBhY2thZ2UgU2lnbmluZyBLZXkgPHN1cHBvcnRAaW5mbHV4 -ZGF0YS5jb20+iQJVBBMBCAA/BgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAUJBaOk -/BYhBJ1TnZDTMo3H1sjTudj/jh99+LB+BQJjyB9PAhsDAAoJENj/jh99+LB+klgQ -AKOKdwTyKOr6+mnRrACz5U3EFxfAXXFGan9Ka7Nzgz4K+FOnTtT1gWwqrPPmTKQk -epNUMcelfX1kCA08yCm0nyw2niqxES40W33ergKUj6jlDx7UQYXWsDQGD9IKksa8 -MWfZlJ3zlrsGKXA4oa+kfY+vltWDVP8WhLcQzm2LywbKvr3WgY80GZbnRjoekiBK -oMKztQVMJG5yNZBo9B4JrqB3wMpnXZxEtqZcBPsJJdXTFKHsQ7kB9TMNorbUvDNH -ohwsprgMw84vHikEk9jyCypXpYq/E/wvkM0CeIUJ36S2vGvACib7BiY6Xv0BQbM4 -rWq2Rrjag1y5vVAF9gJkeo/3rhM6lE1ahDCRq0QcBMVzbxiE+3COIzRPmz14J3Yn -0pkvzlVkNj5UZR8q91ESl+UxkFCP1wzcXgs0dpJWirQIOZ9E2eYv3LcjE68xjW1k -c5q1GOGvJI7aXADxUZ4lFbz+NUb4Ts4HXHc8gV1Gm0vvmIqv2YfAvL5DXbKLdZxh -73CxKvBMmTXIEQ+vQJ3p1ZnUnb+l6DoxEFWg/hXHmE5jY3P6HIVFdliXF5FEs1lr -9snU2Pn1BDL+TBN7SX0QbKqArWA4qyn6eGH8Z1ULoUVBPCjwC9QuInp/9fqifFYo -OM3A51MDGyc/HCVG6jNJEI5h71QGHlPfyQybpjy7rQSe -=YwXc +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 +vqIHrEqk446nGPDqJPS5 +=9iF7 -----END PGP PUBLIC KEY BLOCK----- diff --git a/data/apt/files/gpg-keys/jellyfin.asc b/data/apt/files/gpg-keys/jellyfin.asc deleted file mode 100644 index 618b517..0000000 --- a/data/apt/files/gpg-keys/jellyfin.asc +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- - -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 -oqYC5A== -=OWPs ------END PGP PUBLIC KEY BLOCK----- diff --git a/data/apt/files/gpg-keys/matrix.asc b/data/apt/files/gpg-keys/matrix.asc index 41274cb..4e8d81b 100644 --- a/data/apt/files/gpg-keys/matrix.asc +++ b/data/apt/files/gpg-keys/matrix.asc @@ -12,19 +12,19 @@ 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 @@ -33,7 +33,7 @@ FUV32+oHTkATADF5OnnnCuAgLG3WNBIKOyA1Ov+e0SmFk1So1hU+mE6349v0rp3R LpV2QRDrIAcn6wUHLsEqyQBArvWP+cg5JuPALYR3ZBEgah52tSgnOGnvVWyPPHNo 0bhAFZ9YGToDuE3qPV+ud8qNe4nT7qsZo4NdfFd3JgBHV6CaVwdRMtkut8Xjjmt9 DiVaHS1hgi+METEMFXdhyXMSwFLH6DDF6Uny9LsAEQEAAYkD8gQYAQoAJgIbAhYh -BKr5roQ6dYS1o+TNK89FpRLeLaBYBQJnxeuFBQkO4xMnAcDA9CAEGQEKAB0WIQRV +BKr5roQ6dYS1o+TNK89FpRLeLaBYBQJgd9nFBQkHhS9nAcDA9CAEGQEKAB0WIQRV hszAy7vvx6JYEa30c91EczZd4QUCXLURXgAKCRD0c91EczZd4U5qC/wLYGzvpT+M I7SNg1of/1ekeRXzvXc8m8JC/cHAhrBzUaI8z9LJ7xna2DGt27eqeTtu/Shtknn+ /8VaX9+7wm7UaGHWVmPFkSt1Rs1x5Opxo6kabLc4HxGSc5buNx+awybFEt9VQdSU @@ -43,16 +43,16 @@ uVJPAFF86z39hiGNnYJcikyVXogjwQPs5Od+3PdGQ19heZp8n+2rVkhl+9yZaCHk RRb3hyRWTRtLQhhaMw3zSwekA8VjKSinTyOxnRPa3rc7/rOqb5b8ZUAIzpTLd7al 7+E0fmOfie93KYh+BV6FuL0KJ0RNHm7zrgaVZbjDoqNIgkHK73+3a9NnSefsgbmC VxOxNM3lY7Jun1E/f/KE6dTY7VGPP6aTtQrcq49Zj1MwPc0SG7VlZkwJEM9FpRLe -LaBY9+YQAKXMKKOY7D+cJVKjVDbVuhknB+vLLRIN7Yx6GxRxM0Q6wPo42WmstDui -ex6u5MN0UjoA7+bPrC/vGBGOIr56sIMiaHkCqhoQoz7vwKayTJHa8McO/x8oRMr1 -aPtDgvUU78N7cdSv01wMW7zF/anCESEtbpfOzd5SM5V+XuYJoVzm3KtAdKQIxH0X -khOPvDa9Nn2bCsEvkp0pds0c5STKPWBeMSYSYuJzf48lcmoDilruPl2PaXPY1oxN -ciOGVuiCoT/XAdYuw2iynU5eC6h7W6b9EQZ1XPatFhkfGSucWtypObgCe+UGojOP -xZvqujcKnZBzECzawFu45Gp7TjPXnbsLmH5tv4GvJ9R0AeBnnHzTTpkduq7C7lO/ -X8VyxPpisJZII6s8pymSuw0/0CCNodf4wd1ar7ATCixcmJutWCJi8HLzvfoXEe8J -hE/ZjUEkVpWwxYIsM/U4ImWmrus81dMqBDVHowxwXoeJHsHNeUGTa8fKkPFo7i54 -Y/GhsNRDIk9nOHNqucV6xx3+WPs5p8eEcNFLalqjONcugfOB6Sfo/NaR3Jus7p+7 -kmwJ4YNxXYnogj4I24PT1/+BTFrrjYMXgbVs8s0yL68AHDlEo5MxHk3C82+ukeI6 -97uC8U9NZEpwVDk2mNb3ngwHWzp7InGGi3bwozHPj8bGIPuBaAlF -=3XJ/ +LaBYVA4QALCPlSk7P4e8BySAex3BEoDEhTTZtl89/bqRJpcK8Pvi04Qnqa1fcqYF +gM9LB4OzGst54ipixIQbMuKxdMT3aaqAsAUQvhtrNC5763SjxCWE/J4wDo5ICj8s +WJDMJeyJ7HgBhaTLVSRGE3ADamXI/NxIRxZ3czuS1NIojNcLlVptOzBnYl7dVH7O +cRsp7Qj6L4mNYMLMl70xXXEaI3WHK3OjQ+Qn7x5gv5NhdP/tVjMT0a5p24yw9KwM +FkDn9LYTzu7IskkPlAFl5kirfOHJGie+NuhK/XW3stoIVc3D3qHZhkRx+/y/wfVW +MavMZTMTs2pXtoFA3yIwm8bIwcMPZWU6KoQTQBxGc3vTj4LKlib0f28xYSX+YMsB +X3JZipPUdzR6ApvJA/9Da/u8LQ6K8ji2bvU1vnRKu8/ot4eABX+1+DY8oAlQWPLJ +6G+PpsHCDtOJf76x+JcFHzIBlLyihCjhZbDkcJj59Jm+7TsKHOaQ1ySEkKnUpog8 +R2Xi6A7nF11n2OlW3T5e7K0qpHoUwvecXA854yQocW6GK9N/HPSbC/qDi/lLKZ5J +jsA55fwysSXtnIqaHyvMN2wVCRQFGx3u4NcI2lwR+cqmJlwS93ZYnK33sGPDYQ6D +UiCsvX1EBMQT1Q6GxDcTXBHfW+M4JciUofUpTXO9exBzHHyJd8cN +=FEYi -----END PGP PUBLIC KEY BLOCK----- diff --git a/data/apt/files/gpg-keys/nginx.asc b/data/apt/files/gpg-keys/nginx.asc index 656d40c..d2258b8 100644 --- a/data/apt/files/gpg-keys/nginx.asc +++ b/data/apt/files/gpg-keys/nginx.asc @@ -1,66 +1,5 @@ -----BEGIN PGP PUBLIC KEY BLOCK----- - -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 -vcV0wl+DODz9hw== -=oWlI ------END PGP PUBLIC KEY BLOCK----- ------BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v2.0.22 (GNU/Linux) mQENBE5OMmIBCAD+FPYKGriGGf7NqwKfWC83cBV01gabgVWQmZbMcFzeW+hMsgxH W6iimD0RsfZ9oEbfJCPG0CRSZ7ppq5pKamYs2+EJ8Q2ysOFHHwpGrA2C8zyNAs4I @@ -68,125 +7,22 @@ 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 -ozw9yNdOZmnk2Prj7+mBuchbT3BJOQ== -=AgHy ------END PGP PUBLIC KEY BLOCK----- ------BEGIN PGP PUBLIC KEY BLOCK----- - -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 -UYda9m8fOnaIew== -=TEOn +a2V5IDxzaWduaW5nLWtleUBuZ2lueC5jb20+iQE+BBMBAgAoAhsDBgsJCAcDAgYV +CAIJCgsEFgIDAQIeAQIXgAUCV2K1+AUJGB4fQQAKCRCr9b2Ce9m/YloaB/9XGrol +kocm7l/tsVjaBQCteXKuwsm4XhCuAQ6YAwA1L1UheGOG/aa2xJvrXE8X32tgcTjr +KoYoXWcdxaFjlXGTt6jV85qRguUzvMOxxSEM2Dn115etN9piPl0Zz+4rkx8+2vJG +F+eMlruPXg/zd88NvyLq5gGHEsFRBMVufYmHtNfcp4okC1klWiRIRSdp4QY1wdrN +1O+/oCTl8Bzy6hcHjLIq3aoumcLxMjtBoclc/5OTioLDwSDfVx7rWyfRhcBzVbwD +oe/PD08AoAA6fxXvWjSxy+dGhEaXoTHjkCbz/l6NxrK3JFyauDgU4K4MytsZ1HDi +MgMW8hZXxszoICTTiQEcBBABAgAGBQJOTkelAAoJEKZP1bF62zmo79oH/1XDb29S +YtWp+MTJTPFEwlWRiyRuDXy3wBd/BpwBRIWfWzMs1gnCjNjk0EVBVGa2grvy9Jtx +JKMd6l/PWXVucSt+U/+GO8rBkw14SdhqxaS2l14v6gyMeUrSbY3XfToGfwHC4sa/ +Thn8X4jFaQ2XN5dAIzJGU1s5JA0tjEzUwCnmrKmyMlXZaoQVrmORGjCuH0I0aAFk +RS0UtnB9HPpxhGVbs24xXZQnZDNbUQeulFxS4uP3OLDBAeCHl+v4t/uotIad8v6J +SO93vc1evIje6lguE81HHmJn9noxPItvOvSMb2yPsE8mH4cJHRTFNSEhPW6ghmlf +Wa9ZwiVX5igxcvaIRgQQEQIABgUCTk5b0gAKCRDs8OkLLBcgg1G+AKCnacLb/+W6 +cflirUIExgZdUJqoogCeNPVwXiHEIVqithAM1pdY/gcaQZmIRgQQEQIABgUCTk5f +YQAKCRCpN2E5pSTFPnNWAJ9gUozyiS+9jf2rJvqmJSeWuCgVRwCcCUFhXRCpQO2Y +Va3l3WuB+rgKjsQ= +=EWWI -----END PGP PUBLIC KEY BLOCK----- diff --git a/data/apt/files/gpg-keys/node.asc b/data/apt/files/gpg-keys/node.asc new file mode 100644 index 0000000..1dc1d10 --- /dev/null +++ b/data/apt/files/gpg-keys/node.asc @@ -0,0 +1,52 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 +Comment: GPGTools - https://gpgtools.org + +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 +=CLGF +-----END PGP PUBLIC KEY BLOCK----- diff --git a/data/apt/files/gpg-keys/nodejs.asc b/data/apt/files/gpg-keys/nodejs.asc deleted file mode 100644 index b7637b8..0000000 --- a/data/apt/files/gpg-keys/nodejs.asc +++ /dev/null @@ -1,29 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- - -mQENBFdDN1ABCADaNd/I3j3tn40deQNgz7hB2NvT+syXe6k4ZmdiEcOfBvFrkS8B -hNS67t93etHsxEy7E0qwsZH32bKazMqe9zDwoa3aVImryjh6SHC9lMtW27JPHFeM -Srkt9YmH1WMwWcRO6eSY9B3PpazquhnvbammLuUojXRIxkDroy6Fw4UKmUNSRr32 -9Ej87jRoR1B2/57Kfp2Y4+vFGGzSvh3AFQpBHq51qsNHALU6+8PjLfIt+5TPvaWR -TB+kAZnQZkaIQM2nr1n3oj6ak2RATY/+kjLizgFWzgEfbCrbsyq68UoY5FPBnu4Z -E3iDZpaIqwKr0seUC7iA1xM5eHi5kty1oB7HABEBAAG0Ik5Tb2xpZCA8bnNvbGlk -LWdwZ0Bub2Rlc291cmNlLmNvbT6JATgEEwECACIFAldDN1ACGwMGCwkIBwMCBhUI -AgkKCwQWAgMBAh4BAheAAAoJEC9ZtfmbG+C0y7wH/i4xnab36dtrYW7RZwL8i6Sc -NjMx4j9+U1kr/F6YtqWd+JwCbBdar5zRghxPcYEq/qf7MbgAYcs1eSOuTOb7n7+o -xUwdH2iCtHhKh3Jr2mRw1ks7BbFZPB5KmkxHaEBfLT4d+I91ZuUdPXJ+0SXs9gzk -Dbz65Uhoz3W03aiF8HeL5JNARZFMbHHNVL05U1sTGTCOtu+1c/33f3TulQ/XZ3Y4 -hwGCpLe0Tv7g7Lp3iLMZMWYPEa0a7S4u8he5IEJQLd8bE8jltcQvrdr3Fm8kI2Jg -BJmUmX4PSfhuTCFaR/yeCt3UoW883bs9LfbTzIx9DJGpRIu8Y0IL3b4sj/GoZVq5 -AQ0EV0M3UAEIAKrTaC62ayzqOIPa7nS90BHHck4Z33a2tZF/uof38xNOiyWGhT8u -JeFoTTHn5SQq5Ftyu4K3K2fbbpuu/APQF05AaljzVkDGNMW4pSkgOasdysj831cu -ssrHX2RYS22wg80k6C/Hwmh5F45faEuNxsV+bPx7oPUrt5n6GMx84vEP3i1+FDBi -0pt/B/QnDFBXki1BGvJ35f5NwDefK8VaInxXP3ZN/WIbtn5dqxppkV/YkO7GiJlp -Jlju9rf3kKUIQzKQWxFsbCAPIHoWv7rH9RSxgDithXtG6Yg5R1aeBbJaPNXL9wpJ -YBJbiMjkAFaz4B95FOqZm3r7oHugiCGsHX0AEQEAAYkBHwQYAQIACQUCV0M3UAIb -DAAKCRAvWbX5mxvgtE/OB/0VN88DR3Y3fuqy7lq/dthkn7Dqm9YXdorZl3L152eE -IF882aG8FE3qZdaLGjQO4oShAyNWmRfSGuoH0XERXAI9n0r8m4mDMxE6rtP7tHet -y/5M8x3CTyuMgx5GLDaEUvBusnTD+/v/fBMwRK/cZ9du5PSG4R50rtst+oYyC2ao -x4I2SgjtF/cY7bECsZDplzatN3gv34PkcdIg8SLHAVlL4N5tzumDeizRspcSyoy2 -K2+hwKU4C4+dekLLTg8rjnRROvplV2KtaEk6rxKtIRFDCoQng8wfJuIMrDNKvqZw -FRGt7cbvW5MCnuH8MhItOl9Uxp1wHp6gtav/h8Gp6MBa -=MARt ------END PGP PUBLIC KEY BLOCK----- diff --git a/data/apt/files/gpg-keys/openhab.asc b/data/apt/files/gpg-keys/openhab.asc new file mode 100644 index 0000000..196e60e --- /dev/null +++ b/data/apt/files/gpg-keys/openhab.asc @@ -0,0 +1,52 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +Yyq3xLVDG/Zs7LmgSAiEITxRFTR4qg7k +=r37a +-----END PGP PUBLIC KEY BLOCK----- diff --git a/data/apt/files/gpg-keys/php.asc b/data/apt/files/gpg-keys/php.asc new file mode 100644 index 0000000..ba04e3c --- /dev/null +++ b/data/apt/files/gpg-keys/php.asc @@ -0,0 +1,42 @@ +-----BEGIN PGP ARMORED FILE----- +Comment: Use "gpg --dearmor" for unpacking + +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 +=gNGr +-----END PGP ARMORED FILE----- diff --git a/data/backup/keys/aurto.key.vault b/data/backup/keys/aurto.key.vault new file mode 100644 index 0000000..8cf9e4d --- /dev/null +++ b/data/backup/keys/aurto.key.vault @@ -0,0 +1 @@ +encrypt$gAAAAABg2xbZgDvKN7zvwFWAanfqHpsVJxRzvvPZBN7OzYBYlpjMbr7NCYngOVzMeHrBWoD56QASpBpCXib7GoZhjRbrkA3XLg-xHyC2W0UQrdIm6w3o5RpMji5ll5BdDJJYpCsf_l_lgklBM4k5fb_4X4zjK77J-15B_DdPGzQbAZxw1LT0OV3LrC55MNv_UeVwmDGg07Xy38-GPdFEAzH-lrzfsP7-PBsjaRmdFT_iShrsQgpcecKSBG_zqyxbbZKxG3cRJL791RYVNwGXFWVTZTs0UjbAFd5Q2pHjy10cdio_EnhfCcP2b6pwMjgihvYGwS3j_s90bXf9ko1njxpPXvxauSN6biURa7j7k3EABhywdhV_kcZoWbIK7tLY7ojYi1Al2xx1e-L9jvS66QLnbMrNW_xqVHPple98hYcTawf3yI2n4KSKcsDr71Iu3cOrdJOQkG6QiE2CjTm0J2gySoRvtoqTJjsBPud6LSHrDcbHKenMr9aCSM5MYm_aadyeHh0bphgU5F5ye8UVuAmPmFa12WChxLTWDj7zhgeTJpvbfQUALry8nD6tDOWMOqkXOhJkGV48xBoCKLrtxVgpnKxNu7aTDpJAwxEY9uFyymmD4lXQquQC8eElEl-n2Xz2Z-9fK3uJ \ No newline at end of file diff --git a/data/backup/keys/aurto.pub b/data/backup/keys/aurto.pub new file mode 100644 index 0000000..d590079 --- /dev/null +++ b/data/backup/keys/aurto.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOEqhj3JQ+82FCLVg4a+cRU4FRudnifcwrWgZnvrQGkG diff --git a/data/backup/keys/gce.bind01.key.vault b/data/backup/keys/gce.bind01.key.vault new file mode 100644 index 0000000..e08644e --- /dev/null +++ b/data/backup/keys/gce.bind01.key.vault @@ -0,0 +1 @@ +encrypt$gAAAAABfrlWfFm8-vDqO9So0Ru3QCA_kWvO2bbIcYtnq3VnJfq0QxPKW4TTuUbS8gloq19TbQRTZeZ0-22H-CdIeiXv_SGtKzK7ijbV3pUfNppy5I9c1Kcn--6YnLEBRx9DxhOh3n3i3gxyF8dA9izjp_-XS3XjjPcdw6WAp1z55a6p6ggTDEyXn1MGEUl8405ri8kpe9AtPIBZV7GND8GmH8jG8jrMJGTta_TJlrW_FcsYqcEKf5f1N1ShOCWCxUijlTwLVZzufZCR3-IJpcdKR8L2ifTggT04meHRzd_4HkC3X-3wdfqnoNCo7ln63SeerseN0Gnz_Psk0L9CnwQwWlfTbCMVdn2oiRUc8wLZ06R-GVhdIs9C4jGnQJZeStOFYYtHWgqZcToNx_Bq5zIK4aMa5vZ8cmKgCDWBMfjcaWJ8SKK8_zRZwRbsPOzuzSfvGoAmcnhQbnDmmhtSaka4POk-aH-8ZV_1dNq0JK5g7xcC6vUb1GSvfFPqXhx9ypo48NueHC9seJt7Pp05hP91z8yBT9-CHtMH91G4iBkyJf-DfG65YfDFVmXTU4ikV5UV6leXFkzmIzGshKAwuDuRVWA5tXEHAyoluTaX2nZXziz_wNszj2Fc= \ No newline at end of file diff --git a/data/backup/keys/gce.bind01.pub b/data/backup/keys/gce.bind01.pub new file mode 100644 index 0000000..9db75f4 --- /dev/null +++ b/data/backup/keys/gce.bind01.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIF4wrVPICvYitHaR0Qp6K8LzlPaHothuw0BI3XGiyAmN diff --git a/data/backup/keys/home.kodi-wohnzimmer.key.vault b/data/backup/keys/home.kodi-wohnzimmer.key.vault new file mode 100644 index 0000000..1904a4f --- /dev/null +++ b/data/backup/keys/home.kodi-wohnzimmer.key.vault @@ -0,0 +1 @@ +encrypt$gAAAAABfrlWfJTYZVIlllCPefCyzG16p3-JLyr1vST3xWvkc5rB9jvCNw-7LwP7CSh62YTchvyJBk5NfrDCnZnYhW44rn4I2YWr-LfHkVNIsq_b1Kv7rL_xvgcHt1iww_0Fa0nUmK5gGbbedz0uJtTO_9IS8P7KJUWziW3Ugsajt0NKIAB__-M7d461E6coLKmbkD9EnTGkXGp14U1vA0oyR8xsfHasWtQ8ntNu3it4_SFmu_xMbeEXOV1RZACKkCr-nS7ctjQ4LNgIIdfLWs-KKM1cmCjwDQqPWRIoPD5YJJ8EtBxvUyNc0KT8ySMS7m2TNfw158U2QdO4KQUdbuwPTpDWuhOMRp5nzliEkiw2QHhKbZGbHrliw1AD9naQWUh-R1XtMx3gKRp-vser4RFQk83bhcL63j7dSjzKHpANa3HB0f2GEoek9VOwZIHpXWu1OkJNMVk5a_F8f75Iggmj5xiz_O_nRRhYRA3MzXgfV_QKTvPHEKFvkoh_-esb33qgiJ8tL-5uJ2ADWFbBqy-KoUJDKFeoyDNlJKwFpgFq0Kbd5eJbbVp95D9LCCkdiwQ34_SopMqbVBfauHdloygsgs35ifAvEW1VDyHtz-cpmRDYc0jV-iyI= \ No newline at end of file diff --git a/data/backup/keys/home.kodi-wohnzimmer.pub b/data/backup/keys/home.kodi-wohnzimmer.pub new file mode 100644 index 0000000..b5ff2e9 --- /dev/null +++ b/data/backup/keys/home.kodi-wohnzimmer.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIE/WEgalbJUsr2q3DurqR7NkY9RXnuMs7BmmBgVmW3tj diff --git a/data/backup/keys/home.nas.key.vault b/data/backup/keys/home.nas.key.vault new file mode 100644 index 0000000..84683c7 --- /dev/null +++ b/data/backup/keys/home.nas.key.vault @@ -0,0 +1 @@ +encrypt$gAAAAABh27wEndfbW4cyz1fgM3e87zCqStsK8upwR56flNhpwAMJQJtjflH76nvw63cZYGWjJaOY29jO4y8DONjRoe3OQxH1bt9qgBgSfdW4k1A2axKevj67wphrb5bipJCg_EKFZumRONCSaaFDFlRp8DJlwj4LWxHONENx6KEYtMMZyGRUnh853kYDxA9E2gq7ScXZMAws002iD1sBONCsXOLEcpX8-Yt1f9qDzhfSGh4z7JdBa_xfmjKYAMBl62pPeZoI2c8LnogtjPEdblPJmjBuIVhGb_wP6nF4jdEim57v0lGezPblddTFvsgNcZO9AWIeM4ivtVd0AZaZXHXxSh7aGTKOKn6BiZtvah5Dhc61GL-Iga3sXISuG7EALWVODtwfUBwD-s8gAXfT0_LYh2tkrkPVm39Uwx8hM1WZUyDvQ3ox3a5RxQgenz4YskdNA-2Yw53zxdaCp_sORJJPpsFntoPXtw0aHXGVTdluRDtBJCqDPUVvO69J3jDMDnNXb3W9BrKK1CABbZkd5hLQH9jH6ZY8SOZzr5-RpEPbR4akIKPJAL0lcCFRwS0TgCfTAKDBbz9y19xkzIAM4cjraMlUDS69zegryOzG9u1-Cjj82kNKT95iA70Hm63idJWR0naCRUCu \ No newline at end of file diff --git a/data/backup/keys/home.nas.pub b/data/backup/keys/home.nas.pub new file mode 100644 index 0000000..b556e97 --- /dev/null +++ b/data/backup/keys/home.nas.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBf2z34n5oovv1PjJrDTNQyrI78oEmazeshLKTwheP4x diff --git a/data/backup/keys/home.octoprint-vielschichtigkeit.key.vault b/data/backup/keys/home.octoprint-vielschichtigkeit.key.vault new file mode 100644 index 0000000..39fa436 --- /dev/null +++ b/data/backup/keys/home.octoprint-vielschichtigkeit.key.vault @@ -0,0 +1 @@ +encrypt$gAAAAABfrlWgqqfc6tymm4tFnl4qy6rodRU7ZCMsPXw-bLOBoPdxxPdQEVVvWWK6WhqidBtGRGEvyp32W3rltA_lTZFhSEy5y-xOHK7waviQi2wahK4B3zBYPc-nKOREzbSKqOaaNlpOsReAfyZgizeKb_XGump--sOwLn120k9ImMGmVhhQSx0BdJpi2Z23aqV6TvRgDM2utCR2aRFXyFbFG_TR8exI9tQLg80qaotXv9O5I2pnIyTyanXEm4pZBmN88kGSW-ZPTVO2SpWjfGO46XtPirsFAp7pya-0O8EeXApEGjtQiVUw_JrlQmMTJ14j8AV4m_lNsiu_6bKPawaNJCcSfOF9C_49LMj-0mupyss2Py3qtF-KTxU0TvODg2DnLIMlcxtv_zheYFeY90nPBpQ3Dh8L2qAOd_eDu4gFvQLQvWQyB6aAlChC9ufTrhDFNyNI3Am5oWh32iFcv8Ie7UNtIB0Jc2bHfApJl8LJhizpObLgHtuxK127m2D5jEXRYwjLYDGGDwyL-qfKpxQoKaBPBP8JNxT0LbtsecveAyLIknyqtX3fxvZpon1DbJ0UTwvlUeoRcmOThmtx_hlGS7As12Ds60EnDbuhMddFGnZyo4GObqA= \ No newline at end of file diff --git a/data/backup/keys/home.octoprint-vielschichtigkeit.pub b/data/backup/keys/home.octoprint-vielschichtigkeit.pub new file mode 100644 index 0000000..32866d0 --- /dev/null +++ b/data/backup/keys/home.octoprint-vielschichtigkeit.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII6c5QTi50obr8Eh3pCCy+y8E4HXb/5YwRIVD1WZneO9 diff --git a/data/backup/keys/home.openhab.key.vault b/data/backup/keys/home.openhab.key.vault new file mode 100644 index 0000000..44f9b82 --- /dev/null +++ b/data/backup/keys/home.openhab.key.vault @@ -0,0 +1 @@ +encrypt$gAAAAABhflKcIRszHtJHuBcgaWh7divgjgw72cKDiP7PPk7CQ9xpdSDw3phE7tpVBnaYSjYFcn0lxH5IN7YfgsgQnRFrH4N25-awLwxp6kVsL00Si9F4o8GUBvzobQGJtzEh0nuQ3zmGGfQSLZGKiXkFHLPmnc67Mqtz7zK7Qc5Lp0qqhMJ-2PLEwl5F6WxQU8TcNTlHDgIb23yS2GWfT3DrUvZjgOKkDvS--Huphyklksn3SR3cxHy1wSmlzJxV31t4Rh7YQyj1DcuBy2TIzLAhebtPJbiUZTFsFXDJULiHl1zi5X2jVIc17rpKW_9JMTeBEDZbebyqpOp3bo9zNv4RcC_XEIW7i2hCXNT8RksW5x45-E01jKQpiKgIcJoImcDQAanNh6_xEWEPWiJFVDulkMiJob5EvZjl1j79jOciahq8ycuePWyFAAtDZgpLm9u0JlzOLFL4NbvL8-MypBLpysXTohqDa3SYKlc2-UvsUJD8bagEYsy0Ay_nGQo961AqlWF7vPk2SdYXUjN657PxSbnczOuKv63BmFWEF9Bu8OFOzxIRs1ds7jvK3KChikO91VJMQxsZrSynFBwDm5zpYRsk-k1D2blf2g1yaThd2fijYCe1Lico_nTlyf-dpSrN5szlKW5V \ No newline at end of file diff --git a/data/backup/keys/home.openhab.pub b/data/backup/keys/home.openhab.pub new file mode 100644 index 0000000..25e2a1b --- /dev/null +++ b/data/backup/keys/home.openhab.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKYyrgpO2tCRTP+eEFD127OlRIATw7BxaSgYMnyYAbMS diff --git a/data/backup/keys/home.paperless.key.vault b/data/backup/keys/home.paperless.key.vault new file mode 100644 index 0000000..364fa26 --- /dev/null +++ b/data/backup/keys/home.paperless.key.vault @@ -0,0 +1 @@ +encrypt$gAAAAABgqlxI4OjgrQfSKqCqA8vSbhNpdPwt56Akk73WMcqTs0nf9tiQsGoneptdO-1x5X_-yEI_YE_SywHo4yZ0ABQjUdNpLDojjDqkT2wZPDeSXgoIQFpnf_JZ84aw89_srH6CBEBGDU6bjljiAarrkAyBWaW21DFSuH1SSwuNiy3Rr1GP6HwTgqMVtNc-W4x6pehViOpkiyvvffgYGTY826YXmV4dCapr3Z8l4acOmSucnnc5YxKXSHl5wk9vTDpyhcT6qQJ7d-_cRCDrZtkPYNWNJRjAVmshIg_QRXwgQU_YPqZRrcQIUGMnaIBNjv0LKcSDPDAD2Rv8GHMLF1Vt6brJ_p3ihY_8KrP6QvwKyvSX1CDVxhwYq9WfCqvlqQOIkVLnn_vS-FzqU98cbef-rZsXLVRe7ODrU-Fg5tOVmKp761VGQSF1l4FIZnkQwF5uj-AmJXgaTfkcvoYhWtFEadnrKYmV92GbymiwPB6EG9SRMgcgpMAYCl9If7oEMjuYBs6bfTq0dfA39xWRJQx9zhAMTAAWHewYwEzME5PuTaQCDSRd2qIYik-DemhRp3suuphvjeuJTL5qyHXIH03yCTRxYf28cw0PVC2B696mI-z0I_-FT5Tc9l4pbh3RZlQ7Z8dNewJX \ No newline at end of file diff --git a/data/backup/keys/home.paperless.pub b/data/backup/keys/home.paperless.pub new file mode 100644 index 0000000..db4a767 --- /dev/null +++ b/data/backup/keys/home.paperless.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIbL8JFM5vHyxSf4Ym57K+ssOi7gbk7Ma/+pOoT+1qGy diff --git a/data/backup/keys/htz-cloud.influxdb.key.vault b/data/backup/keys/htz-cloud.influxdb.key.vault new file mode 100644 index 0000000..296f65c --- /dev/null +++ b/data/backup/keys/htz-cloud.influxdb.key.vault @@ -0,0 +1 @@ +encrypt$gAAAAABgoBM4n7eEwMxfav4200d5LoGyLsM67Ps9CCPBgjZjdsOpyQulbp2l4LIhWj1kljgrXZ_LnOaRUf3S8q7-drv3yEfG1d-cyK8vP7r8wkTcawaazM5XdhR8VkgxCyBCuOZmM1vvAmOwIMi1JiQcgiJ4G32ThS085onN3T9HvEu2a9sWYuOlk-yVUBpelqP97vbO6r2n3hn-62AC7Ww-Q_EQ_kcdDdJLOawNe1anJOsOeLb1XOlMIJWI74LZXfszsRi9LmxUpzaB4Gd_nzDLO1AZHD_GOf9UOeeab8PujwhQ4UhbEHCdB-uVH88LGCw25-6eiv0yA_kRulj7InA9sKRyBZ1okSF4Xhl-htez6XwBD6BuA_ly6ulSxWuoOV_qsCNiXhJYGTuKPJS0-wpLyeLb_PV1tlYOKZv3VK5a_EpCRa4fCdX7oj9pcA8ZQkQeFAx0P4b3oYkz8YkDiBINFdOLE177lC6Kuk33sLfsZBuoR7MSjHUtZHPOXUHu8pV0o0_YxxF5fBs6hyReXvCbZB18NikeH4Ki-RR5IE4ofTngf6dIQhCxp9u-cNs-mNP0GRKiYIBUInr9Udpr-ymXRq-7OvyTM92950ePm-qoqjbpVFA8HN057WfkW6N6DASRRa2HjqQJ \ No newline at end of file diff --git a/data/backup/keys/htz-cloud.influxdb.pub b/data/backup/keys/htz-cloud.influxdb.pub new file mode 100644 index 0000000..efa9e6d --- /dev/null +++ b/data/backup/keys/htz-cloud.influxdb.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFpAUytQ0ncucltODEr3MgcKF5U/6TS4zZG1OYJDIEQp diff --git a/data/backup/keys/htz-cloud.luther.key.vault b/data/backup/keys/htz-cloud.luther.key.vault new file mode 100644 index 0000000..13c5671 --- /dev/null +++ b/data/backup/keys/htz-cloud.luther.key.vault @@ -0,0 +1 @@ +encrypt$gAAAAABfrlWgO_QYaKznjoFXGPw4PTjv92niiHE_61_Tp7dOnKiqWHJc06MOxmFdZaf9i8wLH1H0R8MNgt5gGuGDk6frQh1cz_EMyQh9Vo9iBbHI6q5OXYHmTX3mEeeoudhGUNaXwaea0SaErcql_jJDRGrbvxGJH2-wmiJaeZ5oyIkedp6F7_Y1SuRw-c2YG8hEBtjALlLhz3bL25_2V8hzrKZ1OtK1TyoWvdbA7yo2PdE1RfxfzJG5MMCNBTb9ngVvCXz6bZuq6EQidBONOvR7mWncMKeuB_pd87DvxIvahhhI4roHp8H7rbH_6eqRQLKiNBvmJxmqtNlb_wJPFtzTGZUNNOzZLuddJsBZggx6R3CsDigQVK6MKBi6qGlZTsn3nBNhEtX9jmRWU2Xx9IaVNuc9a3qlkMN2qTXg4B6ijMYa6emIva5Y-2ByK4dBwZd9nQSqk_QNcaLA_EVGBah1yIXCTRWqF5A3VrIlPnpVxTZZoLqnyjtWRh23L0-K47V3NuvXS7R1sZGGAapadVenRUH-iRs8493v07aJlH2DHNSuINEw15sPWALWpOiGJ6UdVsZ5FYtXcCTBX87PfmCp6OKChmkRqVXS_j3LTH48HzknZvYP-YY= \ No newline at end of file diff --git a/data/backup/keys/htz-cloud.luther.pub b/data/backup/keys/htz-cloud.luther.pub new file mode 100644 index 0000000..bd609da --- /dev/null +++ b/data/backup/keys/htz-cloud.luther.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO6bxLAHdTe9gQIwFhFWRBKq9BSMeds3lyDK9iud4kpL diff --git a/data/backup/keys/htz-cloud.miniserver.key.vault b/data/backup/keys/htz-cloud.miniserver.key.vault new file mode 100644 index 0000000..a7468c7 --- /dev/null +++ b/data/backup/keys/htz-cloud.miniserver.key.vault @@ -0,0 +1 @@ +encrypt$gAAAAABgoVlzLgIb2UCbDSztRNaLNDY5AaF3BlosclzZvKQPDvgRLobDusDPGCuxreeZ19PB1vOjyT0unuALoM-3qufCutiv9QxmeDwzKy6D9RFn_PVfL2WhNGOG_oO8W_2Itx8Nza-8ta-eQfnR-1FJnti3gXDh60usWwE9rI3C8BMBDiaGBWNqhi_P2r7YoWBsJ06jE-qr7J51ddO1W2VaP_95ebZu9GmAljQkzUy4EdgH5f0xQBgjHFzA5H_OAUMZ-ey3MFXPAXMSFKomIBy4eSks0ghHS5KcJYD3UTjXEdag022CXfNqQDZL99yZm7re4tvQ1nsaiD8rRPciNZHxb2VYEj-OPHEjJnJ4dv_uqba8IPd8Stc5n3A-vklMsZwQWwaAvu12T6m61HbJeCc7WPst8UTJbJJPMhX1bhnvo8qtmB0kRdQ7GhVno0OZRFbHAEgXj8ifXdEEwWuGmw_191LA_UGKjcUau27CxyfY9CnJoah0DSWoZ8_M6haQB4QisiPdDXUilb1Jva3b13U7wubMCSqdZCc5ySnI5womn-GuXWCOQlfwR3sKop5NPs8oeOcN2k_XZUvHm1udcntEMPqEbEBtlP21nUkxZ2nUl4KCpbQQ6iM= \ No newline at end of file diff --git a/data/backup/keys/htz-cloud.miniserver.pub b/data/backup/keys/htz-cloud.miniserver.pub new file mode 100644 index 0000000..35357fd --- /dev/null +++ b/data/backup/keys/htz-cloud.miniserver.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBkINf6i/nlscFFcvyZUrvYlpKZRMo6Si1LbNlClWksA diff --git a/data/backup/keys/htz-cloud.pirmasens.key.vault b/data/backup/keys/htz-cloud.pirmasens.key.vault new file mode 100644 index 0000000..0990166 --- /dev/null +++ b/data/backup/keys/htz-cloud.pirmasens.key.vault @@ -0,0 +1 @@ +encrypt$gAAAAABfrlWgKPszezQgjWLwmoRjEF1k_AedpCj3sYAIrzKDfdSEVuYjj_8tbzflMRuCax9FPCwffQdy2Y-79SuIoHgjVDfrV3jRPTegFhSWudIcbSMrlc-3Ypob_BD2pGyz8XbdYXdaPTz8R7wTLpYgqxWPkBAnHj_AsJeXO3qtbFkuMwqiUST9fFDbNfmUxunbmjk-WYYr6pBNy91dydWVR7Th_XxJNPtTucK1qRJgzaA5aA1UsiMXoc07jkDMVJAvs7Qy1ynofz0hh8DEb8SHo2htPQyKEWljU6vdYQ4PgYIWdP746m4fuDvTVKU2EkMmMxTtBF-lSHpg_AxVt3krB3Geo9MHTzodBmKkwHRRD49ZjY6E1QXQqjsrJ9T8eudokyaLuOZz9AwzgBZfWKNMh1D8BqaJVOoGgK0S1nLvRiONqX0sLq6XmQqEHalR1puMwugOBDNmrt2dBH283Jr9p_zbxe8fnNK0hgOeVJCe9tAr68Cn_dcWJgLsL-KUnhORXLjZXP44k8-k8ovj15cbW8fUobf8VyK6XqyUt119hXMCrjDed0RbjRBYjwm0A9Zv_DjsH6dFVKfyC1mu1nWTeOK0km3H6CnzWEPPhD3bA8YvXAoQfFY= \ No newline at end of file diff --git a/data/backup/keys/htz-cloud.pirmasens.pub b/data/backup/keys/htz-cloud.pirmasens.pub new file mode 100644 index 0000000..7cbe538 --- /dev/null +++ b/data/backup/keys/htz-cloud.pirmasens.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIILD1lwc1lNzVWQDxBxs9//5OUioFGOA7qGZjDykSIRa diff --git a/data/backup/keys/htz-cloud.pleroma.key.vault b/data/backup/keys/htz-cloud.pleroma.key.vault new file mode 100644 index 0000000..06e6894 --- /dev/null +++ b/data/backup/keys/htz-cloud.pleroma.key.vault @@ -0,0 +1 @@ +encrypt$gAAAAABgMXllIGiB__clFctfOC6T4qRhFDrh_WJZU745-DZef2UpKCy0gz_2FlDAIqrNceL-Ahz1AXZrsdHUKPYAZ5AW4ne0b0G6uHQENYB0xv-ZqA3MZS26gzvNM7ejhyTCM1zO1j6ePgIxfZlaalNcuLIRAphuhu7KkJA8sGaoUMjdTqVWJUjj4Le8KHcS-s7PhB1XjkyHYxb0cKFgPxs1CgHWVjfCviVnl3yFAF1aLvYsbNcpzM_RGGIIA9YsO3yPQ8Mfk4B3truuNg1mdNaunpnhoTImF2cSNoI64f2mVaSNxxRXm1NG2qUJkZN8ZQlW8k7A1w_zUwHw9-JaimZejfPWrhew7krAbPQWEqOz7Km0RkQdbzFzxWECDIOQ_Z87n_yEFLSN3sAHA0eQ-a6oqj5Ybga5p9eeNNdOYAZyU_6KfSl9U6XSKT16brAXnsZevWQHk06ObdOPhJW5SMIQwk0TZXUOMZ11T0o0-2IMGBngOjoOxqt7gjZoiLFt4c8BkFcDkpTj25asyG2iF-2jWZ1cY91F5nDkIE3CSQzD7DYANyTI7ik9qACiY25bBYOwo9HS9TEcE-wDS2_jKolFFmEx5EFdxzIpSXdWB7EznbizgqAtu2eYubASKlBKILpeVZiqKZi8 \ No newline at end of file diff --git a/data/backup/keys/htz-cloud.pleroma.pub b/data/backup/keys/htz-cloud.pleroma.pub new file mode 100644 index 0000000..1795293 --- /dev/null +++ b/data/backup/keys/htz-cloud.pleroma.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK7vz3CMmmHmnWZs4b+Ohh4wnUgcME8PvZscjgS+91Qd diff --git a/data/backup/keys/htz-cloud.sewfile.key.vault b/data/backup/keys/htz-cloud.sewfile.key.vault new file mode 100644 index 0000000..ab1b31f --- /dev/null +++ b/data/backup/keys/htz-cloud.sewfile.key.vault @@ -0,0 +1 @@ +encrypt$gAAAAABfrlWhKNaNm-FvjJIB97rK-RoXRnLHHZ63k8Y-beVmSwuYnXYEjZLSD5yrvE3TtkodVikztjx4Cuck6lTECQR2MwSSlZ76L_uJOCmwyCKbDmjCRAfJsr8ni0WIIDa6GBWeqy1KDqZsaqEJwaH_zF6Ps-JHsUB7NCpqcDLGCTGOQLUrgH_Qzyi4Jme0LAnH2DeY7bSyzOGdLezwGUd2nhv7eKet0NeJwWWTnN3HSd6KGJybZLR2I2FsqiNutqGNLnJgeuTHHsUVUxroJepmE4bC0sK9kd_yWWQDNTVc2MRsJA2XkfgfeWzusmjQyho-9iOucX66E2DnSLOSVfvV1ZQ5iTUx_iYQstDs_V48-Za8OEh0wtMvWJlw4fIZvT2CTbFMjv-Z3ID9O8zu-MOZTKJlvGgQzaCJlvI1xMAd9UcfwKvoejGrZNZdHdadyjB_hbNZk1e2KLYEXsnSzIyTU544K4yWOaKpA70di_rQHfrgUosdRn-CtZkWJolUzKVILNmaaI1gZYI3jr3SYqWWfHjVIlQIt8z5qmR527bvEKhJhDIkJ-RnvTNHeXx9Kqw3VPIWxHaYSS1Fv-M47e2rXsM5eDfPWRsQvYOiQO3g0EbMQhjho8o= \ No newline at end of file diff --git a/data/backup/keys/htz-cloud.sewfile.pub b/data/backup/keys/htz-cloud.sewfile.pub new file mode 100644 index 0000000..4d33a5a --- /dev/null +++ b/data/backup/keys/htz-cloud.sewfile.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN9fWj0+jwIxDSvwyP6sOiFeI6huU/kQ+N5nIBAj+2eT diff --git a/data/backup/keys/htz.ex42-1048908.key.vault b/data/backup/keys/htz.ex42-1048908.key.vault new file mode 100644 index 0000000..69129e2 --- /dev/null +++ b/data/backup/keys/htz.ex42-1048908.key.vault @@ -0,0 +1 @@ +encrypt$gAAAAABfrlWhxrcCNO5KHOsPsxD5ZymUgHG3my4qIJxfr3nJQyBVMRjFjxx2akQubpWWG9UC8xKthSvADXUZxjcGTAvqcELX60W2cdvJ90bY8RGHQ-Dua6-PsThurLVJeWZSmxo3vCneTj0lYEdAwK1aiZsRvxLjWhkyRELXvgPhC3GeNnS0SeC1AHGuRJVnC3ZMbRfSps1_LBxRvIES_acDJSfsRpcLg0oPmdpkDV9wdB0ZBuimngUYCl6jZ-syofI9yRU9q9lpNtZbahKAIBKNHeFzkgC6I5oi8e2-mZqnh_BSLomvRXPdZRvlHQWsSPNX2_25IlZiXyXrBIsN5rXAAwl16PNZjuG703WWiV2RxifGRux7cbJVE-LREBKCADgLduOZPe2voXo3jRq8v4NZfTtk8CKSm4QxS6Q7fRb7_0dAWZadd_dap8HigCUkr_5l-CotSKhiBNTAwyClLSMpDW1oUAaeLgM2YLF7V8TlWAwtxKi1lqmDchoWk221CQ97njVfhUOCNrdiGXOtFeiB-JRsXK8eAgthDzrR2F78s2w9NGZf0SdRxxNNil1f7ikDZfXbsdagaP_HZvjmq8oeTcwibcjsGl7HDVw0xV_7SvOJ3iDhLdQ= \ No newline at end of file diff --git a/data/backup/keys/htz.ex42-1048908.pub b/data/backup/keys/htz.ex42-1048908.pub new file mode 100644 index 0000000..88b121e --- /dev/null +++ b/data/backup/keys/htz.ex42-1048908.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFn5SDyIV+GtSqSDvKPsfkxRgmUKdu8eOOyEWUo5ZtJl diff --git a/data/backup/keys/kunsi-p14s.key.vault b/data/backup/keys/kunsi-p14s.key.vault new file mode 100644 index 0000000..f2ee06a --- /dev/null +++ b/data/backup/keys/kunsi-p14s.key.vault @@ -0,0 +1 @@ +encrypt$gAAAAABiB-rPruxytUp5eFUDx-bfXhTHoXbV4E71--i0EFgQxVn0bmgfNrQQL21mAHm9JqSnwtzHxuHW5C_VYXb1vsg6b3lopue3i4XPHZYFe0VU5SDFdKbP2JEQcuMZfYqjN49MxM3bGVkTiErNpf-Ctgf_sop02O_IYNR3fhvD8IST32RUrfqYHPAky9O48pon202bPi10jPMu2dZTevE3ODtBHdiY1Sx7vTzpUiVskXj9H3A3dzywM2w7KpHiUx5sROaOWNZBQ2MASQLfIbAe1mQobCpySKsMNhbxmpTO2Cg75a8tLbtTicrzwU9DB8HOLn5L3ed-K1bPpP57_bWrxl9_Jrvgu6PgDB8b1PTInycej8o7zZKF-UTi1aGcjJAvSRymWDb045WBQs3HIJJuBlKoHwjMUN7Vw9u1JqooTSmJWFql3pdIlhR3YZxTe5wrT1jxHeyxKPk7YlNqcj6nlK8v9QT9w24IdF0yekVl_HVnFgZ4EQ_DH_wdKTnAJWLOMkqYjlFCz0HS_IOF-X3oPr8UcbXzQ6dtcJAh3nR6kJRUIfifzEk0hBkZZ8axiDt2KFFYLqv5SM5TmtRuxeJq38Eqa-uv62w2_lJZiLQ6wFHR7UoGgBexp65vGe3cDnN7j1fPXgGo \ No newline at end of file diff --git a/data/backup/keys/kunsi-p14s.pub b/data/backup/keys/kunsi-p14s.pub new file mode 100644 index 0000000..636ca3f --- /dev/null +++ b/data/backup/keys/kunsi-p14s.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGDTtww1OWI29zxXpUANToHzzBR/Kp0Jqpii0+JUr3MY kunsi@kunsi-p14s.kunbox.net diff --git a/data/backup/keys/kunsi-t470.pub b/data/backup/keys/kunsi-t470.pub new file mode 100644 index 0000000..1d712a5 --- /dev/null +++ b/data/backup/keys/kunsi-t470.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC+ja1z5VRQzaKCCePsUM14qMr9QR94qlWc7Je5Poki9UmC1t/TyxRVzcCBL1ZdIfBGx6QKtfkEbvhgb3nxVt3PvXjoJrc6wwGLmNrVsU6B88y35g7nzupQiPKYJwkNzJ9j6Dmkgj1F5Q+aY2SitDaX6vqICLJ4Al/ZFw2IQxVJfC7JXRJ9jRMG5o9gWoE3gWDYEAmw+HU2mNzyeuaD12qJw9DHUimAlgkOWzll3gh9WclsYnnXGrCCn5fyHFUCJl+XXAIy519z7YTpKih02rsIOw5dnaGClBZD/YQu2ZKVFZiwIVH7aBiqHOmtgRyWTQgjbh/fMpIN0ar2f/iZsWYUjd6et48TOmXZYIPCQ5FivXNvxt9oo1XZfq76UHBwlmypLJIWROMbz375n2M6hr3hECuxuPjKEUXAv05KiC1aJ4xc6pFoVhqwAR99hvHw5U4o7/ko2NVjNpTu6Jr5DT5VaQLIdDDjC/93kUjMpdD/8P72bEn7454+WexU6OE6uvNiHj1fetrptr2UAuzVfnCoaV8pBqY7X95gk+lnSENdpr8ltJYMg8s0Z7Pzz0OxsZtzzDY5VmWfC9TCdJkN5lT8IbnaixsYlWdjQl1lMmZGElmelfU3K7YQLAbZiHmHKe4hTl9ZoCcWdTQ3d4y2t1DBos+N2HZNdtFCyOS8esDdMw== diff --git a/data/backup/keys/ovh.icinga2.key.vault b/data/backup/keys/ovh.icinga2.key.vault new file mode 100644 index 0000000..93964c5 --- /dev/null +++ b/data/backup/keys/ovh.icinga2.key.vault @@ -0,0 +1 @@ +encrypt$gAAAAABfrlWizt5Lp7t_CRYxVrlPmXFKSKKpNzWIKaM8X6l-7eUD-vDMN9G1tj6nucjQ3sHOll7WXM367HIcqIlOQfUDM2Qat3_4MstsKnEHUvoPh1xyjrui74ZQvLrdedYjtQ_YlsLJnoHkqLThJQ1D3pazifMYouF0CO9MMz4pVxTNiSGYPzVaixUN_LcMm9-u0vWaVh3UqDa3mLxufI36C5lKR6p7jEhB3vTpxtahquDxSjMmCYQv1AiEbPfoh0-8mFlZ5QZ9ZPxno5q_5SnZViv4jDuLLcW1VeK4ocOP2vjh8QuN2uc2-AuQRzykOAHBjprKcjgrp_M9sejy4W5I40wgpMliPtgc8z_tdBhU5uLwKR50l0xjCW9oR7mPQIzrs8Y6b-KPO3Hy9v2iCKYT0XOLiY9fCF_hmIk-hN7ekS2zUlU4TzRC9nDD-YBX28mqXU7n1-0QciDjVkpmcxvBFzBbNt5XXJJ7jLdfj6fx2keErnmSLWAnMv-ztJX93sfxYfnQejqhYIc_H81xF4Nm3P3V7lf8PeR_FsfqvQujR9ECBWQ6vo8-5KnAiYnMSyPapirY8b4FPUjKhEgel5goSZ4DhbmUBKPVecByUTYSBAXP76IyXRE= \ No newline at end of file diff --git a/data/backup/keys/ovh.icinga2.pub b/data/backup/keys/ovh.icinga2.pub new file mode 100644 index 0000000..a0045cc --- /dev/null +++ b/data/backup/keys/ovh.icinga2.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIE5hLAqBz7Vm6oVv+oye5hQCsRI3cPA9q5B8KCWYCYUw diff --git a/data/backup/keys/rx300.key.vault b/data/backup/keys/rx300.key.vault new file mode 100644 index 0000000..b272d12 --- /dev/null +++ b/data/backup/keys/rx300.key.vault @@ -0,0 +1 @@ +encrypt$gAAAAABg2xbjGmqokuwp9mIL5CX0fmGhvxpeYJGam2csaFKM5UqpgpnE9BFSUUkJRPOc0cnXH7xNriDJaY6EXEd959gkCMm0Cwu4H7t8XUeHNPfeqoyp7R1mmddnDp5BglbhkI6VJqCiD4YhmDzAieu6YY9Ho-E0SR-kOB-z9Jfw1P8yUzaF4GzNqKdWlSaTSt_fq2aotIQm13ukrewZChA8xY_1mMVgxcfVfOLFFRNVCrW1oRcH0qaQ_6_7ZsRZat_8tCgjknFLb9suBGBNbwl7yxlayaRfbN36VevSX4iSA4Q_nvSZ40oV5otqljpMyUpbVRbeZb0uAJFbn_8nEWc0FKR5iJy-mXcToBlx0Rc8wPmHuG2Gdf0BJDFK8AIIL9p-ucqYdvfU8oC_dsHlnhIXnf0dc9PdP-9Lnh3Ov1Lkm-i0GLa6K6nPrtRXgDaj_fv1V01-0vYF_t4vs_4VbjMMXGhUXI94lRw59vFB4WJQluir2ut-jDQR0Ek0U3g5-ziRbg4t77JzKjeUymbguT2BAT0er7W0zfKUcQ5VizSJ3j1U7VtbVJ7E3710BQ_1pCoz9HAt_BcxYSJ3bnhRR9V_NdaSdtPeIVqQ0G69hKbwNYZ0CAEAgIhbRgeyDeMev6WhWN6T5We- \ No newline at end of file diff --git a/data/backup/keys/rx300.pub b/data/backup/keys/rx300.pub new file mode 100644 index 0000000..6fff864 --- /dev/null +++ b/data/backup/keys/rx300.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAID/pOUa5sbFtqzHZF2qnG+MroI8Z65FRnYAiS1CrqCss diff --git a/data/c3voc-addons/files b/data/c3voc-addons/files new file mode 120000 index 0000000..e2f9229 --- /dev/null +++ b/data/c3voc-addons/files @@ -0,0 +1 @@ +../nginx/files \ No newline at end of file diff --git a/data/c3voc-addons/files/error.html b/data/c3voc-addons/files/error.html deleted file mode 120000 index 26606f0..0000000 --- a/data/c3voc-addons/files/error.html +++ /dev/null @@ -1 +0,0 @@ -../../nginx/files/error.html \ No newline at end of file diff --git a/data/c3voc-addons/files/extras b/data/c3voc-addons/files/extras deleted file mode 120000 index afe5648..0000000 --- a/data/c3voc-addons/files/extras +++ /dev/null @@ -1 +0,0 @@ -../../nginx/files/extras \ No newline at end of file diff --git a/data/c3voc-addons/files/gpg-keys b/data/c3voc-addons/files/gpg-keys deleted file mode 120000 index c649d44..0000000 --- a/data/c3voc-addons/files/gpg-keys +++ /dev/null @@ -1 +0,0 @@ -../../apt/files/gpg-keys \ No newline at end of file diff --git a/data/c3voc-addons/files/not_found.html b/data/c3voc-addons/files/not_found.html deleted file mode 120000 index b6964cb..0000000 --- a/data/c3voc-addons/files/not_found.html +++ /dev/null @@ -1 +0,0 @@ -../../nginx/files/not_found.html \ No newline at end of file diff --git a/data/c3voc-addons/files/ssl b/data/c3voc-addons/files/ssl deleted file mode 120000 index 348aeea..0000000 --- a/data/c3voc-addons/files/ssl +++ /dev/null @@ -1 +0,0 @@ -../../ssl \ No newline at end of file diff --git a/data/forgejo/files/ssh-keys/carlene.key.vault b/data/gitea/files/ssh-keys/rx300.key.vault similarity index 100% rename from data/forgejo/files/ssh-keys/carlene.key.vault rename to data/gitea/files/ssh-keys/rx300.key.vault diff --git a/data/forgejo/files/ssh-keys/carlene.pub b/data/gitea/files/ssh-keys/rx300.pub similarity index 100% rename from data/forgejo/files/ssh-keys/carlene.pub rename to data/gitea/files/ssh-keys/rx300.pub diff --git a/data/icinga2/icingaweb2_nginx.conf b/data/icinga2/icingaweb2_nginx.conf deleted file mode 100644 index bd9415e..0000000 --- a/data/icinga2/icingaweb2_nginx.conf +++ /dev/null @@ -1,15 +0,0 @@ - location ~ \.php$ { - include fastcgi.conf; - fastcgi_split_path_info ^(.+\.php)(/.+)$; - fastcgi_pass unix:/run/php/php8.2-fpm.sock; - fastcgi_param SCRIPT_FILENAME /usr/share/icingaweb2/public/index.php; - fastcgi_param ICINGAWEB_CONFIGDIR /etc/icingaweb2; - } - - location = / { - return 301 https://$host/authentication/login; - } - - location / { - try_files $1 $uri $uri/ /index.php$is_args$args; - } diff --git a/data/jenkins-ci/files/ssh-keys/rx300.key.vault b/data/jenkins-ci/files/ssh-keys/rx300.key.vault new file mode 100644 index 0000000..e56190a --- /dev/null +++ b/data/jenkins-ci/files/ssh-keys/rx300.key.vault @@ -0,0 +1 @@ +encrypt$gAAAAABg6vNNuCZcmhH52dQDiD4ePsbXhz0kHSjqX3yduJ6E5NylWEdKNtjtrfc9bu1WNnDBO0YpsqxIeax2u1xc6gstohVfbu2MgwGJKpA7J5Py6xiQL82YKJcwV7k0EZ7ilWbqlzXuSDh40KG3GWOTPiw_CbsbDEpCU09x1hUs1_0BTPAU6ln4t7ync7ZjFZf_vRBTlrnZWchzXoSwppzedAZeaptfhMWn_-8oARoYvxJf3pkmTSGjovNMvDak_sscq_M2rldng6_oboR4iTo_6eY6bpCjEGD3xMeSzLhDZsJ4c0l9bZBDef-NRWA7Ewptc4KYKVvzKlgyrByqSV8TCmYn4aBgOusv-VAW3VqKg2rHi3nq5L50zkPwWmHC6_rdtIS-pAlnR5A0HJYdXGyf2eQSq3UkrZA3BIFlqUWrvS8aTWxp9CUL5C9oRGpL8P3fVfExiqhmcLGamHZb1Y2kjxX8EMcSCRLgiVO9DwIpXlEm86HfgVcXaL0wpibM32PD0sspOPILThE5P9WETGhpFAWDkWR0WaYQjZuAVlXTtk8tgdh0vC2auQl2pEVbvvnZaa04Ohp2QgE3AJLg3tdekLciwCQmPm0bpX8xYvJ49vNWG-SCaAlLHzLVIMFXFY53-SBOHYnE \ No newline at end of file diff --git a/data/jenkins-ci/files/ssh-keys/rx300.pub b/data/jenkins-ci/files/ssh-keys/rx300.pub new file mode 100644 index 0000000..55ce7ec --- /dev/null +++ b/data/jenkins-ci/files/ssh-keys/rx300.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHZnYhsdtGUYJiFcvfqTLljGkInnFTOoDF/WZniLtPjH diff --git a/data/matrix-synapse/rx300/homeserver_signing.key.vault b/data/matrix-synapse/rx300/homeserver_signing.key.vault new file mode 100644 index 0000000..120737d --- /dev/null +++ b/data/matrix-synapse/rx300/homeserver_signing.key.vault @@ -0,0 +1 @@ +encrypt$gAAAAABeiaEqyvC5b9qRtL9I760dD51BJ9ZMKjofyORoSedhjqfHM0Pp-x_UECvoZgrtY8dgcq0Ste27YlSofnPwLM6Jr6wXfNX-Ih8WZD7hV6yQdEQ6wmj2FYilmMknGdQ_yVnu5TRe_malgW78n6hRQc7DsdsEfw== \ No newline at end of file diff --git a/data/minecraft/files/rx300 b/data/minecraft/files/rx300 new file mode 100644 index 0000000..19e41fe --- /dev/null +++ b/data/minecraft/files/rx300 @@ -0,0 +1,59 @@ +#Minecraft server properties +#Sun Nov 06 13:56:13 UTC 2022 +allow-flight=true +allow-nether=true +broadcast-console-to-ops=true +broadcast-rcon-to-ops=true +debug=false +difficulty=easy +enable-command-block=false +enable-jmx-monitoring=true +enable-query=false +enable-rcon=true +enable-status=true +enforce-secure-profile=true +enforce-whitelist=true +entity-broadcast-range-percentage=100 +force-gamemode=false +function-permission-level=2 +gamemode=creative +generate-structures=true +generator-settings={} +hardcore=false +hide-online-players=false +level-name=/home/minecraft/world +level-seed= +level-type=minecraft\:normal +max-chained-neighbor-updates=1000000 +max-players=20 +max-tick-time=60000 +max-world-size=29999984 +motd=CutieMC +network-compression-threshold=256 +online-mode=true +op-permission-level=4 +player-idle-timeout=0 +prevent-proxy-connections=false +previews-chat=false +pvp=true +query.port=25565 +rate-limit=0 +rcon.password= +rcon.port=25575 +require-resource-pack=false +resource-pack-prompt= +resource-pack-sha1= +resource-pack= +server-ip= +server-port=25565 +simulation-distance=10 +snooper-enabled=false +spawn-animals=true +spawn-monsters=false +spawn-npcs=true +spawn-protection=16 +sync-chunk-writes=true +text-filtering-config= +use-native-transport=true +view-distance=32 +white-list=true diff --git a/data/nextcloud/nginx.conf b/data/nextcloud/nginx.conf deleted file mode 100644 index 34267ad..0000000 --- a/data/nextcloud/nginx.conf +++ /dev/null @@ -1,41 +0,0 @@ - location ^~ /.well-known { - location = /.well-known/carddav { return 301 /remote.php/dav/; } - location = /.well-known/caldav { return 301 /remote.php/dav/; } - - return 301 /index.php$request_uri; - } - - - location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/) { return 404; } - location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) { return 404; } - - location ~ \.(?:css|js|mjs|svg|gif|png|jpg|ico|wasm|tflite|map)$ { - try_files $uri /index.php$request_uri; - # 182 days, 14 hours, 54 minutes, 23 seconds. I have no clue why - # this exact value, but i copied it from the example config. - add_header Cache-Control "public, max-age=15778463, $asset_immutable"; - - location ~ \.wasm$ { - default_type application/wasm; - } - } - - location ~ \.woff2?$ { - try_files $uri /index.php$request_uri; - expires 7d; - } - - location /remote { - return 301 /remote.php$request_uri; - } - - location / { - try_files $uri $uri/ /index.php$request_uri; - } - - # cursed shit, use like this to have the 'map' feature outside the regular nginx config -} - -map $arg_v $asset_immutable { - "" ""; - default "immutable"; diff --git a/data/nginx/files/extras/htz-cloud.aurto/aurto b/data/nginx/files/extras/aurto/aurto similarity index 100% rename from data/nginx/files/extras/htz-cloud.aurto/aurto rename to data/nginx/files/extras/aurto/aurto diff --git a/data/nginx/files/extras/carlene/nextcloud b/data/nginx/files/extras/carlene/nextcloud deleted file mode 120000 index eaabf9e..0000000 --- a/data/nginx/files/extras/carlene/nextcloud +++ /dev/null @@ -1 +0,0 @@ -../../../../nextcloud/nginx.conf \ No newline at end of file diff --git a/data/nginx/files/extras/home.paperless-sophie/paperless b/data/nginx/files/extras/home.paperless-sophie/paperless new file mode 100644 index 0000000..1aa1b28 --- /dev/null +++ b/data/nginx/files/extras/home.paperless-sophie/paperless @@ -0,0 +1,3 @@ + location /static/ { + alias /opt/paperless/static/; + } diff --git a/data/nginx/files/extras/htz-cloud.luther/luther-ps b/data/nginx/files/extras/htz-cloud.luther/luther-ps new file mode 100644 index 0000000..f5a95e6 --- /dev/null +++ b/data/nginx/files/extras/htz-cloud.luther/luther-ps @@ -0,0 +1,51 @@ + location ~ ^/sites/.*/private/ { + return 403; + } + + location ~ ^/sites/[^/]+/files/.*\.php$ { + deny all; + } + + location ~ (^|/)\. { + return 403; + } + + location / { + try_files $uri /index.php?$query_string; + } + + location /update { + try_files $uri /update.php; + } + + location @rewrite { + rewrite ^ /index.php; + } + + location ~ /vendor/.*\.php$ { + deny all; + return 404; + } + + location ~* \.(engine|inc|install|make|module|profile|po|sh|.*sql|theme|twig|tpl(\.php)?|xtmpl|yml)(~|\.sw[op]|\.bak|\.orig|\.save)?$|/(\.(?!well-known).*|Entries.*|Repository|Root|Tag|Template|composer\.(json|lock)|web\.config)$|/#.*#$|\.php(~|\.sw[op]|\.bak|\.orig|\.save)$ { + deny all; + return 404; + } + + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { + try_files $uri @rewrite; + expires max; + log_not_found off; + } + + location ~ ^/sites/.*/files/styles/ { + try_files $uri @rewrite; + } + + location ~ ^(/[a-z\-]+)?/system/files/ { + try_files $uri /index.php?$query_string; + } + + if ($request_uri ~* "^(.*/)index\.php/(.*)") { + return 307 $1$2; + } diff --git a/data/nginx/files/extras/htz-cloud.miniserver/matrix-dimension b/data/nginx/files/extras/htz-cloud.miniserver/matrix-dimension new file mode 100644 index 0000000..e13c482 --- /dev/null +++ b/data/nginx/files/extras/htz-cloud.miniserver/matrix-dimension @@ -0,0 +1 @@ +add_header Content-Security-Policy "frame-ancestors 'self' chat.sophies-kitchen.eu"; diff --git a/data/nginx/files/extras/htz-cloud.miniserver/sophies-kitchen.eu b/data/nginx/files/extras/htz-cloud.miniserver/sophies-kitchen.eu index 2f321f7..cc5c4e3 100644 --- a/data/nginx/files/extras/htz-cloud.miniserver/sophies-kitchen.eu +++ b/data/nginx/files/extras/htz-cloud.miniserver/sophies-kitchen.eu @@ -8,13 +8,3 @@ location /.well-known/matrix/server { default_type application/json; add_header Access-Control-Allow-Origin *; } - -location /.well-known/webfinger { - return 302 'https://chaos.social/.well-known/webfinger?resource=acct:sophie@chaos.social'; -} - -location /social { - return 200 'Mastodon'; - default_type text/html; - add_header Access-Control-Allow-Origin *; -} diff --git a/data/nginx/files/extras/htz-cloud.pleroma/pleroma b/data/nginx/files/extras/htz-cloud.pleroma/pleroma new file mode 100644 index 0000000..7e69502 --- /dev/null +++ b/data/nginx/files/extras/htz-cloud.pleroma/pleroma @@ -0,0 +1,2 @@ + access_log /var/log/nginx/pleroma.log gdpr; + error_log /var/log/nginx/error.log; diff --git a/data/nginx/files/extras/htz-cloud.sewfile/sewfile.franzi.business b/data/nginx/files/extras/htz-cloud.sewfile/sewfile.franzi.business new file mode 100644 index 0000000..9312c7e --- /dev/null +++ b/data/nginx/files/extras/htz-cloud.sewfile/sewfile.franzi.business @@ -0,0 +1,23 @@ + location / { + proxy_pass http://127.0.0.1:8000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $server_name; + proxy_read_timeout 1200s; + } + + location /seafhttp { + rewrite ^/seafhttp(.*)$ $1 break; + proxy_pass http://127.0.0.1:8082; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_connect_timeout 36000s; + proxy_read_timeout 36000s; + proxy_send_timeout 36000s; + send_timeout 36000s; + proxy_request_buffering off; + } + + location /media { + alias /opt/seafile/seafile-server-latest/seahub/media; + } diff --git a/data/nginx/files/extras/icinga2/icingaweb2 b/data/nginx/files/extras/icinga2/icingaweb2 deleted file mode 120000 index b6a8498..0000000 --- a/data/nginx/files/extras/icinga2/icingaweb2 +++ /dev/null @@ -1 +0,0 @@ -../../../../icinga2/icingaweb2_nginx.conf \ No newline at end of file diff --git a/data/nginx/files/extras/rottenraptor-server/dokuwiki b/data/nginx/files/extras/rottenraptor-server/dokuwiki deleted file mode 100644 index 2e9b682..0000000 --- a/data/nginx/files/extras/rottenraptor-server/dokuwiki +++ /dev/null @@ -1,33 +0,0 @@ - location ~ ^/lib.*\.(js|css|gif|png|ico|jpg|jpeg|svg)$ { - expires 365d; # browser caching - } - - location ~ /(install.php) { deny all; } - - location ~ /(\.ht|\.git|\.hg|\.svn|\.vs|data|conf|bin|inc|vendor|README|VERSION|SECURITY.md|COPYING|composer.json|composer.lock) { - #return 404; # https://www.dokuwiki.org/install:nginx?rev=1734102057#nginx_particulars - deny all; # Returns 403 - } - - # Support for X-Accel-Redirect - location ~ ^/data/ { - internal; - } - - location / { - try_files $uri $uri/ @dokuwiki; - - # This means; where $uri is 'path', if 'GET /path' doesnt exist, redirect - # client to 'GET /path/' directory. If neither, goto @dokuwiki rules. - } - - location @dokuwiki { - rewrite ^/_media/(.*) /lib/exe/fetch.php?media=$1 last; - rewrite ^/_detail/(.*) /lib/exe/detail.php?media=$1 last; - rewrite ^/_export/([^/]+)/(.*) /doku.php?do=export_$1&id=$2 last; -# rewrite ^/tag/(.*) /doku.php?id=tag:$1&do=showtag&tag=tag:$1 last; #untested - rewrite ^/(.*) /doku.php?id=$1&$args last; - - # rewrites "doku.php/" out of the URLs if you set the userewrite - # setting to .htaccess in dokuwiki config page - } diff --git a/data/nginx/files/extras/rx300/franzi.business b/data/nginx/files/extras/rx300/franzi.business new file mode 100644 index 0000000..472d106 --- /dev/null +++ b/data/nginx/files/extras/rx300/franzi.business @@ -0,0 +1,15 @@ + gzip on; + gzip_vary on; + gzip_min_length 10240; + gzip_proxied expired no-cache no-store private auth; + gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml image/svg+xml; + + location /css/ { + expires 7d; + add_header Cache-Control "public, no-transform"; + } + + location /img/ { + expires 30d; + add_header Cache-Control "public, no-transform"; + } diff --git a/data/nginx/files/extras/rx300/paste.franzi.business b/data/nginx/files/extras/rx300/paste.franzi.business new file mode 100644 index 0000000..93f035d --- /dev/null +++ b/data/nginx/files/extras/rx300/paste.franzi.business @@ -0,0 +1,5 @@ + autoindex on; + + location = / { + autoindex off; + } diff --git a/data/nginx/files/extras/rx300/wiki.franzi.business b/data/nginx/files/extras/rx300/wiki.franzi.business new file mode 100644 index 0000000..cc1fc01 --- /dev/null +++ b/data/nginx/files/extras/rx300/wiki.franzi.business @@ -0,0 +1,12 @@ + location ~ /(data|conf|bin|inc|vendor)/ { + deny all; + } + + location / { try_files $uri $uri/ @dokuwiki; } + + location @dokuwiki { + rewrite ^/_media/(.*) /lib/exe/fetch.php?media=$1 last; + rewrite ^/_detail/(.*) /lib/exe/detail.php?media=$1 last; + rewrite ^/_export/([^/]+)/(.*) /doku.php?do=export_$1&id=$2 last; + rewrite ^/(.*) /doku.php?id=$1&$args last; + } diff --git a/data/nginx/files/extras/voc.pretalx/pretalx b/data/nginx/files/extras/voc.pretalx/pretalx index 8c82109..1d1c718 100644 --- a/data/nginx/files/extras/voc.pretalx/pretalx +++ b/data/nginx/files/extras/voc.pretalx/pretalx @@ -25,3 +25,12 @@ expires 365d; add_header Cache-Control "public"; } + + location /Uluagh8Oichai4Uk/ { + alias /var/www/pretalx/; + access_log off; + expires 365d; + add_header Cache-Control "public"; + autoindex on; + } + diff --git a/data/openvpn-client/c3voc.conf.vault b/data/openvpn-client/c3voc.conf.vault new file mode 100644 index 0000000..e18a68e --- /dev/null +++ b/data/openvpn-client/c3voc.conf.vault @@ -0,0 +1 @@ +encrypt$gAAAAABje8PnbzxHl_1Lr3mpXemItAaxmkeKsKtZ1dWVxcK9DJ8MUNKwryWcmcMkpHFFgYrjmyU3pw93vmlPn6wa0Vc5IcY4ZR3xqO9LqhgXtzD_PGXwAhL9vTEVinDdBS_3S9ub9w8LhlLv99eHVbojqCw7xHtwvo4Nc78EZexuHrhitWEP-ailL_UGXpeaQzUZegjzK8lbUqdgEIUFQb7nraZGm3ZwHVt8oQ3Qeipb6joiFo1jChFiIIRXk1M4TqZAHiRCWIuMomXxDio386WcvnEpghVAebU5s2EgSIjoaDW9DQhLNzuUAFjJW_ugBJNZd3wA3m0CdpSWskpi3ppK0YRbIOxepgtoFa_sITu0OdTRKUgbEnNU8zePwf6zHe2ujH_AjHQ_F1Y46KDsk5yi_8yC5Ml8ivyHkUV0CI4eRYd5pwl0HxFh-gaxZoCPfVec2-13gLY_eugtydTux0Ci4DXsc_RnPUvKpMS5eTPSK-YggB_ctjUV4-Au-WQQ3830-gruYePxnuhtSRsxNbf_MsUVKPM6zYdHg6sXX7RN7EvZ-tyATPVTdwDDf-F0xjiRMQd8gNcklELo--OjKV-J2yj6bZNG3TVDk74DVKiogytrvevQYG-cMIIPLFNBIRrhn5Xycy2ypZj3R-qvfksb0aQtTl3NYzWrJZBw8n0HtUxtLZRqH-e4zz0ft6rKdI576NIjNHksMeKt_8W_Rty-huNicrXX2tZYoi3_D5EglFtRuhgygSPoFiPh-BU5bQaconMDuQki5vemSGYL8tC1Oy4VhnMHwGRHBm76a4LsC_lBB97uWlBtZ7ubd8CmXQfijxewWmKliMOlsMgBG8nb25cpxBoklPpq4VG_JKMNGZN1Sa-e4TdLe4Men655qMZ1eUyp0AYiScQplwKDcADlFUmbuj7FBqZ5hqKhgnLZydUk2skZsD_GydNEA9PAkULM34p24T0sND-BmLnE7TAtdEaxpNq9uhsVSEa59EJhCq0Zygs3MTSAWZ8r1rxPVfwvTdEm30whhqEwn53zbFLQWCnKbINUx37MMrgyRAYL_kP6JLlz8ANQYCu5TFGwn2_d6vEahesXAvIB8CuN2CMqx5XMQrI5GE45g0a0vp3tLUuU_4RX5qLBPCig5UvxXA0PXuSsuhvKRMN8Le0h-s4KEX6xWon4rb7adsj9WuyMDolySqW3FB7grf-eqx3S_PfCZEL3w-URzuQbkKUH0BgDkltmTr6ZgoNqWxVIbYDIjzO4TGNOItDWQBrAOlOakTj2X3NyOim1btLw8RlVRRdcUNq2ueLquyrcvGOhFMkAYYgXR34Z7FE4DG70omfETAzc4jhvcggYRjxZLwMcImbs_q6ZhfYY_SQkNP7_ot2lE8UoU13j3mKYdZoMQ0LL_IRMt4g_CYWtHRjKY0m2cmP4avwK469H337LXwijwrSLNP6jUtqbUyhX-HiGtkJ6ZlIzH7JHfO5CEl7Fu_3ljla9CTKcXybORj_ElwHWOufACHbpC8jc6LLnxwYVjBiFuCIn2JiulGygef8LQemXHN6vud1xWtKf_OhJFDGkJX1D-IwYK_5MGkLZZUj6K4NMelWQIecR5qkYcDOc1-URKxUO8-g_pALbTzrVaf6aybQl9xQasyFb84aD0Gp8CgmDQG0yt_KH0TQNr9-mUQhS4baEF4O4TwrgERdl0sJ-521wBCyq2M3hAbcBtP1n8vxjfxkv9PLBaRHldGoPqCWDQmEnT57CZToj_MjVI_mJRPJ900VZk8IRIkmmeiGup0jbJujrAf6sQ5MGIUMVBEA_gc9qFgRruU-2PpA0mwsbomsv0aUSZKXSHMF_KyHoSC73haDNxzifbbJV2PzNVp1ce_j9m3V1SUbAgKUaIBzf52hDfC2Ub373EXE5z0JmvnLNWYe5SLw5iLLOXiriujzNsEdi5_AoOEx5wuLNwhR9mmvB8giUsbp0c-EC_JC3vPt1W-6unsb2CnMrIvqjRLVXhE0ZyzVtAl0JVlQ9bb3Va5HL2aLE3DOQrMl1E0iddmsNrsJrGM80X1RGMwyXrVNoDTjkxVTKg4tqngV4BCYkzD7xkKh5mBatYCSwetb2IRslut5SvJOBzJ-wLNjxcWiBIs2NEEGMfj8WjiXY7JOmaneXjprrsVsmvDAlHEMjtZpXlML72lfYkF64SA9uhz2wQLKuUXCWZPENCytYz52TtEtePmPOKP4CPi_w1QyP7CLhymOWZAQQc3xHDnL3orpUbstpYgdo34D-iuSyd3quQLTJQnPTC1fKxJuNrKBxftqs3ZbE4EBxLjBxhW3hVadS4-VYzdc--nv8hPLQU1k8IpGAJ5U7kmxROKQMJEqr9Ay4zosY8AqnPqD48cJ5o2hDSa9Znve9QIaXKV1dH3WPsF8aEu71E7hH-TXo-56HY_lxfPejaa7Ls3JZ6JJKNh8KncQU1AdARIU9Gw-bCpfQuKTaB7F6OdrqcGd4Qhic0kvIkWzFGLKUsQ_UigcbdW0h1kIU6qZJxV-8KQMhHOUsoXgVExkNU7bBlXxCa8-owQkTY1auTyCDvGIET36UzKyfSyympBIdL3YWNphgErhI4ZMrr3ol6iPAWqlQYxpu9OY1XYq63KvSXirIm3YEW0_FqCm2jgQdYqXoelgpAqmTSCfCaZTRMm__zqf0xqVUTYagVGUHUNpTKwr_YD-F7KtgnGH_KDSt-auNBfAJEMB9-c1AgmkYff4FLhiu_pUJaD7U1qwac8fu1amf9obUNTX_zArJqYwOCFKJcRR7mOH_TABT58VaCcMPaI6cKKoBj_UtfSKH-m_Vq_N6uMbcMFZahhBuLGKTtidCqHENz1IGo8FePAUaFgg7rviyHg4cfZMXkI8YG5S447rj5F52j2nOsWWS2yxUGVbgIUFqCEDk_c4eeEBhzfFVc4gyPssuAOWn-FvIrMOInNyctgqQSmRpYzorsYzTtdJCO1wnz5m-gbrGKkwd10TTf2Wt24xxhPOsAGv_ZFD2jlKtzAseRvR9lKAVr-roApPS1Ikeeq2mDrwrz5qEX9L8U5TCh3GVihQRbOtDphivDmeAEu_OS5yZyDFEtqoea31dtz3dmbLws8_ph_7E9ZDHv8OmAbDVC0hoq65Wl6r2jeJ-nnowy4ntRqw9zUfwJnMb56cXAbsLUnKr_CJ5sk0ip3yRJW7tcMwVOB33QZWfrlr9IJJEKkKS56BuuhZriUQCqT6ZXf0U64GHirSz8C7uG7bPKk9cSO9dKAPMAhhuzf7Z9wTlXtGfja_XbHL0zaSc5xINrdTZiXRidaj0YSHNw3aPokwAmzsDZv8kVwwX7Wdnb_StkClle5EuIVcRfeyz7l5jQC-Bsqe3mVnN3KmPAWzHhT_p3TDk843OEN59b6vv286Z_kEijIu2ujW5isdZLnUgvprTq9LkLaAvSF53ruPiWR7lPg4vrT9Ag8P6No1wDuTKK9M7ZI79a7optNYlJw_dWCjE0VU4cFF74Kxdg9kjnsrkQrNInDFFwCQRfTMr2gPTXdMmWJX1a_U1PGUdoAv7v5pwPoXPO2iaBeqw98GpCPc463mOOpp2_rrKbUIfJ9IjCFN8MBvbvnHxQoLrif-D5xvFaZ1CxtfMSLo4jecJFQ62kRxbkOfNlRGyVX9e9ZN8LJ3Hr5hKx6EJelUktjpYdZZjr9jmQa8E7mmKzw918nbaQEt28xp_yJ2G18EqYw5k1fICvYwbrSwVnJnrFIOc3dNbMz9jt2CLccNx6V1w5bLagGj99zWdpywEqpzrIUFUz0rpQRD9kbHHwaTCPZ0R2tW8XFYN6nPvaTMsJWRXR4Z9jqW6x95vB6O11sCOM_z8fJYjHWTsA0VQbzdglHo7iKDH7qjprC8AtHzYSVknP4WSIOst93Me9KTmZNcNls34vS507SeJpMMQ9JOT4Vd_ZGcvZmhhZ2pbAxyruglTOmdF5Dny5PZfiAACgCY74s7H759o2jPDiY6cJddanH44uCtXVSWsBLbFh9ImWKWfFPH6kffAq1UoLRvAoz3apZGdCU4gLpUYgevudO7y6jL5U5xQC9pyKJuwQ5TpXBpZ3ADVvpttcilAVi4oc-zgigJRxiJAl2SxpN0BfcW43cLM17s26xEEtry_bFv_K4_DjAV2lkVxCebHAvXnSoJu8Ub8_59bZTCov690l48wa0yHf6ANnxFkvV1dmweTdLvplSfVRbRICrljm2fMYJpI2IIJ1JGKHzY2T76oeIzoitwgAetWgz04w8beC8YTv1zwMNOoXslz3XYRHBE2Z6BQ2DGWgFMlfBcea8aUJKJJC1E93iz2GHNysFLYF8gLrM1obE26G1q5i6djJtmF7fSQyterDRIpvQNR8WhMKn5z-oGzOU1ZwTXhuYOV7CITDHfUuAd11hT6hbiDp1m9JfCmZZCkUdPayH57XdNKwsTm1C9m3vwdTVGmySTqvhiRGKnz5jBhnI1qQloIqRNbtUjicpCd_vpUbgPaYxQYZZZS3OjVAcMNqb3EFO2G-E6uS5EY9C8iIzMRDpc4T5PnT3WdvlqPPPWOEAIHRvlIInOyI5g_q6hR9NyJ_-pR-ebz7KUbXZnv4TxS9gSnfBeDPGLZ3TQ0YJJ_ecXWzwuT-TYRDO4WlQxssci_KayBlK6NVeCs6c4JhDiKghID6gBiy3StNDmvNKzb0jwv1vPhuJ6TLFr3NHXx4wqCKu9W8hIGx3d5KceCfubhzF0qW7GmorGWeud5WDMNn9KSBMyIrRT3YwpHzaDEyCcKaIwfZLEWSIV7io3cB1STdKHUJ_6NHTPsTA-4f7nFk5AnNl9MtVCK82si5w0v6-PU8z6Otu4JdoCGUx_ppPPnAYsuiWqQGswEJszgCRjckshMr6LZn804C2urW--JMUcMn8Zb5CCDut6HDk002hKDhprsMJKItp5raIM03u4m75gBA4b0gu_PLCbzAOQRY_gGUsxk3jL1LvLrq0mmlS8w51Ri4i6gDFJ6FviSFjhpMGPqwONX78HnFYlWajdGTbEc_0Q-l_zrhuh3iP2vxvuh1Es75g3X6AxcxTJYn7wfE4whWv_g8NCg6kW7NAM91AmUzf5SG2sEqYa-wy7JYDOIqVj7K6CiagEsKEXEyeu17VrpH5FQCqzfd3pCDECPFbwF28Y7A74VvL45GnmG0Iup5qmcZJWQ60ZYaxxq37jVRGX464-lnygem4leqHBa30_-a6lWywPCiJYSedfxZ1ekrqiAlYAKDS2VpI6fbRmgwQMf4p381iUBIbjpXO7VVneBS4CCY0H1G9TdXVhWsArMzODxw2reTo0oSHyGkXhvImEkBnPeqpJFtT7rc90Aw6BeeZMcVwiM7_1xvfZ6c6N6ldBii4kcJAuQ5qq8Ew-mriYknK1wnX0QzYReO7uu5hgb3jPC5L59MO8LysjBN0JgWRl6z0BU0bPBnClscgkHbkqDtWBToUThpymJSJe9HeH_2PfUWvAUMh-139fUoLsKW27agLYgySuP1vYdNUCxda32R5DlCe-5c_O6cZhokSng9BeFgtldHu1s_phs0w0EYdMuBGzi_n62-77_kGwwHBkwPK4q-ti-dkACMvyQQdbxFOAiQWcLmjAkFelufq_ydYlUst7OzFlJ232onjLV4xRBYvn9aiIoaxCwxFswuWHeQ_SDdOfFcEu12SuOuvH6y9t_s8Tmus_PTbzLoHCX4VOe1hytZV-WCr8M_9RuMseInz1Qb0pIbi6tXgMjLukTVmNu0KOeQrFkEtggpLhYkEE2REajUhlo7gpdWH0nRazsU-cM1WbVChDsf6BXYlaDziOi4DyQViXDWjQ9jM-xUtCaWngVcpnx0wnNd5j04G2oIF1a9T0ZH1_vsgZwvX-KmX-KBY8qcv0zUA3anBKPUeZ0n0JGN7Suj_Upl-IobJM2nv_HbI8CYFFa9SGphxxKSPNA-FMZH0n8cLG50hOWJ7GSn1DtNY3_9uZC4my3nnJ9DDFTS8xhH2-UHHqFy7sAP3GthtDJsydQnZ5lfI47S8J7XC55bWxYrphYOcDhZbn-r2gKIniyncwODrx2yX_4TXHXjxjQScRZliJ-AlmKcFnSXBbL1LPoWSwqtxaB0_f5F9U5CfnPa7kSnmqit6bNvdvzJ3HVWAaUKTkcnLeOAz17MNH9gPuoY2SpXe5siLykWxcwdzYlkCfU9-IbnC_tJqyadfWnVsvOJ6YiPxEOofy-ZFzpq7YRbz3cxLq6Zm3QzKovYPbDEdpimU_pt08HSmQyTqP8WMsoXOF3otqt_Q2nYrRCwljfY-SACU8-zCw0eU_rrV_FLuYgoiwnyFBIWtr35vHs6ZEevpjvBUg-ikkWBgLUV7WpX6V2976orH3oF4hmewllyLDOGaChCcFnOZOj9EEbYJfp6FaqQjzICr1ShXwSp5K_E-BEVax6bsmLkH_AY1B0CIlc_zN_o-sS0vjs4dlQwD7dYciayOFh3nvSwrR-IZiUrPMmnqq-4oo18k7LjNQTQmZh-OWIROBxhfjVIRb0V1MR2SS0INYgtqpycuFjKYgAIxeY_of0BlBwm-4YkuOKzA4gvGY9Cxd4rLx99tU6wR3YQ7VVGX0tLUDPqtyKnjMqxbCRO2ciToXvC6svzG1l0OZdYc-ao_8fha-MHDogUSej4o8dsvd46QZf4dy9teafEtrnJZ3TGVlTOoHjkoFYsXuhKWz6djGIAN6-XSGToaBeBNccgtlr_cCitEW_5QJ3YVjJH7IIZlNJpGC58fq3_KnoX2LnDpdWSbuU-inkNeXMkZA48RbFbvOtjiD4CwsAjKNJ84ay5Tfa-nH0DLdwyXytQk48FWlUMAHdSY7HIAlS2I8bHIcPSaMWk1HcUOrxuxc_J-M8KXmD3OKzNg_p_OeBEjCUne1oiMTiWUSwU3kSbajIu11t6W_wDWx_l0LeGmt1TfNS1cXvq1mbPWZF_0wtUMXGCNrj7040to_mic3SoWwKc6GApePZ9xlktTBRNmdPzxwz1d3Fotrh-ALRrfskXa0quDBI_TerFZs07yboGjhBXbijtXsxw3RLoCPSB6jXDEI7rwz5xoA4D_67B2kL35mM_IPCmu2lqBEJUGKucB4x1E7ru4YungoYLSZynSIFZOtuQ3ZxELtIbNy1rESycClW9D-QmqkoMzUOohvPiVyGdMTP3uChSPCRZ4xiCaSWrQEPRKYm69zBnQtbYAfBsXT0Km-OKANYEDn4KTTZL4nSdkhFKK0dxHBigKJw1YHbw5mUMe1HJ05EfTP3BlClhqDtvQj-ybuPKcJJ-bgqUbf5jg8UrOBoc1s-LsFSCEajvR3Su2xUJM6jlqcRYAFtsGL8weUvlWvrFQ7hnh6WCS099ByIk-lKkMNfbSPD9OBKGAPdXaGPKVSyytzvLgk-Fv-qLCYgIx_-olcGdDGMnNZVrlAysiGK0lAJA0Cxf3qK-5nm4FP-hQ_aVegddt11Kt2zyq5_T8O81sO-DI-Ef4TTEJPr5HfRXVff4I5Mpy5J_-Wso84AdtcCQjU3wjBE0waPP0EIvrBLvxQfG9nQywujk6dte4o2AuT4ysJDD6ff5DP3Ccq0moAKqTXwAA26z3F0qgXV1TaoPoiWXcg8bMIyDvidtXB3yjDWjpgRDkKRnruDwWYeDho0mQqfJeJf8AAjDEYCyYZNm_KFtc8G-6s71hrx8R4OPoO6qn4aCEG06bP8VB24AqoHlIyS7osmWF5SF1pl51otNHVZ-0h5gmLCq58VZJPvFnXwf3Q3ipXUvWVq2jzohlX2T6IPz4NfJjBzu_Veng9HW42sL6qF1aE26lIyG2YD5_1zLRSg0Rsm7BhOQ3ei_Kp-gyseHvVS0L5FxRmtVxMF3OavJg_Y195M0g5k_2ubVVuPzGZq6aGBmTTZedYjdgIJ8QA5Oa70VCwbsNK0ATAsi77I1R1sY15KDblFj4omlu71zzr-PlUecSK3I_VoFzI4g4SFUM3eNm-0lmEqWDKHHhjyhxYIkWGGtfCOB5MOiqEZbnLVNeEvjRaXB6A_LVwtGs-muVB85dp8Xu_-gQF-ctxp7lelY1mnr4lHHJwSL-5_Q5BUn9OScGWIsBG3XSjCOdJMmrwFp4JJs3wNRbJle8WKKb0IVQ65zqBwrUc37ek105KHeU1GiAaJeALGLgTfx62cjGkg98sWemoDGcXiL748ZQvcfbWTNDsk6o4_PLvRfqxttLdZmeiCcmuHBazv_WASwDYwjA2MHHzAOqZCiK84xtJm-SOvoCqmfngwer2e79585hjgsirj8YylH3-C5zu9N9rntDWJtUtGTy71qKV_IY_S-Wp-eEbpIXcD0LR-V1VABfrsF8CLgKnX-Q1x2BGjLywCEUNR7SSP_B8MJ00LNM0uhGF8d6I1t4CO2Njf7gxbCwSXvkXayojvHzvxIElqTBo6H6JFNrD2T7Mhb6arXY0fjmLYfSpAlY07noByxnm2f7qY0Im7oRhM9RiIGmoe0jaaIoH6IRQOc47u_uOh0JbceS2eWMkB1hO-NHy-w5Bdt5g0_wGgyqNjxNKGmpXfUn43rizTk5r3sXvK64fnA6PYXB_zLtF51z-_6kdGMNh3KqWrxldkQUop06wKJ5kjssgLaDnas6tkB6UuBFSpwp5GDWSrD_i5u2aOH-mqWtXu2FQSB_jtj8sDG2gbqDjhz1SWbzZwp-ONgPkgvmpCiUvZ8_lI9BH0JzVjPRMHmACIN3xp4zc-hkK18cTGniYSk2A91uYcgsgsMD6n5iuSzRe1G7zyIRLF3ty177fkDxGsCXYaGUExurD5cLHOtgJU7f6pK4DPcuZs9EbaoIO4vMADEy0rD50D5OxHsGXVdPJHcYZflGFOo3WdU5PbgAGbWeMyi1wsT4VnkzeD2GdQfXH6GmECLL3lyAcnXBml2myeRO-aKqk0QCpd1L054RV-fbr-CuJg9L1k1A8l9dg1t-JvhOaGZT2wBhnt0DrRKJtktXzuKyVUwTffkHlXkASAYiLk8YN6ReHThr540KkF_FZyfADIaPHZ7AaIr6vnKC4jshDYoXTZJRElHlpgLWgo-hBVCmxAYsRHOk2ihwpU8jfLFC_97ZBUZJht6PDiU_fikgiZ_BTE4sLA5ZUs8_GPCN1Tz_hE5FM2YlmyXxEzvorFgItpl8KYQ6cvJvtiXkGakxiJvEqCPHxrn7wwJW6ctPBDFC42X-dVlxueQvuo3yFXJ5w4hapUL6h_bM_KYD365FDnnf-JL2yHsw5mL9y7fydR4eViQemIsj8Iw7_vjOnz21MWsH2h-kS0_BjAd8nPLGNDM7Omi16TXK_9xP8ZysEYnf2JyZeo81tPGg6XmR6fBoKmrBWdwxbxzCR1Gai4umbzlL0vil_nSoOZ9zRl4vR8SDxDpOV7Njp7TsaBy6Cy5bmE7XhxRZKtmZ4upnESY-EcRAch2j1zKlwIhYthrJWG1InsvGa5yotxwY5bhz8VM6TGdiFxC3yn4zwoS0SYf6YlL1C65COj7NiVITkAJQlRcorzyCa-CAPmvJ5BkYV3SvlLtIp2QiKC25pPnZl4U25rWB09LOnLW5ckfcYoCFCL3-QPnwuXdsEAQ-LUDQT8TqiZpnN7-gLSnLVdNgUDoHHkJTndJZFklcMQNCNmGHlTBrz0CDjikVpXmMZZ4Ahy_d0MoUoH1vXGzs-duxFZYXwPNGXGjcYvZ-sFV3R-cNM-SlnAq_XkWA4xxEzDotdYU72u9CeBS8pt1_en1hi7H96FK638PChKZthH7wr6k1M2d-De0QerSiRtAA8egfMnUlAIGBEx40YM-1-UCont-9TiKdkUBxwydb5sBcJZChK0hoIV244-qsByvSM9lAnp8eQV4Q_FqNkTaFJVr0jz9RQE9xIXeHi7KSQkRPRTHCTBxpkiXJf-_pipMZ2r6mWpzLu8ypjycJVFNHT4SjLFN6axjF8iBzSZl5VueIxD7iOmgMT4JSPOTlK3jywOoI2JRgT4eOmWvh-El-M1zwKjvVY6SoVY87CHoSuVtcM6TfVhb9geXjULdXXXtPgzOV9wFkc4W476YY_qtomnMNtU8YU_vBANyRRvlAOoQSnDwh7qW9NvEeAS9aftmlOFfJiWCG9SaLXMP4KIJ9cl-FFLlgREcupLAPb3kqCBF92a8VH1D5f_qPlOzR6HZf6DQjznNkPMZfhbYhr0miB7lYSDn4EaDHxXUbtpfvUpFv7ZjukGP3DvpWrTaNXh2EoNpWmVGJ6ovnYzQlPVtKqcd8XuQxMOm94V9LDLQE_Navc0H2U= \ No newline at end of file diff --git a/data/openvpn-client/smedia-priv.conf.vault b/data/openvpn-client/smedia-priv.conf.vault new file mode 100644 index 0000000..e537847 --- /dev/null +++ b/data/openvpn-client/smedia-priv.conf.vault @@ -0,0 +1 @@ +encrypt$gAAAAABjfQln8FpE4uWbo-nqbkXRv72SVSeQaUKM7H38QT9TfBaXSWHbwMGJLr8wa7LS8IXTy0CiZd6VA3GUi4oWjVAw1qYnuE2Unn4tf99nYqOG1iP9BWMNtR5CKx1tDblaJy9vSvFGQGuSdjHpcRXnfynW3PHJZpHRjqTxMc5wGVNF0Nh1RNADpQ5hcJ66VBpdY1yKVbgMKdrqJqj4a1qm7dqrEemFdVJbR_O3_ZKOM-9rjma18Raje2b9DV-XdcuOs8RsnK_RWzEkBdUnv8AKeW6jV-h9-TEQS4H8A_LDdVOXwh-nF3Um_SCGip2VKo-nJqe3PT38MkBi6VWtReO2AgwE6ZSNxF4c8X8PjDMXnQF8nUhtHLYGNu6qArgT8XeBrRmxESm1bLlkMWsXElTRvtNoVZfwcuapZU2DoMslGmpkf76-ryEPRmmfPtuAgKEY9DsBSnJL1ogp1xqmVucXiePKqfEGhZ1kyTBJFGq3JyLcL8NUoLBbXOwoVLDW_3V1-yg-GolsJ8w_jKMm1f8wKmupSYICOcORuEZy7piKmZRIEYv7Xbi9VVQWd0xY8_3d6VZJKlNSZhv7Sip0maWDA17IAedPSDQmspmqcpgCcBTT1NROFfNYCT3ZiNLsA1A4pSJoER72o_72l1S_NVRc-wwwNoE7eSw77ZftriB8Hx2Ke69phAdT_auwUVP5hR8s99RsS16Gb1W6_TCMj3abwTxM7o4gqpfmlfKf8b1HOu_2NtALy4DITvTTL25c4IbuWDxb7saPR239etoI41BLsANx8Coq2OCm_iHmmeNe8eiz_n_Yu3tE_EIv05eiFxo5GIRIKqbiN-QLdaISeNNUCW01YBMPwnEW9MKqFd7w5eVzdHwdNB0jK_b6bC8G-qura2E6BMOGUfOSqm9P8ylAHvvljEK6wwDDYwt2TUwSi8YpfDThv5xlwAwj6bz8tlBdGDspIRhPth7P9p75ZZQZqDfYnliWl3c5QA4HV6JJ1534CeVpdCJCqfG3Txs43CWkFUxPA7Su1pDVnHBZig1m9Up_KxWSA_nPk2WUzoTIUfwI-e8IE-D0TlZ7Tn73fwpzVR-Bwr6j52D6BAsIx8KFw9yunf_uokDbaGed29SdoITnDthy8SzkVdu04PsaznDZ-D_Dh1uLnZM-F6PKVMh8QmwYsg81D5-fzHqRAYlyBpR4HHtksSDdaWfvYhjR8qedTa0g5X83FcQZ4DuZCnJNa6SNcFpa3DqyLc7iwMckFg2nppKeum2MoP4hQJ_h-CVvd2kgNey9EmrcOXgJs8O5wJEOI-L0oR34XrYhmnGAkjwyng_omt9hTzIGHrbVqktkgkI4ZELFde1TKGbvHVoIC_z2ig_sZZDRqZ5HgNYmAX5mesMWVY4J0Pqr0UL6dUZ_r87__r8eBVGl29uwEw9cEyzbqJh19qOyo0WrVfwr1_8jqBZvhN6Dfss5uJH1Yv7GC4j3Vrsv-fZ-sZTgRSmtid-k1bxTUhlJYYcONc9kqr8ko7EiLQwLO8m-u9AHVoRpIJou3lZ6s3O0pZj6v_P1DAuy6YF8Oa1sC5D3loePdF4V2WV5ElPCBl1GoIxjGo7afM6x4hjzIAxk6anspv7VOL55qq_StfDP7WrVq84Zxn2oUBuc7RV9DvWzTAfZx-Wo7ITwnaUQdsCQ2SVUxOJZpWAxZwPKjFCcNEo5pEmuyBU2OmlyFQo2OAwi7_zhzgMftbpFOUPlAI1MMlSFaxmIRRk3nBKvQQm3uS-bZwy_UcDaWSjZ0QqH1RUIKtrsi_2P3WRz7g2Wojz1paLVcT5GdLXK96aX9N1L2lzS_Q8CYswno5mS9VcUPKylRUMtnNE1QfdBCalg_0q0XVUZaP7Jz5-F0-hbDt0A2uev5YEr0EdZVdhMKnntSo09RB0garHyW2Isw-YqxRAIgVZ69FJ-mNANUgd8n59tsgY9puP-WYd-big5eQM3NoOip5e623rYbOfG3Mtuc-ki6-1-HfJhIEon0vBpTFozgkipEAsn1-yZHWgXTbwbErz5eNNPcdgOUu5SIyJLuwiNv6AO8kRvK8le-TNqbcMF1TAhW09o2IlMPqNxhCBlPc3YtVtj4z3KcrPirUp0m8LCCyykAh3Y3vODbg-H1AOnX5MJUyaHSXrgnRbu2-PsbjwHD9x5VgZTvJgeNYDf8vi6Rqfa8HlKwt-YfmNetMJoiZZ3lT88O1VlaAVuep_TneDixHoqMlLTuWJ_6MnqOjGGap-6tkCYArZVfTufyjrfg6CaU-iLwTWmAPnoqexABc6tfZOHqjWo89uGhVbp_VfsKVfcEIlOKP1ioFCWC01zpCe4hzOJEPWb8DOrg2ZyC4nsHAleL8Ni9CxqNT9J28tnh-7h_K6I0t9wd0eLZTCu0ZY-Atwwb0IICjJmLNN7ac19G6OvSAErw-hw1Aadj-pZtfCYvtFWpu6WzST5pMxejut3Y_4O-CjisN5uGp4zLKsbQ7NGHZUzuSl58Q3I1jc7DyN5xCRa4IDRKZIzf0gr7S9nZ64E3A4NoXo5gemSVnVHlv9luN4-ak_sM36BE05DW-U9UmHtT8Jjj2C97oOq4fgf8dpFZ9bDty0z8pbsvVwkhrDGPw-xzhfu6qlVPLApizYxkxcM6WZYgAM6EjFWeNJu0vP9iUbXCaczXfs3dphmO2NII-DuekHQMjh4sLfWQ3hniN-2yU0S8cHUUl0xRr5_BhsSqC-gbh03UgUeP1d_NSXon0EsBHbl0vOQwJ8XKSyxBRCmNiGhevChiUdhzpVJwmq665KgiL200ldW8uOEIqHA8ZdQmgcxjkuYJtIWrNNTazlNfyFHt1-9Ir-IkAnjEk-l7s3rAqQ-TpFIC7jjYF52rSZ8MTzjxHlftEtkd2ifbqBgvfIlaCn1ff_LMynP1ijq6UX5r7pOlVMIPasJMG08gt7lmLTZIbI0lJKVD9Ar7qBsQzQCD25Y8rlsKFW3YZtGL3RMnPH2BmeszQ4mpNT9MJVe5DhV8IP0YO3ulM5IGiPj9bf9rDb6um8DjG4AfylREez-eZhDvibjJNyK7B4h9FxjhtZQSybXyJxiglUp5UV8oq8XZ4pE2GzE7KJFpjDOBjA7DGFNNSSjUSdtdqHr-4DKv3tBovcGrzQkPkt6omHB_q_cZk3Xi8e0uhMtixDknL5NdHBoXO7LIus1XykUlZLmlMoE8ct0Sqyq7nVGS3966wyBLe3nCgROi210z5sOcCZYzJSrJvlONjV2ltUZ-kJJnjUrcixFaqGcB8w3wxkfFqNrTeMxVqCLpKak4wO8ZS1xF-_46me4RG5cGB-TDU4i7Am5BXX0FrVnAl2TdjRe2qrLJkIZB4HSTJAcmfsj34HOCunTsCgZcLI4y8XbPHoN3PpZMi0o0uy2HMxSE_UUS80hR_pq8gpd1FGyikV9b-UdW0AuDpxYK9MmFNOXUSAl0SXJ77wXWGxFt1kc4WgtLGawRgr8cdE9nYpQr-VKlVvg3j7ruojD7c73tVwkZAi_8F9uiXaxHfszgskAiNOQN2J9jKWwks1XfBXqD-l_4yRBGu0dHCGYI_1xE1CFTUpXsRDoM7EyeR5dXZKWuaAlEetxdlQcyClCFyskAjNCw5ET3_b3wZOaZpGItIEIy0vfdAH9gB9bzDZfjFG13K2Dx5SYVm98ZgbIQMjSXMa-IA99qOPVMpDh6TX6fmH8Q-c-h6W5BeDoO4dR5_36QlADyxEBtvjtb-XaMlbM8ha3V_KpkcT0sOP8fSm6xxkONkVsmms1oYZPcxEu_4pvkJbQNIZKWtbb0BNS5uEen6Sp37nEQN2ERcL8SqxoWVhYs6kiDeVmcycIcGUh0S5NKucw5mwoMnfP9qKK5xG6XKaQtaRgCHb0Ji_W4MmD-jNJayMksi3PD6U_gI3FcEhdZzkgv2YNNWQML4xeKz_VIkzmb8lfmQdoc792YyaWtuEVqR3z-c3L8gUu7VuA6Q6LIqhswK3SB2J9vkUuMLLUvet9vPNsvtLLNJ3kkVGMcTCDNPQGfOF9nh8_gKB7fIJYRLozk9xSP9JoqAtTQlT-lunPNc-52cBkPIo2ziaUc73ICI7eLKJSTfMhTThqvhLGQSv0Lqj87O7gGR9G5U7gxRtz7s5ghEoD-SRv5drvSudPMfKf4KFF9K3KycHdFEGWoL5cGOXetl8y3bmFiT2bjoedmBCboSdr2GZthf9RYcqJwTz54IxkoDp11bgdvo3VWAvEA6Deobsryjb4wq8G1VvlIK9ZaH7gxbKYc4wJ83nIqbO6H_W00rr5uXq9SoArYmKF6eMzI2o_geyPtibmCljDdrx3X78P-8iumHJVqv45pDEo1zkPF0XoXFr0RlIEsiZBOoMGBi9NKZvCAkD4w_cZw82sZQOQv3HkTBfUKrf1K7UsqUXHz5HNyYbmJojUR-ttTY6o3q5ysQ-trToH8KjDBNF6reRdEZh3fuxYt1gnJriCR_RRRI8vOseuJZm8WgoBNSSSyrzCUP_CyCfZrVXxpfPm0ElTalwa6DCyOyKW3MVut_vaneluUZ5Mrfc9mDy0lH3RJ3XREkAOKugqhDQaUh7ExTmPwreEQR8GX0GIxRa6g8QqGljWF8pkkDYXa9CWj2lj3Xwzuj9GYmlY5d-VzFkbWYlsP2k6NrOfzK-2D1ZN9n2TwkMlEj-zQVZtgdt0M9Jvp3tuCku5zxhRXE0JEQPm12wcpuLIJQmb9cgwyTkMMOclkSTeUsepo2xGPNAQ4dK383suQD7TcgFdllyQ1udFUuJTDCDs0rr2OLspxif74qp_x0MF-9dJJfRD6uKPWUzUKhIswzD5nY9EH040DxBnX4n_NNO1xaViNlUiD2NNOL86e3jlxNAqf7Q8DJJ7XHOPpiherB4VbudCad8ddilq3URd-oVRmxR63lVlGdvaDkKBzE13Zpqe2acErEvKfuUgO2oUdXiLBczOSvcGhcELn72jIKkBeR79klJgdNsntCdBzM_o3M-OPzkGpu3u5tIn2al8JwElB_dCdNauJbLo0yYBncXMUs9SZtqdm3Jk_bQYaAJ7Wua9ZJTB5_bT9BTZyj-GEvyAPAS5w3IkwhXE9wA5zlh-LvsK26qWnMiTc3IKCunav8DbEUoSNj_ACTD6zcUqoggiIREjoye-kTlERU09CZZWSmU29zB9gDlYaycGpexcdvdpMBpO1-unw1cdqkBO8bbeb7Jh6eBVYwWbAzKCJutEzJ7jBGNmeRVbqgtLcHrWUD2eW8e_-K-xFJG4Snt0IMIQdetRZVFAio4VR9XEqN6JQ8RjDWX1N5BrWMe5VW1wP7S9Jd_pQpOC4cGRuiIO9ATFamVvmre-CuI789pO8tMVrXQ3GGCI391CVXtQMTyXbRUkU-9r9RVfRX6R-v0TZm4Iq1IY4nDt53QbpACMg1c9KbKZnDoNJ6TCs16oJ0YnAqpCSohXq4d94UsCC61eTPBxRbK8iZ6yCulCxOI9g4-s000KTrS54_cfQ-TBd3OwrKe6aIAfO3w2ZXb-AAnxHlF5ih_0-J2fvFqfkiowa2kecozFwPzcddKRlF2gfGjD3v8LwP0VC7RW3onemwRTVpb7bXXyhKQAoJ33DhVACcU6wC8TpPZpndot8X6B5sZjhbugw2t5yIOHJJLqGNUZPKfN27K5TzeJdVS2t6CcDhhIVtE3O5eOMnUABK6xnDP5SzPbfkWP4yZqbKxbqQuOI9qlyoxZlZIYHqohmF4QgGtCc2SDhQW2qXW88Q7zo_OhUxNLRu7TldSo0qCcMou_vqU8zjhALUtASJQtFlWINGVmxJ0Qci-9OaNWeVBi9Tj9MVFAbcaYKKOxusy3ZQcjfkDueRKP-hZXBUGERj5yN7jEDEGjMKB3ykVRNfWogyX9Jy0TB98UYsb8Fm4-SxGrs8atgnfVZzVQY0vcXEuJPT9MYPZRMIST0-SNcYUlMnnqq6xaSoUwVMyy5VnI_KdilQWJ3Mv42TA23JZcK0kXtsWZY9WQX8ppwimUidvKAWLSKWAN2Po7L_LVOpOl6kI1xqXquD-zFH_XFRr4r3rmm9vYOXL932eSVFKo5S5U7ACSVq6cBXegyf3IxGESxFhb0xTinT7iIjESHh7VwpwWm74F8AtOoPODscL00S6uMevWbYtRSpbf2e8wFJSLImMlE9QKKos2o7HPhpqDLSqA9F3Qtz-ymtmCZADk37ZTwYtpNZzVqSx2iTH_GpgY43gPyollG_LXPVCfj0LKpiylIHZJ75DEqjSvePkGCPQxuqbfVR7PqZ2U1rRSUddhY_VzZvFYjai-GRZDJf1EBSgvnYZolnIcubfggsCYB6iZOgpgxZtPIW1Dz67IhV9-J6rTZMuZ2SSf6zZCxf4JyQ0eTuzu7Bw9scys64R65K1NLe_JCdADQhkW1XqrCfdUIVrxyeYV-W46-LvcGGCfeBmRNfRoPgitnsOHTcHtjd8eGXzGRyXYNKWAfzgZBl0IZS2kMsyj0hOJLoR9b7Cu56vkdAJKKQQb_hu09DQuly9BVG5MG4nxh7UPp6rpwr7b1w58cUcKfEeEeQrzoV5KB_XzycHkYgpbeluBArGkgpgnKUAL47SbyBeFcSSzURxnvnsFFH-s3o1H-BFCHQ4Ciu-vcgxQ7IEywwCRAICLhfFzhoL6N1jw9PMZF-yBaQ6O8cheAzRiP0OFHOk-ygMEuQJu8JzDy0Ux7_Y6lHQGHkmmoVOoRyEFAGsZoPmFwKEF1aNo5_xsOpz5mEyRDeiNh8TvOk9MyW7fwpmDe130YUP6kuzRlkJ7YbChu1WxQspkBn5qFsjrMBav0NfIFO5m3HN4WxuyMlG8ZiXalagGFu8kCKuzvAjf0A8NjBpv8ReOBSDfH1Pa3ABOlShbMCRoFNnuuqje_oflKQ5r1-AboBXjgyJuxa01PeKRazLSvtHR2ETBAgNZTBw8knVWRkvVkNGgVI_AZuZQpirF1iHevGzCl87RsZQoAnoqxwDdkapjXvopi1zKyBu9h3H6z1nv-vYdl6lW-tREjx4eT49spEwq3eOr4rLULTXDcMZBKKDEuFlZDzwVd2diazxMmVYJNEyzmqUs5UeufsAzJeZCGBwA4HxaaxLJu1PzCjeBPKxa7PVaU7SP8dqu8N8MkOOGP4sB6Sjn6e_yoGvx_0tcNRxNhzV7FLsX4cMHKRrXCqphR_k4bea3AqEEbvX9y63p22y1iTVzYtIEXMlzJnusC_5v5ZJxyQRneiYz0z8GIJiZvNBaLkk-zhRndiMoTTiG82bCyL2SuYR8kDFP6naXfXIzH2psP1XHCpmyKGceqBzkuW8BjaYqNM8-DK876sW-xW-zPsacFTYL0iCxHqYILfpCxia1e0JO_-RX4AjGoasftm66wmIOvb_J_lcIDJiDkh9sAH8ZfKF-_Q79Hdi5K97ysEyd7gWU6GZlKh9rdnHTiJbAM9x49EqHM7knzO1i4Jc5ey4DBdx2oLnWOeDoY_bvUyF8qCBJkCOTuBjyeEss8Pg2w8pOyyRZjFPMeatADUPM2UR1cntLHBGkselEkoVMxT_3rzq_lotxAQQERoCoGvnbf4n-nKPE1g2js6tEM6lSg88C-7j83CvwmqqfLe4jE1SwsvQ80q7YsS16c3VKnzH40E7pL_NDl9YlTbrgLDKNKFQIkx-6t0dlMeDb7bB4JiAivEUpJ1RpTdlNOpP-LgfasqI6a1OP7VrXsJEnBIm7xHiqiklJ5WA29511aIfIDrMJPW-U1imBK77jJp_7EenOac5jsgIXayHnh2zBWmzqyddccDtFEwcbyIfxkfoSxkNGjddYkI6ImI2ECRc_ukHVMEIqVH25sOxb-9Lss_aSAi7-qGgAIM7f-KJ3TyMCRMHFPm66xeRTOa8JUi5C0h57nUSG5OvK18uSODYL1BBNM-4JrJGZTVFCot23oLTUmM3M5xNxrJ8VY8JybBraFzgwZ0dJ_tEENSb9x-MZlG42cLhovSOr3vmbwkEN5dVDaK1otC0vgJglyZfXHiBocNPn3Tb1R4wbqEdvXuijUtbKNr3xBWXsKPBrInu4yHkOxNN6eFjtZBcXcIzyQucvrvcFVqjLrZBY7ni5Rrz13b7mDG90BpVF4JBdSuv_5vAw-DbCXYbaXpxo9sUah-68v0EBlILyLqJl5uKLJumCh2r_FYB6yyJrLAmk9Lz8GPhNhC9TyEBTZk2G78_LcMN5y5fJRfElTtXbnTIDjSyN6wAhqFNVoblV_6yZgzXRg1B2PUU0CSzj6aTpXT_2m3fRhKOe9x3Pvd72ZzEj2Ls4Pvn_oFMoPCVTaaNFiX5hu1mbGv67ngJE8egT1xUIJwNC987tIh8c88FnT-D-Z4lyA_PLJ75d-6MwpwNoi3qM-BGt6EUkSlQvFMGFuO2mT8QCY_E8OlKPUmUPiapwzYYj8Gmr7TOxa_H9TJhTvGjWLDc8JkhRb93zjBgwtkxi0ZM4m-EO0RYRkqiz1AtqFPRJKmRQ5C4EURB0bDu89y19YK4YPBhtcCgJ_nvpsG7Bf0IMJsQyH5bVrQSBS2bLZ-ggjjysEO8TaAK79UiBJuW6jbbOANPJVcKC9dSlGkGoft4KJCsP_MyZ28_joWbeamk5Ic4XKxx9ydHCuFPXrk2LfoOrCPyEEOU05dpdCjbBfZhU0q_Lohb4lo3zz8F5wF86V_VZCRfe00gk2DxRyM32zfbhQlf3Ikp5AphpMvqYqKdiwDsAypUJjsbUMOSkjeD6qqgHGfeOR5Mk8s2U21VgXqtHJzhaQud8aiF_8E5vMFOzbY20y5iWMeSK5owu2j5ODmC--iU1HLAX0TnfUKPa48qnYO_s4hG9UTgeOIwZKalnonBIeUPwVk1gUciy4s0-CJ7Nmh2s5s-3Hhqgf8nLaJrnekm_4Yp3iTG9c8UyPYM7JxSM01yFxQreGHBzhpj6Me9hNLqdNGWuNCI3ANnDTFdXb3skQYaFeF8RS0MPEoOfoDeY9nirniZ9bMk69fCUDcUqpKJ6RolFiD_d6raJPnr1FYPpWklmxbh_14VJ6ApJJYbKR9dGcAHGGhISPNsN4arC3RwdTGj24rrwA0zHI-U11MmFwW2fSobW0KKwcnc6-QD-nf5NRowedYCTZxWMwlXzV6Qu3szkTjs_Gn4nWqqBgiJdWAlGNQNIAVqnkDaoGDQccvQNT2mjvFdBL3oKxvTSPVF-xA3ZNBYEzF2YkiIvS8f7GBrfnli6LYecAlEsF6j0kFlUarR8kA1boNpXhbDm8x4TvUk5b4mGhn1dfz77UGmlXhs-bu-XTpY59TsjaIIBGM6CZBM7SRw5vQWEqIXAxhcRBE3sMRj2Da4WnnJVan0l_h8iF4r_XgE5PAmqYL4p_-ENS_thdtDFSnfYWuUU9_U7KCvssJC3FjkIPc-Ix0NmmEiVnyDh9s98sn_KG2k4J2vQ4BPsgkx8chlRd-eBmhyEw4wzBNUII1zis5V_jyJX727r3PEXN-iAOLkWHaVY-kpfQSfVbnb73FPAicZWyKMfnTbDRZBBerKKzZznvC3IEuQowJo2cvfxaKjTKkQyJRyG49QaAxgXl-bv31DOHQRcIvmvRROF-uJjTt0AKrEP5W3wiiznQZxQWZARSpV8MfezoRGdfjUqphJBIE5TdZMhcWW4Yl5tL34QNgqktJRCey3RrN2Q69bv8wiWrXcchotJ64n5xJ6Cawr31H-CajE= \ No newline at end of file diff --git a/data/powerdns/files/bind-zones/cybert-media.net b/data/powerdns/files/bind-zones/cybert-media.net new file mode 100644 index 0000000..9ce2544 --- /dev/null +++ b/data/powerdns/files/bind-zones/cybert-media.net @@ -0,0 +1,9 @@ +${header} + +$ORIGIN cybert-media.net. + +@ IN A 159.69.11.231 + IN AAAA 2a01:4f8:c2c:c410::1 + IN TXT "v=spf1 a ~all" + +www IN CNAME cybert-media.net. diff --git a/data/powerdns/files/bind-zones/die-brontosaurier-waren-es.org b/data/powerdns/files/bind-zones/die-brontosaurier-waren-es.org new file mode 100644 index 0000000..8633268 --- /dev/null +++ b/data/powerdns/files/bind-zones/die-brontosaurier-waren-es.org @@ -0,0 +1,9 @@ +${header} + +$ORIGIN die-brontosaurier-waren-es.org. + +; ends up on rx300.kunbox.net +@ IN A 31.47.232.106 + IN AAAA 2a00:f820:528::2 + IN MX 10 rx300.kunbox.net. + IN TXT "v=spf1 mx ~all" diff --git a/data/powerdns/files/bind-zones/emails.sexy b/data/powerdns/files/bind-zones/emails.sexy new file mode 100644 index 0000000..c430731 --- /dev/null +++ b/data/powerdns/files/bind-zones/emails.sexy @@ -0,0 +1,3 @@ +${header} + +$ORIGIN emails.sexy. diff --git a/data/powerdns/files/bind-zones/eskalation.jetzt b/data/powerdns/files/bind-zones/eskalation.jetzt new file mode 100644 index 0000000..fc09ecc --- /dev/null +++ b/data/powerdns/files/bind-zones/eskalation.jetzt @@ -0,0 +1,9 @@ +${header} + +$ORIGIN eskalation.jetzt. + + +queere IN NS ns1.athena7.eu. +queere IN NS ns2.athena7.eu. +queere IN NS ns3.athena7.eu. +queere IN NS ns4.athena7.eu. diff --git a/data/powerdns/files/bind-zones/felix-kunsmann.de b/data/powerdns/files/bind-zones/felix-kunsmann.de new file mode 100644 index 0000000..ea21366 --- /dev/null +++ b/data/powerdns/files/bind-zones/felix-kunsmann.de @@ -0,0 +1,5 @@ +${header} + +$ORIGIN felix-kunsmann.de. + +@ IN MX 10 rx300.kunbox.net. diff --git a/data/powerdns/files/bind-zones/flauschehorn.sexy b/data/powerdns/files/bind-zones/flauschehorn.sexy new file mode 100644 index 0000000..accc22e --- /dev/null +++ b/data/powerdns/files/bind-zones/flauschehorn.sexy @@ -0,0 +1,15 @@ +${header} + +$ORIGIN flauschehorn.sexy. + +@ IN A 5.189.140.103 + IN AAAA 2a02:c207:3002:8320:feed:f2c1:c0ff:ee + IN MX 10 rx300.kunbox.net. + IN TXT "v=spf1 mx ~all" + +_dmarc IN TXT "v=DMARC1; p=quarantine; rua=mailto:hostmaster@kunbox.net; ruf=mailto:postmaster@kunsmann.eu; fo=0:d:s; adkim=r; aspf=r" + +uO4aNejDvVdw8BKne3KJIqAvCQMJ0416._domainkey IN TXT ( "v=DKIM1; k=rsa; " + "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnh5Ym9PO7r+wdOIKfopvHzn3KU3qT6IlCG/gvvbmIqoeFQfRbAe3gQmcG6RcLue55cJQGhI6y2r0lm59ZeoHR40aM+VabAOlplekM7xWmoXb/9vG2OZLIqAyF4I+7GQmTN6B9keBHp9SWtDUkI0B0G9neZ5MkXJP705M0duxritqQlb4YvCZwteHiyckKcg9aE9j+GF2EEawBoVDp" + "oveoB3+wgde3lWEUjjwKFtXNXxuN354o6jgXgPNWtIEdPMLfK/o0CaCjZNlzaLTsTegY/+67hdHFqDmm8zXO9s+Xiyfq7CVq21t7wDhQ2W1agj+up6lH82FMh5rZNxJ6XB0yQIDAQAB" +) ; diff --git a/data/powerdns/files/bind-zones/franzi.business b/data/powerdns/files/bind-zones/franzi.business new file mode 100644 index 0000000..2f8e3ea --- /dev/null +++ b/data/powerdns/files/bind-zones/franzi.business @@ -0,0 +1,43 @@ +${header} + +$ORIGIN franzi.business. + +; ends up on rx300.kunbox.net +@ IN A 31.47.232.106 + IN AAAA 2a00:f820:528::2 + IN MX 10 rx300.kunbox.net. + IN TXT "v=spf1 mx a:sewfile.htz-cloud.kunbox.net ~all" + +chat IN CNAME rx300.kunbox.net. +dimension IN CNAME rx300.kunbox.net. +git IN CNAME rx300.kunbox.net. +jenkins IN CNAME rx300.kunbox.net. +matrix IN CNAME rx300.kunbox.net. +mta-sts IN CNAME rx300.kunbox.net. +netbox IN CNAME rx300.kunbox.net. +sewfile IN CNAME sewfile.htz-cloud.kunbox.net. +paste IN CNAME rx300.kunbox.net. +postfixadmin IN CNAME rx300.kunbox.net. +radicale IN CNAME rx300.kunbox.net. +rss IN CNAME rx300.kunbox.net. +status IN CNAME icinga2.ovh.kunbox.net. +tickets IN CNAME franzi-business.cname.pretix.eu. +travelynx IN CNAME rx300.kunbox.net. +unicornsden IN CNAME rx300.kunbox.net. +wiki IN CNAME rx300.kunbox.net. + +_matrix._tcp IN SRV 10 10 443 matrix + +_dmarc IN TXT "v=DMARC1; p=quarantine; rua=mailto:hostmaster@kunbox.net; ruf=mailto:postmaster@kunsmann.eu; fo=0:d:s; adkim=r; aspf=r" +_mta-sts IN TXT "v=STSv1;id=20201111;" +_smtp._tls IN TXT "v=TLSRPTv1;rua=mailto:hostmaster@kunbox.net" +_token._dnswl IN TXT "gg3mbwjx9bbuo5osvh7oz6bc881wcmc" + +2019._domainkey IN TXT ( "v=DKIM1; k=rsa; " + "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwkg6UAcu3V98hal1UVf6yB0WT1CKDS0AK83CUlSP8bUwraPxkxK1nkQOUsmjbQs6a3FhdsKprMi32GeUaTVvZg81JIybPk3jNugfNWfSjs2TXPomYu+XD2pmmbR3cZlzC5NGR2nmBFt/P/S2ihPHj35KziiBIwK1TdvOi1M2+upCjK33Icco0ByCm0gJpD2O0cbqcBcUKqd6X440" + "vYhNXH1ygp0e91P0iRnvS9sg6yD0xjD8kD6j/8GfxBY+9bpU3EvDoBgyJSbjw5b6PUVJbKMXzw1NIRNj0SXKs5BakjS8+7u62vR11IPCYRwy+yr0rDT0tNegM7gStIIgoTpOoQIDAQAB" +) ; +uO4aNejDvVdw8BKne3KJIqAvCQMJ0416._domainkey IN TXT ( "v=DKIM1; k=rsa; " + "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnh5Ym9PO7r+wdOIKfopvHzn3KU3qT6IlCG/gvvbmIqoeFQfRbAe3gQmcG6RcLue55cJQGhI6y2r0lm59ZeoHR40aM+VabAOlplekM7xWmoXb/9vG2OZLIqAyF4I+7GQmTN6B9keBHp9SWtDUkI0B0G9neZ5MkXJP705M0duxritqQlb4YvCZwteHiyckKcg9aE9j+GF2EEawBoVDp" + "oveoB3+wgde3lWEUjjwKFtXNXxuN354o6jgXgPNWtIEdPMLfK/o0CaCjZNlzaLTsTegY/+67hdHFqDmm8zXO9s+Xiyfq7CVq21t7wDhQ2W1agj+up6lH82FMh5rZNxJ6XB0yQIDAQAB" +) ; diff --git a/data/powerdns/files/bind-zones/kunbox.net b/data/powerdns/files/bind-zones/kunbox.net index bb45655..ba40c0b 100644 --- a/data/powerdns/files/bind-zones/kunbox.net +++ b/data/powerdns/files/bind-zones/kunbox.net @@ -1,49 +1,23 @@ -$TTL 60 -@ IN SOA ns-mephisto.kunbox.net. hostmaster.kunbox.net. ( - ${SERIAL} - 3600 - 600 - 86400 - 300 - ) - - -${NAMESERVERS} +${header} $ORIGIN kunbox.net. -; ends up on carlene.kunbox.net -@ IN A 193.135.9.29 - IN AAAA 2a0a:51c0:0:225::2 +; ends up on rx300.kunbox.net +@ IN A 31.47.232.106 + IN AAAA 2a00:f820:528::2 ; Needs to have a working Mail address, otherwise Telekom goes mimimi - IN MX 10 mail.franzi.business. - IN TXT "v=spf1 mx a:mail.kunsmann.info ~all" - -; delegate acme stuff to psql-managed zone -_acme-challenge IN CNAME _acme-challenge.kunbox.net.le.kunbox.net. -_acme-challenge.home IN CNAME _acme-challenge.home.kunbox.net.le.kunbox.net. - -; aurto, keep old name -aurto IN CNAME aurto.htz-cloud - -; stuff running at home -jellyfin.home IN CNAME nas.home + IN MX 10 rx300 + IN TXT "v=spf1 mx ~all" ; Mail servers -mta-sts IN CNAME carlene +mta-sts IN CNAME rx300 -; legacy Nameservers +; Nameservers ns-1 IN A 34.89.208.78 ns-2 IN A 35.187.109.249 ns-3 IN A 35.228.143.71 -; temp, while updating names -; XXX remove 2023-07-01 -ns-primary IN CNAME ns-mephisto -ns-ionos IN CNAME ns-mephisto -ns-digitalocean IN CNAME ns-ghirahim - % for record in sorted(metadata_records): ${record} % endfor @@ -53,7 +27,7 @@ ${record} ; record here to avoid creating loops. ; We're still publishing DKIM keys and have enabled TLSRPT, though. _mta-sts IN TXT "v=STSv1;id=20201111;" -_smtp._tls IN TXT "v=TLSRPTv1;rua=mailto:tlsrpt@kunbox.net" +_smtp._tls IN TXT "v=TLSRPTv1;rua=mailto:hostmaster@kunbox.net" _token._dnswl IN TXT "6akc10htbgmg56e072w0w2n0wql4oezu" 2019._domainkey IN TXT ( "v=DKIM1; k=rsa; " diff --git a/data/powerdns/files/bind-zones/kunsmann.eu b/data/powerdns/files/bind-zones/kunsmann.eu new file mode 100644 index 0000000..ed4ff73 --- /dev/null +++ b/data/powerdns/files/bind-zones/kunsmann.eu @@ -0,0 +1,31 @@ +${header} + +$ORIGIN kunsmann.eu. + +; ends up on rx300.kunbox.net +@ IN A 31.47.232.106 + IN AAAA 2a00:f820:528::2 + IN MX 10 rx300.kunbox.net. + IN TXT "v=spf1 mx ~all" + +git IN CNAME rx300.kunbox.net. +grafana IN CNAME influxdb.htz-cloud.kunbox.net. +icinga IN CNAME icinga2.ovh.kunbox.net. +influxdb IN CNAME influxdb.htz-cloud.kunbox.net. +luther-ps IN CNAME luther.htz-cloud.kunbox.net. +mta-sts IN CNAME rx300.kunbox.net. +statusmonitor.icinga IN CNAME icinga2.ovh.kunbox.net. + +_dmarc IN TXT "v=DMARC1; p=quarantine; rua=mailto:hostmaster@kunbox.net; ruf=mailto:postmaster@kunsmann.eu; fo=0:d:s; adkim=r; aspf=r" +_mta-sts IN TXT "v=STSv1;id=20201111;" +_smtp._tls IN TXT "v=TLSRPTv1;rua=mailto:hostmaster@kunbox.net" +_token._dnswl IN TXT "5mx0rv9ru8s1zz4tf4xlt48osh09czmg" + +2019._domainkey IN TXT ( "v=DKIM1; k=rsa; " + "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwkg6UAcu3V98hal1UVf6yB0WT1CKDS0AK83CUlSP8bUwraPxkxK1nkQOUsmjbQs6a3FhdsKprMi32GeUaTVvZg81JIybPk3jNugfNWfSjs2TXPomYu+XD2pmmbR3cZlzC5NGR2nmBFt/P/S2ihPHj35KziiBIwK1TdvOi1M2+upCjK33Icco0ByCm0gJpD2O0cbqcBcUKqd6X440" + "vYhNXH1ygp0e91P0iRnvS9sg6yD0xjD8kD6j/8GfxBY+9bpU3EvDoBgyJSbjw5b6PUVJbKMXzw1NIRNj0SXKs5BakjS8+7u62vR11IPCYRwy+yr0rDT0tNegM7gStIIgoTpOoQIDAQAB" +) ; +uO4aNejDvVdw8BKne3KJIqAvCQMJ0416._domainkey IN TXT ( "v=DKIM1; k=rsa; " + "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnh5Ym9PO7r+wdOIKfopvHzn3KU3qT6IlCG/gvvbmIqoeFQfRbAe3gQmcG6RcLue55cJQGhI6y2r0lm59ZeoHR40aM+VabAOlplekM7xWmoXb/9vG2OZLIqAyF4I+7GQmTN6B9keBHp9SWtDUkI0B0G9neZ5MkXJP705M0duxritqQlb4YvCZwteHiyckKcg9aE9j+GF2EEawBoVDp" + "oveoB3+wgde3lWEUjjwKFtXNXxuN354o6jgXgPNWtIEdPMLfK/o0CaCjZNlzaLTsTegY/+67hdHFqDmm8zXO9s+Xiyfq7CVq21t7wDhQ2W1agj+up6lH82FMh5rZNxJ6XB0yQIDAQAB" +) ; diff --git a/data/powerdns/files/bind-zones/trans-agenda.de b/data/powerdns/files/bind-zones/trans-agenda.de new file mode 100644 index 0000000..7da66d3 --- /dev/null +++ b/data/powerdns/files/bind-zones/trans-agenda.de @@ -0,0 +1,4 @@ +${header} + +$ORIGIN trans-agenda.de. + diff --git a/data/powerdns/files/bind-zones/trans-agenda.eu b/data/powerdns/files/bind-zones/trans-agenda.eu new file mode 100644 index 0000000..4c665ee --- /dev/null +++ b/data/powerdns/files/bind-zones/trans-agenda.eu @@ -0,0 +1,22 @@ +${header} + +$ORIGIN trans-agenda.eu. + +@ IN MX 10 rx300.kunbox.net. + IN TXT "v=spf1 a mx ~all" + +mta-sts IN CNAME rx300.kunbox.net. + +_dmarc IN TXT "v=DMARC1; p=quarantine; rua=mailto:hostmaster@kunbox.net; ruf=mailto:postmaster@kunsmann.eu; fo=0:d:s; adkim=r; aspf=r" +_mta-sts IN TXT "v=STSv1;id=20201111;" +_smtp._tls IN TXT "v=TLSRPTv1;rua=mailto:hostmaster@kunbox.net" +_token._dnswl IN TXT "5mx0rv9ru8s1zz4tf4xlt48osh09czmg" + +2019._domainkey IN TXT ( "v=DKIM1; k=rsa; " + "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwkg6UAcu3V98hal1UVf6yB0WT1CKDS0AK83CUlSP8bUwraPxkxK1nkQOUsmjbQs6a3FhdsKprMi32GeUaTVvZg81JIybPk3jNugfNWfSjs2TXPomYu+XD2pmmbR3cZlzC5NGR2nmBFt/P/S2ihPHj35KziiBIwK1TdvOi1M2+upCjK33Icco0ByCm0gJpD2O0cbqcBcUKqd6X440" + "vYhNXH1ygp0e91P0iRnvS9sg6yD0xjD8kD6j/8GfxBY+9bpU3EvDoBgyJSbjw5b6PUVJbKMXzw1NIRNj0SXKs5BakjS8+7u62vR11IPCYRwy+yr0rDT0tNegM7gStIIgoTpOoQIDAQAB" +) ; +uO4aNejDvVdw8BKne3KJIqAvCQMJ0416._domainkey IN TXT ( "v=DKIM1; k=rsa; " + "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnh5Ym9PO7r+wdOIKfopvHzn3KU3qT6IlCG/gvvbmIqoeFQfRbAe3gQmcG6RcLue55cJQGhI6y2r0lm59ZeoHR40aM+VabAOlplekM7xWmoXb/9vG2OZLIqAyF4I+7GQmTN6B9keBHp9SWtDUkI0B0G9neZ5MkXJP705M0duxritqQlb4YvCZwteHiyckKcg9aE9j+GF2EEawBoVDp" + "oveoB3+wgde3lWEUjjwKFtXNXxuN354o6jgXgPNWtIEdPMLfK/o0CaCjZNlzaLTsTegY/+67hdHFqDmm8zXO9s+Xiyfq7CVq21t7wDhQ2W1agj+up6lH82FMh5rZNxJ6XB0yQIDAQAB" +) ; diff --git a/data/powerdns/files/bind-zones/warnochwas.de b/data/powerdns/files/bind-zones/warnochwas.de new file mode 100644 index 0000000..2ff9e1f --- /dev/null +++ b/data/powerdns/files/bind-zones/warnochwas.de @@ -0,0 +1,3 @@ +${header} + +$ORIGIN warnochwas.de. diff --git a/data/proftpd/files/home.paperless.conf b/data/proftpd/files/home.paperless.conf deleted file mode 100644 index 49a9c5b..0000000 --- a/data/proftpd/files/home.paperless.conf +++ /dev/null @@ -1,67 +0,0 @@ -Include /etc/proftpd/modules.conf - -UseIPv6 on - - IdentLookups off - - -ServerName "home.paperless" -ServerType standalone -DeferWelcome off - -DefaultServer on - -DisplayLogin welcome.msg -DisplayChdir .message true - -DenyFilter \*.*/ - -RequireValidShell off - -Port 21 - -PassivePorts 49152 50192 - -MaxInstances 30 - -User proftpd -Group nogroup - -Umask 022 022 - -TransferLog /var/log/proftpd/xferlog -SystemLog /var/log/proftpd/proftpd.log - - - QuotaEngine off - - - - Ratios off - - - - DelayEngine on - - - - ControlsEngine off - ControlsMaxClients 2 - ControlsLog /var/log/proftpd/controls.log - ControlsInterval 5 - ControlsSocket /var/run/proftpd/proftpd.sock - - - - AdminControlsEngine off - - - - User nobody - Group nogroup - UserAlias anonymous ftp - - - AllowAll - - diff --git a/data/ssl/_.franzi.business.crt.pem b/data/ssl/_.franzi.business.crt.pem new file mode 100644 index 0000000..50d05c7 --- /dev/null +++ b/data/ssl/_.franzi.business.crt.pem @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEiTCCA3GgAwIBAgISBEiaFE6qZ3+AhUkmqKta5OSuMA0GCSqGSIb3DQEBCwUA +MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD +EwJSMzAeFw0yMjExMDYwNjA3MTZaFw0yMzAyMDQwNjA3MTVaMBoxGDAWBgNVBAMT +D2ZyYW56aS5idXNpbmVzczB2MBAGByqGSM49AgEGBSuBBAAiA2IABFdgHf2P15+0 +as3iN/M7itWsdWCtH35cGIf871AeU5OhB4JDNbb5aDsho9ga/vIsjpB1Xh3EhNvP +I3b8KT9JUUE/dIRaWvNp8OSKihiU72mXIIlmslVW2AeqwBGMU0L+46OCAl0wggJZ +MA4GA1UdDwEB/wQEAwIHgDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw +DAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUsY9YAWIXWlFiQi/JImI6LFxrc6gwHwYD +VR0jBBgwFoAUFC6zF7dYVsuuUAlA5h+vnYsUwsYwVQYIKwYBBQUHAQEESTBHMCEG +CCsGAQUFBzABhhVodHRwOi8vcjMuby5sZW5jci5vcmcwIgYIKwYBBQUHMAKGFmh0 +dHA6Ly9yMy5pLmxlbmNyLm9yZy8wLQYDVR0RBCYwJIIRKi5mcmFuemkuYnVzaW5l +c3OCD2ZyYW56aS5idXNpbmVzczBMBgNVHSAERTBDMAgGBmeBDAECATA3BgsrBgEE +AYLfEwEBATAoMCYGCCsGAQUFBwIBFhpodHRwOi8vY3BzLmxldHNlbmNyeXB0Lm9y +ZzCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB2ALc++yTfnE26dfI5xbpY9Gxd/ELP +ep81xJ4dCYEl7bSZAAABhEvD10MAAAQDAEcwRQIhAM2BBzR9UWZNuK3+nk6AdaJL +1j8OvFPZnb+CJqdYtBe8AiAJM4kwOyZLzK/ZGXzwBJLjRTXs2hJZ4qXUzszhv/hs ++QB2AHoyjFTYty22IOo44FIe6YQWcDIThU070ivBOlejUutSAAABhEvD2UYAAAQD +AEcwRQIgfMXcWDFe5IKe6n4D9t3zpecF7wCIje8pBd4WQ3OfxM4CIQDpGTCU2pUI +Hfwkq+6a2j6Lh3baERBbrfnGDF2AOjjelzANBgkqhkiG9w0BAQsFAAOCAQEAMGiD +9uo+WVO+p/HFA+bHM/1ZaTDBONP72YHPx0tdFvQAPQ59n8n6KsE2w9cioNHiRYVv +WhoHjWXtzsCiJzNvc4wuTCxJkBtfSAvsOGqGMQJ+cQym+aSBKqSKvKsIQQjOmz/p +sere5gqTkhuCfnbF8AL7JqDFld4knlbzzsdhj0SjcAO4OUA8SdHdGq192hVRB+nL +IFb6Ax4jD/fQ19j+uL+F1MgMmwUkVF77X279FGlax9PGpmQ47aLj5w7qDpZxfHf9 +Z2nq14Bk6USZcz9hR+gq38lvo6aU/0MvPey9QiIzLg78K0gEQ1o3qoUIl+9erSLR +ssU+fmyZoeNBV6q8xw== +-----END CERTIFICATE----- diff --git a/data/ssl/_.franzi.business.crt_intermediate.pem b/data/ssl/_.franzi.business.crt_intermediate.pem new file mode 100644 index 0000000..efd07a1 --- /dev/null +++ b/data/ssl/_.franzi.business.crt_intermediate.pem @@ -0,0 +1,63 @@ + +-----BEGIN CERTIFICATE----- +MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw +WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg +RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP +R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx +sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm +NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg +Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG +/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB +Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA +FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw +AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw +Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB +gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W +PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl +ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz +CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm +lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4 +avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2 +yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O +yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids +hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+ +HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv +MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX +nLRbwHOoq7hHwg== +-----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +MIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XC +ov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpL +wYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+D +LtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK +4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5 +bHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5y +sR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZ +Xmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4 +FQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBc +SLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2ql +PRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TND +TwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw +SwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1 +c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx ++tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEB +ATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQu +b3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0LmNvbS9E +U1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFHm0WeZ7tuXkAXOACIjIGlj26Ztu +MA0GCSqGSIb3DQEBCwUAA4IBAQAKcwBslm7/DlLQrt2M51oGrS+o44+/yQoDFVDC +5WxCu2+b9LRPwkSICHXM6webFGJueN7sJ7o5XPWioW5WlHAQU7G75K/QosMrAdSW +9MUgNTP52GE24HGNtLi1qoJFlcDyqSMo59ahy2cI2qBDLKobkx/J3vWraV0T9VuG +WCLKTVXkcGdtwlfFRjlBz4pYg1htmf5X6DYO8A4jqv2Il9DjXA6USbW1FzXSLr9O +he8Y4IWS6wY7bCkjCWDcRQJMEhg76fsO3txE+FiYruq9RUWhiF1myv4Q6W+CyBFC +Dfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5 +-----END CERTIFICATE----- diff --git a/data/ssl/_.franzi.business.key.pem.vault b/data/ssl/_.franzi.business.key.pem.vault new file mode 100644 index 0000000..60ada7b --- /dev/null +++ b/data/ssl/_.franzi.business.key.pem.vault @@ -0,0 +1 @@ +encrypt$gAAAAABjZ10m0BnUbl5777KN6VHf6uAdtcs15-osbqRoQq6epRuWllD-ziy_2N7BrOkRcmfSJaB8zZ1l1bLD6ws3SlI7jvbkahvWnuKinkGiE30SGGjqr6MY_NJGawdox8OJWrsWLFYJJjrePl_mmVtx9G41oBreKizj1YPswzbzsFociJ0zF0xlx99sjjLxRB5PEaI3fwK1eXDmODGZ__dwKxINGSB2zxPb10Vwtnsp3cmaUiKh1TfIghQAm523cAuHPys1-tNXuJpvhPY3tIxB5gHZYiBXMzcS64mD1KqEubsnplxQlK-N_mJ7Q6n0xReG00pqvm5twRI5g7PoHYLH7nZI7KYOSI2XMAS7gP6Uy-H60BQKAHXuX4yutznVRJspv0wa4kfW9vcBfFECBhFeC8tAAkgAc-NvAsDYk6tYSi2k3N2zXsiyHy0NL-JMnUEicQT3YZNnfkoYqjuxwFbQvgtZZun38w== \ No newline at end of file diff --git a/data/ssl/_.home.kunbox.net.crt.pem b/data/ssl/_.home.kunbox.net.crt.pem index 4fb984a..317b57b 100644 --- a/data/ssl/_.home.kunbox.net.crt.pem +++ b/data/ssl/_.home.kunbox.net.crt.pem @@ -1,22 +1,27 @@ -----BEGIN CERTIFICATE----- -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 +sc1/2y3z9deYm4qHw/w= -----END CERTIFICATE----- diff --git a/data/ssl/_.home.kunbox.net.crt_intermediate.pem b/data/ssl/_.home.kunbox.net.crt_intermediate.pem index 59039ae..efd07a1 100644 --- a/data/ssl/_.home.kunbox.net.crt_intermediate.pem +++ b/data/ssl/_.home.kunbox.net.crt_intermediate.pem @@ -1,27 +1,63 @@ -----BEGIN CERTIFICATE----- -MIIEVzCCAj+gAwIBAgIRAIOPbGPOsTmMYgZigxXJ/d4wDQYJKoZIhvcNAQELBQAw +MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjQwMzEzMDAwMDAw -WhcNMjcwMzEyMjM1OTU5WjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg -RW5jcnlwdDELMAkGA1UEAxMCRTUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNCzqK -a2GOtu/cX1jnxkJFVKtj9mZhSAouWXW0gQI3ULc/FnncmOyhKJdyIBwsz9V8UiBO -VHhbhBRrwJCuhezAUUE8Wod/Bk3U/mDR+mwt4X2VEIiiCFQPmRpM5uoKrNijgfgw -gfUwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD -ATASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSfK1/PPCFPnQS37SssxMZw -i9LXDTAfBgNVHSMEGDAWgBR5tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcB -AQQmMCQwIgYIKwYBBQUHMAKGFmh0dHA6Ly94MS5pLmxlbmNyLm9yZy8wEwYDVR0g -BAwwCjAIBgZngQwBAgEwJwYDVR0fBCAwHjAcoBqgGIYWaHR0cDovL3gxLmMubGVu -Y3Iub3JnLzANBgkqhkiG9w0BAQsFAAOCAgEAH3KdNEVCQdqk0LKyuNImTKdRJY1C -2uw2SJajuhqkyGPY8C+zzsufZ+mgnhnq1A2KVQOSykOEnUbx1cy637rBAihx97r+ -bcwbZM6sTDIaEriR/PLk6LKs9Be0uoVxgOKDcpG9svD33J+G9Lcfv1K9luDmSTgG -6XNFIN5vfI5gs/lMPyojEMdIzK9blcl2/1vKxO8WGCcjvsQ1nJ/Pwt8LQZBfOFyV -XP8ubAp/au3dc4EKWG9MO5zcx1qT9+NXRGdVWxGvmBFRAajciMfXME1ZuGmk3/GO -koAM7ZkjZmleyokP1LGzmfJcUd9s7eeu1/9/eg5XlXd/55GtYjAM+C4DG5i7eaNq -cm2F+yxYIPt6cbbtYVNJCGfHWqHEQ4FYStUyFnv8sjyqU8ypgZaNJ9aVcWSICLOI -E1/Qv/7oKsnZCWJ926wU6RqG1OYPGOi1zuABhLw61cuPVDT28nQS/e6z95cJXq0e -K1BcaJ6fJZsmbjRgD5p3mvEf5vdQM7MCEvU0tHbsx2I5mHHJoABHb8KVBgWp/lcX -GWiWaeOyB7RP+OfDtvi2OsapxXiV7vNVs7fMlrRjY1joKaqmmycnBvAq14AEbtyL -sVfOS66B8apkeFX2NY4XPEYV4ZSCe8VHPrdrERk2wILG3T/EGmSIkCYVUMSnjmJd -VQD9F6Na/+zmXCc= +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw +WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg +RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP +R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx +sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm +NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg +Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG +/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB +Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA +FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw +AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw +Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB +gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W +PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl +ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz +CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm +lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4 +avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2 +yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O +yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids +hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+ +HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv +MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX +nLRbwHOoq7hHwg== +-----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +MIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XC +ov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpL +wYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+D +LtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK +4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5 +bHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5y +sR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZ +Xmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4 +FQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBc +SLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2ql +PRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TND +TwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw +SwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1 +c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx ++tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEB +ATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQu +b3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0LmNvbS9E +U1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFHm0WeZ7tuXkAXOACIjIGlj26Ztu +MA0GCSqGSIb3DQEBCwUAA4IBAQAKcwBslm7/DlLQrt2M51oGrS+o44+/yQoDFVDC +5WxCu2+b9LRPwkSICHXM6webFGJueN7sJ7o5XPWioW5WlHAQU7G75K/QosMrAdSW +9MUgNTP52GE24HGNtLi1qoJFlcDyqSMo59ahy2cI2qBDLKobkx/J3vWraV0T9VuG +WCLKTVXkcGdtwlfFRjlBz4pYg1htmf5X6DYO8A4jqv2Il9DjXA6USbW1FzXSLr9O +he8Y4IWS6wY7bCkjCWDcRQJMEhg76fsO3txE+FiYruq9RUWhiF1myv4Q6W+CyBFC +Dfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5 -----END CERTIFICATE----- diff --git a/data/ssl/_.home.kunbox.net.key.pem.vault b/data/ssl/_.home.kunbox.net.key.pem.vault index e17988a..6dd0aa4 100644 --- a/data/ssl/_.home.kunbox.net.key.pem.vault +++ b/data/ssl/_.home.kunbox.net.key.pem.vault @@ -1 +1 @@ -encrypt$gAAAAABnuvHlF1U1dT-xIICT5GmDxxqm0hQAgshQSA46WrVoo18ypjyxQE1qRzPNdp0xHKPYwpGmAoT7ftX7U3X3sjIvH8W5DUNMEBPZk6Z2yPxsyMDqUbxqJUOkjsSjVf1GZ_n3R5kZfb-THJMjNQMy3tL5RwrSvZjsYeYT-NwBle5rUKZpgE_6sDr5jSr8xpNx87gJr1vqgnZIBPllU47CJQy7LHEsVcCvbKhpVoau02LlPAoApVt_iYYm1fL_E6jFGfnCwGoeiytMc2fl1DPWS8q8oauQ1pNVTWQ2BXnLiXoc8u3hgp93PpT2LubYgIrVXpY8iErNtghuXi_HmqL37btdN5h-p1Div-R_5uva1maXffduwutCd5xWJK__G_bhqiSoEaKEMvo_H47vqbi7Hvwi70ckYek9KD_bIb2W8zBEPl1Q2436Uz54B0muXv6X7OoZlTj51_gZUcT3cp8SDJqAWDpnWg== \ No newline at end of file +encrypt$gAAAAABjZ10mtywN2Tx7b0-sZywDVcNo5gQbnzjwlMjQPktMwmRBwGMbQVcwuGhhopu5vd4Ztw8aGO5lf-SQmLWgdpR4aIrPNx1Iu4urF2LMV-BMLSgmF85ADQzlbiBvrzGAnIoVUjwXYyGj1Wst4feWMKBDc_kThinYhSplMZ_yjEbMj0eMGRzjSclkvAm24KWi7l_LQAklRELuQQyopHDo47AxehNI-nvLfO0FfXZJpkdrMV1V8lSqyXwBSW3McJKH8bbmVEX8qq-mNntBNpe3n5V2ninj72aC0D572hfMp-jKC6xccf-CqnmX1qaWGGj1yiFDdBxfOSU-kO6204BVtfspMtkI75YAYE_7aA-GUiHfXaNHvDhf2uMb8ssbJUdvGS_oLx1qnKiyeyJ6RRhl71xxXjNEo0hPYYY1BGj6hjq30R8aGknkQNCjyCD87Sc7qh95KpMmY4d82xI70xeS4mk8hEgCow== \ No newline at end of file diff --git a/data/ssl/_.home.sophies-kitchen.eu.crt.pem b/data/ssl/_.home.sophies-kitchen.eu.crt.pem deleted file mode 100644 index bc6c33e..0000000 --- a/data/ssl/_.home.sophies-kitchen.eu.crt.pem +++ /dev/null @@ -1,24 +0,0 @@ ------BEGIN CERTIFICATE----- -MIID9jCCA3ygAwIBAgISBaRtAN5dI7hI3l+MeuwXGm48MAoGCCqGSM49BAMDMDIx -CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQDEwJF -NTAeFw0yNTAzMTkxNzI1NTVaFw0yNTA2MTcxNzI1NTRaMCIxIDAeBgNVBAMTF2hv -bWUuc29waGllcy1raXRjaGVuLmV1MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEMpwz -KfaRqcoUak1UJzHRmcy1Zz/9KmlEoja94JwEO7qqARCOJedwJ/MS8Zkz3ZkJvjv5 -iIXe9u6qbn/C8RS+/UqunvnCxTJeWMcXaI2p9M+DE7PlPQiIP1t/SPQ2QsIso4IC -YzCCAl8wDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEF -BQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBSspYDX4yydAiYu+8XZw/Vu7IrW -xDAfBgNVHSMEGDAWgBSfK1/PPCFPnQS37SssxMZwi9LXDTBVBggrBgEFBQcBAQRJ -MEcwIQYIKwYBBQUHMAGGFWh0dHA6Ly9lNS5vLmxlbmNyLm9yZzAiBggrBgEFBQcw -AoYWaHR0cDovL2U1LmkubGVuY3Iub3JnLzA9BgNVHREENjA0ghkqLmhvbWUuc29w -aGllcy1raXRjaGVuLmV1ghdob21lLnNvcGhpZXMta2l0Y2hlbi5ldTATBgNVHSAE -DDAKMAgGBmeBDAECATAtBgNVHR8EJjAkMCKgIKAehhxodHRwOi8vZTUuYy5sZW5j -ci5vcmcvNjEuY3JsMIIBBAYKKwYBBAHWeQIEAgSB9QSB8gDwAHcATnWjJ1yaEMM4 -W2zU3z9S6x3w4I4bjWnAsfpksWKaOd8AAAGVr6ZJYgAABAMASDBGAiEA2TRwcna6 -vp3yZSUfXjd14SFvTZtXucSMJQQERKgwDekCIQCEppv+qukiFo4SjQBMQ50ptVXC -LMJZVy4A6VuMCmj3VQB1AOCSs/wMHcjnaDYf3mG5lk0KUngZinLWcsSwTaVtb1QE -AAABla+mSgEAAAQDAEYwRAIgXjJYEE32AFXfqx43ZOQrgP5cGdK5znOGCSxmjcMg -S/UCIBZNBTNVtJWGYKJQgS+bx7EbDDWobar7shNd1/jK0Kt3MAoGCCqGSM49BAMD -A2gAMGUCMQCoQeeM5wcNWCgtjoWPqduuEP/W0M4UrBydd2tVAAE7dbYb2Batj2Gg -qnaDMK2j/+ACMCNtwr4CWsgMAsK8HlDVM0UBvzEFOy2X+hkGzqOe0kfN+abHP0Sf -L0aZkl5gt8NcKg== ------END CERTIFICATE----- diff --git a/data/ssl/_.home.sophies-kitchen.eu.crt_intermediate.pem b/data/ssl/_.home.sophies-kitchen.eu.crt_intermediate.pem deleted file mode 100644 index 59039ae..0000000 --- a/data/ssl/_.home.sophies-kitchen.eu.crt_intermediate.pem +++ /dev/null @@ -1,27 +0,0 @@ - ------BEGIN CERTIFICATE----- -MIIEVzCCAj+gAwIBAgIRAIOPbGPOsTmMYgZigxXJ/d4wDQYJKoZIhvcNAQELBQAw -TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjQwMzEzMDAwMDAw -WhcNMjcwMzEyMjM1OTU5WjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg -RW5jcnlwdDELMAkGA1UEAxMCRTUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNCzqK -a2GOtu/cX1jnxkJFVKtj9mZhSAouWXW0gQI3ULc/FnncmOyhKJdyIBwsz9V8UiBO -VHhbhBRrwJCuhezAUUE8Wod/Bk3U/mDR+mwt4X2VEIiiCFQPmRpM5uoKrNijgfgw -gfUwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD -ATASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSfK1/PPCFPnQS37SssxMZw -i9LXDTAfBgNVHSMEGDAWgBR5tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcB -AQQmMCQwIgYIKwYBBQUHMAKGFmh0dHA6Ly94MS5pLmxlbmNyLm9yZy8wEwYDVR0g -BAwwCjAIBgZngQwBAgEwJwYDVR0fBCAwHjAcoBqgGIYWaHR0cDovL3gxLmMubGVu -Y3Iub3JnLzANBgkqhkiG9w0BAQsFAAOCAgEAH3KdNEVCQdqk0LKyuNImTKdRJY1C -2uw2SJajuhqkyGPY8C+zzsufZ+mgnhnq1A2KVQOSykOEnUbx1cy637rBAihx97r+ -bcwbZM6sTDIaEriR/PLk6LKs9Be0uoVxgOKDcpG9svD33J+G9Lcfv1K9luDmSTgG -6XNFIN5vfI5gs/lMPyojEMdIzK9blcl2/1vKxO8WGCcjvsQ1nJ/Pwt8LQZBfOFyV -XP8ubAp/au3dc4EKWG9MO5zcx1qT9+NXRGdVWxGvmBFRAajciMfXME1ZuGmk3/GO -koAM7ZkjZmleyokP1LGzmfJcUd9s7eeu1/9/eg5XlXd/55GtYjAM+C4DG5i7eaNq -cm2F+yxYIPt6cbbtYVNJCGfHWqHEQ4FYStUyFnv8sjyqU8ypgZaNJ9aVcWSICLOI -E1/Qv/7oKsnZCWJ926wU6RqG1OYPGOi1zuABhLw61cuPVDT28nQS/e6z95cJXq0e -K1BcaJ6fJZsmbjRgD5p3mvEf5vdQM7MCEvU0tHbsx2I5mHHJoABHb8KVBgWp/lcX -GWiWaeOyB7RP+OfDtvi2OsapxXiV7vNVs7fMlrRjY1joKaqmmycnBvAq14AEbtyL -sVfOS66B8apkeFX2NY4XPEYV4ZSCe8VHPrdrERk2wILG3T/EGmSIkCYVUMSnjmJd -VQD9F6Na/+zmXCc= ------END CERTIFICATE----- diff --git a/data/ssl/_.home.sophies-kitchen.eu.key.pem.vault b/data/ssl/_.home.sophies-kitchen.eu.key.pem.vault deleted file mode 100644 index 8f76986..0000000 --- a/data/ssl/_.home.sophies-kitchen.eu.key.pem.vault +++ /dev/null @@ -1 +0,0 @@ -encrypt$gAAAAABn2wvcFmCiy7gpvvwJzRVNJSSxLvlld2ob9O2ivyekdR6y1_k90Q1xZhs7-ombGAIyez1D7lvuNhYQrnff5TqRa9wKbIVyqOOj4lc5qS2jJWyMl9BCr7Fu0mdW0_33Ke5nGpc3mAMjwTLCn8aw-I_I0kALuhKvZ_H31Oy0Mdjw9rau8TmeWGmJDiPMyHlg_C6s2Gvj2VKHVuGeSVg01frjlTveK-ZsJNGvKm7njCqvqGJytFeV6iHzWYyzMTk8-z_xtv-PKH82ME_IdGVv8YcgmCrXWzzA35A3YEaac7uKui1RFzqN6K5sYL1hsxU9rAyidNRd1fp0CRlpyJWgcf_ykoe2u3ManhFOdMmJdx_nrt2znNLaiQqcSHWuws7pGeSZtX72rGa5ZEBF5xeTruhRSQyjMUuBZrqi75QKyYnpmNSpgh0fDHqHUVmSQ5vInd8Tai2BWz3oqKhrkqJMIXlKQn35Jw== \ No newline at end of file diff --git a/data/travelynx/files/imprint/carlene b/data/travelynx/files/imprint/rx300 similarity index 100% rename from data/travelynx/files/imprint/carlene rename to data/travelynx/files/imprint/rx300 diff --git a/data/users/files/tmux/sophie.conf b/data/users/files/tmux/sophie.conf index 80598f6..d8c2819 100644 --- a/data/users/files/tmux/sophie.conf +++ b/data/users/files/tmux/sophie.conf @@ -1,4 +1,39 @@ -### keybindings +# https://github.com/seebi/tmux-colors-solarized/blob/master/tmuxcolors-256.conf +set-option -g status-style bg=colour235,fg=colour136 + +# set window split +bind-key v split-window -h +bind-key b split-window + +# default window title colors +set-window-option -g window-status-style fg=colour39,bg=default,dim + +# active window title colors +set-window-option -g window-status-current-style fg=colour235,bg=colour113,bright + +# pane border +set-option -g pane-border-style fg=colour235 #base02 +set-option -g pane-active-border-style fg=colour240 #base01 + +# message text +set-option -g message-style bg=colour235 #base02 +set-option -g message-style fg=colour166 #orange + +# pane number display +set-option -g display-panes-active-colour colour33 #blue +set-option -g display-panes-colour colour166 #orange +# clock +set-window-option -g clock-mode-colour green #green + + +set -g status-interval 1 +set -g status-justify left # center align window list +set -g status-left-length 14 +set -g status-right-length 140 +#set -g status-left '#[default]〘 ' +set -g status-left '#[fg=green,bright]#(uname -r | cut -c 1-8)#[default]〘' +set -g status-right "〙#[fg=red,bg=default]⇑#(uptime -p |sed 's/\ week/w/; s/\ days/d/; s/\ day/d/; s/\ hours/h/; s/\ minutes/m/; s/\ minute/m/; s/,//g; s/up//') #[fg=green,bg=default]⎋ #(cat /proc/loadavg | awk '{print $1,$2,$3}') #[fg=blue] %Y-%m-%d #[fg=white,bg=default] %H:%M #[fg=green] #H" + # C-b is not acceptable -- Vim uses it set-option -g prefix C-a bind-key C-a last-window @@ -24,7 +59,17 @@ set -g visual-activity on # Vi copypaste mode set-window-option -g mode-keys vi +#bind-key -t vi-copy 'v' begin-selection +#bind-key -t vi-copy 'y' copy-selection +#/home/sophie/.tmux.conf:68: usage: bind-key [-cnr] [-T key-table] key command [arguments] [0/0] + + +# hjkl pane traversal +bind h select-pane -L +bind j select-pane -D +bind k select-pane -U +bind l select-pane -R # set to main-horizontal, 60% height for main pane bind m set-window-option main-pane-height 60\; select-layout main-horizontal @@ -34,51 +79,28 @@ bind-key C command-prompt -p "Name of new window: " "new-window -n '%%'" # reload config bind r source-file ~/.tmux.conf \; display-message "Config reloaded..." -# set window split -bind-key v split-window -h -bind-key b split-window - # auto window rename set-window-option -g automatic-rename -set -g status-interval 2 +# color +set -g default-terminal "tmux-256color" -#################################### -# new theme +# status bar +#set-option -g status-utf8 on -set-window-option -g status-style bg=colour236,fg=white -# left -set-window-option -g status-left "#[bg=colour240,fg=white] #S #[fg=colour236,reverse]" -set-window-option -g status-left-length 40 -# right -set-window-option -g status-right "#[fg=black,bg=colour208]#(uptime -p |sed 's/\ week/w/; s/\ day/d/; s/\ hour/h/; s/\ minute/m/; s/s//g; s/,//g; s/up//') #[bg=colour236,fg=white] #(cat /proc/loadavg | awk '{print $1,$2,$3}') #[fg=colour252]#[fg=black,bg=colour252,nobold] %Y-%m-%d #[bold]%H:%M #[fg=colour231,bg=colour240] #H " -set-window-option -g status-right-length 80 -# Status bar window currently active -set-window-option -g window-status-current-format "#[fg=colour236]#[default,bold] #I #[fg=colour123,reverse]#[default]#[bg=colour123] #W #[fg=colour236,reverse]" -# colour33 is green -set-window-option -g window-status-current-style none,bg=colour33,fg=black -# Status bar window in background (not active) -set-window-option -g window-status-format "#[fg=colour236,nounderscore]#[default,bold,nounderscore] #I #[fg=colour240,reverse]#[default]#[bg=colour240]#[nounderscore] #[default]#[fg=colour231,bg=colour240]#W#[nounderscore] #[fg=colour236,reverse]" +# https://github.com/edkolev/dots/blob/master/tmux.conf +# Updates for tmux 1.9's current pane splitting paths. -# Black on green -set-window-option -g window-status-style none,bg=colour76,fg=black +# from powerline +run-shell "tmux set-environment -g TMUX_VERSION_MAJOR $(tmux -V | cut -d' ' -f2 | cut -d'.' -f1 | sed 's/[^0-9]*//g')" +run-shell "tmux set-environment -g TMUX_VERSION_MINOR $(tmux -V | cut -d' ' -f2 | cut -d'.' -f2 | sed 's/[^0-9]*//g')" -# -# Status bar window last active (Tmux 1.8+) -# +# rm mouse mode fail +if-shell '\( #{$TMUX_VERSION_MAJOR} -eq 2 -a #{$TMUX_VERSION_MINOR} -ge 1\) -o #{$TMUX_VERSION_MAJOR} -gt 2' 'set -g mouse off' +if-shell '\( #{$TMUX_VERSION_MAJOR} -eq 2 -a #{$TMUX_VERSION_MINOR} -lt 1\) -o #{$TMUX_VERSION_MAJOR} -le 1' 'set -g mode-mouse off' -set-window-option -g window-status-last-style none,bg=cyan,fg=black - -# -# Status bar window with activity/silence (monitor-activity, monitor-silence) -# - -# colour127 is pink -set-window-option -g window-status-activity-style bold,bg=colour127,fg=black - -# -# Status bar window with bell triggered -# - -# red is urgent -set-window-option -g window-status-bell-style bold,bg=red,fg=black +# fix pane_current_path on new window and splits +if-shell "#{$TMUX_VERSION_MAJOR} -gt 1 -o \( #{$TMUX_VERSION_MAJOR} -eq 1 -a #{$TMUX_VERSION_MINOR} -ge 8 \)" 'unbind c; bind c new-window -c "#{pane_current_path}"' +if-shell "#{$TMUX_VERSION_MAJOR} -gt 1 -o \( #{$TMUX_VERSION_MAJOR} -eq 1 -a #{$TMUX_VERSION_MINOR} -ge 8 \)" "unbind '\"'; bind '\"' split-window -v -c '#{pane_current_path}'" +if-shell "#{$TMUX_VERSION_MAJOR} -gt 1 -o \( #{$TMUX_VERSION_MAJOR} -eq 1 -a #{$TMUX_VERSION_MINOR} -ge 8 \)" 'unbind v; bind v split-window -h -c "#{pane_current_path}"' +if-shell "#{$TMUX_VERSION_MAJOR} -gt 1 -o \( #{$TMUX_VERSION_MAJOR} -eq 1 -a #{$TMUX_VERSION_MINOR} -ge 8 \)" 'unbind %; bind % split-window -h -c "#{pane_current_path}"' diff --git a/groups.py b/groups.py index b5acfd9..d99ced7 100644 --- a/groups.py +++ b/groups.py @@ -3,6 +3,7 @@ from pathlib import Path from bundlewrap.utils import error_context +groups = {} for group in Path(join(repo_path, "groups")).rglob("*.py"): with error_context(filename=str(group)): with open(group, 'r') as f: diff --git a/groups/features.py b/groups/features.py index 04dc7d0..4605270 100644 --- a/groups/features.py +++ b/groups/features.py @@ -11,28 +11,13 @@ groups['dns'] = { 'powerdns', }, 'metadata': { - 'apt': { - 'unattended-upgrades': { - 'spread_in_group': 'dns', - }, - }, 'powerdns': { + 'features': { + 'bind': True, + 'pgsql': True, + }, # Overridden in node metadata for primary server 'is_secondary': True, }, }, } - -groups['switches-mikrotik'] = { - 'bundles': { - 'routeros', - }, - 'metadata': { - 'routeros': { - 'syslog-server': '172.19.138.20', - }, - }, - 'locking_node': 'home.router', - 'os': 'routeros', - 'username': 'admin', -} diff --git a/groups/locations.py b/groups/locations.py index 43e7674..94d7d8d 100644 --- a/groups/locations.py +++ b/groups/locations.py @@ -1,3 +1,32 @@ +groups['gce'] = { + 'bundles': { + 'gce-workaround', + }, + 'member_patterns': { + r"gce\..*", + }, + 'metadata': { + 'hosts': { + 'entries': { + '169.254.169.254': { + 'metadata.google.internal', + }, + }, + }, + 'location': 'gce', + 'nameservers': { + '8.8.8.8', + '8.8.4.4', + }, + 'postfix': { + # It's fine to do this without authentificating to the relayhost. + # These Systems are not supposed to send mail anywhere else + # than our own domains. + 'relayhost': '[rx300.kunbox.net]:2525', + }, + }, +} + groups['htz'] = { 'subgroup_patterns': { r'htz\-.+', @@ -49,33 +78,29 @@ groups['home'] = { 'home.router', }, 'vars.notification.sms': False, - 'show_on_statuspage': False, }, 'postfix': { # It's fine to do this without authentificating to the relayhost. # These Systems are not supposed to send mail anywhere else # than our own domains. - 'relayhost': '[mail.franzi.business]:2525', + 'relayhost': '[rx300.kunbox.net]:2525', }, }, } -groups['sophie'] = { - 'supergroups': { - 'linux', - }, +groups['ovh'] = { 'member_patterns': { - r"sophie\..*", + r"ovh\..*", }, 'metadata': { - 'icinga_options': { - 'exclude_from_monitoring': True, - }, - 'backup-client': { - 'target': 'htz-hel.backup-sophie', + 'location': 'ovh', + 'postfix': { + 'relayhost': '[rx300.kunbox.net]:2525', }, 'users': { - 'sophie': {}, + 'debian': { + 'delete': True, + }, }, }, } @@ -92,9 +117,6 @@ groups['voc'] = { 'day': 1, }, }, - 'icinga_options': { - 'show_on_statuspage': False, - }, 'location': 'voc', }, } diff --git a/groups/os.py b/groups/os.py index 34f49b2..21d4a60 100644 --- a/groups/os.py +++ b/groups/os.py @@ -13,13 +13,13 @@ groups['raspberry'] = { groups['linux'] = { 'subgroups': { + 'arch', 'debian', 'raspberry', }, 'bundles': { 'basic', 'cron', - 'kernel-modules', 'nftables', 'openssh', 'postfix', @@ -33,13 +33,21 @@ groups['linux'] = { 'users', }, 'metadata': { + 'apt': { + 'unattended-upgrades': { + 'reboot_mail_to': libs.defaults.hostmaster_email, + }, + }, 'backup-client': { - 'target': 'backup-kunsi', + 'target': 'htz-hel.backup-kunsi', }, 'firewall': { 'port_rules': { '*': { - 'icinga2', + 'ovh.icinga2', + }, + '*/udp': { + 'ovh.icinga2', }, }, }, @@ -47,13 +55,23 @@ groups['linux'] = { 'pip_command': 'pip3', } +groups['arch'] = { + 'bundles': { + 'pacman', + }, + 'os': 'arch', +} + groups['debian'] = { - 'subgroup_patterns': { - '^debian-[a-z]+$', + 'subgroups': { + 'debian-buster', + 'debian-bullseye', + 'debian-sid', }, 'bundles': { 'apt', 'backup-client', + 'molly-guard', }, 'os': 'debian', 'pip_command': 'pip3', @@ -67,14 +85,13 @@ groups['debian-bullseye'] = { 'os_version': (11,) } -groups['debian-bookworm'] = { - 'os_version': (12,) -} - -groups['debian-trixie'] = { - 'os_version': (13,) -} - groups['debian-sid'] = { 'os_version': (99,) } + +groups['junos'] = { + 'dummy': True, + 'cmd_wrapper_outer': '{}', + 'cmd_wrapper_inner': '{}', + 'os': 'freebsd', +} diff --git a/hooks/deploy_commit_hash_to_node.py b/hooks/deploy_commit_hash_to_node.py deleted file mode 100644 index caddaad..0000000 --- a/hooks/deploy_commit_hash_to_node.py +++ /dev/null @@ -1,5 +0,0 @@ -def node_apply_end(repo, node, duration, interactive, result, **kwargs): - if not node.os in node.OS_FAMILY_UNIX: - return - - node.run(f'echo "{repo.revision}" > /var/lib/bundlewrap/last_apply_commit_id') diff --git a/hooks/test_apply_dummy_mode.py b/hooks/test_apply_dummy_mode.py deleted file mode 100644 index 8ba58c1..0000000 --- a/hooks/test_apply_dummy_mode.py +++ /dev/null @@ -1,8 +0,0 @@ -from os import environ - -from bundlewrap.exceptions import SkipNode - - -def node_apply_start(repo, node, interactive=False, **kwargs): - if environ.get('BW_VAULT_DUMMY_MODE') or environ.get('BW_PASS_DUMMY_MODE'): - raise SkipNode('refusing apply because dummy mode is active') diff --git a/hooks/test_backup_metadata.py b/hooks/test_backup_metadata.py index c8498eb..4937989 100644 --- a/hooks/test_backup_metadata.py +++ b/hooks/test_backup_metadata.py @@ -2,7 +2,6 @@ from bundlewrap.exceptions import BundleError from bundlewrap.utils.text import bold, green, yellow from bundlewrap.utils.ui import io - def test_node(repo, node, **kwargs): if not node.has_bundle('backup-client'): return diff --git a/hooks/test_metadata_dashes_vs_underscores.py b/hooks/test_metadata_dashes_vs_underscores.py index b7c7419..698ab56 100644 --- a/hooks/test_metadata_dashes_vs_underscores.py +++ b/hooks/test_metadata_dashes_vs_underscores.py @@ -4,7 +4,6 @@ from bundlewrap.exceptions import BundleError from bundlewrap.utils.text import bold, green from bundlewrap.utils.ui import io - def test_underscore_vs_dash(node, metadata, path=[]): for k, v in metadata.items(): if not isinstance(k, str): diff --git a/hooks/test_unattended_upgrades_spread.py b/hooks/test_unattended_upgrades_spread.py deleted file mode 100644 index dbf87ce..0000000 --- a/hooks/test_unattended_upgrades_spread.py +++ /dev/null @@ -1,24 +0,0 @@ -from bundlewrap.exceptions import BundleError -from bundlewrap.utils.text import bold, green, yellow -from bundlewrap.utils.ui import io - - -def test(repo, **kwargs): - for node in repo.nodes: - if not node.has_bundle('apt'): - continue - - spread = node.metadata.get('apt/unattended-upgrades/spread_in_group', None) - if spread is None: - continue - - for rnode in repo.nodes_in_group(spread): - rspread = rnode.metadata.get('apt/unattended-upgrades/spread_in_group', None) - - if spread != rspread: - raise BundleError(f'{node.name} sets apt/unattended-upgrades/spread_in_group to "{spread}", but node {rnode.name} in that group does set "{rspread}"!') - - io.stdout('{x} {node} apt/unattended-upgrades/spread_in_group matches'.format( - x=green("✓"), - node=bold(node.name), - )) diff --git a/hooks/test_zfs_consistency.py b/hooks/test_zfs_consistency.py index d7231e5..132afe3 100644 --- a/hooks/test_zfs_consistency.py +++ b/hooks/test_zfs_consistency.py @@ -25,7 +25,7 @@ def test_node(repo, node, **kwargs): pool_name = name.split('/', 1)[0] - if pool_name not in zfs_pools: + if pool_name not in zfs_pools and node.os != 'arch': raise BundleError('{n} zfs_dataset:{ds} wants zfs_pool:{pool}, which wasn\'t found'.format( n=node.name, ds=name, diff --git a/libs/defaults.py b/libs/defaults.py index 3125b48..e746722 100644 --- a/libs/defaults.py +++ b/libs/defaults.py @@ -5,18 +5,17 @@ influxdb_org = 'encrypt$gAAAAABgg9hyjz4XtvG8NBw9uYxiumS3v7YKIrtc9tTTABg1f9R22gzn influxdb_token = 'encrypt$gAAAAABgg9Ag632Xyuc6SWXaR1uH2tLOChmVKAoBIikhjntSSD2qJFL_eouVQGXCLH2HEuSbSdEXcTPn2qmhOiA9jmFdoDSbVbQUsp0EID1wLsWYG_Um2KOxZSF-tn9eDZlgShQYySjzO3nQRmdlJpVLUnGHsiwv_sHD2FstXGpfzTPZq5_egUqEc0K2X-aN2J6BTYc2fZAN' influxdb_url = 'https://influxdb.kunsmann.eu/' -nameservers_ipv4 = ['1.1.1.1', '1.0.0.1'] -nameservers_ipv6 = ['2606:4700::1111', '2606:4700:4700::1001'] +nameservers_ipv4 = ['9.9.9.10'] +nameservers_ipv6 = ['2620:fe::10'] nameservers = [*nameservers_ipv4, *nameservers_ipv6] # FIXME database conflicts redis_databases = { 'matrix-media-repo': 7, 'netbox': (4, 5), - 'nextcloud': 7, + 'rspamd': 6, 'paperless-ng': None, # probably 0, but undocumented 'pretalx': (1, 2, 3), - 'rspamd': 6, } security_email = f'mailto:{hostmaster_email}' diff --git a/libs/demagify.py b/libs/demagify.py deleted file mode 100644 index 02180f0..0000000 --- a/libs/demagify.py +++ /dev/null @@ -1,22 +0,0 @@ -import bwpass - - -def demagify(something, vault): - if isinstance(something, str): - if something.startswith('!bwpass:'): - return bwpass.password(something[8:]) - elif something.startswith('!bwpass_attr:'): - identifier, attribute = something[13:].split(':', 1) - return bwpass.attr(identifier, attribute) - elif something.startswith('!decrypt:'): - return vault.decrypt(something[9:]) - return something - elif isinstance(something, dict): - return {k:demagify(v, vault) for k,v in something.items()} - elif isinstance(something, list): - return [demagify(i, vault) for i in something] - elif isinstance(something, set): - return {demagify(i, vault) for i in something} - elif isinstance(something, tuple): - return tuple([demagify(i, vault) for i in something]) - return something diff --git a/libs/faults.py b/libs/faults.py index 848ea84..ad3735c 100644 --- a/libs/faults.py +++ b/libs/faults.py @@ -1,10 +1,7 @@ -from json import dumps, loads - -from tomlkit import dumps as toml_dumps +from json import loads, dumps from bundlewrap.metadata import metadata_to_json from bundlewrap.utils import Fault -from bundlewrap.utils.text import toml_clean def resolve_faults(dictionary: dict) -> dict: @@ -40,19 +37,3 @@ def join_faults(faults, by=' '): lambda o: by.join([i.value for i in o]), o=result, ) - - -def dict_as_json(json): - return Fault( - 'dict_as_json', - lambda o: metadata_to_json(o) + '\n', - o=json - ) - - -def dict_as_toml(toml): - return Fault( - 'dict_as_toml', - lambda o: toml_clean(toml_dumps(resolve_faults(o), sort_keys=True)) + '\n', - o=toml - ) diff --git a/libs/firewall.py b/libs/firewall.py index 7a2fa32..68b852d 100644 --- a/libs/firewall.py +++ b/libs/firewall.py @@ -1,5 +1,5 @@ -from ipaddress import IPv4Network, ip_network from os.path import abspath, dirname, join +from ipaddress import ip_network, IPv4Network REPO_PATH = dirname(dirname(abspath(__file__))) @@ -44,8 +44,3 @@ named_networks = { }, }, } - -global_ip4_blocklist = { - "141.98.11.0/24", # 2024-01-21, smtp login bruteforce -} -global_ip6_blocklist = set() diff --git a/libs/juniper.py b/libs/juniper.py new file mode 100644 index 0000000..9549a77 --- /dev/null +++ b/libs/juniper.py @@ -0,0 +1,149 @@ +import random + +# copied from https://github.com/peering-manager/peering-manager/blob/main/devices/crypto/juniper.py + + +# This code is the result of the attempt at converting a Perl module, the expected +# result might not actually be what we really want it to be ¯\_(ツ)_/¯ +# +# https://metacpan.org/pod/Crypt::Juniper + + +MAGIC = "$9$" + +FAMILY = [ + "QzF3n6/9CAtpu0O", + "B1IREhcSyrleKvMW8LXx", + "7N-dVbwsY2g4oaJZGUDj", + "iHkq.mPf5T", +] +EXTRA = {} +for counter, value in enumerate(FAMILY): + for character in value: + EXTRA[character] = 3 - counter + +NUM_ALPHA = [x for x in "".join(FAMILY)] +ALPHA_NUM = {NUM_ALPHA[x]: x for x in range(0, len(NUM_ALPHA))} + +ENCODING = [ + [1, 4, 32], + [1, 16, 32], + [1, 8, 32], + [1, 64], + [1, 32], + [1, 4, 16, 128], + [1, 32, 64], +] + + +def __nibble(cref, length): + nib = cref[0:length] + rest = cref[length:] + + if len(nib) != length: + raise Exception(f"Ran out of characters: hit '{nib}', expecting {length} chars") + + return nib, rest + + +def __gap(c1, c2): + return (ALPHA_NUM[str(c2)] - ALPHA_NUM[str(c1)]) % (len(NUM_ALPHA)) - 1 + + +def __gap_decode(gaps, dec): + num = 0 + + if len(gaps) != len(dec): + raise Exception("Nibble and decode size not the same.") + + for x in range(0, len(gaps)): + num += gaps[x] * dec[x] + + return chr(num % 256) + + +def __reverse(current): + reversed = list(current) + reversed.reverse() + return reversed + + +def __gap_encode(pc, prev, encode): + __ord = ord(pc) + + crypt = "" + gaps = [] + for mod in __reverse(encode): + gaps.insert(0, int(__ord / mod)) + __ord %= mod + + for gap in gaps: + gap += ALPHA_NUM[prev] + 1 + prev = NUM_ALPHA[gap % len(NUM_ALPHA)] + crypt += prev + + return crypt + + +def __randc(counter=0): + return_value = "" + for _ in range(counter): + return_value += NUM_ALPHA[random.randrange(len(NUM_ALPHA))] + return return_value + + +def is_encrypted(value): + return value.startswith(MAGIC) + + +def decrypt(value): + if not value: + return "" + + if not is_encrypted(value): + return value + + chars = value.split("$9$", 1)[1] + first, chars = __nibble(chars, 1) + toss, chars = __nibble(chars, EXTRA[first]) + previous = first + decrypted = "" + + while chars: + decode = ENCODING[len(decrypted) % len(ENCODING)] + nibble, chars = __nibble(chars, len(decode)) + gaps = [] + for i in nibble: + g = __gap(previous, i) + previous = i + gaps += [g] + decrypted += __gap_decode(gaps, decode) + + return decrypted + + +def encrypt(value, salt=None): + if not value: + return "" + + if not isinstance(value, str): + value = str(value) + + if is_encrypted(value): + return value + + if not salt: + salt = __randc(1) + rand = __randc(EXTRA[salt]) + + position = 0 + previous = salt + crypted = MAGIC + salt + rand + + for x in value: + encode = ENCODING[position % len(ENCODING)] + crypted += __gap_encode(x, previous, encode) + previous = crypted[-1] + position += 1 + + return crypted diff --git a/libs/keys.py b/libs/keys.py index 4db382b..1565fee 100644 --- a/libs/keys.py +++ b/libs/keys.py @@ -1,11 +1,8 @@ import base64 - -from nacl.encoding import Base64Encoder from nacl.public import PrivateKey - +from nacl.encoding import Base64Encoder from bundlewrap.utils import Fault - def gen_privkey(repo, identifier): return repo.vault.random_bytes_as_base64_for(identifier) diff --git a/libs/s2s.py b/libs/s2s.py index 8372ec2..1d57128 100644 --- a/libs/s2s.py +++ b/libs/s2s.py @@ -4,38 +4,18 @@ AS_NUMBERS = { # 4290xxxxxx 'home': 4290000138, 'htz-cloud': 4290000137, - 'ionos': 4290000002, - 'revision': 4290000078, - 'rottenraptor': 4290000030, -} - -WG_AUTOGEN_NODES = [ - # only ever append to this list. If a node vanishes, set its name to - # `None`. You may remove nodes from the end of this, though it's not - # recommended to do so. - - None, # fkusei-locutus never used this - 'home.router', - 'htz-cloud.wireguard', - 'icinga2', - None, # daisy -] - -WG_AUTOGEN_SETTINGS = { - # special settings to apply when peering with a specific node - 'home.router': { - 'firewall': {'versatel'}, - 'no_autoconnect': True, - 'persistent_keepalive': False, - }, + 'ovh': 4290000001, } def get_subnet_for_connection(repo, peer_a, peer_b): - assert peer_a in WG_AUTOGEN_NODES - assert peer_b in WG_AUTOGEN_NODES + # XXX this assumes there are never more than 128 nodes which match that expression + nodes = sorted({node.name for node in repo.nodes if node.has_bundle('wireguard')}) - pos_peer_a = WG_AUTOGEN_NODES.index(peer_a) - pos_peer_b = WG_AUTOGEN_NODES.index(peer_b) + assert peer_a in nodes + assert peer_b in nodes + + pos_peer_a = nodes.index(peer_a) + pos_peer_b = nodes.index(peer_b) vpn_subnet = list(IPv4Network('169.254.0.0/16').subnets(new_prefix=24))[pos_peer_a] return list(IPv4Network(vpn_subnet).subnets(new_prefix=31))[pos_peer_b] diff --git a/libs/ssh.py b/libs/ssh.py deleted file mode 100644 index fe3b9b4..0000000 --- a/libs/ssh.py +++ /dev/null @@ -1,94 +0,0 @@ -from base64 import b64decode, b64encode -from functools import lru_cache -from hashlib import sha3_224 - -from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey -from cryptography.hazmat.primitives.serialization import (Encoding, - NoEncryption, - PrivateFormat, - PublicFormat) - -from bundlewrap.utils import Fault - - -@lru_cache(maxsize=None) -def generate_ed25519_private_key(username, node): - return Fault( - f'private key {username}@{node.name}', - lambda username, node: _generate_ed25519_private_key(username, node), - username=username, - node=node, - ) - - -@lru_cache(maxsize=None) -def generate_ed25519_public_key(username, node): - return Fault( - f'public key {username}@{node.name}', - lambda username, node: _generate_ed25519_public_key(username, node), - username=username, - node=node, - ) - - -def _generate_ed25519_private_key(username, node): - privkey_bytes = Ed25519PrivateKey.from_private_bytes(_secret(username, node)) - - nondeterministic_privatekey = privkey_bytes.private_bytes( - encoding=Encoding.PEM, - format=PrivateFormat.OpenSSH, - encryption_algorithm=NoEncryption(), - ).decode() - - # get relevant lines from string - nondeterministic_bytes = b64decode( - ''.join(nondeterministic_privatekey.split('\n')[1:-2]) - ) - - # sanity check - if nondeterministic_bytes[98:102] != nondeterministic_bytes[102:106]: - raise Exception("checksums should be the same: whats going on here?") - - # replace random bytes with deterministic values - random_bytes = sha3_224(_secret(username, node)).digest()[0:4] - deterministic_bytes = ( - nondeterministic_bytes[:98] - + random_bytes - + random_bytes - + nondeterministic_bytes[106:] - ) - - # reassemble file - deterministic_privatekey = '\n'.join( - [ - '-----BEGIN OPENSSH PRIVATE KEY-----', - b64encode(deterministic_bytes).decode(), - '-----END OPENSSH PRIVATE KEY-----', - ] - ) + '\n' - - return deterministic_privatekey - - -def _generate_ed25519_public_key(username, node): - return ( - Ed25519PrivateKey.from_private_bytes(_secret(username, node)) - .public_key() - .public_bytes( - encoding=Encoding.OpenSSH, - format=PublicFormat.OpenSSH, - ) - .decode() - + f' {username}@{node.name}' - ) - - -@lru_cache(maxsize=None) -def _secret(username, node): - return b64decode( - str( - node.repo.vault.random_bytes_as_base64_for( - f"{username}@{node.name}", length=32 - ) - ) - ) diff --git a/libs/tools.py b/libs/tools.py index 4f98677..8e225a5 100644 --- a/libs/tools.py +++ b/libs/tools.py @@ -1,11 +1,10 @@ -from ipaddress import IPv4Address, IPv4Network, ip_address, ip_network +from ipaddress import ip_address, ip_network, IPv4Address, IPv4Network -from bundlewrap.exceptions import BundleError, NoSuchGroup, NoSuchNode +from bundlewrap.exceptions import NoSuchGroup, NoSuchNode, BundleError from bundlewrap.utils.text import bold, red from bundlewrap.utils.ui import io - -def resolve_identifier(repo, identifier, linklocal=False, only_physical=False, allow_private=True): +def resolve_identifier(repo, identifier): """ Try to resolve an identifier (group or node). Return a set of ip addresses valid for this identifier. @@ -34,15 +33,6 @@ def resolve_identifier(repo, identifier, linklocal=False, only_physical=False, a found_ips = set() for node in nodes: for interface, config in node.metadata.get('interfaces', {}).items(): - if only_physical and not ( - interface.startswith('bond') or - interface.startswith('br') or - interface.startswith('en') or - interface.startswith('et') or - interface == 'default' # dummy nodes use these - ): - continue - for ip in config.get('ips', set()): if '/' in ip: found_ips.add(ip_address(ip.split('/')[0])) @@ -62,15 +52,7 @@ def resolve_identifier(repo, identifier, linklocal=False, only_physical=False, a 'ipv6': set(), } - has_public_ips = bool([ip for ip in found_ips if not ip.is_private]) - for ip in found_ips: - if ip.is_link_local and not linklocal: - continue - - if ip.is_private and not allow_private and has_public_ips: - continue - if isinstance(ip, IPv4Address): ip_dict['ipv4'].add(ip) else: diff --git a/netbox_dump.json b/netbox_dump.json new file mode 100644 index 0000000..c013f00 --- /dev/null +++ b/netbox_dump.json @@ -0,0 +1,1322 @@ +{ + "home": { + "devices": { + "home.nas": { + "bond0": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": null, + "type": "lag", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "br0": { + "description": "", + "enabled": true, + "ip_addresses": [ + "172.19.138.20/24" + ], + "lag": null, + "mode": "tagged-all", + "type": "bridge", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "br42": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "bridge", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "eno1": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": null, + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "enp8s0f0": { + "description": "home.sw01 (41)", + "enabled": true, + "ip_addresses": [], + "lag": "bond0", + "mode": null, + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "enp8s0f1": { + "description": "home.sw01 (43)", + "enabled": true, + "ip_addresses": [], + "lag": "bond0", + "mode": null, + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "enp9s0f0": { + "description": "home.sw01 (45)", + "enabled": true, + "ip_addresses": [], + "lag": "bond0", + "mode": null, + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "enp9s0f1": { + "description": "home.sw01 (47)", + "enabled": true, + "ip_addresses": [], + "lag": "bond0", + "mode": null, + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": null + } + } + }, + "home.router": { + "enp1s0": { + "description": "home.sw01 (2)", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": null, + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "enp1s0.100": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": null, + "type": "virtual", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "enp1s0.23": { + "description": "", + "enabled": true, + "ip_addresses": [ + "172.19.139.1/24" + ], + "lag": null, + "mode": null, + "type": "virtual", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "enp1s0.42": { + "description": "", + "enabled": true, + "ip_addresses": [ + "172.19.138.1/24" + ], + "lag": null, + "mode": null, + "type": "virtual", + "vlans": { + "tagged": [], + "untagged": null + } + } + }, + "home.sw01": { + "1": { + "description": "Isanet", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.dmz" + } + }, + "10": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "ffwi.client" + } + }, + "11": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "ffwi.client" + } + }, + "12": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "ffwi.client" + } + }, + "13": { + "description": "home.ejgwdesk", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "14": { + "description": "Schreibtisch Franzi", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "15": { + "description": "Schreibtisch Sophie", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "16": { + "description": "home.snom-wohnzimmer", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "17": { + "description": "home.drucker-sophie", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "18": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "19": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "2": { + "description": "home.router (enp1s0)", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "tagged", + "type": "1000base-t", + "vlans": { + "tagged": [ + "home.clients", + "home.dmz", + "home.wan" + ], + "untagged": null + } + }, + "20": { + "description": "RIPE-Probe #28280", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.dmz" + } + }, + "21": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "22": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "23": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "24": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "25": { + "description": "home.kodi-wohnzimmer", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "26": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "27": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "28": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "29": { + "description": "Sofa-Kabel", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "3": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "ffwi.client" + } + }, + "30": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "31": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "32": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "33": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": "LAG3", + "mode": null, + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "34": { + "description": "Patchpanel unten (17)", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "35": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": "LAG3", + "mode": null, + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "36": { + "description": "Patchpanel unten (18)", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "37": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": "LAG1", + "mode": null, + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "38": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "39": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": "LAG1", + "mode": null, + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "4": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "ffwi.client" + } + }, + "40": { + "description": "info-beamer 12199 (LAN)", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "41": { + "description": "home.nas (enp8s0f0)", + "enabled": true, + "ip_addresses": [], + "lag": "LAG2", + "mode": null, + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "42": { + "description": "Patchpanel unten (21)", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.wan" + } + }, + "43": { + "description": "home.nas (enp8s0f1)", + "enabled": true, + "ip_addresses": [], + "lag": "LAG2", + "mode": null, + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "44": { + "description": "home.bubble01", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "45": { + "description": "home.nas (enp9s0f0)", + "enabled": true, + "ip_addresses": [], + "lag": "LAG2", + "mode": null, + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "46": { + "description": "home.winkeeinhorn-1", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "tagged", + "type": "1000base-t", + "vlans": { + "tagged": [ + "ffwi.mesh" + ], + "untagged": "home.clients" + } + }, + "47": { + "description": "home.nas (enp9s0f1)", + "enabled": true, + "ip_addresses": [], + "lag": "LAG2", + "mode": null, + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "48": { + "description": "home.winkeeinhorn-2", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "tagged", + "type": "1000base-t", + "vlans": { + "tagged": [ + "ffwi.mesh" + ], + "untagged": "home.clients" + } + }, + "49": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": null, + "type": "1000base-x-sfp", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "5": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "ffwi.client" + } + }, + "50": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": null, + "type": "1000base-x-sfp", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "51": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": null, + "type": "1000base-x-sfp", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "52": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": null, + "type": "1000base-x-sfp", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "6": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "ffwi.client" + } + }, + "7": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "ffwi.client" + } + }, + "8": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "ffwi.client" + } + }, + "9": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "ffwi.client" + } + }, + "LAG1": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "lag", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "LAG2": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "tagged", + "type": "lag", + "vlans": { + "tagged": [ + "ffwi.client", + "ffwi.mesh", + "home.clients", + "home.dmz", + "home.wan" + ], + "untagged": null + } + }, + "LAG3": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "lag", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "VLAN42": { + "description": "", + "enabled": true, + "ip_addresses": [ + "172.19.138.2/24" + ], + "lag": null, + "mode": "access", + "type": "virtual", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + } + }, + "home.sw02": { + "ge-0/0/0": { + "description": "snom", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "ge-0/0/1": { + "description": "bubble", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "ge-0/0/10": { + "description": "sophie", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "ge-0/0/11": { + "description": "sophie", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "ge-0/0/12": { + "description": "franzi", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "ge-0/0/13": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": null, + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "ge-0/0/14": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": null, + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "ge-0/0/15": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": null, + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "ge-0/0/16": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": null, + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "ge-0/0/17": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": null, + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "ge-0/0/18": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": null, + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "ge-0/0/19": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": null, + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "ge-0/0/2": { + "description": "freifunk", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "tagged", + "type": "1000base-t", + "vlans": { + "tagged": [ + "ffwi.mesh" + ], + "untagged": "home.clients" + } + }, + "ge-0/0/20": { + "description": "kodi", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "ge-0/0/21": { + "description": "infobeamer", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "ge-0/0/22": { + "description": "fritzbox", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.wan" + } + }, + "ge-0/0/23": { + "description": "router", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "tagged", + "type": "1000base-t", + "vlans": { + "tagged": [ + "home.clients", + "home.dmz", + "home.wan" + ], + "untagged": null + } + }, + "ge-0/0/3": { + "description": "freifunk", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "tagged", + "type": "1000base-t", + "vlans": { + "tagged": [ + "ffwi.mesh" + ], + "untagged": "home.clients" + } + }, + "ge-0/0/4": { + "description": "wohnzimmer", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "ge-0/0/5": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": null, + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "ge-0/0/6": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": null, + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "ge-0/0/7": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": null, + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "ge-0/0/8": { + "description": "drucker", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "ge-0/0/9": { + "description": "ripe-probe", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": "home.dmz" + } + }, + "ge-0/1/0": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": null, + "type": "1000base-x-sfp", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "ge-0/1/1": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": null, + "type": "1000base-x-sfp", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "ge-0/1/2": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": null, + "type": "1000base-x-sfp", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "ge-0/1/3": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": null, + "type": "1000base-x-sfp", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "home.clients": { + "description": "", + "enabled": true, + "ip_addresses": [ + "172.19.138.4/24" + ], + "lag": null, + "mode": null, + "type": "virtual", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "xe-0/1/0": { + "description": "nas", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "tagged", + "type": "10gbase-x-sfpp", + "vlans": { + "tagged": [ + "ffwi.client", + "ffwi.mesh", + "home.clients", + "home.dmz" + ], + "untagged": null + } + }, + "xe-0/1/1": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "10gbase-x-sfpp", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + }, + "xe-0/1/2": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": "access", + "type": "10gbase-x-sfpp", + "vlans": { + "tagged": [], + "untagged": "home.clients" + } + } + }, + "home.usv01": { + "LAN": { + "description": "", + "enabled": true, + "ip_addresses": [ + "172.19.138.3/24" + ], + "lag": null, + "mode": null, + "type": "100base-tx", + "vlans": { + "tagged": [], + "untagged": null + } + } + } + }, + "vlans": { + "ffwi.client": 8, + "ffwi.mesh": 7, + "home.clients": 42, + "home.dmz": 23, + "home.wan": 100 + } + }, + "meerfarbig gmbh & co. kg": { + "devices": { + "rx300": { + "IPMI": { + "description": "", + "enabled": true, + "ip_addresses": [ + "10.250.179.2/32" + ], + "lag": null, + "mode": null, + "type": "100base-tx", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "LAN1": { + "description": "", + "enabled": true, + "ip_addresses": [ + "2a00:f820:528::2/64", + "31.47.232.106/29" + ], + "lag": null, + "mode": null, + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": null + } + }, + "LAN2": { + "description": "", + "enabled": true, + "ip_addresses": [], + "lag": null, + "mode": null, + "type": "1000base-t", + "vlans": { + "tagged": [], + "untagged": null + } + } + } + }, + "vlans": {} + } +} \ No newline at end of file diff --git a/nodes.py b/nodes.py index 1798613..75e6f1f 100644 --- a/nodes.py +++ b/nodes.py @@ -3,19 +3,9 @@ from os.path import join from pathlib import Path import bwpass - from bundlewrap.metadata import atomic from bundlewrap.utils import error_context -for name, data in nodes.items(): - data.setdefault('metadata', {}) - - if 'password' in data: - data['password'] = vault.decrypt(data['password']) - if 'ipmi' in data: - data['ipmi'].update(libs.demagify.demagify(data['ipmi'], vault)) - data['metadata'].update(libs.demagify.demagify(data['metadata'], vault)) - for node in Path(join(repo_path, "nodes")).rglob("*.py"): with error_context(filename=str(node)): with open(node, 'r') as f: diff --git a/nodes/attributes.py b/nodes/attributes.py deleted file mode 100644 index eda23f4..0000000 --- a/nodes/attributes.py +++ /dev/null @@ -1,37 +0,0 @@ -from bundlewrap.utils.scm import get_rev -from bundlewrap.utils.text import bold, red -from bundlewrap.utils.ui import io - - -@node_attribute -def needs_apply(node): - if node.dummy: - return False - - if node.os not in node.OS_FAMILY_UNIX: - return True - - try: - applied = node.run( - 'cat /var/lib/bundlewrap/last_apply_commit_id', - may_fail=True, - ).stdout.decode().strip() - - if not applied or applied != get_rev(): - return True - except Exception as e: - io.stderr(f'{red("!!!")} {bold(node.name)} {e!r}') - - return False - - -@node_attribute -def uses_bw_managed_ssl(node): - if not node.has_bundle('nginx'): - return False - - for vhost in node.metadata.get('nginx/vhosts', {}).values(): - if vhost['ssl'] not in (None, False, 'letsencrypt'): - return True - - return False diff --git a/nodes/aurto.py b/nodes/aurto.py new file mode 100644 index 0000000..d7a98c3 --- /dev/null +++ b/nodes/aurto.py @@ -0,0 +1,99 @@ +nodes['aurto'] = { + 'hostname': '31.47.232.107', + 'bundles': { + 'backup-client', + 'check-mail-received', + }, + 'groups': { + 'arch', + 'webserver', + }, + 'metadata': { + 'icinga_options': { + 'also_affected_by': { + 'rx300', + }, + 'period': 'daytime', + }, + 'backups': { + 'paths': { + '/var/cache/pacman/aurto', + }, + }, + 'check-mail-received': { + 't-online': { + 'email': 'franzi.kunsmann@t-online.de', + 'imap_host': 'secureimap.t-online.de', + 'imap_pass': bwpass.attr('t-online.de/franzi.kunsmann@t-online.de', 'imap'), + }, + }, + 'description': [ + 'When adding packages to aurto, please also add those packages to ~/PACKAGES', + 'Wenn Pakete zu aurto hinzugefügt werden, trage sie bitte auch in ~/PACKAGES ein', + ], + 'interfaces': { + 'enp1s0': { + 'ips': { + '31.47.232.107/29', + '2a00:f820:528::3/64', + }, + 'gateway4': '31.47.232.105', + 'gateway6': '2a00:f820:528::1', + }, + }, + 'nginx': { + 'vhosts': { + 'aurto': { + 'domain': 'aurto.kunbox.net', + 'webroot': '/var/cache/pacman/aurto', + 'extras': True, + }, + }, + }, + 'pacman': { + 'enable_aurto': False, + 'additional_config': { + 'Include = /etc/pacman.d/aurto', + }, + 'unattended-upgrades': { + 'is_enabled': True, + 'hour': 22, # one hour after the host + }, + }, + 'sudo': { + 'extra_configs': { + '50_aurto_passwordless': { + '%wheel ALL=(ALL) NOPASSWD: /usr/bin/arch-nspawn', + '%wheel ALL=(ALL) NOPASSWD: /usr/bin/pacsync aurto', + '%wheel ALL=(ALL) NOPASSWD:SETENV: /usr/bin/makechrootpkg', + }, + }, + }, + 'users': { + 'aurto': { + 'groups': { + 'wheel', + }, + 'ssh_pubkey': { + # e1mo + 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBfbb4m4o89EumFjE8ichX03CC/mWry0JYaz91HKVJPb e1mo', + 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAID9x/kL2fFqQSEyFvdEgiM2UKYAZyV1oct9alS6mweVa e1mo (ssh_0x6D617FD0A85BAADA)', + # f2k1de + 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGrvhqC/tZzpLMs/qy+1xNSVi2mfn8LXPIEhh7dcGn9e', + 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDH5+j2vDW1FHSSEEI/Sf5qiKJq1uoxGO5BPv84mqohvol7GxDFObv69tn7g6HYfZY/SaS75C4ZXy+cKa0xy8UCpF0SBa2xHASkenS9v55oweDL4rYSPARzn2XKt3RFJG/d8V5NOWtcyq5DFSzewUF35E4hx1pUc/CIxgJEem5ZvzvN0hlIKXUN2djkVUx+mz6RryBysLTJEFBamjJxIkvDG/PZU73W4SHaKAYV4Ojz2NY7T5/NYKePfIU5F9pkE3RU0LRj58usvA1eP0PvEArWlGNCd8EJU+HQ5xr2dZ6MKPpEyG0KJkC88DuapeF5RwUV53ZhNpF+QgzpI72fH5up', + # kunsi + 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICYst1HK+gJYhNxzqJGnz4iB73pa89Xz2yH+8wufOcsA', + 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC+ja1z5VRQzaKCCePsUM14qMr9QR94qlWc7Je5Poki9UmC1t/TyxRVzcCBL1ZdIfBGx6QKtfkEbvhgb3nxVt3PvXjoJrc6wwGLmNrVsU6B88y35g7nzupQiPKYJwkNzJ9j6Dmkgj1F5Q+aY2SitDaX6vqICLJ4Al/ZFw2IQxVJfC7JXRJ9jRMG5o9gWoE3gWDYEAmw+HU2mNzyeuaD12qJw9DHUimAlgkOWzll3gh9WclsYnnXGrCCn5fyHFUCJl+XXAIy519z7YTpKih02rsIOw5dnaGClBZD/YQu2ZKVFZiwIVH7aBiqHOmtgRyWTQgjbh/fMpIN0ar2f/iZsWYUjd6et48TOmXZYIPCQ5FivXNvxt9oo1XZfq76UHBwlmypLJIWROMbz375n2M6hr3hECuxuPjKEUXAv05KiC1aJ4xc6pFoVhqwAR99hvHw5U4o7/ko2NVjNpTu6Jr5DT5VaQLIdDDjC/93kUjMpdD/8P72bEn7454+WexU6OE6uvNiHj1fetrptr2UAuzVfnCoaV8pBqY7X95gk+lnSENdpr8ltJYMg8s0Z7Pzz0OxsZtzzDY5VmWfC9TCdJkN5lT8IbnaixsYlWdjQl1lMmZGElmelfU3K7YQLAbZiHmHKe4hTl9ZoCcWdTQ3d4y2t1DBos+N2HZNdtFCyOS8esDdMw== cardno:000609506971', + # n0emis + 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEcOPtW5FWNIdlMQFoqeyA1vHw+cA8ft8oXSbXPzQNL9 n0emis@n0emis.eu', + 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC8xqVakxJ+AwcIrS/wyL03N++pE09epwMFlIMXWvlpwwEp1J/0H7nygwxk/9LIZdabs/ETWn0s8oHAkc7YR1c6ajSTCDiZEYATAWt7t8t4Gw/80c8u8T50lIqmiDEEVbOVv3Vta/pAN4hAUp9U5DpYCkQbvF+NKKcK3Yp8d9usNC6ohqgTK+IGAEdMhvpbbNppDMXoWHuynBzUX7TS6ST6yEr0tD+CBbCpbfcMuwTI3lNtfywEVpuFaeHqDZx2QDrEX4bg0dRKgQstbXYdqmBfnOiBpUr8Wyl8U1J24rN+E07pBw/8KDGWbVg19/Ex8o4ht/p5voUfKVjD/DwWXTLntBirjfAgQAm4GH/qP4x3zNiTtlYlQFbXSk6VEVrTrxCB5rTWvGnhg31tk5P3YwvagDmGABazY5s/8tlttSc1yWBctWQJCjxSqcCLekxG4D1rVuGKCKOZgflQ9QFdQlKycInPBek3zi0i3GYkE1YnNFye5ggOnxT8qGuKjfdtZI9qvMJQO8lbEDzbYQvNns1V/k4ZobiihYwrG5TJUzZFEpMYetDK6tI8BRU11d+ja0jWzguj5/7wc0nrr/BiZ8FkAr2fZ60j2aI5kG0s3qjbrQbB/RXaGP9hRU0+480+IokNJJIcjv5iwH5ophdrjC8GH4So2kPPt0NXob1yNysdjw== simeon@noemis.me (OLD)', + }, + }, + 'kunsi': { + 'groups': { + 'wheel', + }, + }, + }, + }, +} diff --git a/nodes/backup-kunsi.toml b/nodes/backup-kunsi.toml deleted file mode 100644 index 4a47ae4..0000000 --- a/nodes/backup-kunsi.toml +++ /dev/null @@ -1,38 +0,0 @@ -hostname = "2001:67c:b54:1::f" -bundles = ["backup-server", "dm-crypt", "zfs"] -groups = ["debian-bookworm"] - -[metadata] -nameservers = ["2001:4860:4860::8888"] - -[metadata.apt.packages.qemu-guest-agent] - -[metadata.apt.unattended-upgrades] -# requires manual apply to unlock disks -reboot_enabled = false - -[metadata.interfaces.ens18] -ips = ["2001:67c:b54:1::f/64"] -gateway6 = "2001:67c:b54:1::1" - -[metadata.backups] -# this is the backup server -exclude_from_backups = true - -[metadata.backup-server.zpool_create_options] -ashift = 12 - -[metadata.backup-server.encrypted-devices.WVT0RNKF] -device = "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi4" -passphrase = "!bwpass:bw/backup-kunsi/ata-ST20000NM007D-3DJ103_WVT0RNKF" - -[metadata.backup-server.encrypted-devices.WVT0V0NQ] -device = "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi5" -passphrase = "!bwpass:bw/backup-kunsi/ata-ST20000NM007D-3DJ103_WVT0V0NQ" - -[metadata.backup-server.encrypted-devices.WVT0W64H] -device = "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi6" -passphrase = "!bwpass:bw/backup-kunsi/ata-ST20000NM007D-3DJ103_WVT0W64H" - -[metadata.zfs] -scrub_when = "Wed 08:00 Europe/Berlin" diff --git a/nodes/carlene.toml b/nodes/carlene.toml deleted file mode 100644 index 3b53d0f..0000000 --- a/nodes/carlene.toml +++ /dev/null @@ -1,281 +0,0 @@ -hostname = "193.135.9.29" -groups = [ - "debian-bookworm", - "webserver", -] -bundles = [ - "check-mail-received", - "dovecot", - "forgejo", - "matrix-media-repo", - "matrix-stickerpicker", - "matrix-synapse", - "mautrix-telegram", - "mautrix-whatsapp", - "miniflux", - "netbox", - "nextcloud", - "ntfy", - "oidentd", - "php", - "postfixadmin", - "postgresql", - "redis", - "rspamd", - "smartd", - "travelynx", - "weechat", - "zfs", -] - -# for auto-deployment of salonkatrin.de -[metadata.apt.packages.jekyll] - -[metadata.check-mail-received.t-online] -email = "franzi.kunsmann@t-online.de" -imap_host = "secureimap.t-online.de" -imap_pass = "!bwpass_attr:t-online.de/franzi.kunsmann@t-online.de:imap" - -[metadata.forgejo] -version = "11.0.0" -sha1 = "3a12529ab21ca04f2b3e6cf7a6c91af18f00ee5d" -domain = "git.franzi.business" -enable_git_hooks = true -install_ssh_key = true -internal_token = "!decrypt:encrypt$gAAAAABfPncYwCX-NdBr9LdxLyGqmjRJqhmwMnWsdZy6kVOWdKrScW78xaqbJ1tpL1J4qa2hcZ7TQj3l-2mkyJNJOenGzU3TsI-gYMj9vC4m8Bhur5zboxjD4dQXaJbD1WSyHJ9sPJYsWP3Gjg6I19xeq9xMlAI6xaS9vOfuoI8nZnnQPx1NjfQEj03Jxf8a0-3F20sfICst1xRa5K48bpq1PFkK_oRojg==" -lfs_secret_key = "!decrypt:encrypt$gAAAAABfPnd1vgNDt86-91YhviQw8Z0djSp4f_tBt76klDv-ZcwxP1ryJzqJ7qnfaTe_6DYCfc82gEzvVDsyBlCoAkGpt1AI2_LCKetuSCnDPjtGvwdQl3A53lFEdG2UJl1uUiR7f8Vr" -oauth_secret_key = "!decrypt:encrypt$gAAAAABfPnbfTISbldhS0WyxVKBHVVoOMcar7Kxmh1kkmiUGd-RzbbnNzzhEER_owjttPQcACPfGKZ6WklaSsXjLq8km4P6A9QmPbC06GmHbc91m0odCb1KiY7SZeUD35PiRiGSq50dz" -security_secret_key = "!decrypt:encrypt$gAAAAABfPnc-R7pkDj4pQgHDb6pzlNYNJgiWdeBFsX7IsHSnCtNPbZxCdtSL8cHtQzVO1KbSxS7zCwssmgiR8Kj54Z-koD-FQbjpbKWoIPw8SsyeqBVlZhIeEzhw_1t7_7ZTvv1O8AePdNYel9JJb_TaAZ8Vx46ZfsEPy8zaaHrqOekHC6RAnB4=" - -[metadata.interfaces.'eno*'] -ips = [ - "193.135.9.29/24", - "2a0a:51c0:0:225::2/64", -] -gateway4 = "193.135.9.1" -gateway6 = "2a0a:51c0:0:225::1" - -[metadata.matrix-media-repo] -admins = ["@kunsi:franzi.business"] -datastore_id = "3fff5da324ed784c771d638bb6be5917" -sha1 = "453c12cfb9f2c44c509620b63f94f8a9e2d048ef" -upload_max_mb = 500 -version = "v1.3.8" -[metadata.matrix-media-repo.homeservers.'franzi.business'] -api = "synapse" -domain = "http://[::1]:20080/" -signing_key_path = "/etc/matrix-synapse/mmr.signing.key" - -[metadata.matrix-stickerpicker] -# use this bot token: encrypt$gAAAAABfVK51ErJ6gfsOOkbRxSHDnVYmf7EihAQf7Uwj9og3TlAw64WRsA6ZVEgTSvOdLB3SMKZ-cTEhwkCOpbymq-_WLhes-hZALhN-H_oXHaxTQErJ0lARynKmjM-4ZhoGlUWlfh4Q -domain = "matrix-stickers.franzi.business" -[metadata.matrix-stickerpicker.config] -access_token = "!decrypt:encrypt$gAAAAABg-wBmGbAy-Ou1mkG2w5UyoqWmWYzDr4ZavyUQdmG_VtrUSmwHjx-qcBGIz_7NniD3zKm9GGvzRZItDu5zYiojcudYr74TkWJKhdDrgFbcWlfJJ_m3bWzrSORaTYzBGRckp2Vz_8xHgDk1W03vpT6mdIPMDzjuINssIcPs0YDth25W942tMfPA2csvLADY50qVRMJpdBOVIWba55o0g6-mAAQLOz6Ld4cCvYqZsqXsxjT8JUytJv_uSG4zgCS_aX20JlAyJWpJgT8FQF5HzIbsko_-Z9-TwtY7yllJp5Ri3n0WaDaWoMmUfhLvkMJeymmOc32A4WJBAePQ_2F-_oUDE7t97A-m3ZiMVAEefDnH5MkoiQEJTfHrJsXRkdBT_BnJlY1CoAuXpRYDdvbVDwN_qZHHHtqsno437l9S6GgDK_-sKBiojYkYsfHcJCdSEqeFGuxT" -homeserver = "https://matrix.franzi.business" -user_id = "@dimension:franzi.business" - -[metadata.matrix-synapse] -admin_contact = "mailto:hostmaster@kunbox.net" -baseurl = "matrix.franzi.business" -server_name = "franzi.business" -trusted_key_servers = ["matrix.org", "161.rocks"] -additional_client_config.'im.vector.riot.jitsi'.preferredDomain = "meet.ffmuc.net" -wellknown_also_on_vhosts = ["franzi.business"] - -[metadata.mautrix-telegram] -version = "v0.15.2" -homeserver.domain = "franzi.business" -homeserver.url = "https://matrix.franzi.business" -telegram.api_id = "!decrypt:encrypt$gAAAAABfVK5SmDDru-UQxitkE5VhPArnUBhaRbAqQPvAW2Fh3fd1XDrWxa3Qn4BSnJAPNWglH5wil_SXUMcIm95FMhPe8dVeMQ==" -telegram.api_token = "!decrypt:encrypt$gAAAAABfVK5jHuUly1xr9Iku362k7oF4ZYRhLGzNJh3aJpiNrLfAy_DJpTwucx4FV_g45dyQF5boqG2rgdDfwsJN_Ab95es6T4SPGiXIxJOBlvIln1Torwh16pXKchhUTn_PQ077Ll1W" -# same as for matrix-dimension -telegram.bot_token = "!decrypt:encrypt$gAAAAABfVK51ErJ6gfsOOkbRxSHDnVYmf7EihAQf7Uwj9og3TlAw64WRsA6ZVEgTSvOdLB3SMKZ-cTEhwkCOpbymq-_WLhes-hZALhN-H_oXHaxTQErJ0lARynKmjM-4ZhoGlUWlfh4Q" -provisioning.enabled = true -provisioning.shared_secret = "!decrypt:encrypt$gAAAAABfVKflEMAi07C_QGP8cy97hF-4gGPym0oF6p4WSMdAveTpx-hFsZd2s7v9ubw99yIsyKx0dHOJI0UND7hV1rKZdvjy4Qa642abZ2wwW7SWTqvuP_qVtrf6-klc2QKTzeD9c_LVsyZ2dqz_JxRPq3MRXgkubZuWOZ6FmFlAlteTffoGfWE=" -[metadata.mautrix-telegram.permissions] -"'*'" = "relaybot" -'franzi.business' = "full" -"'@kunsi:franzi.business'" = "admin" - -[metadata.mautrix-whatsapp] -version = "v0.12.0" -sha1 = "02094da0a164099d4d35e5edb4b87875ad694833" -permissions."'@kunsi:franzi.business'" = "admin" -[metadata.mautrix-whatsapp.homeserver] -domain = "franzi.business" -url = "https://matrix.franzi.business" - -[metadata.miniflux] -domain = "rss.franzi.business" - -[metadata.netbox] -domain = "netbox.franzi.business" -version = "v4.2.8" -admins.kunsi = "hostmaster@kunbox.net" - -[metadata.nextcloud] -domain = "warnochwas.de" - -[metadata.nginx.'security.txt'] -contact = "mailto:security@kunsmann.eu" -Encryption = "https://franzi.business/gpg_hi-kunsmann.eu.asc" - -[metadata.nginx.vhosts.'afra.berlin'.locations.'/'] -redirect = "https://afra-berlin.de" -mode = 302 - -[metadata.nginx.vhosts.forgejo] -domain_aliases = ["git.kunsmann.eu"] - -[metadata.nginx.vhosts.'franzi.business'] -domain = "franzi.business" -webroot_config.owner = "kunsi" - -[metadata.nginx.vhosts.'gaenseblum.eu'.webroot_config] -owner = "skye" - -[metadata.nginx.vhosts.kunsitracker] -domain = "kunsitracker.de" -locations.'/'.target = "https://travelynx.franzi.business/" -locations.'/'.proxy_pass_host = "travelynx.franzi.business" -locations.'= /'.target = "https://travelynx.franzi.business/p/Kunsi" -locations.'= /'.proxy_pass_host = "travelynx.franzi.business" - -[metadata.nginx.vhosts.mta-sts] -domain = "mta-sts.kunbox.net" -domain_aliases = [ - "mta-sts.franzi.business", - "mta-sts.kunsmann.eu", -] -force_domain = false - -[metadata.nginx.vhosts.redirector] -domain = "kunbox.net" -domain_aliases = [ - "carlene.kunbox.net", - "kunsmann.eu", -] -[metadata.nginx.vhosts.redirector.locations.'/'] -redirect = "https://franzi.business/" -[metadata.nginx.vhosts.redirector.locations.'/.well-known/openpgpkey/'] -alias = "/var/www/franzi.business/.well-known/openpgpkey" -additional_config = [ - "add_header Access-Control-Allow-Origin *", - "default_type application/octet-stream", -] - -[metadata.ntfy] -domain = "ntfy.franzi.business" -ratelimit-exempt-hosts = [ - "carlene", - "icinga2", -] - -[metadata.php] -packages = [ - 'gd', - 'imagick', - 'imap', - 'intl', - 'mbstring', - 'opcache', - 'pgsql', - 'readline', - 'xml', - 'yaml', -] - -[metadata.postfix] -message_size_limit_mb = 100 -myhostname = "mail.franzi.business" -blocked_recipients = [ - "!decrypt:encrypt$gAAAAABlrPHMqx7o9pscfSx4Elayrzwun9jcTYOM4XrcAoUWaHJ9vP_7P5G7V3nwdB8pWfObNew-2IOihn5EPS-0ej2gn9rI4iDnMG_6S2IBCDYMqZMn1W0=", # deadname - "tectu@kunsmann.eu", -] - -[metadata.postfixadmin] -domain = "postfixadmin.franzi.business" -setup_password = "!decrypt:encrypt$gAAAAABgnNGpAqUs--qBXII9ZPcHtxaELy9e2Dx9O44n4l0O4nMHPoIyaPW5HkvpQ2zWTlh5OfjjOgunRtE_voJuY0Kdtji37ixAnuL9ErOJ0LDY5QfMkNPUgPs5alwz1baqYq6rqJ7NDmB0gHraY46v5eG79R2EyQ==" -version = "3.3.15" - -[metadata.postgresql] -version = 15 - -[metadata.rspamd] -ignore_spam_check_for_ips = [ - # entropia - '45.140.180.32/27', # Entropia e. V. - '45.140.180.112/28', # MicroPOC - '2a0e:c5c0:0:201::/64', # Entropia e. V. - '2a0e:c5c0:0:307::/64', # MicroPOC - - # c3kl - '116.202.19.236', - '2a01:4f8:1c17:cc52::/64', - - # ccc - '212.12.55.65', - '212.12.55.67', - '2a00:14b0:4200:3000:23:55:0:65', - - # IN-Berlin mailman - '130.133.8.35', - '192.109.42.28', - '192.109.42.122', - '193.29.188.9', - '217.197.80.23', - '217.197.80.134', - '2001:bf0:c000:a::2:134', - - # c3voc - '185.106.84.32/26', - '2001:67c:20a0:e::/64', - - # DENOG - '195.20.121.100', - '2001:1440:201:101::5', -] -password = "!bwpass:bw/rx300/rspamd" -dkim = "uO4aNejDvVdw8BKne3KJIqAvCQMJ0416" - -[metadata.smartd] -disks = [ - "/dev/disk/by-id/nvme-SAMSUNG_MZVL22T0HBLB-00B00_S677NF0W503350", - "/dev/disk/by-id/nvme-SAMSUNG_MZVL22T0HBLB-00B00_S677NX0W114380", -] - -[metadata.systemd-timers.timers.42c3-topic] -command = "/home/kunsi/42c3-topic.sh" -user = "kunsi" -when = "04:00:00 Europe/Berlin" - -[metadata.travelynx] -version = "2.11.23" -mail_from = "travelynx@franzi.business" -domain = "travelynx.franzi.business" - -[metadata.users.skye] -ssh_pubkey = [ - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCO0KG3/hnMO6UsReyEHvV4y7fYmJGQeCVnmw2xUoM4so2ZacWDi27aQbMq6wWb/JsUh4j3OOvEfNvf27LU6wpqcxM/QO22YjLsOtVzVnGjupsKAnN/nKy+X7KhspaF9qKFpmseBpuEAAnaxnreEFNC2tHarzJzgj+Y+Bmkg4tnMWsVc6EoBp1R2xmsdeRtgcQwms3xX9COeAjkFNgniGfqigO2AxPgC68h3GqSlcPzgpJ7ukvtCRCs/g3R+9GCnxsamd3AYhaRCIKauIyA44WqtH8lAH5+g16tU8WYcK1KySuwLt418kXDDJrZXaOLbxRl+jrShIdPoGhqs1y6KlOVTbj9TBVGt8CtV8JsLwzH2GCdLjImcXWUob2j2sxgBGTWiTfWf98XBLmBQwbAlBJ01gsHhJxDx0E2ttxueSjyg4hTzWCH0TlRmbpUDdIlqLgwHxmh97YFF5oqkgWGjSt7jxrW8Q9+FeMi5L2qHzKez5Z3quOhDIXWjEcpxqQQ2Lc=", -] - -[metadata.weechat] -user = "kunsi" -relay_domain = "irc.franzi.business" - -[[metadata.zfs.pools.tank.when_creating.config]] -devices = [ - "/dev/nvme0n1p3", - "/dev/nvme1n1p3", -] -type = "mirror" - -[metadata.zfs.datasets.tank] -primarycache = "metadata" - -[metadata.zfs.datasets.'tank/sewfile'] -mountpoint = "/mnt/sewfile/" - -[metadata.vm] -cpu = 24 -ram = 64 diff --git a/nodes/entropia-jira.toml b/nodes/entropia-jira.toml new file mode 100644 index 0000000..d648b3a --- /dev/null +++ b/nodes/entropia-jira.toml @@ -0,0 +1,17 @@ +hostname = "45.140.180.45" +dummy = true + +[metadata.icinga_options] +period = "daytime" +pretty_name = "ticket.gulas.ch" + +[metadata.icinga2_api.nginx.services."NGINX VHOST jira CERTIFICATE"] +check_command = "check_https_cert_at_url" +"vars.domain" = "ticket.gulas.ch" +"vars.notification.mail" = true + +[metadata.icinga2_api.nginx.services."NGINX VHOST jira CONTENT"] +check_command = "check_http_wget" +"vars.http_wget_contains" = "login.jsp" +"vars.http_wget_url" = "https://ticket.gulas.ch/secure/Dashboard.jspa" +"vars.notification.sms" = true diff --git a/nodes/fkusei-locutus.py b/nodes/fkusei-locutus.py new file mode 100644 index 0000000..7340a46 --- /dev/null +++ b/nodes/fkusei-locutus.py @@ -0,0 +1,189 @@ +nodes['fkusei-locutus'] = { + 'hostname': '172.19.138.96', + 'bundles': { + 'arch-with-gui', + 'bird', + 'lldp', + 'lm-sensors', + 'nfs-client', + 'systemd-boot', + 'telegraf-battery-usage', + 'wireguard', + 'voc-tracker-worker', + 'zfs', + }, + 'groups': { + 'arch', + }, + 'metadata': { + 'arch-with-gui': { + 'autologin_as': 'fkunsmann', + }, + 'bird': { + 'bgp_neighbors': { + 'smedia': { + 'local_as': 4200128002, + 'local_ip': '10.200.128.2', + 'neighbor_as': 64900, + 'neighbor_ip': '10.200.128.1', + }, + }, + }, + 'firewall': { + 'port_rules': { + # obs websocket thingie - just allow all RFC1918 ips here + #'4444': { + # '10.0.0.0/8', + # '172.16.0.0/12', + # '192.168.0.0/16', + #}, + # For the occasional file-share using `python -m http.server` + '8000': {'*'}, + }, + }, + 'interfaces': { + 'enp0s31f6': { + 'dhcp': True, + 'ips': { + '172.19.138.96', # for static dhcp lease + }, + 'mac': 'e8:6a:64:ef:cc:5c', + }, + # there is also wlp2s0, but that's managed by netctl + }, + 'location': 'home', # not actually true, but needed for static dhcp lease + 'nfs-client': { + 'mounts': { + 'nas-storage': { + 'mountpoint': '/mnt/nas', + 'serverpath': '172.19.138.20:/storage/nas', + 'mount_options': { + 'retry=0', + 'ro', + }, + }, + }, + }, + 'openssh': { + 'restrict-to': { + 'rfc1918', + 'ipv6', + }, + }, + 'pacman': { + 'linux-lts': True, + 'packages': { + # video drivers + 'xf86-video-intel': {}, + + # for i3pystatus + 'iw': {}, + 'wireless_tools': {}, + + # all that other random stuff one needs + 'apachedirectorystudio': {}, + 'direnv': {}, + 'freerdp': {}, + 'mosquitto': {}, + 'sdl_ttf': {}, # for compiling testcard + 'thermald': {}, + 'virt-manager': {}, + }, + }, + 'systemd-boot': { + 'default': 'arch-lts', + 'entries': { + 'arch-lts': { + 'title': 'Arch Linux (LTS kernel)', + 'linux': '/vmlinuz-linux-lts', + 'initrd': [ + '/intel-ucode.img', + '/initramfs-linux-lts.img', + ], + 'options': { + 'zfs=zroot/system/root', + 'rw', + }, + }, + 'arch-lts-fallback': { + 'title': 'Arch Linux (LTS kernel, no ucode, fallback initramfs)', + 'linux': '/vmlinuz-linux-lts', + 'initrd': [ + '/initramfs-linux-lts-fallback.img', + ], + 'options': { + 'zfs=zroot/system/root', + 'rw', + }, + }, + }, + }, + 'timezone': 'Europe/Berlin', + 'users': { + 'fkunsmann': { + 'password': vault.decrypt('encrypt$gAAAAABgLmmuQGRUStrQawoPee-758emIYn2u8-8ebrgzNAFSp7ifeFDdXXvs-zL3QogwNYlCtBHboH2xfy1rSj6OF5bbNO-tg=='), + 'shell': '/usr/bin/fish', + 'sudo_commands': { + 'ALL', + }, + }, + 'sophie': { + 'delete': True, + }, + }, + 'voc-tracker-worker': { + 'url': 'https://tracker.c3voc.de/rpc', + 'token': vault.decrypt('encrypt$gAAAAABiYqaFl4CqOc8DTQIn49Qq0KgAJSzA19GKPNMbyHIjYg0JkvY0sK43ps8CbJWMRR6hJHVK-nP4vrWLwyoWWqt8N8aASMur4odC2s8pEHQKM0TXg4cRwobQz_lyJgrYa2VYdhcD'), + 'secret': vault.decrypt('encrypt$gAAAAABiYqaYbY-3IbnRk-S25pqxrOGN7ovgPo3kBYz8ZqKDedPRzskKZefpLHxBbCOZKjg1XNT4cKbIs5cPCLdj7HdY4beAhnXl4EHZZdxU1zVC7sJCmz9XOS_Ac0UOgOlUFMiet14U'), + }, + 'wireguard': { + 'privatekey': vault.decrypt('smedia$NotViaThisRepository'), + 'peers': { + 'smedia': { + 'my_ip': '10.200.128.2/20', + 'my_port': 51820, + 'endpoint': '185.122.180.82:51820', + 'psk': vault.decrypt('smedia$NotViaThisRepository'), + 'pubkey': vault.decrypt('smedia$NotViaThisRepository'), + }, + }, + }, + 'zfs': { + 'datasets': { + # this is not a complete list, but we can't create that + # structure using bundlewrap anyway, so there's no point + # in adding it here. + 'zroot': { + 'compression': 'lz4', + 'relatime': 'on', + 'xattr': 'sa', + 'primarycache': 'metadata' + # encryption is enabled, too. + }, + 'zroot/system/journal': { + 'mountpoint': '/var/log/journal', + 'acltype': 'posix', + }, + 'zroot/system/root': { + 'canmount': 'noauto', + 'mountpoint': '/', + }, + 'zroot/user/fkunsmann': { + 'mountpoint': '/home/fkunsmann', + }, + }, + 'snapshots': { + 'retain_per_dataset': { + 'zroot/user/fkunsmann': { + # juuuuuuuust to be sure + 'hourly': 100, + }, + }, + 'snapshot_never': { + 'zroot/system/journal', + }, + }, + }, + }, + 'os': 'arch', +} diff --git a/nodes/gce/README b/nodes/gce/README new file mode 100644 index 0000000..2ca735d --- /dev/null +++ b/nodes/gce/README @@ -0,0 +1 @@ +Google Compute Engine diff --git a/nodes/gce/bind01.py b/nodes/gce/bind01.py new file mode 100644 index 0000000..3dce25c --- /dev/null +++ b/nodes/gce/bind01.py @@ -0,0 +1,62 @@ +# ns-1.kunbox.net +# Frankfurt, Germany + +nodes['gce.bind01'] = { + 'hostname': '34.89.208.78', + 'bundles': { + 'nodejs', + 'powerdnsadmin', + }, + 'groups': { + 'debian-buster', + 'dns', + 'webserver', + }, + 'metadata': { + 'backups': { + # This is the primary DNS server. However, we only use + # replication for DynDNS, currently. No need for backups here. + 'exclude_from_backups': True, + }, + 'interfaces': { + 'ens4': { + 'ips': { + '10.156.0.4', + }, + 'gateway4': '10.156.0.1', + }, + }, + 'external_ipv4': '34.89.208.78', + 'icinga_options': { + 'pretty_name': 'ns-1.kunbox.net', + }, + 'nginx': { + 'vhosts': { + 'ns-1.kunbox.net': { + 'locations': { + '/': { + 'target': 'http://127.0.0.1:8000/', + }, + }, + 'website_check_path': '/login', + 'website_check_string': 'PowerDNS', + }, + }, + }, + 'postgresql': { + 'version': '11', + }, + 'powerdns': { + 'is_secondary': False, + 'secondary_nameservers': 'dns', + 'my_hostname': 'ns-1.kunbox.net', + }, + 'powerdnsadmin': { + 'version': 'v0.3.0', + }, + 'vm': { + 'cpu': 1, + 'ram': 1, + }, + }, +} diff --git a/nodes/gce/dns02.py b/nodes/gce/dns02.py new file mode 100644 index 0000000..def2765 --- /dev/null +++ b/nodes/gce/dns02.py @@ -0,0 +1,38 @@ +# ns-2.kunbox.net +# Belgium + +nodes['gce.dns02'] = { + 'hostname': '35.187.109.249', + 'bundles': set(), + 'groups': { + 'debian-buster', + 'dns', + }, + 'metadata': { + 'interfaces': { + 'ens4': { + 'ips': { + '10.132.0.2', + }, + 'gateway4': '10.132.0.1', + }, + }, + 'external_ipv4': '35.187.109.249', + 'icinga_options': { + 'pretty_name': 'ns-2.kunbox.net', + }, + 'backups': { + 'exclude_from_backups': True, + }, + 'postgresql': { + 'version': '11', + }, + 'powerdns': { + 'my_hostname': 'ns-2.kunbox.net', + }, + 'vm': { + 'cpu': 1, + 'ram': 1, + }, + }, +} diff --git a/nodes/gce/dns03.py b/nodes/gce/dns03.py new file mode 100644 index 0000000..fb23f27 --- /dev/null +++ b/nodes/gce/dns03.py @@ -0,0 +1,38 @@ +# ns-3.kunbox.net +# Finland + +nodes['gce.dns03'] = { + 'hostname': '35.228.143.71', + 'bundles': set(), + 'groups': { + 'debian-buster', + 'dns', + }, + 'metadata': { + 'interfaces': { + 'ens4': { + 'ips': { + '10.166.0.2', + }, + 'gateway4': '10.166.0.1', + }, + }, + 'external_ipv4': '35.228.143.71', + 'icinga_options': { + 'pretty_name': 'ns-3.kunbox.net', + }, + 'backups': { + 'exclude_from_backups': True, + }, + 'postgresql': { + 'version': '11', + }, + 'powerdns': { + 'my_hostname': 'ns-3.kunbox.net', + }, + 'vm': { + 'cpu': 1, + 'ram': 1, + }, + }, +} diff --git a/nodes/home.appletv-wohnzimmer.toml b/nodes/home.appletv-wohnzimmer.toml deleted file mode 100644 index 5febb38..0000000 --- a/nodes/home.appletv-wohnzimmer.toml +++ /dev/null @@ -1,9 +0,0 @@ -dummy = true - -[metadata.interfaces.default] -ips = ["172.19.138.73"] -dhcp = true -mac = "c0:95:6d:5e:82:47" - -[metadata.icinga_options] -exclude_from_monitoring = true diff --git a/nodes/home.aruba325-office.toml b/nodes/home.aruba325-office.toml deleted file mode 100644 index 1515e76..0000000 --- a/nodes/home.aruba325-office.toml +++ /dev/null @@ -1,6 +0,0 @@ -dummy = true - -[metadata.interfaces.eth0] -ips = ["172.19.138.53"] -dhcp = true -mac = "f0:5c:19:cf:9e:72" diff --git a/nodes/home.aruba325-schlafzimmer.toml b/nodes/home.aruba325-schlafzimmer.toml deleted file mode 100644 index 27be1ce..0000000 --- a/nodes/home.aruba325-schlafzimmer.toml +++ /dev/null @@ -1,6 +0,0 @@ -dummy = true - -[metadata.interfaces.eth0] -ips = ["172.19.138.52"] -dhcp = true -mac = "b4:5d:50:c7:11:78" diff --git a/nodes/home.aruba325-wohnzimmer.toml b/nodes/home.aruba325-wohnzimmer.toml deleted file mode 100644 index e3263fd..0000000 --- a/nodes/home.aruba325-wohnzimmer.toml +++ /dev/null @@ -1,6 +0,0 @@ -dummy = true - -[metadata.interfaces.eth0] -ips = ["172.19.138.51"] -dhcp = true -mac = "f0:5c:19:cf:9f:7e" diff --git a/nodes/home.encoder96.toml b/nodes/home.encoder96.toml deleted file mode 100644 index ca9bdce..0000000 --- a/nodes/home.encoder96.toml +++ /dev/null @@ -1,9 +0,0 @@ -dummy = true - -[metadata.interfaces.default] -ips = ["172.19.138.99"] -dhcp = true -mac = "6c:4b:90:5c:e3:6d" - -[metadata.icinga_options] -exclude_from_monitoring = true diff --git a/nodes/home.fujitsu-n7100.toml b/nodes/home.fujitsu-n7100.toml deleted file mode 100644 index 07d51c0..0000000 --- a/nodes/home.fujitsu-n7100.toml +++ /dev/null @@ -1,9 +0,0 @@ -dummy = true - -[metadata.interfaces.default] -ips = ["172.19.138.75"] -dhcp = true -mac = "00:01:29:59:a9:8c" - -[metadata.icinga_options] -exclude_from_monitoring = true diff --git a/nodes/home.hass.toml b/nodes/home.hass.toml deleted file mode 100644 index afb204f..0000000 --- a/nodes/home.hass.toml +++ /dev/null @@ -1,32 +0,0 @@ -hostname = "172.19.138.25" -bundles = [ - 'homeassistant', - 'nginx', - 'pyenv', -] -groups = ["debian-bookworm"] - -[metadata.icinga_options] -also_affected_by = ['home.nas'] - -[metadata.interfaces.enp1s0] -ips = [ - "172.19.138.25/24", -] -gateway4 = "172.19.138.1" -ipv6_accept_ra = true - -[metadata.vm] -cpu = 2 -ram = 2 - -[metadata.homeassistant] -domain = 'hass.home.kunbox.net' -api_secret = '!decrypt:encrypt$gAAAAABm9lNg_mNhyzb4S6WRtVRDmQFBnPpoCwyqMnilRrAFUXc-EDvv-nYXPbSIbjTf7ZReTPtqr8k3WrGPqiuqhJ60LVv4A5DMqT5c6hTVr4WbhP4DPEIPgfd5aq6U9_-H9WDyQYHKjnunLJEYtEREzmhTq3XsYeQ05DyE7hfnQ-zVoBb0CsAK7GdhihRTdvhXv2N9M04_rigyBP-roRcUgCqwyHuWJc0IPAyn3R4Mr43ZqgR2fn6dNV_YUVKn9c0nWxIwRnYy6Ff_Te9NoGVmXxkiNUX-90bBLKFiCzrRAtizxrTiQb2SRipaWbgOlV6wbMy2KNux' - -[metadata.pyenv] -version = 'v2.4.23' -python_versions = ["3.13.1"] - -[metadata.nginx.vhosts.homeassistant] -ssl = '_.home.kunbox.net' diff --git a/nodes/home.lgtv-wohnzimmer.toml b/nodes/home.lgtv-wohnzimmer.toml deleted file mode 100644 index 611e16a..0000000 --- a/nodes/home.lgtv-wohnzimmer.toml +++ /dev/null @@ -1,9 +0,0 @@ -dummy = true - -[metadata.interfaces.default] -ips = ["172.19.138.72"] -dhcp = true -mac = "ac:5a:f0:32:05:7b" - -[metadata.icinga_options] -exclude_from_monitoring = true diff --git a/nodes/home.mixer96.toml b/nodes/home.mixer96.toml deleted file mode 100644 index 815205f..0000000 --- a/nodes/home.mixer96.toml +++ /dev/null @@ -1,9 +0,0 @@ -dummy = true - -[metadata.interfaces.default] -ips = ["172.19.138.98"] -dhcp = true -mac = "54:e1:ad:a6:0d:1f" - -[metadata.icinga_options] -exclude_from_monitoring = true diff --git a/nodes/home.o2-joggler.toml b/nodes/home.o2-joggler.toml deleted file mode 100644 index 8dffb68..0000000 --- a/nodes/home.o2-joggler.toml +++ /dev/null @@ -1,16 +0,0 @@ -hostname = "172.19.138.95" -dummy = true -# - -[metadata.interfaces.eth0] -# only used for debugging, device uses wifi otherwise -ips = ["169.254.172.100"] -mac = "9a:d0:d7:e7:b0:bb" - -[metadata.interfaces.wlan0] -ips = ["172.19.138.94"] -dhcp = true -mac = "00:0e:8e:22:9c:9b" - -[metadata.icinga_options] -exclude_from_monitoring = true diff --git a/nodes/home.r630.toml b/nodes/home.r630.toml deleted file mode 100644 index f41bb19..0000000 --- a/nodes/home.r630.toml +++ /dev/null @@ -1,33 +0,0 @@ -hostname = "172.19.138.22" -groups = ["debian-bookworm"] -bundles = ["docker-engine", "nginx", "redis"] - -ipmi_hostname = "172.19.138.23" -ipmi_username = "root" -ipmi_password = "calvin" -ipmi_interface = "lanplus" - -[metadata] -icinga_options.exclude_from_monitoring = true -backups.exclude_from_backups = true - -[metadata.interfaces.eno3] -ips = [ - "172.19.138.22/24", -] -gateway4 = "172.19.138.1" -ipv6_accept_ra = true - -[metadata.nftables.forward] -50-local-forward = [ - 'ct state { related, established } accept', - 'iifname eno3 accept', - 'ip6 nexthdr ipv6-icmp accept', -] - -[metadata.users.molly] -password = "!decrypt:dummy$no" - -[metadata.vm] -cpu = 56 -ram = 128 diff --git a/nodes/home.snom-wohnzimmer.toml b/nodes/home.snom-wohnzimmer.toml deleted file mode 100644 index 65d8eda..0000000 --- a/nodes/home.snom-wohnzimmer.toml +++ /dev/null @@ -1,6 +0,0 @@ -dummy = true - -[metadata.interfaces.default] -ips = ["172.19.138.40"] -dhcp = true -mac = "00:04:13:26:EE:1B" diff --git a/nodes/home.switch-rack.toml b/nodes/home.switch-rack.toml deleted file mode 100644 index 57014f0..0000000 --- a/nodes/home.switch-rack.toml +++ /dev/null @@ -1,3 +0,0 @@ -groups = ["switches-mikrotik"] -hostname = "172.19.138.4" -password = "encrypt$gAAAAABkI1Eqsust7XuYFK2-FaRzXWM5fOXumhdi5fWNokLtM0CBAqVqc5zcg37XH_JIZvkhp3buKvswcvd_znaV3Rb8kKeJTs4_VJo6OsvbiWkujfT50HspoUXER0JSZSmeZts8a_2i" diff --git a/nodes/home.usv01.toml b/nodes/home.usv01.toml deleted file mode 100644 index 2125fdb..0000000 --- a/nodes/home.usv01.toml +++ /dev/null @@ -1,8 +0,0 @@ -dummy = true - -[metadata.interfaces.default] -ips = ["172.19.138.3"] - -[metadata.icinga2_api.usv.services."USV STATUS"] -check_command = "check_usv" -"vars.notification.mail" = true diff --git a/nodes/home.winkeeinhorn-vm.toml b/nodes/home.winkeeinhorn-vm.toml deleted file mode 100644 index c28c39b..0000000 --- a/nodes/home.winkeeinhorn-vm.toml +++ /dev/null @@ -1,15 +0,0 @@ -dummy = true - -[metadata.icinga_options] -also_affected_by = ['home.nas'] - -[metadata.interfaces.default] -ips = ["172.19.138.10"] -dhcp = true -mac = "52:54:00:b0:4e:4d" - -[metadata.icinga2_api.freifunk.services."NODE HEALTH"] -check_command = "check_freifunk_node" -"vars.url" = "https://map.freifunk-mwu.de/data/meshviewer.json" -"vars.id" = "525400b04e4d" -"vars.notification.mail" = true diff --git a/nodes/home.wled-aftonsparv.toml b/nodes/home.wled-aftonsparv.toml deleted file mode 100644 index 661a403..0000000 --- a/nodes/home.wled-aftonsparv.toml +++ /dev/null @@ -1,9 +0,0 @@ -dummy = true - -[metadata.interfaces.default] -ips = ["172.19.138.71"] -dhcp = true -mac = "84:fc:e6:11:34:80" - -[metadata.icinga_options] -exclude_from_monitoring = true diff --git a/nodes/home.wled-raketenlaemp.toml b/nodes/home.wled-raketenlaemp.toml deleted file mode 100644 index a151839..0000000 --- a/nodes/home.wled-raketenlaemp.toml +++ /dev/null @@ -1,9 +0,0 @@ -dummy = true - -[metadata.interfaces.default] -ips = ["172.19.138.74"] -dhcp = true -mac = "84:fc:e6:11:34:74" - -[metadata.icinga_options] -exclude_from_monitoring = true diff --git a/nodes/home/bubble01.py b/nodes/home/bubble01.py new file mode 100644 index 0000000..6dedcfe --- /dev/null +++ b/nodes/home/bubble01.py @@ -0,0 +1,13 @@ +# Mitel RFP35 +nodes['home.bubble01'] = { + 'dummy': True, + 'metadata': { + 'interfaces': { + 'default': { + 'ips': { + '172.19.138.41', + }, + }, + }, + }, +} diff --git a/nodes/home/downloadhelper.py b/nodes/home/downloadhelper.py index 4bd2f10..56a3b7d 100644 --- a/nodes/home/downloadhelper.py +++ b/nodes/home/downloadhelper.py @@ -5,26 +5,21 @@ nodes['home.downloadhelper'] = { 'transmission', }, 'groups': { - 'debian-bullseye', + 'debian-buster', }, 'metadata': { - 'icinga_options': { - 'also_affected_by': { - 'home.nas', - }, - }, 'interfaces': { - 'enp1s0.3001': { + 'enp1s0.8': { 'dhcp': True, 'send_hostname': False, }, - 'enp1s0.1138': { + 'enp1s0.42': { 'ips': { '172.19.138.27/24', }, 'routes': { # VPN - '172.19.128.0/20': { + '172.19.136.0/22': { 'via': '172.19.138.1', }, }, @@ -35,14 +30,14 @@ nodes['home.downloadhelper'] = { }, 'lldp': { 'interfaces': { - 'enp1s0.1138', + 'enp1s0.42', }, }, 'nfs-client': { 'mounts': { 'storage': { 'mountpoint': '/mnt/nas', - 'serverpath': '172.19.138.20:/mnt/download', + 'serverpath': '172.19.138.20:/storage/download', 'mount_options': { 'retry=0', 'rw', @@ -56,7 +51,7 @@ nodes['home.downloadhelper'] = { 'download-queue-size': 10, }, 'restrict-to': { - '172.19.128.0/20', + '172.19.136.0/22', }, }, }, diff --git a/nodes/home/drucker-sophie.py b/nodes/home/drucker-sophie.py new file mode 100644 index 0000000..98b349f --- /dev/null +++ b/nodes/home/drucker-sophie.py @@ -0,0 +1,14 @@ +nodes['home.drucker-sophie'] = { + 'dummy': True, + 'metadata': { + 'interfaces': { + 'default': { + 'ips': { + '172.19.138.61', + }, + 'dhcp': True, + 'mac': '00:14:38:9E:29:E3', + }, + }, + }, +} diff --git a/nodes/home/ejgwdesk.py b/nodes/home/ejgwdesk.py new file mode 100644 index 0000000..ba5c76d --- /dev/null +++ b/nodes/home/ejgwdesk.py @@ -0,0 +1,17 @@ +nodes['home.ejgwdesk'] = { + 'dummy': True, + 'metadata': { + 'interfaces': { + 'default': { + 'ips': { + '172.19.138.99', + }, + 'dhcp': True, + 'mac': '54:04:A6:EF:A8:01', + }, + }, + 'icinga_options': { + 'exclude_from_monitoring': True, + }, + }, +} diff --git a/nodes/home/home.sw02.toml b/nodes/home/home.sw02.toml new file mode 100644 index 0000000..8e4520a --- /dev/null +++ b/nodes/home/home.sw02.toml @@ -0,0 +1,5 @@ +hostname = "172.19.138.4" +groups = ["junos"] + +[metadata.junos] +version = ["15", "1R5", "5"] diff --git a/nodes/home/kodi-wohnzimmer.py b/nodes/home/kodi-wohnzimmer.py new file mode 100644 index 0000000..d91fca5 --- /dev/null +++ b/nodes/home/kodi-wohnzimmer.py @@ -0,0 +1,53 @@ +nodes['home.kodi-wohnzimmer'] = { + 'hostname': '172.19.138.24', + 'bundles': { + 'lm-sensors', + 'kodi', + 'nfs-client', + 'smartd', + }, + 'groups': { + 'debian-bullseye', + }, + 'metadata': { + 'apt': { + 'packages': { + 'intel-media-va-driver-non-free': {}, + }, + 'unattended-upgrades': { + 'day': 6, + 'hour': 2, + }, + }, + 'interfaces': { + 'eno1': { + 'ips': { + '172.19.138.24/24', + }, + 'gateway4': '172.19.138.1', + 'ipv6_accept_ra': True, + }, + }, + 'nfs-client': { + 'mounts': { + 'nas-storage': { + 'mountpoint': '/mnt/nas', + 'serverpath': '172.19.138.20:/storage/nas', + 'mount_options': { + 'retry=0', + 'ro', + }, + }, + }, + }, + 'smartd': { + 'disks': { + '/dev/nvme0', + }, + }, + 'vm': { + 'cpu': 2, + 'ram': 4, + }, + }, +} diff --git a/nodes/home/nas.py b/nodes/home/nas.py index ebfdc2c..34ae010 100644 --- a/nodes/home/nas.py +++ b/nodes/home/nas.py @@ -3,26 +3,22 @@ nodes['home.nas'] = { 'hostname': '172.19.138.20', 'bundles': { - 'avahi-daemon', 'backup-client', - 'jellyfin', 'lm-sensors', 'mixcloud-downloader', 'mosquitto', 'nfs-server', - 'rsyslogd', - 'samba', + 'scansnap', 'smartd', 'vmhost', 'zfs', }, 'groups': { 'debian-bullseye', - 'webserver', }, 'metadata': { 'interfaces': { - 'br1138': { + 'br42': { 'ips': { '172.19.138.20/24', }, @@ -39,10 +35,6 @@ nodes['home.nas'] = { 'packages': { 'mpv': {}, - # for hardware transcoding of video - 'firmware-amd-graphics': {}, - 'mesa-va-drivers': {}, - # for compiling yate 'autoconf': {}, 'subversion': {}, @@ -55,17 +47,15 @@ nodes['home.nas'] = { # systemctl start yate }, }, - 'avahi-daemon': { - 'use-ipv6': False, # because having a dynamic address confuses the network somehow - }, 'backups': { 'paths': { - '/storage/nas/', - }, - }, - 'cron': { - 'jobs': { - 'avahi-aruba-fixup': '17,47 * * * * root /usr/bin/systemctl restart avahi-daemon.service', + '/storage/nas/Audiobooks', + '/storage/nas/Bilder', + '/storage/nas/Bilder_Archiv', + '/storage/nas/Books', + '/storage/nas/Musik', + '/storage/nas/Musikvideos', + '/storage/nas/normen', }, }, 'groups': { @@ -73,15 +63,17 @@ nodes['home.nas'] = { }, 'firewall': { 'port_rules': { - '4679/tcp': { # Dell ULNM + '4679': { # Dell ULNM '172.19.136.0/25', '172.19.138.0/24', }, - '5060/tcp': { # yate SIP + '5060': { # yate SIP 'home.snom-wohnzimmer', + 'home.bubble01', }, - '5061/tcp': { # yate SIPS + '5061': { # yate SIPS 'home.snom-wohnzimmer', + 'home.bubble01', }, # yate RTP uses some random UDP port. We cannot firewall # it, because for incoming calls the other side decides @@ -91,14 +83,7 @@ nodes['home.nas'] = { # to deal with randomly changing IPs here. '*/udp': { 'home.snom-wohnzimmer', - }, - }, - }, - 'mixcloud-downloader': { - 'netrc': { - 'soundcloud': { - 'username': 'oauth', - 'password': bwpass.attr('soundcloud.com/hi@kunsmann.eu', 'oauth_token'), + 'home.bubble01', }, }, }, @@ -129,77 +114,57 @@ nodes['home.nas'] = { 'restrict-to': { '172.19.136.0/25', '172.19.138.0/24', - 'htz-cloud.molly-connector', }, }, 'nfs-server': { 'shares': { - '/mnt/download': { + '/storage/download': { 'home.downloadhelper': 'rw,all_squash,anonuid=65534,anongid=1012,no_subtree_check', }, '/storage/nas': { - '172.19.138.0/24': 'ro,all_squash,anonuid=65534,anongid=65534,no_subtree_check,insecure', + '172.19.138.0/24': 'ro,all_squash,anonuid=65534,anongid=65534,no_subtree_check', }, '/srv/paperless': { 'home.paperless': 'rw,all_squash,anonuid=65534,anongid=65534,no_subtree_check', }, - }, - }, - 'nginx': { - 'vhosts': { - 'jellyfin': { - 'create_logs': True, - 'domain': 'jellyfin.home.kunbox.net', - 'ssl': '_.home.kunbox.net', + '/srv/scansnap': { + '172.19.138.0/24': 'rw,all_squash,anonuid=65534,anongid=65534,no_subtree_check', }, }, }, - 'rsyslogd': { - 'restrict-to': { - 'home', - }, - }, - 'samba': { - 'restrict-to': { - '172.19.138.0/24', - }, - 'timemachine-shares': { - 'apfelcomputer', - 'verrat', - }, - }, 'smartd': { 'disks': { '/dev/nvme0', - # nas/timemachine disks - '/dev/disk/by-id/ata-WDC_WD6003FFBX-68MU3N0_V8GE15GR', - '/dev/disk/by-id/ata-WDC_WD6003FFBX-68MU3N0_V8HJ406R', - '/dev/disk/by-id/ata-WDC_WD6003FFBX-68MU3N0_V8HJBTLR', - '/dev/disk/by-id/ata-WDC_WD6003FFBX-68MU3N0_V8HJGN6R', - '/dev/disk/by-id/ata-WDC_WD6003FFBX-68MU3N0_V8J8ZKRR', - '/dev/disk/by-id/ata-WDC_WD6003FFBX-68MU3N0_V9JS5UYL', - - # ssdpool disks - '/dev/disk/by-id/ata-INTEL_SSDSC2KB960G8_PHYF244001QU960CGN', - '/dev/disk/by-id/ata-INTEL_SSDSC2KB960G8_PHYF244002AS960CGN', + # ZFS cache disks + '/dev/disk/by-id/ata-TS64GSSD370_B807810503', + '/dev/disk/by-id/ata-TS64GSSD370_B807810527', + }, + }, + 'sysctl': { + 'options': { + # XXX find out if this is really needed + 'net.ipv4.ip_forward': '1', }, }, 'systemd-networkd': { + 'bonds': { + 'bond0': { + 'match': { + 'enp8*', + 'enp9*', + }, + }, + }, 'bridges': { 'br0': { 'match': { - 'eno1', + 'bond0', }, }, - 'br1138': { + 'br42': { 'match': { - 'br0.1138', - }, - }, - 'br1139': { - 'match': { - 'br0.1139', + 'br0.42', }, }, }, @@ -210,8 +175,8 @@ nodes['home.nas'] = { 'nas_permissions': { 'command': [ 'chown -R :nas /storage/nas/', - r'find /storage/nas/ -type d -exec chmod 0775 {} \;', - r'find /storage/nas/ -type f -exec chmod 0664 {} \;', + 'find /storage/nas/ -type d -exec chmod 0775 {} \;', + 'find /storage/nas/ -type f -exec chmod 0664 {} \;', ], 'when': '*-*-* 02:00:00', }, @@ -221,37 +186,44 @@ nodes['home.nas'] = { 'enable_x_forwarding_for_admins': True, }, 'users': { - #'inbox': { - # 'ssh_pubkey': { - # #'command="/usr/share/rsync/scripts/rrsync -wo /storage/inbox/",no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding ', - # }, - #}, + 'f2k1de': { + 'ssh_pubkey': { + 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGrvhqC/tZzpLMs/qy+1xNSVi2mfn8LXPIEhh7dcGn9e', + 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDH5+j2vDW1FHSSEEI/Sf5qiKJq1uoxGO5BPv84mqohvol7GxDFObv69tn7g6HYfZY/SaS75C4ZXy+cKa0xy8UCpF0SBa2xHASkenS9v55oweDL4rYSPARzn2XKt3RFJG/d8V5NOWtcyq5DFSzewUF35E4hx1pUc/CIxgJEem5ZvzvN0hlIKXUN2djkVUx+mz6RryBysLTJEFBamjJxIkvDG/PZU73W4SHaKAYV4Ojz2NY7T5/NYKePfIU5F9pkE3RU0LRj58usvA1eP0PvEArWlGNCd8EJU+HQ5xr2dZ6MKPpEyG0KJkC88DuapeF5RwUV53ZhNpF+QgzpI72fH5up', + }, + }, + 'inbox': { + 'ssh_pubkey': { + #'command="/usr/share/rsync/scripts/rrsync -wo /storage/inbox/",no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding ', + 'command="/usr/share/rsync/scripts/rrsync -wo /storage/inbox/",no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDl9zOB7FBeqecfGBRQXZB9nM8e2HNIOKj7IhjgD47GUPh/niD4kUWfVsd6JiNs6RZZE7mQBAKD1wh3/sTd5Twn3ptMIZpoTrLAYEknICzdtwoLRlkHVfb3eK/Q9ufpOGV7Pd24viONSSWSgtd/GcXFCclpEtM06/47USwytFcN5NPmE3/yi68IKDSbIo3hWNo5ZUdeS7g0v+/uF/DkYMJRv0oQatcZx+P/yPLrKqekg/5nMw3RHRwcYVCDqoTc2KjAwWJQw1hOtt105tOpfmbo4eX9cmjcw3Eihwdyl+EeZelaTay1oIzHlKnuxp2oTI0O0KHNQngRt7YDgnEICY16SvyIOJD9ZOam1VeOr0+Z8QgPgGu82Wv+UG+/21yjIoB48VlkNNNpUBeGTBad23Cb+wHVFC5PIQN4iEH2i0PS0xVCIU2bOlXUPJx6/XK51vFoZdknH/8/Mr0jvMsw9i3QSrSy76AjxkexNYje0phNiseMRCakZ8uKdL2yA0g3P5s=', + }, + }, 'kunsi': { 'groups': { 'nas', }, }, + 'sophie': { + 'groups': { + 'nas', + }, + }, + 'qcn': { + 'ssh_pubkey': { + #'command="/usr/share/rsync/scripts/rrsync -ro /storage/nas/movies/",no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding ', + 'command="/usr/share/rsync/scripts/rrsync -ro /storage/nas/movies/",no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILAwUA5t2cSy9YD+ilu5nklvokSRAoNOq/gUV73/KTsv lexi@aranea', + 'command="/usr/share/rsync/scripts/rrsync -ro /storage/nas/movies/",no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC7cCmJ1+btuwpbGrGAuiK8R/hTMCK7CFK0aK2vPcSy+ lexi@kanaya', + 'command="/usr/share/rsync/scripts/rrsync -ro /storage/nas/movies/",no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILLx+8d429D1KjaqOaGRFK09j6j3/FuU4xQMsrNLdflg lexi@toriel', + 'command="/usr/share/rsync/scripts/rrsync -ro /storage/nas/Serien_Englisch/",no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPGPse+vv3+kHBYt6bdab/4AbP1hU34/3qH9SBuC8LCJ jenny@normandy', + }, + }, }, 'zfs': { 'module_options': { 'zfs_arc_max_gb': 8, }, 'pools': { - 'ssdpool': { - 'when_creating': { - 'config': [ - { - 'type': 'mirror', - 'devices': { - '/dev/disk/by-id/ata-INTEL_SSDSC2KB960G8_PHYF244001QU960CGN', - '/dev/disk/by-id/ata-INTEL_SSDSC2KB960G8_PHYF244002AS960CGN', - }, - }, - ], - 'ashift': 12, - }, - }, - 'tank': { + 'storage': { 'when_creating': { 'config': [ { @@ -261,58 +233,81 @@ nodes['home.nas'] = { '/dev/disk/by-id/ata-WDC_WD6003FFBX-68MU3N0_V8HJ406R', '/dev/disk/by-id/ata-WDC_WD6003FFBX-68MU3N0_V8HJBTLR', '/dev/disk/by-id/ata-WDC_WD6003FFBX-68MU3N0_V8HJGN6R', - '/dev/disk/by-id/ata-WDC_WD6003FFBX-68MU3N0_V9JS5UYL', + '/dev/disk/by-id/ata-WDC_WD6003FFBX-68MU3N0_V8HJU4NR', '/dev/disk/by-id/ata-WDC_WD6003FFBX-68MU3N0_V8J8ZKRR', }, }, + { + 'type': 'log', + 'devices': { + '/dev/disk/by-id/ata-TS64GSSD370_B807810503-part1', + '/dev/disk/by-id/ata-TS64GSSD370_B807810527-part1', + }, + }, + { + 'type': 'cache', + 'devices': { + '/dev/disk/by-id/ata-TS64GSSD370_B807810503-part2', + '/dev/disk/by-id/ata-TS64GSSD370_B807810527-part2', + }, + }, ], 'ashift': 12, }, }, }, 'datasets': { - 'ssdpool': { + 'storage': { 'primarycache': 'metadata', }, - 'ssdpool/yate': { + 'storage/opt-yate': { 'mountpoint': '/opt/yate', }, - 'ssdpool/download': { - 'mountpoint': '/mnt/download', - 'quota': '858993459200', # 800 GB + 'storage/f2k1de': { + 'mountpoint': '/storage/f2k1de', }, - 'ssdpool/paperless': { + 'storage/download': { + 'mountpoint': '/storage/download', + }, + 'storage/inbox': { + 'quota': str(1024*1024*1024*1024), # 1TB + 'mountpoint': '/storage/inbox', + }, + 'storage/nas': { + 'mountpoint': '/storage/nas', + }, + 'storage/paperless': { 'mountpoint': '/srv/paperless', }, - 'tank': { - 'primarycache': 'metadata', - }, - 'tank/nas': { - 'acltype': 'off', - 'atime': 'off', - 'compression': 'off', - 'mountpoint': '/storage/nas', + 'storage/scan': { + 'mountpoint': '/srv/scansnap', }, }, 'snapshots': { 'retain_per_dataset': { - 'tank/nas': { - # juuuuuuuust to be sure. - 'daily': 14, - 'weekly': 6, - 'monthly': 12, - }, - 'ssdpool/download': { + 'storage/download': { 'hourly': 48, 'daily': 0, 'weekly': 0, 'monthly': 0, }, - 'ssdpool/paperless': { + 'storage/nas': { + # juuuuuuuust to be sure. + 'daily': 14, + 'weekly': 6, + 'monthly': 12, + }, + 'storage/paperless': { 'daily': 14, 'weekly': 6, 'monthly': 24, }, + 'storage/scan': { + 'hourly': 6, + 'daily': 0, + 'weekly': 0, + 'monthly': 0, + }, }, }, }, diff --git a/nodes/home/openhab.py b/nodes/home/openhab.py new file mode 100644 index 0000000..efbb029 --- /dev/null +++ b/nodes/home/openhab.py @@ -0,0 +1,36 @@ +nodes['home.openhab'] = { + 'hostname': '172.19.138.21', + 'bundles': { + 'nginx', + 'openhab', + }, + 'groups': { + 'debian-bullseye', + }, + 'metadata': { + 'interfaces': { + 'enp1s0': { + 'ips': { + '172.19.138.21/24', + }, + 'gateway4': '172.19.138.1', + 'ipv6_accept_ra': True, + }, + }, + 'nginx': { + 'vhosts': { + 'openhab': {'ssl': '_.home.kunbox.net'}, + }, + }, + 'openhab': { + 'domain': 'openhab.home.kunbox.net', + 'java_opts': { + 'user.timezone': 'Europe/Berlin', + }, + }, + 'vm': { + 'cpu': 2, + 'ram': 2, + }, + }, +} diff --git a/nodes/sophie/paperless.py b/nodes/home/paperless-sophie.py similarity index 76% rename from nodes/sophie/paperless.py rename to nodes/home/paperless-sophie.py index 9319c7a..929bd24 100644 --- a/nodes/sophie/paperless.py +++ b/nodes/home/paperless-sophie.py @@ -1,4 +1,4 @@ -nodes['sophie.paperless'] = { +nodes['home.paperless-sophie'] = { 'hostname': '172.19.138.30', 'bundles': { 'nfs-client', @@ -49,12 +49,22 @@ nodes['sophie.paperless'] = { 'nginx': { 'vhosts': { 'paperless': { + 'domain': 'paperless-sophie.home.kunbox.net', 'ssl': '_.home.kunbox.net', + 'locations': { + '/': { + 'target': 'http://127.0.0.1:22070', + 'websockets': True, + 'proxy_set_header': { + 'X-Forwarded-Host': '$server_name', + }, + }, + }, + 'extras': True, }, }, }, 'paperless': { - 'domain': 'paperless-sophie.home.kunbox.net', 'version': 'ng-1.4.4', 'timezone': 'Europe/Berlin', }, diff --git a/nodes/home/paperless.py b/nodes/home/paperless.py index f7035a5..3dd957e 100644 --- a/nodes/home/paperless.py +++ b/nodes/home/paperless.py @@ -6,18 +6,12 @@ nodes['home.paperless'] = { 'redis', 'postgresql', 'paperless-ng', - 'proftpd', }, 'groups': { - 'debian-trixie', + 'debian-buster', 'webserver', }, 'metadata': { - 'icinga_options': { - 'also_affected_by': { - 'home.nas', - }, - }, 'interfaces': { 'enp1s0': { 'ips': { @@ -42,23 +36,30 @@ nodes['home.paperless'] = { 'nginx': { 'vhosts': { 'paperless': { - 'create_logs': True, + 'domain': 'paperless.home.kunbox.net', 'ssl': '_.home.kunbox.net', + 'locations': { + '/': { + 'target': 'http://127.0.0.1:22070', + 'websockets': True, + 'proxy_set_header': { + 'X-Forwarded-Host': '$server_name', + }, + }, + '/static/': { + 'alias': '/opt/paperless/static/', + }, + }, + 'max_body_size': '100M', }, }, }, 'paperless': { - 'domain': 'paperless.home.kunbox.net', - 'version': 'v2.15.3', + 'version': 'ng-1.4.4', 'timezone': 'Europe/Berlin', }, 'postgresql': { - 'version': 15, - }, - 'proftpd': { - 'restrict-to': { - 'home.fujitsu-n7100', - }, + 'version': '11', }, 'vm': { 'cpu': 2, diff --git a/nodes/sophie/rechenmonster.py b/nodes/home/rechenmonster.py similarity index 92% rename from nodes/sophie/rechenmonster.py rename to nodes/home/rechenmonster.py index ee862f7..f4e76ad 100644 --- a/nodes/sophie/rechenmonster.py +++ b/nodes/home/rechenmonster.py @@ -1,4 +1,4 @@ -nodes['sophie.rechenmonster'] = { +nodes['home.rechenmonster'] = { 'hostname': '172.19.138.98', 'bundles': { 'basic', @@ -54,6 +54,9 @@ nodes['sophie.rechenmonster'] = { }, }, 'users': { + 'kunsi': { + 'password': vault.decrypt('encrypt$gAAAAABgLmmuQGRUStrQawoPee-758emIYn2u8-8ebrgzNAFSp7ifeFDdXXvs-zL3QogwNYlCtBHboH2xfy1rSj6OF5bbNO-tg=='), + }, 'sophie': { 'password': vault.decrypt('encrypt$gAAAAABiEAyiedXL6ZnvelOMumhcB73X72SXZhjS_G0EDYVK5-NQ3_J_0h1W1HkFBNe5tShGNmg88jUiULRBn5u2IoiRGiDrYg=='), }, @@ -88,9 +91,6 @@ nodes['sophie.rechenmonster'] = { 'storage/video': { 'mountpoint': '/video', }, - 'storage/nas': { - 'mountpoint': '/nas', - }, }, }, }, diff --git a/nodes/home/router.py b/nodes/home/router.py index c84b4ef..d033c1c 100644 --- a/nodes/home/router.py +++ b/nodes/home/router.py @@ -2,8 +2,7 @@ nodes['home.router'] = { 'hostname': '172.19.138.1', 'bundles': { 'bird', - 'jool', - 'kea-dhcp-server', + 'dhcpd', 'nginx', 'pppd', 'radvd', @@ -13,20 +12,18 @@ nodes['home.router'] = { 'wireguard', }, 'groups': { - 'debian-bookworm', + 'debian-bullseye', }, 'metadata': { 'interfaces': { - 'enp1s0.1138': { - 'ips': { - '172.19.138.1/24', - 'fe80::1/64', - }, - }, - 'enp1s0.1139': { + 'enp1s0.23': { 'ips': { '172.19.139.1/24', - 'fe80::1/64', + }, + }, + 'enp1s0.42': { + 'ips': { + '172.19.138.1/24', }, }, }, @@ -45,50 +42,65 @@ nodes['home.router'] = { # connected longer than 24 hours. We install this cronjob # to make sure we don't get disconnected randomly during the # day. - 'restart_pppd': r'23 2 * * * root systemctl restart pppoe && date -u +\%s > /var/tmp/pppd-last-restart.status', + 'restart_pppd': '23 2 * * * root systemctl restart pppoe && date -u +\%s > /var/tmp/pppd-last-restart.status', }, }, - 'kea-dhcp-server': { + 'dhcpd': { 'subnets': { - 'enp1s0.1138': { - 'lower': '172.19.138.100', - 'higher': '172.19.138.250', - 'subnet': '172.19.138.0/24', - 'options': { - 'domain-name-servers': '172.19.138.1', - 'routers': '172.19.138.1', - }, - }, - 'enp1s0.1139': { - 'lower': '172.19.139.200', - 'higher': '172.19.139.250', + 'enp1s0.23': { + 'range_lower': '172.19.139.200', + 'range_higher': '172.19.139.250', 'subnet': '172.19.139.0/24', 'options': { + 'broadcast-address': '172.19.139.255', 'domain-name-servers': '172.19.139.1', 'routers': '172.19.139.1', + 'subnet-mask': '255.255.255.0', }, }, + 'enp1s0.42': { + 'range_lower': '172.19.138.100', + 'range_higher': '172.19.138.250', + 'subnet': '172.19.138.0/24', + 'options': { + 'broadcast-address': '172.19.138.255', + 'domain-name': 'franzi-home.kunbox.net', + 'domain-name-servers': '172.19.138.1', + 'domain-search': 'home.kunbox.net', + 'routers': '172.19.138.1', + 'subnet-mask': '255.255.255.0', + }, + }, + }, + }, + 'hosts': { + 'entries': { + # Hackaround to force wireguard to only use IPv4 for + # the connection to this system. + '51.195.47.180': { + 'wireguard.ovh.kunbox.net', + }, }, }, 'icinga_options': { # override group default - 'also_affected_by': atomic(set()), + 'also_affected_by': atomic({ + 'ovh.wireguard', + }), # disabled on group level # XXX reenable this once we can leave the house safely again #'vars.notification.sms': True }, 'nftables': { - 'forward': { + 'rules': { '50-router': [ - 'ct state { related, established } accept', - 'iifname enp1s0.1138 accept', - 'ip6 nexthdr ipv6-icmp accept', - 'tcp dport 22 accept', - ], - }, - 'prerouting': { - '50-router': [ - 'tcp dport 2022 dnat 172.19.138.20:22', + # This is a router. Allow forwarding traffic for internal networks. + 'inet filter forward ct state { related, established } accept', + + # yaaaaay, IPv6! No NAT! + 'inet filter forward ip6 nexthdr ipv6-icmp accept', + 'inet filter forward tcp dport 22 accept', + 'nat prerouting tcp dport 2022 dnat 172.19.138.20:22', ], }, }, @@ -96,7 +108,6 @@ nodes['home.router'] = { 'restrict-to': { '172.19.136.0/25', '172.19.138.0/24', - 'htz-cloud.molly-connector', }, 'vhosts': { 'vnstat': { @@ -107,16 +118,8 @@ nodes['home.router'] = { }, 'radvd': { 'interfaces': { - 'enp1s0.1138': { - 'rdnss': { - 'fe80::1', - }, - }, - 'enp1s0.1139': { - 'rdnss': { - 'fe80::1', - }, - }, + 'enp1s0.23': {}, + 'enp1s0.42': {}, }, }, 'postfix': { @@ -127,29 +130,38 @@ nodes['home.router'] = { 'pppd': { 'username': vault.decrypt('encrypt$gAAAAABfruZ5AZbgJ3mfMLWqIMx8o4bBRMJsDPD1jElh-vWN_gnhiuZVjrQ1-7Y6zDXNkxXiyhx8rxc2enmvo26axd7EBI8FqknCptXAPruVtDZrBCis4TE='), 'password': vault.decrypt('encrypt$gAAAAABfruaXEDkaFksFMU8g97ydWyJF8p2KcSDJJBlzaOLDsLL6oCDYjG1kMPVESOzqjn8ThtSht1uZDuMCstA-sATmLS-EWQ=='), - 'interface': 'enp1s0.7', + 'interface': 'enp1s0.100', 'dyndns': { 'domain': 'franzi-home.kunbox.net', - 'url': 'https://ns-mephisto.kunbox.net/nic/update?hostname=franzi-home.kunbox.net&myip={ips}', + 'url': 'https://ns-1.kunbox.net/nic/update?hostname=franzi-home.kunbox.net&myip={ip}', 'username': vault.decrypt('encrypt$gAAAAABfr8DLAJhmUIhdxLq83I8MnRRvkRgDZcO8Brvw1KpvplC3K8ZGj0jIIWD3Us33vIP6t0ybd_mgD8slpRUk78Kqd3BMoQ=='), 'password': vault.decrypt('encrypt$gAAAAABfr8Cq5M1hweeJTQAl0dLhFntdlw-QnkIYUQpY-_ycODVWOpyeAwjwOgWLSdsdXIUvqcoiXPZPV-BE12p5C42NGnj9r7sKYpoGz8xfuGIk6haMa2g='), }, 'nftables-rules.d': { - 'inet filter forward iifname enp1s0.1139 oifname $INTERFACE accept', + 'inet filter forward iif enp1s0.23 oif $INTERFACE accept', + 'inet filter forward iif enp1s0.42 accept', }, }, 'unbound': { - 'dns64': False, 'restrict-to': { '172.19.138.0/23', - 'fe80::/64', }, }, 'users': { - 'fkunsmann': {}, + 'f2k1de': { + 'ssh_pubkey': { + 'command="/bin/false",no-pty ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGrvhqC/tZzpLMs/qy+1xNSVi2mfn8LXPIEhh7dcGn9e', + 'command="/bin/false",no-pty ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDH5+j2vDW1FHSSEEI/Sf5qiKJq1uoxGO5BPv84mqohvol7GxDFObv69tn7g6HYfZY/SaS75C4ZXy+cKa0xy8UCpF0SBa2xHASkenS9v55oweDL4rYSPARzn2XKt3RFJG/d8V5NOWtcyq5DFSzewUF35E4hx1pUc/CIxgJEem5ZvzvN0hlIKXUN2djkVUx+mz6RryBysLTJEFBamjJxIkvDG/PZU73W4SHaKAYV4Ojz2NY7T5/NYKePfIU5F9pkE3RU0LRj58usvA1eP0PvEArWlGNCd8EJU+HQ5xr2dZ6MKPpEyG0KJkC88DuapeF5RwUV53ZhNpF+QgzpI72fH5up', + }, + }, + 'fkunsmann': { + 'sudo_commands': { + 'ALL', + }, + }, }, 'vnstat': { - 'interface': 'enp1s0.7', + 'interface': 'enp1s0.100', }, 'vm': { 'cpu': 2, @@ -158,12 +170,18 @@ nodes['home.router'] = { 'wide-dhcp6c': { 'source': 'ppp0', 'targets': { - 'enp1s0.1138': '1', - 'enp1s0.1139': '2', + 'enp1s0.23': '2', + 'enp1s0.42': '1', }, }, 'wireguard': { - 'snat_ip': '172.19.138.1', + 'external_hostname': 'franzi-home.kunbox.net', # Set via DynDNS + 'peers': { + 'ovh.wireguard': { + 'health_check': True, + 'snat_to': '172.19.138.1', + }, + }, }, }, } diff --git a/nodes/home/snom-wohnzimmer.py b/nodes/home/snom-wohnzimmer.py new file mode 100644 index 0000000..ce7d1a7 --- /dev/null +++ b/nodes/home/snom-wohnzimmer.py @@ -0,0 +1,14 @@ +nodes['home.snom-wohnzimmer'] = { + 'dummy': True, + 'metadata': { + 'interfaces': { + 'default': { + 'ips': { + '172.19.138.40', + }, + 'dhcp': True, + 'mac': '00:04:13:26:EE:1B', + }, + }, + }, +} diff --git a/nodes/home/sw01.py b/nodes/home/sw01.py new file mode 100644 index 0000000..b49e308 --- /dev/null +++ b/nodes/home/sw01.py @@ -0,0 +1,12 @@ +nodes['home.sw01'] = { + 'dummy': True, + 'metadata': { + 'interfaces': { + 'default': { + 'ips': { + '172.19.138.2', + }, + }, + }, + }, +} diff --git a/nodes/home/usv01.py b/nodes/home/usv01.py new file mode 100644 index 0000000..77a95a2 --- /dev/null +++ b/nodes/home/usv01.py @@ -0,0 +1,27 @@ +nodes['home.usv01'] = { + 'dummy': True, + 'metadata': { + 'interfaces': { + 'default': { + 'ips': { + '172.19.138.3', + }, + }, + }, + 'icinga2_api': { + 'usv': { + 'services': { + 'USV STATUS': { + 'check_command': 'check_usv', + 'vars.notification.mail': True, + }, + }, + }, + }, + }, +} + +# Every system which is connected to the USV needs to have Dell Local +# Node Manager installed: +# +# A backup of this file is available in home.nas:/storage/nas diff --git a/nodes/home/winkeeinhorn-1.py b/nodes/home/winkeeinhorn-1.py new file mode 100644 index 0000000..063b25a --- /dev/null +++ b/nodes/home/winkeeinhorn-1.py @@ -0,0 +1,25 @@ +nodes['home.winkeeinhorn-1'] = { + 'dummy': True, + 'metadata': { + 'interfaces': { + 'default': { + 'ips': { + '172.19.138.11', + }, + 'dhcp': True, + 'mac': 'f4:06:8d:df:05:60', + }, + }, + 'icinga2_api': { + 'freifunk': { + 'services': { + 'NODE HEALTH': { + 'check_command': 'check_freifunk_node', + 'vars.url': 'https://map.freifunk-mwu.de/data/meshviewer.json', + 'vars.id': 'f4068ddf055f', + }, + }, + }, + }, + }, +} diff --git a/nodes/home/winkeeinhorn-2.py b/nodes/home/winkeeinhorn-2.py new file mode 100644 index 0000000..e9dfa44 --- /dev/null +++ b/nodes/home/winkeeinhorn-2.py @@ -0,0 +1,25 @@ +nodes['home.winkeeinhorn-2'] = { + 'dummy': True, + 'metadata': { + 'interfaces': { + 'default': { + 'ips': { + '172.19.138.12', + }, + 'dhcp': True, + 'mac': 'f4:06:8d:df:03:38', + }, + }, + 'icinga2_api': { + 'freifunk': { + 'services': { + 'NODE HEALTH': { + 'check_command': 'check_freifunk_node', + 'vars.url': 'https://map.freifunk-mwu.de/data/meshviewer.json', + 'vars.id': 'f4068ddf0337', + }, + }, + }, + }, + }, +} diff --git a/nodes/home/winkeeinhorn-vm.py b/nodes/home/winkeeinhorn-vm.py new file mode 100644 index 0000000..618110b --- /dev/null +++ b/nodes/home/winkeeinhorn-vm.py @@ -0,0 +1,25 @@ +nodes['home.winkeeinhorn-vm'] = { + 'dummy': True, + 'metadata': { + 'interfaces': { + 'default': { + 'ips': { + '172.19.138.10', + }, + 'dhcp': True, + 'mac': '52:54:00:b0:4e:4d', + }, + }, + 'icinga2_api': { + 'freifunk': { + 'services': { + 'NODE HEALTH': { + 'check_command': 'check_freifunk_node', + 'vars.url': 'https://map.freifunk-mwu.de/data/meshviewer.json', + 'vars.id': '525400b04e4d', + }, + }, + }, + }, + }, +} diff --git a/nodes/home/wled-wohnzimmer.py b/nodes/home/wled-wohnzimmer.py new file mode 100644 index 0000000..df781b9 --- /dev/null +++ b/nodes/home/wled-wohnzimmer.py @@ -0,0 +1,17 @@ +nodes['home.wled-wohnzimmer'] = { + 'dummy': True, + 'metadata': { + 'interfaces': { + 'default': { + 'ips': { + '172.19.138.70', + }, + 'dhcp': True, + 'mac': '3c:61:05:d0:ba:1a', + }, + }, + 'icinga_options': { + 'exclude_from_monitoring': True, + }, + }, +} diff --git a/nodes/htz-cloud.molly-connector.toml b/nodes/htz-cloud.molly-connector.toml deleted file mode 100644 index eeea694..0000000 --- a/nodes/htz-cloud.molly-connector.toml +++ /dev/null @@ -1,8 +0,0 @@ -dummy = true - -# Machine is managed by molly and does SNAT for her vpn infrastructure. -# Putting this into my hetzner cloud project was the easiest way to do -# interconnect. - -[metadata.interfaces.default] -ips = ["172.19.137.5"] diff --git a/nodes/htz-cloud.prometheus.toml b/nodes/htz-cloud.prometheus.toml deleted file mode 100644 index 6532493..0000000 --- a/nodes/htz-cloud.prometheus.toml +++ /dev/null @@ -1,7 +0,0 @@ -hostname = "138.199.210.112" -groups = ["debian-bookworm"] - -[metadata.interfaces.eth0] -ips = ["138.199.210.112/32", "2a01:4f8:1c1e:65e4::1/64"] -gateway4 = "172.31.1.1" -gateway6 = "fe80::1" diff --git a/nodes/htz-cloud/README b/nodes/htz-cloud/README new file mode 100644 index 0000000..d1bf55d --- /dev/null +++ b/nodes/htz-cloud/README @@ -0,0 +1 @@ +Hetzner Cloud diff --git a/nodes/htz-cloud/influxdb.py b/nodes/htz-cloud/influxdb.py index e3dc166..ba1274a 100644 --- a/nodes/htz-cloud/influxdb.py +++ b/nodes/htz-cloud/influxdb.py @@ -3,12 +3,10 @@ nodes['htz-cloud.influxdb'] = { 'bundles': { 'grafana', 'influxdb2', - 'telegraf_airgradient', - 'telegraf-monitors-mikrotik', 'zfs', }, 'groups': { - 'debian-bullseye', + 'debian-buster', 'webserver', }, 'metadata': { @@ -34,7 +32,7 @@ nodes['htz-cloud.influxdb'] = { }, 'routes': { # VPN - '172.19.128.0/20': { + '172.19.136.0/22': { 'via': '172.19.137.1', }, }, @@ -45,8 +43,7 @@ nodes['htz-cloud.influxdb'] = { 'login_max_duration': '30d', }, 'icinga_options': { - # no public access - 'show_on_statuspage': False, + 'pretty_name': 'InfluxDB', }, 'nginx': { 'vhosts': { @@ -67,13 +64,16 @@ nodes['htz-cloud.influxdb'] = { }, }, }, - 'telegraf_airgradient': { - 'Home': vault.decrypt('encrypt$gAAAAABlr3KvHLSHLFwVr5hvJ1j676Flm5fVLumqpBcffjYWXjPjSovDXCyEcVqhxfsX-GNut2dXsenFQoFShaAugLV_zVQYaLnNQipbZqI0cXfsMht1iZPyOxlSzy3YoZ3voSaeiLll'), - }, 'telegraf': { 'input_plugins': { 'builtin': { 'snmp': [ + { + 'agents': ['udp://172.19.138.2'], + 'agent_host_tag': 'host', + 'table': [{'oid': 'IF-MIB::ifTable'}], + 'interval': '10s', + }, { 'agents': ['udp://172.19.138.3'], 'agent_host_tag': 'host', diff --git a/nodes/htz-cloud/luther.py b/nodes/htz-cloud/luther.py new file mode 100644 index 0000000..6e30f57 --- /dev/null +++ b/nodes/htz-cloud/luther.py @@ -0,0 +1,109 @@ +nodes['htz-cloud.luther'] = { + 'bundles': { + 'php', + 'postgresql', + 'zfs', + }, + 'groups': { + 'debian-buster', + 'webserver', + }, + 'metadata': { + 'interfaces': { + 'eth0': { + 'ips': { + '195.201.136.20', + '2a01:4f8:c2c:fc3b::1/64', + }, + 'gateway4': '172.31.1.1', + 'gateway6': 'fe80::1', + }, + 'ens10': { + 'ips': { + '172.19.137.4/32', + }, + 'routes': { + # VPN + '172.19.136.0/22': { + 'via': '172.19.137.1', + }, + }, + }, + }, + 'apt': { + 'packages': { + 'php-apcu': {}, + 'php-uploadprogress': {}, + }, + }, + 'cron': { + 'jobs': { + 'luther-ps': vault.decrypt('encrypt$gAAAAABfnUqTXXpUYCA2DxllTKgbKg6YguCBbguJ0rerFGi9UNxEuTO6eqReqraS9FzNmLl81S_20bYwXM5W8pNwV5I5i6BVz1M37TxdsMCAxMG-9G0ZHFXeE4K5a4MWxuyYkrVPtK_hNFOciwxDDwPYT8tH_Jahdqmr8fZcCcsICzsSOxycn89VEm2ODnfH24Azrj6mVq5cPMc_xkdWnn-dSMCvPXpjjg==').format_into('*/10 * * * * www-data /usr/bin/curl -s {}'), + }, + }, + 'icinga_options': { + 'period': 'daytime', + 'pretty_name': 'Lutherkirchengemeinde Pirmasens', + 'vars.notification.sms': False, + }, + 'nginx': { + 'vhosts': { + 'luther-ps': { + 'domain': 'luther-ps.kunsmann.eu', + 'php': True, + 'extras': True, + 'website_check_path': '/user/login', + 'website_check_string': 'Username', + }, + }, + }, + 'php': { + 'version': '7.4', + 'packages': { + 'curl', + 'gd', + 'json', + 'mbstring', + 'pgsql', + 'xml', + }, + }, + 'postgresql': { + 'version': '11', + 'users': { + 'luther-ps': { + # can't use password_for() here, application is unmanaged + 'password': vault.decrypt('encrypt$gAAAAABfnSxJtRTeWRTO_ubSqpBbH8L-khPamKtSiUYbuMIoyJnoF_oSfUlMpTpQsmdDh61F3JQEH0xfYOkzkiCGZONRHyYdqkTjWV4Ku1Avdb0SL74VG6NihUJOpZlhOKnuniopCwuW'), + }, + }, + 'databases': { + 'luther-ps': { + 'owner': 'luther-ps', + }, + }, + }, + 'zfs': { + 'pools': { + 'tank': { + 'when_creating': { + 'config': [{ + 'devices': {'/dev/sdb'}, + }], + }, + }, + }, + 'datasets': { + 'tank/luther-website': { + 'mountpoint': '/var/www/luther-ps', + 'needed_by': { + 'directory:/var/www/luther-ps', + }, + }, + }, + }, + 'vm': { + 'cpu': 1, + 'ram': 2, + }, + }, +} diff --git a/nodes/htz-cloud/miniserver.py b/nodes/htz-cloud/miniserver.py new file mode 100644 index 0000000..17322ae --- /dev/null +++ b/nodes/htz-cloud/miniserver.py @@ -0,0 +1,265 @@ +# sophie's miniserver + +nodes['htz-cloud.miniserver'] = { + 'bundles': { + 'element-web', + 'hedgedoc', + 'matrix-dimension', + 'matrix-media-repo', + 'matrix-synapse', + 'nodejs', + 'ntfy', + 'mautrix-telegram', + 'postgresql', + 'zfs', + }, + 'groups': { + 'debian-bullseye', + 'webserver', + }, + 'metadata': { + 'interfaces': { + 'eth0': { + 'ips': { + '157.90.20.62', + '2a01:4f8:c2c:840f::1/64', + }, + 'gateway4': '172.31.1.1', + 'gateway6': 'fe80::1', + }, + }, + 'apt': { + 'packages': { + 'mosh': {}, + 'weechat': {}, + 'weechat-core': {}, + 'weechat-curses': {}, + 'weechat-perl': {}, + 'weechat-plugins': {}, + 'weechat-python': {}, + 'weechat-ruby': {}, + }, + 'repos': { + 'weechat': { + 'items': { + 'deb https://weechat.org/debian {os_release} main', + }, + }, + }, + }, + 'backup-client': { + 'pre-hooks': { + 'sophie-weechat': \ + 'echo \'core.weechat */layout store\' >> /home/sophie/.weechat/weechat_fifo\n' \ + 'echo \'core.weechat */save\' >> /home/sophie/.weechat/weechat_fifo\n', + }, + 'target': "htz-hel.backup-sophie", + }, + 'backups': { + 'paths': { + '/home/sophie/.weechat', + }, + }, + 'element-web': { + 'url': 'chat.sophies-kitchen.eu', + 'version': 'v1.11.16', + 'config': { + 'default_server_config': { + 'm.homeserver': { + 'base_url': 'https://matrix.sophies-kitchen.eu', + 'server_name': 'sophies-kitchen.eu', + }, + }, + 'brand': 'sophies-kitchen.eu', + 'showLabsSettings': True, + 'integrations_ui_url': 'https://dimension.sophies-kitchen.eu/riot', + 'integrations_rest_url': 'https://dimension.sophies-kitchen.eu/api/v1/scalar', + 'integrations_widgets_urls': { + 'https://dimension.sophies-kitchen.eu/widgets' + }, + 'default_theme': 'dark', + 'defaultCountryCode': 'DE', + 'jitsi': { + 'preferredDomain': 'meet.ffmuc.net', + }, + 'map_style_url': "https://api.maptiler.com/maps/openstreetmap/style.json?key=fU3vlMsMn4Jb6dnEIFsx" + }, + }, + 'hedgedoc': { + 'version': '1.9.6', + 'config': { + 'production': { + 'allowAnonymousEdits': True, + 'domain': 'pad.sophies-kitchen.eu', + }, + }, + }, + 'icinga_options': { + 'pretty_name': 'sophies-kitchen.eu', + 'vars.notification.sms': False, + }, + 'letsencrypt': { + 'concat_and_deploy': { + 'sophie-weechat': { + 'match_domain': 'i.sophies-kitchen.eu', + 'target': '/home/sophie/.weechat/ssl/relay.pem', + 'chown': 'sophie:sophie', + 'chmod': '0440', + 'commands': [ + 'echo \'core.weechat */relay sslcertkey\' >> /home/sophie/.weechat/weechat_fifo' + ], + }, + }, + 'domains': { + 'i.sophies-kitchen.eu': set(), + 'webdump.sophies-kitchen.eu': set(), + 'matrix.sophies-kitchen.eu': { + 'sophies-kitchen.eu', + }, + }, + }, + 'matrix-dimension': { + 'url': 'dimension.sophies-kitchen.eu', + 'version': 'c6d047c', # XXX master is broken as of 2021-11-27 + 'homeserver': { + 'name': 'sophies-kitchen.eu', + 'clientServerUrl': 'https://matrix.sophies-kitchen.eu', + 'accessToken': vault.decrypt('encrypt$gAAAAABg4btB0KGk068ahGZzR0w_Lm1bj1wUbB2WfNNs2bp3PwM4Ftp6MjQnrF-CejZfrF0NjPJw9Z4MrgileHP0sVw04mvgKSHfTf8gv4kTB6WuCIxHeMWHUDx00LTWL73fSlhCK0o1'), + }, + 'admins': [ + '@sophie:sophies-kitchen.eu', + ], + 'telegram': { + 'botToken': vault.decrypt('encrypt$gAAAAABg4bcQVzBF_iXdDtjRQD-O37GHdbHwWXyhCLPOuJLbv3ezUeXKR203hkCXkjfItSHi4NiTEgQPadDZTRkavaRpvAoaQV1a4srCS_Y-NU4RiOmkrVFJ_Xhw6UZvwjQUQ0QPOx9t'), + }, + }, + 'matrix-media-repo': { + 'version': 'v1.2.12', + 'sha1': 'c2dfa521c2eea9a0dcde9f1c7803f52ce6d0352e', + 'homeservers': { + 'sophies-kitchen.eu': { + 'domain': 'http://[::1]:20080/', + 'api': 'synapse', + }, + }, + 'admins': { + '@sophie:sophies-kitchen.eu', + }, + 'upload_max_mb': 500, + }, + 'matrix-synapse': { + 'server_name': 'sophies-kitchen.eu', + 'baseurl': 'matrix.sophies-kitchen.eu', + 'admin_contact': 'mailto:foobar@sophies-kitchen.eu', + 'trusted_key_servers': { + 'matrix.org', + }, + }, + 'mautrix-telegram': { + 'version': 'v0.12.2', + 'homeserver': { + 'domain': 'sophies-kitchen.eu', + 'url': 'https://matrix.sophies-kitchen.eu', + }, + 'provisioning': { + 'enabled': False, + 'shared_secret': '""', + }, + 'permissions': { + 'sophies-kitchen.eu': 'full', + "'@sophie:sophies-kitchen.eu'": 'admin', + }, + 'telegram': { + 'api_id': vault.decrypt('encrypt$gAAAAABgnqdXhCTwtCXJhSaCZsiNfHPtjwlYtV1sUAux7JZdejN3xItU9RJLeNu4gUniv36XbBoxKwVtqqyV3RcAs-PgumcfYQ=='), + 'api_token': vault.decrypt('encrypt$gAAAAABgnqd5IdpYRmW-C4ONBSXQfiJrpTVQX0rP0eKoDnLnVTLg-5olSjcw2gVvEKWLnsGEZIgVcG7yEs-sqYRxeiQLFFpSn-Z4We0mhj0CUeFoD-eXJsp-bAgLv9PJoMv5Gjb8r9i6'), + 'bot_token': '""', + }, + }, + 'nameservers': { + '213.133.98.98', + '213.133.99.99', + '213.133.100.100', + '2a01:4f8:0:1::add:1010', + '2a01:4f8:0:1::add:9999', + '2a01:4f8:0:1::add:9898', + }, + 'nftables': { + 'rules': { + '50-sophie-weechat': [ + 'inet filter input udp dport { 60000-61000 } accept', + 'inet filter input tcp dport 9001 accept', + ], + }, + }, + 'nginx': { + 'vhosts': { + 'matrix-dimension': { + 'extras': True, + }, + 'sophies-kitchen.eu': { + 'webroot': '/var/www/sophies-kitchen.eu/_site/', + 'extras': True, + }, + 'matrix-synapse': { + 'domain': 'matrix.sophies-kitchen.eu', + }, + 'webdump.sophies-kitchen.eu': { + 'webroot_config': { + 'owner': 'sophie', + 'group': 'sophie', + 'mode': '0755', + }, + 'extras': True, + }, + 'recipes.sophies-kitchen.eu': { + 'webroot_config': { + 'owner': 'sophie', + 'group': 'sophie', + 'mode': '0755', + }, + }, + }, + }, + 'nodejs': { + 'version': 16, + }, + 'ntfy': { + 'domain': 'ntfy.sophies-kitchen.eu', + }, + 'postgresql': { + 'version': '11', + }, + 'sysctl': { + 'options': { + # XXX find out if this is really needed + 'net.ipv4.ip_forward': '1', + 'net.ipv6.conf.all.forwarding': '1', + }, + }, + 'vm': { + 'cpu': 2, + 'ram': 4, + }, + 'users': { + 'sophie': { + 'enable_linger': True, + 'ssh_pubkey': [ + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDILcYrMQNRVXAm5L+7No1ZumqfCyRc1QZmTY3O7Q8hsE4+fCAvwsWm2aSMfLL3NnIl8Nm1Rixzic5jdYKYNIY3SlX1wvTB+MhGb2eyVSd7c/Y98aCLSlDkQ2sebjpdA1FoJOeGD3qxqDwj0+KckXU2ZaSSQY7CxVsjH65UxCHqVAg+6uLdNbj7j850s1B9NXVXef+sBQ5jUngXxnqQWwNh2Mn8auwumkeEG4SYf96wyFkLvmBitOng/GyLWl9YPnXXHHDnatcVipy7y34qw4CQ4P84anecbA+Bqr9IcxBW6qYmYgRKEnAcmEfjQd+BI1gCLB1BBEmb/qp+mVLd4tOh sophie@carbon" + ], + }, + }, + 'zfs': { + 'pools': { + 'tank': { + 'when_creating': { + 'config': [{ + 'devices': { + '/dev/disk/by-id/scsi-0HC_Volume_23952298', + }, + }] + }, + }, + }, + }, + }, +} diff --git a/nodes/htz-cloud/pirmasens.py b/nodes/htz-cloud/pirmasens.py index 908e85e..67d7e12 100644 --- a/nodes/htz-cloud/pirmasens.py +++ b/nodes/htz-cloud/pirmasens.py @@ -10,7 +10,7 @@ nodes['htz-cloud.pirmasens'] = { 'unbound', }, 'groups': { - 'debian-bookworm', + 'debian-buster', 'webserver', }, 'metadata': { @@ -37,25 +37,39 @@ nodes['htz-cloud.pirmasens'] = { }, 'nginx': { 'vhosts': { - 'salonkatrin-v2': { - 'domain': 'salonkatrin.de', - 'domain_aliases': { - 'www.salonkatrin.de', - 'old.salonkatrin.de', - }, + 'mail.kunsmann.info': { + 'webroot': '/opt/postfixadmin/public/', + 'php': True, + 'website_check_path': '/login.php', + 'website_check_string': 'login', + }, + 'salonkatrin.de': { 'website_check_path': '/', 'website_check_string': 'Salon Katrin', + }, + 'salonkatrin-v2': { + 'domain': 'dev.salonkatrin.de', 'webroot_config': { - 'owner': 'forgejo-carlene', + 'owner': 'autojenkins', + }, + }, + 'salonkatrin-www': { + 'domain': 'www.salonkatrin.de', + 'locations': { + '/': { + 'redirect': 'https://salonkatrin.de$request_uri', + }, }, }, }, }, 'php': { + 'version': '7.4', 'packages': { 'gd', 'imap', 'intl', + 'json', 'mbstring', 'opcache', 'pgsql', @@ -68,8 +82,7 @@ nodes['htz-cloud.pirmasens'] = { 'message_size_limit_mb': 50, }, 'postfixadmin': { - 'domain': 'mail.kunsmann.info', - 'version': '3.3.15', + 'version': '3.3.13', 'setup_password': vault.decrypt('encrypt$gAAAAABgnNGpAqUs--qBXII9ZPcHtxaELy9e2Dx9O44n4l0O4nMHPoIyaPW5HkvpQ2zWTlh5OfjjOgunRtE_voJuY0Kdtji37ixAnuL9ErOJ0LDY5QfMkNPUgPs5alwz1baqYq6rqJ7NDmB0gHraY46v5eG79R2EyQ=='), }, 'postgresql': { @@ -79,8 +92,11 @@ nodes['htz-cloud.pirmasens'] = { 'password': vault.decrypt('encrypt$gAAAAABfp7qzym32R6Go1A6oax0NGQM7EBMckbEbnZC6-RSKx-klSJsL57XbSUTD-AJM-gBIPzlmor-3bfVxPWLRYXtO8uTVw6jNQ1yt15ReHkOTijVqV2ACk-LTDBG3p4YKBn0pQgNvvjXhWV_J1-Pgjywbl4sHXc0zqjCGZ6xtEn6ywj0Pd599JJjREF4QCIFVZVWuKvo1'), }, 'users': { - 'forgejo-carlene': {}, + 'autojenkins': {}, 'frank': {}, + 'sophie': { + 'delete': True, + }, }, 'vm': { 'cpu': 2, diff --git a/nodes/htz-cloud/pleroma.py b/nodes/htz-cloud/pleroma.py new file mode 100644 index 0000000..b57d13c --- /dev/null +++ b/nodes/htz-cloud/pleroma.py @@ -0,0 +1,85 @@ +nodes['htz-cloud.pleroma'] = { + 'bundles': { + 'pleroma', + 'postgresql', + 'zfs', + }, + 'groups': { + 'debian-buster', + 'webserver', + }, + 'metadata': { + 'interfaces': { + 'eth0': { + 'ips': { + '159.69.11.231', + '2a01:4f8:c2c:c410::1/64', + }, + 'gateway4': '172.31.1.1', + 'gateway6': 'fe80::1', + }, + 'ens10': { + 'ips': { + '172.19.137.5/32', + }, + 'routes': { + # VPN + '172.19.136.0/22': { + 'via': '172.19.137.1', + }, + }, + }, + }, + 'icinga_options': { + 'period': 'daytime', + 'pretty_name': 'cybert-media.net', + }, + 'cron': { + 'jobs': { + 'auto-authorize-sm-users': '* * * * * root echo "UPDATE users SET approval_pending=false WHERE email LIKE \'\\%@seibert-media.net\' AND approval_pending=true;" | psql pleroma >/dev/null', + }, + }, + 'nginx': { + 'vhosts': { + 'pleroma': { + 'max_body_size': '16M', + 'extras': True, + }, + 'pleroma-www-redir': { + 'domain': 'www.cybert-media.net', + 'locations': { + '/': { + 'redirect': 'https://cybert-media.net$request_uri', + }, + }, + }, + }, + }, + 'pleroma': { + 'version': '2.2.2', + 'url': 'cybert-media.net', + 'secret_key': vault.decrypt('encrypt$gAAAAABgMVXXclfxVY022fM0Fdf94Oh3sxVlK0lYyBO_CsQFEbZcMua3w1oJY8_9d1JcrCJSSeBRTDnt-ZkRCQ6xKoALo8Rl7s9DPxa7J0vHdkggeZ3IHaOyXBcBPdx8vILyKDLHRXacaynOUBOjy6RIl6Qf2wH1ASbphCcjD-Njricg4PG6Rcixm87fF60rLBjAAkRoz5ZQnXlut1rhjLj-z-7UpA68fkeyPVJXbroWBJdmvCUt92dwjuGARsku2XI22mVvjtJJ'), + }, + 'postfix': { + 'myhostname': 'cybert-media.net', + }, + 'postgresql': { + 'version': '11', + }, + 'vm': { + 'cpu': 1, + 'ram': 2, + }, + 'zfs': { + 'pools': { + 'tank': { + 'when_creating': { + 'config': [{ + 'devices': {'/dev/sdb'}, + }], + }, + }, + }, + }, + }, +} diff --git a/nodes/htz-cloud/sewfile.py b/nodes/htz-cloud/sewfile.py new file mode 100644 index 0000000..95cdcf3 --- /dev/null +++ b/nodes/htz-cloud/sewfile.py @@ -0,0 +1,93 @@ +# this node runs only seafile. Seafile and the mysql server are not +# managed by bundlewrap. + +nodes['htz-cloud.sewfile'] = { + 'bundles': { + 'seafile', + 'zfs', + }, + 'groups': { + 'debian-buster', + 'webserver', + }, + 'metadata': { + 'interfaces': { + 'eth0': { + 'ips': { + '116.203.205.248', + '2a01:4f8:c0c:c71b::1/64', + }, + 'gateway4': '172.31.1.1', + 'gateway6': 'fe80::1', + }, + 'ens10': { + 'ips': { + '172.19.137.3/32', + }, + 'routes': { + # VPN + '172.19.136.0/22': { + 'via': '172.19.137.1', + }, + }, + }, + }, + 'backups': { + 'paths': { + '/mnt/seafile-data', + '/var/tmp/mysqldumps', + }, + }, + 'backup-client': { + 'pre-hooks': { + 'mysqldump': \ + 'test -d /var/tmp/mysqldumps || mkdir -p /var/tmp/mysqldumps\n'\ + 'rm /var/tmp/mysqldumps/*.sql\n'\ + 'mysqldump --databases ccnet_db > /var/tmp/mysqldumps/ccnet_db.sql\n'\ + 'mysqldump --databases seafile_db > /var/tmp/mysqldumps/seafile_db.sql\n'\ + 'mysqldump --databases seahub_db > /var/tmp/mysqldumps/seahub_db.sql\n', + }, + }, + 'icinga_options': { + 'pretty_name': 'sewfile.franzi.business', + 'vars.notification.sms': False, + }, + 'nginx': { + 'vhosts': { + 'sewfile.franzi.business': { + 'ssl': '_.franzi.business', + 'max_body_size': '0', + 'extras': True, + 'website_check_path': '/accounts/login/', + 'website_check_string': 'Username', + }, + }, + }, + 'vm': { + 'cpu': 1, + 'ram': 2, + }, + 'zfs': { + 'pools': { + 'tank': { + 'when_creating': { + 'config': [{ + 'devices': {'/dev/sdb'}, + }], + }, + }, + }, + 'datasets': { + 'tank/mysql': { + 'mountpoint': '/var/lib/mysql', + }, + 'tank/seafile-data': { + 'mountpoint': '/mnt/seafile-data', + 'needed_by': { + 'bundle:seafile', + }, + }, + }, + }, + }, +} diff --git a/nodes/htz-cloud/wireguard.py b/nodes/htz-cloud/wireguard.py index 1139390..2837438 100644 --- a/nodes/htz-cloud/wireguard.py +++ b/nodes/htz-cloud/wireguard.py @@ -5,7 +5,7 @@ nodes['htz-cloud.wireguard'] = { 'wireguard', }, 'groups': { - 'debian-bookworm', + 'debian-buster', }, 'metadata': { 'interfaces': { @@ -33,37 +33,7 @@ nodes['htz-cloud.wireguard'] = { }, 'bird': { 'static_routes': { - '10.73.0.0/16', '172.19.137.0/24', - '172.19.136.62/31', - '172.19.136.64/31', - '172.19.136.66/31', - '192.168.100.0/24', - }, - }, - 'nftables': { - 'forward': { - '50-router': [ - 'ct state { related, established } accept', - 'oifname eth0 accept', - ], - }, - 'input': { - '50-wireguard': [ - 'udp dport 1194 accept', - 'udp dport 51800 accept', - 'udp dport 51804 accept', - 'udp dport 51805 accept', - - # wg.c3voc.de - 'udp dport 51801 ip saddr 185.106.84.42 accept', - 'udp dport 51801 ip6 saddr 2001:67c:20a0:e::189 accept', - ], - }, - 'postrouting': { - '50-router': [ - 'oifname eth0 masquerade', - ], }, }, 'vm': { @@ -71,70 +41,14 @@ nodes['htz-cloud.wireguard'] = { 'ram': 2, }, 'wireguard': { - 'snat_ip': '172.19.137.2', 'peers': { - 'c3voc': { - 'endpoint': 'wg.c3voc.de:13337', - 'my_ip': '10.44.0.35/24', - 'my_port': 51801, - 'their_ip': '10.44.0.1', - 'pubkey': vault.decrypt('encrypt$gAAAAABl_fnDW_9u0RLQpKmiE9V-4DjEcEVSaGp5NohG8tBD3tayGkrDd-LahgeEhDeWlCnoomErZi6HHCag3ODeoKivPr9F_UfdKPEOlCoDkMahqud8p5_3edi-TvIt30Bq_45yeIOo'), - 'masquerade': True, - 'routes': { - '10.73.0.0/16', - }, - }, - 'fra-jana': { - 'endpoint': 'gw.as212226.net:40000', - 'my_ip': '192.168.48.11/24', - 'my_port': 51802, - 'their_ip': '192.168.48.1', - 'pubkey': vault.decrypt('encrypt$gAAAAABnCA7M0Jg0cQwIaYCYEYN74MOSQK30rbhxD6tDIi2VEBqPh-UHrt7MdRzI4AUZ-p0MzjIdsps_DdGBkUTwA_UKD15Q_tg_LJNwDb04zvgSqc3hnJ4jeS2ZZEED0T1dVJ7E0YNS'), - 'masquerade': True, - 'routes': { - '192.168.100.0/24', - }, - }, - 'kunsi-oneplus7': { - 'endpoint': None, - 'exclude_from_monitoring': True, - 'my_ip': '172.19.136.62', - 'my_port': 51800, - 'their_ip': '172.19.136.63', - 'psk': vault.decrypt('encrypt$gAAAAABlbr26kyQ_DNIObVNtG31e1uSZkfDKH9Y1tzq8ZNSAMeuEh30cMJBZQskLLYqt5HUGd-YFwYQB_E7oa-WWbHmDh4vAxJ22Efr85tA0TWsgkc2KvKHqZrNo-GCXhxCqs7SqhW1C'), - 'pubkey': vault.decrypt('encrypt$gAAAAABlbr27doNVsPXF7hMpAp93fP-h_jlW10zycZAHy05r4R7rOZrLqf5b-lhdamx_kQxypYtcW-jOCYgcqWNsId7RluEmFo3drFuUYKIa32YU_U0Pe5EjVRFz_tuf9NRPPugmHb22'), - }, - #'kunsi-p14s': { - # 'endpoint': None, - # 'exclude_from_monitoring': True, - # 'my_ip': '172.19.136.64', - # 'my_port': 1194, - # 'their_ip': '172.19.136.65', - #}, - 'apfelcomputer': { - 'endpoint': None, - 'exclude_from_monitoring': True, - 'my_ip': '172.19.136.64', - 'my_port': 1194, - 'their_ip': '172.19.136.65', - 'psk': vault.decrypt('encrypt$gAAAAABnc7LZSHWmOOQJpbtnpMn9QuWnbiB-6rShwgqbilVd45GzkUwOfEHBw28P_TVm9XJgFiQPOIo12DdxPCzSxKRtcqzji72QCzTlze4ZYWjL-iHm7TydLcKzXOTCO42LKpkMPUgR'), - 'pubkey': vault.decrypt('encrypt$gAAAAABnc7LZpfAeig8yCdcZ-NegshXl-DmkJr0F2OlQR2fqhVnrfKPjgOu-5Cq09KnhdvhomGx_9ZtoFS_3OsVqcFHEasBh27aQN41xZPzEN5-qIPQRnmVoTHpufcU6tC-37Fq-PeAE'), - }, - 'revision-dect-vpn': { - 'endpoint': None, - 'exclude_from_monitoring': True, - 'my_port': 51804, - 'my_ip': '172.19.136.66', - 'their_ip': '172.19.136.67', - }, - 'rottenraptor-vpn': { - 'endpoint': None, - 'exclude_from_monitoring': True, - 'my_port': 51805, - 'my_ip': '172.19.136.68', - 'their_ip': '172.19.136.69', + 'ovh.wireguard': { + 'snat_to': '172.19.137.2', }, }, + 'subnets': { + '172.19.137.0/24', + }, }, }, } diff --git a/nodes/htz-hel/backup-kunsi.py b/nodes/htz-hel/backup-kunsi.py new file mode 100644 index 0000000..be66592 --- /dev/null +++ b/nodes/htz-hel/backup-kunsi.py @@ -0,0 +1,53 @@ +nodes['htz-hel.backup-kunsi'] = { + 'hostname': '2a01:4f9:6b:2d99::1337', + 'bundles': { + 'backup-server', + 'dm-crypt', + 'zfs', + }, + 'groups': { + 'debian-bullseye', + }, + 'metadata': { + 'apt': { + 'unattended-upgrades': { + # requires manual apply after reboot to unlock dm-crypt + # devices + 'reboot_enabled': False, + }, + }, + 'interfaces': { + 'ens18': { + 'ips': { + '2a01:4f9:6b:2d99::1337/64', + }, + 'gateway6': '2a01:4f9:6b:2d99::2', + }, + }, + 'backups': { + # This is the backup target. + 'exclude_from_backups': True, + }, + 'backup-server': { + 'encrypted-devices': { + '/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi1-part1': bwpass.password('bw/backup-kunsi/encryption-passphrase'), + }, + 'clients': { + 'kunsi-t470': { + 'user': 'kunsi-t470', + 'exclude_from_monitoring': True, + 'retain': { + 'daily': 30, + 'weekly': 6, + 'monthly': 12, + }, + }, + }, + }, + 'openssh': { + 'allowed_users': { + 'kunsi-t470', # backup user + }, + }, + }, +} diff --git a/nodes/sophie/backupserver.py b/nodes/htz-hel/backup-sophie.py similarity index 84% rename from nodes/sophie/backupserver.py rename to nodes/htz-hel/backup-sophie.py index 42c6292..dfd492d 100644 --- a/nodes/sophie/backupserver.py +++ b/nodes/htz-hel/backup-sophie.py @@ -6,7 +6,6 @@ nodes['htz-hel.backup-sophie'] = { }, 'groups': { 'debian-bullseye', - 'sophie', }, 'metadata': { 'apt': { @@ -31,19 +30,21 @@ nodes['htz-hel.backup-sophie'] = { 'gateway6': '2a01:4f9:6b:2d99::2', }, }, + 'icinga_options': { + 'pretty_name': 'backup.sophies-kitchen.eu', + }, 'vm': { 'cpu': 4, 'ram': 8, }, 'backup-server': { 'zfs-base': 'tank/backups', - 'my_hostname': 'backup.sophies-kitchen.eu', }, 'nftables': { - 'input': { + 'rules': { '50-sophie-misc': [ - 'udp dport { 60000-61000 } accept', - 'tcp dport 5201 accept', + 'inet filter input udp dport { 60000-61000 } accept', + 'inet filter input tcp dport 5201 accept', ], }, }, @@ -52,9 +53,6 @@ nodes['htz-hel.backup-sophie'] = { 'tank/ejgwthink': { 'mountpoint': '/mnt/backups/ejgwthink', }, - 'tank/ejgwdesk': { - 'mountpoint': '/mnt/backups/ejgwdesk', - }, 'tank/moto-sophie': { 'mountpoint': '/mnt/backups/moto-sophie', }, diff --git a/nodes/htz-hel/proxmox-backupstorage.toml b/nodes/htz-hel/proxmox-backupstorage.toml new file mode 100644 index 0000000..19d83d3 --- /dev/null +++ b/nodes/htz-hel/proxmox-backupstorage.toml @@ -0,0 +1,19 @@ +hostname = "2a01:4f9:6b:2d99::c0ff:ee" +dummy = true + +# How to install: +# - Get server at Hetzner (no IPv4) +# - Install latest proxmox compatible debian +# - RAID5 +# - 50G for system +# - leave rest unpartitioned +# - install zfs +# - create additional partitions for remaining disk space +# - create raidz on those partitions +# - enable ipv6 forwarding +# - install proxmox via apt + +# VM config: +# - IPv6 only +# - IP from the /64 hetzner gives us +# - Gateway is the host itself, to work around the MAC filter hetzner uses diff --git a/nodes/icinga2.toml b/nodes/icinga2.toml deleted file mode 100644 index 3194c8b..0000000 --- a/nodes/icinga2.toml +++ /dev/null @@ -1,64 +0,0 @@ -hostname = "217.160.71.39" -bundles = [ - "bird", - "icinga2", - "icinga2-statuspage", - "php", - "postgresql", -# 'simple-icinga-dashboard', - "unbound", - "wireguard", -] -groups = [ - 'debian-bookworm', - 'webserver', -] - -[metadata] -location = "ionos" -icinga_options.pretty_name = "icinga.franzi.business" - -[metadata.interfaces.ens192] -ips = [ - "217.160.71.39/32", - "2001:8d8:1800:d5::1/128" -] -gateway4 = "10.255.255.1" -gateway6 = "fe80::1" - -[metadata.bird] -static_routes = ["172.19.136.4/32"] - -[metadata.icinga2] -web_domain = "icinga.franzi.business" -ntfy.pass = "!decrypt:encrypt$gAAAAABkMtfD8lenogwJc8uKeGZUQ8QVWHMpAqY_GLW3VhF3Jt0TOC4JiJn49qfaC9Ij5rw6GGsowNIsNBe1Ac83HXOLveANEU2o-O4fp5TxNF0xFWebCCtcaTkj_L2DjUbSUe8QVDn3" -ntfy.url = "https://ntfy.franzi.business/icinga2" -ntfy.user = "!decrypt:encrypt$gAAAAABkMtfW_tyGDUh7TkVX6AN8wSkKixWcQiOrPUWHtDZqnzjqrAkfD40fD8M_PiPDvW5pAa6xHNcUSU34jHolxnC44rDiLw==" -sipgate.pass = "!bwpass_attr:sipgate.de/hi@kunsmann.eu:icinga_token" -sipgate.user = "!bwpass_attr:sipgate.de/hi@kunsmann.eu:icinga_tokenid" - -[metadata.icinga2.api_users.icinga2beamer] -# Used with -password = "!decrypt:encrypt$gAAAAABf3wM9YS5ZpRdhp3xyIFX21_MK0omzqHqykWbWdkZWp2xyJ6awaUSXODnZQ5j-rws6n0yrpaeMdXoj1irb2FrgxMDTdfCh88hIsqcKGOObzwGaRg6Ze0tuiMrzIfOO3tRnc9Kd" -permissions = [ - "objects/query/Host", - "objects/query/Service", -] - -[metadata.icinga2-statuspage] -DOMAIN = "status.franzi.business" -SERVICEGROUP_ID = 80 - -[metadata.icinga2-statuspage.NAME_REPLACEMENTS] -" PROCESS$" = " SERVICE" -".+ VHOST (.+) CONTENT" = "WEB ACCESS \\1" - -[metadata.postgresql] -version = 15 - -[metadata.wireguard] -snat_ip = "172.19.136.4" - -[metadata.vm] -cpu = 2 -ram = 2 diff --git a/nodes/kunsi-p14s.py b/nodes/kunsi-p14s.py new file mode 100644 index 0000000..8952f4d --- /dev/null +++ b/nodes/kunsi-p14s.py @@ -0,0 +1,248 @@ +nodes['kunsi-p14s'] = { + 'hostname': 'localhost', + 'bundles': { + 'arch-with-gui', + 'backup-client', + 'lldp', + 'lm-sensors', + 'nfs-client', + 'openvpn-client', + 'systemd-boot', + 'telegraf-battery-usage', + 'vmhost', + 'voc-tracker-worker', + 'zfs', + }, + 'groups': { + 'arch', + }, + 'metadata': { + 'arch-with-gui': { + 'autologin_as': 'kunsi', + }, + 'backup-client': { + # only alert people if we're missing more than a week of backups + 'one_backup_every_hours': 7 * 24, + }, + 'firewall': { + 'port_rules': { + # obs websocket thingie - just allow all RFC1918 ips here + #'4444': { + # '10.0.0.0/8', + # '172.16.0.0/12', + # '192.168.0.0/16', + #}, + # For the occasional file-share using `python -m http.server` + '8000': {'*'}, + }, + }, + 'interfaces': { + 'br0': { + #'ips': {'10.73.100.103/16'}, + #'gateway4': '10.73.0.254', + 'dhcp': True, + }, + # there is also wlp3s0, but that's managed by netctl + }, + 'nfs-client': { + 'mounts': { + 'nas-scansnap': { + 'mountpoint': '/mnt/scansnap', + 'serverpath': '172.19.138.20:/srv/scansnap', + 'mount_options': { + 'retry=0', + 'rw', + }, + }, + 'nas-storage': { + 'mountpoint': '/mnt/nas', + 'serverpath': '172.19.138.20:/storage/nas', + 'mount_options': { + 'retry=0', + 'ro', + }, + }, + }, + }, + 'openssh': { + 'restrict-to': { + 'rfc1918', + 'ipv6', + }, + }, + 'openvpn-client': { + 'configs': { + 'c3voc': { + 'running': None, + 'enabled': False, + }, + 'smedia-priv': { + 'running': None, + 'enabled': False, + }, + }, + }, + 'pacman': { + 'no_extract': { + 'etc/sudoers.d/ctdb', # samba junk + }, + 'packages': { + # for hardware support + 'amd-ucode': {}, + 'mesa': {}, + + # various video drivers + 'libva-mesa-driver': {}, + 'mesa-vdpau': {}, + 'xf86-video-amdgpu': {}, + + # for i3pystatus + 'iw': {}, + 'wireless_tools': {}, + + # all that other random stuff one needs + 'abcde': {}, + 'apachedirectorystudio': {}, + 'claws-mail': {}, + 'claws-mail-themes': {}, + 'ferdi-bin': {}, + 'ffmpeg': {}, + 'gumbo-parser': {}, # for claws litehtml + 'imagemagick': {}, + 'inkscape': {}, + 'mosquitto': {}, + 'perl-musicbrainz-discid': {}, # for abcde + 'perl-webservice-musicbrainz': {}, # for abcde + 'samba': {}, + 'xf86-input-wacom': {}, + }, + }, + 'sysctl': { + 'options': { + # XXX temp, try to find out why the system randomly + # hangs when using wifi, but only after suspending or + # switching from ethernet. + 'net.ipv6.conf.wlp3s0.disable_ipv6': '1', + }, + }, + 'systemd-boot': { + 'default': 'arch', + 'entries': { + 'arch': { + 'title': 'Arch Linux', + 'linux': '/vmlinuz-linux', + 'initrd': [ + '/amd-ucode.img', + '/initramfs-linux.img', + ], + 'options': { + 'zfs=zroot/system/root', + 'rw', + }, + }, + 'arch-fallback': { + 'title': 'Arch Linux (no ucode, fallback initramfs)', + 'linux': '/vmlinuz-linux', + 'initrd': [ + '/initramfs-linux-fallback.img', + ], + 'options': { + 'zfs=zroot/system/root', + 'rw', + }, + }, + }, + }, + 'systemd-networkd': { + 'bridges': { + 'br0': { + 'match': { + 'enp2s0f0', + 'enp5s0', + }, + }, + }, + }, + 'timezone': 'Europe/Berlin', + 'users': { + 'kunsi': { + 'password': vault.decrypt('encrypt$gAAAAABgLmmuQGRUStrQawoPee-758emIYn2u8-8ebrgzNAFSp7ifeFDdXXvs-zL3QogwNYlCtBHboH2xfy1rSj6OF5bbNO-tg=='), + 'shell': '/usr/bin/fish', + }, + 'sophie': { + 'delete': True, + }, + }, + 'voc-tracker-worker': { + 'url': 'https://tracker.c3voc.de/rpc', + 'token': vault.decrypt('encrypt$gAAAAABiYqaFl4CqOc8DTQIn49Qq0KgAJSzA19GKPNMbyHIjYg0JkvY0sK43ps8CbJWMRR6hJHVK-nP4vrWLwyoWWqt8N8aASMur4odC2s8pEHQKM0TXg4cRwobQz_lyJgrYa2VYdhcD'), + 'secret': vault.decrypt('encrypt$gAAAAABiYqaYbY-3IbnRk-S25pqxrOGN7ovgPo3kBYz8ZqKDedPRzskKZefpLHxBbCOZKjg1XNT4cKbIs5cPCLdj7HdY4beAhnXl4EHZZdxU1zVC7sJCmz9XOS_Ac0UOgOlUFMiet14U'), + }, + 'zfs': { + 'pools': { + 'zroot': { + 'when_creating': { + 'config': [{ + 'devices': [ + '/dev/disk/by-id/nvme-UMIS_RPETJ1T24MGE2QDQ_SS0L25218X3RC1BG1182-part2', + ], + }], + 'ashift': 12, + }, + }, + }, + 'datasets': { + # this is not a complete list, but we can't create that + # structure using bundlewrap anyway, so there's no point + # in adding it here. + 'zroot': { + 'compression': 'lz4', + 'relatime': 'on', + 'xattr': 'sa', + 'primarycache': 'metadata' + # encryption is enabled, too. + }, + 'zroot/movies': { + 'mountpoint': '/media/movies', + }, + 'zroot/system/journal': { + 'mountpoint': '/var/log/journal', + 'acltype': 'posix', + }, + 'zroot/system/libvirt': { + 'mountpoint': '/var/lib/libvirt', + 'needed_by': { + 'bundle:vmhost', + }, + }, + 'zroot/system/video': { + 'mountpoint': '/video', + 'needed_by': { + 'bundle:voc-tracker-worker', + }, + }, + 'zroot/system/root': { + 'canmount': 'noauto', + 'mountpoint': '/', + }, + 'zroot/user/kunsi': { + 'mountpoint': '/home/kunsi', + }, + }, + 'snapshots': { + 'retain_per_dataset': { + 'zroot/user/kunsi': { + # juuuuuuuust to be sure + 'hourly': 100, + }, + }, + 'snapshot_never': { + 'zroot/movies', + 'zroot/system/journal', + 'zroot/system/video', + }, + }, + }, + }, + 'os': 'arch', +} diff --git a/nodes/kunsi-seibert-x1.py b/nodes/kunsi-seibert-x1.py new file mode 100644 index 0000000..19ec8bf --- /dev/null +++ b/nodes/kunsi-seibert-x1.py @@ -0,0 +1,67 @@ +# work laptop. Only apply interactively. + +nodes['kunsi-seibert-x1'] = { + 'dummy': True, + 'hostname': '172.19.138.240', + 'bundles': { + 'basic', + 'lldp', + 'lm-sensors', + 'nfs-client', + 'pacman', + 'openssh', + 'sudo', + 'systemd', + 'telegraf', + 'telegraf-battery-usage', + 'users', + }, + 'groups': set(), + 'metadata': { + 'timezone': 'Europe/Berlin', + 'icinga_options': { + 'exclude_from_monitoring': True, + }, + 'locale': { + 'default': 'en_DK.UTF-8', + }, + 'lldp': { + 'hostname': 'fkunsmann-seibertmedia', + }, + 'nfs-client': { + 'mounts': { + 'nas-storage': { + 'mountpoint': '/mnt/nas', + 'serverpath': '172.19.138.20:/storage/nas', + 'mount_options': { + 'retry=0', + 'ro', + }, + }, + }, + }, + 'pacman': { + 'install_gui': True, + }, + 'telegraf': { + 'influxdb_url': 'https://influxdb.kunsmann.eu/', + 'influxdb_token': vault.decrypt('encrypt$gAAAAABgg9Ag632Xyuc6SWXaR1uH2tLOChmVKAoBIikhjntSSD2qJFL_eouVQGXCLH2HEuSbSdEXcTPn2qmhOiA9jmFdoDSbVbQUsp0EID1wLsWYG_Um2KOxZSF-tn9eDZlgShQYySjzO3nQRmdlJpVLUnGHsiwv_sHD2FstXGpfzTPZq5_egUqEc0K2X-aN2J6BTYc2fZAN'), + 'influxdb_org': vault.decrypt('encrypt$gAAAAABgg9hyjz4XtvG8NBw9uYxiumS3v7YKIrtc9tTTABg1f9R22gzn55q8ULP9X3wlsPMUQs_DH7CgGv9neYmvVAriRoyd8g=='), + 'influxdb_bucket': vault.decrypt('encrypt$gAAAAABgg9iMnq0nKpODMiMN4NtUw231iqpbyDXV-O8epOAGDSL4jcf3CaSa2bLZzH2fJFaKWjW-dpVd384x6KqSQU19XpfsWA=='), + }, + 'users': { + 'kunsi': { + 'password': vault.decrypt('encrypt$gAAAAABgLmmuQGRUStrQawoPee-758emIYn2u8-8ebrgzNAFSp7ifeFDdXXvs-zL3QogwNYlCtBHboH2xfy1rSj6OF5bbNO-tg=='), + 'shell': '/usr/bin/fish', + 'ssh_pubkey': { + # work key + 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICYst1HK+gJYhNxzqJGnz4iB73pa89Xz2yH+8wufOcsA', + }, + }, + 'sophie': { + 'delete': True, + }, + }, + }, + 'os': 'arch', +} diff --git a/nodes/kunsi-t470.py b/nodes/kunsi-t470.py new file mode 100644 index 0000000..61f21d4 --- /dev/null +++ b/nodes/kunsi-t470.py @@ -0,0 +1,104 @@ +# My own laptop. + +nodes['kunsi-t470'] = { + 'dummy': True, + 'hostname': 'no', + 'bundles': { + 'lldp', + 'lm-sensors', + 'nfs-client', + 'telegraf-battery-usage', + }, + 'groups': { + 'arch', + }, + 'metadata': { + 'timezone': 'Europe/Berlin', + 'icinga_options': { + 'exclude_from_monitoring': True, + }, + 'hosts': { + 'entries': { + '10.101.64.10': { + 'www.wifionice.de', + 'wifionice.de', + }, + }, + }, + 'interfaces': { + 'br0': { + 'dhcp': True, + 'use_dhcp_domains': True, + 'send_hostname': False, + }, + # there is also wlp4s0, but that's managed by netctl + }, + 'firewall': { + 'port_rules': { + # obs websocket thingie - just allow all RFC1918 ips here + '4444': { + '10.0.0.0/8', + '172.16.0.0/12', + '192.168.0.0/16', + }, + # For the occasional file-share using `python -m http.server` + '8000': {'*'}, + }, + }, + 'locale': { + 'default': 'en_DK.UTF-8', + }, + 'nfs-client': { + 'mounts': { + 'nas-scansnap': { + 'mountpoint': '/mnt/scansnap', + 'serverpath': '172.19.138.20:/srv/scansnap', + 'mount_options': { + 'retry=0', + 'rw', + }, + }, + 'nas-storage': { + 'mountpoint': '/mnt/nas', + 'serverpath': '172.19.138.20:/storage/nas', + 'mount_options': { + 'retry=0', + 'ro', + }, + }, + }, + }, + 'openssh': { + 'restrict-to': { + '10.0.0.0/8', + '172.16.0.0/12', + '192.168.0.0/16', + 'ipv6', + }, + }, + 'pacman': { + 'install_gui': True, + }, + 'systemd-networkd': { + 'bridges': { + 'br0': { + 'match': { + 'enp0s31f6', + }, + }, + }, + }, + 'users': { + 'kunsi': { + 'password': vault.decrypt('encrypt$gAAAAABgLmmuQGRUStrQawoPee-758emIYn2u8-8ebrgzNAFSp7ifeFDdXXvs-zL3QogwNYlCtBHboH2xfy1rSj6OF5bbNO-tg=='), + 'shell': '/usr/bin/fish', + # FIXME move qemu VMs out of /home/kunsi + 'home-mode': '0755', + }, + 'sophie': { + 'delete': True, + }, + }, + }, + 'os': 'arch', +} diff --git a/nodes/ns-ghirahim.toml b/nodes/ns-ghirahim.toml deleted file mode 100644 index a8581c6..0000000 --- a/nodes/ns-ghirahim.toml +++ /dev/null @@ -1,26 +0,0 @@ -hostname = "46.101.91.6" -groups = [ - "debian-bullseye", - "dns", -] - -[metadata.interfaces.eth0] -ips = [ - "46.101.91.6/20", - "2a03:b0c0:1:d0::bc2:6001/124", -] -gateway4 = "46.101.80.1" -gateway6 = "2a03:b0c0:1:d0::1" - -[metadata.postfix] -# It's fine to do this without authentificating to the relayhost. -# These Systems are not supposed to send mail anywhere else -# than our own domains. -relayhost = "[mail.franzi.business]:2525" - -[metadata.postgresql] -version = "15" - -[metadata.vm] -cpu = 1 -ram = 1 diff --git a/nodes/ns-mephisto.toml b/nodes/ns-mephisto.toml deleted file mode 100644 index a4494fa..0000000 --- a/nodes/ns-mephisto.toml +++ /dev/null @@ -1,36 +0,0 @@ -hostname = "82.165.52.168" -bundles = [ - "nodejs", - "powerdnsadmin", -] -groups = [ - "debian-bullseye", - "dns", - "webserver", -] - -[metadata.interfaces.ens192] -ips = [ - "82.165.52.168/32", - "2a01:239:31c:9b00::1/80" -] -gateway4 = "82.165.52.1" -gateway6 = "fe80::1" - -[metadata.nginx.vhosts.powerdnsadmin] -domain = "ns-mephisto.kunbox.net" - -[metadata.postgresql] -version = "15" - -[metadata.powerdns] -is_secondary = false -secondary_nameservers = "dns" -features.bind = true - -[metadata.powerdnsadmin] -version = "v0.4.2" - -[metadata.vm] -cpu = 2 -ram = 2 diff --git a/nodes/ns-sargeras.toml b/nodes/ns-sargeras.toml deleted file mode 100644 index 53f64b0..0000000 --- a/nodes/ns-sargeras.toml +++ /dev/null @@ -1,26 +0,0 @@ -hostname = "46.102.156.104" -groups = [ - "debian-bookworm", - "dns", -] - -[metadata.interfaces.ens18] -ips = [ - "46.102.156.104/26", - "2a0d:f302:113:73e6::1/48", -] -gateway4 = "46.102.156.65" -gateway6 = "2a0d:f302:113::1" - -[metadata.postfix] -# It's fine to do this without authentificating to the relayhost. -# These Systems are not supposed to send mail anywhere else -# than our own domains. -relayhost = "[mail.franzi.business]:2525" - -[metadata.postgresql] -version = "15" - -[metadata.vm] -cpu = 2 -ram = 2 diff --git a/nodes/ovh/icinga2.py b/nodes/ovh/icinga2.py new file mode 100644 index 0000000..1c930be --- /dev/null +++ b/nodes/ovh/icinga2.py @@ -0,0 +1,158 @@ +nodes['ovh.icinga2'] = { + 'bundles': { + 'bird', + 'icinga2', + 'php', + 'postgresql', + 'simple-icinga-dashboard', + 'unbound', + 'wireguard', + 'zfs', + }, + 'groups': { + 'debian-bullseye', + 'webserver', + }, + 'metadata': { + 'interfaces': { + 'eth0': { + 'ips': { + '51.195.44.8', + '2001:41d0:701:1100::2618/128' + }, + 'gateway4': '51.195.44.1', + 'gateway6': '2001:41d0:701:1100::1' + }, + 'dummy-snat': { + 'ips': { + '172.19.136.3', + }, + }, + }, + 'bird': { + 'static_routes': { + '172.19.136.3/32', + }, + }, + 'icinga2': { + 'api_users': { + 'dashboard': { + 'password': vault.password_for('ovh.icinga2 icinga2 api_user dashboard'), + 'permissions': { + 'objects/query/Service' + }, + }, + # Used with + 'icinga2beamer': { + 'password': vault.decrypt('encrypt$gAAAAABf3wM9YS5ZpRdhp3xyIFX21_MK0omzqHqykWbWdkZWp2xyJ6awaUSXODnZQ5j-rws6n0yrpaeMdXoj1irb2FrgxMDTdfCh88hIsqcKGOObzwGaRg6Ze0tuiMrzIfOO3tRnc9Kd'), + 'permissions': { + 'objects/query/Host', + 'objects/query/Service' + }, + }, + }, + 'restrict-to': { + '172.19.138.0/24', + }, + 'sipgate_user': bwpass.attr('sipgate.de/hi@kunsmann.eu', 'icinga_tokenid'), + 'sipgate_pass': bwpass.attr('sipgate.de/hi@kunsmann.eu', 'icinga_token'), + }, + 'icinga2_api': { + 'custom': { + # redundant monitoring of services/hosts + 'services': { + 'flauschekatze.space CERTIFICATE': { + 'check_command': 'check_https_cert_at_url', + 'vars.domain': 'flauschekatze.space', + }, + 'matrix.flauschekatze.space CERTIFICATE': { + 'check_command': 'check_https_cert_at_url', + 'vars.domain': 'matrix.flauschekatze.space', + }, + }, + }, + }, + 'nginx': { + 'vhosts': { + 'icingaweb': { + 'domain': 'icinga.kunsmann.eu', + 'webroot': '/usr/share/icingaweb2/public', + 'extras': True, + }, + 'icinga_statusmonitor': { + 'domain': 'statusmonitor.icinga.kunsmann.eu', + 'locations': { + '/': { + 'target': 'http://127.0.0.1:5000/', + } + }, + }, + 'statuspage': { + 'domain': 'status.franzi.business', + 'ssl': '_.franzi.business', + 'webroot': '/opt/simple-icinga-dashboard/out', + }, + }, + }, + 'php': { + 'version': '8.0', + 'packages': { + 'curl', + 'gd', + 'intl', + 'imagick', + 'ldap', + 'mysql', + 'opcache', + 'pgsql', + 'readline', + 'xml', + }, + }, + 'postgresql': { + 'version': '11', + }, + 'simple-icinga-dashboard': { + 'icinga2_api': { + 'baseurl': 'https://127.0.0.1:5665', + 'username': 'dashboard', + 'password': vault.password_for('ovh.icinga2 icinga2 api_user dashboard'), + }, + 'filters': { + 'services': '"checks_with_sms" in service.groups', + }, + 'output': { + 'page_title': 'franzi.business Service Status', + }, + 'prettify': { + 'CONTENT': '', + 'NGINX': 'WEBSERVER', + 'PROCESS': 'SERVICE', + }, + }, + 'wireguard': { + 'peers': { + 'ovh.wireguard': { + 'snat_to': '172.19.136.3', + }, + }, + }, + 'zfs': { + 'pools': { + 'tank': { + 'when_creating': { + 'config': [{ + 'devices': { + '/dev/sdb' + }, + }], + }, + }, + }, + }, + 'vm': { + 'cpu': 1, + 'ram': 2, + }, + }, +} diff --git a/nodes/ovh/wireguard.py b/nodes/ovh/wireguard.py new file mode 100644 index 0000000..6e92c59 --- /dev/null +++ b/nodes/ovh/wireguard.py @@ -0,0 +1,61 @@ +nodes['ovh.wireguard'] = { + 'bundles': { + 'bird', + 'wireguard', + }, + 'groups': { + 'debian-buster', + }, + 'metadata': { + 'interfaces': { + 'eth0': { + 'ips': { + '51.195.47.180', + '2001:41d0:701:1100::20da/128' + }, + 'gateway4': '51.195.44.1', + 'gateway6': '2001:41d0:701:1100::1' + }, + }, + 'bird': { + 'static_routes': { + '172.19.136.64/26', + }, + }, + 'backups': { + 'exclude_from_backups': True, + }, + 'vm': { + 'cpu': 1, + 'ram': 2, + }, + 'wireguard': { + 'peers': { + 'ovh.icinga2': {}, + 'home.router': { + 'health_check': True, + }, + 'htz-cloud.wireguard': {}, + 'kunsi-oneplus3': { + 'their_ip': '172.19.136.65', + 'my_ip': '172.19.136.64', + 'my_port': 51819, + 'psk': vault.decrypt('encrypt$gAAAAABgKYeeuPfokbk7lSbbJX-52kap5Cs3tdCHpezkKcExV-yLTHPjszIcAh1T9wW1BtGElRdZea7VTikV3qEu3bupiSqEW4l2lmD5cn2ERYRfuVCoYSkOlmEGokHUX7Nja4G_A2_x'), + 'pubkey': vault.decrypt('encrypt$gAAAAABgKYdTqLG3DcB13QqQadUxyzIjvSxwgZQNjorQi-ADSLsNdDbhikSAGQnSmGelLB74V175awIIir768WEnpLJUKX6nt_i2BxOP3JazvKZSQECkiK8G-IRn8wWWgKarfmtqRwh6'), + 'exclude_from_monitoring': True, + }, + 'sophie-ejgwthink': { + 'their_ip': '172.19.136.67', + 'my_ip': '172.19.136.66', + 'my_port': 51818, + 'psk': vault.decrypt('encrypt$gAAAAABhWWg7WWnVAl3R46oXfPHnmsuXIFELWoMb4wGeDDInKUAwjtI6Y9nYkMpvdxiPRbHnwG4sPxgUAu3l83E4BLTNwb-9_ZYPjz6bQQGYA7oYvCdsezWYYx22hmu8wJhq_j4sMyLK'), + 'pubkey': vault.decrypt('encrypt$gAAAAABhWWg7fSm9snyXS_VLCpEv28_o2fvu6MRzrqngbKQ41DSAQE5fg4ADSbQpi0uwP_6VE_aGo56z1qmLV9wHpOUYCqgYk57w2KcuHR92r_Cw6iNs_h85k38nFGkmuvHzUecqpCNa'), + 'exclude_from_monitoring': True, + }, + }, + 'restrict-to': { + '*', + }, + }, + }, +} diff --git a/nodes/proxmox-backupstorage.toml b/nodes/proxmox-backupstorage.toml deleted file mode 100644 index 7f10946..0000000 --- a/nodes/proxmox-backupstorage.toml +++ /dev/null @@ -1,51 +0,0 @@ -hostname = "192.168.100.31" -dummy = true - -ipmi_hostname = "192.168.100.30" -ipmi_username = "root" -ipmi_password = "!bwpass:192.168.100.30/root" -ipmi_interface = "lanplus" - -[metadata.icinga2_api.smartd.services."SMART STATUS CT480BX500SSD1_2314E6C5C695"] -check_command = "sshmon" -"vars.sshmon_command" = "CT480BX500SSD1_2314E6C5C695" - -[metadata.icinga2_api.smartd.services."SMART STATUS CT480BX500SSD1_2314E6C5C6C8"] -check_command = "sshmon" -"vars.sshmon_command" = "CT480BX500SSD1_2314E6C5C6C8" - -[metadata.icinga2_api.smartd.services."SMART STATUS ST20000NM007D-3DJ103_WVT0RNKF"] -check_command = "sshmon" -"vars.sshmon_command" = "ST20000NM007D-3DJ103_WVT0RNKF" - -[metadata.icinga2_api.smartd.services."SMART STATUS ST20000NM007D-3DJ103_WVT0V0NQ"] -check_command = "sshmon" -"vars.sshmon_command" = "ST20000NM007D-3DJ103_WVT0V0NQ" - -[metadata.icinga2_api.smartd.services."SMART STATUS ST20000NM007D-3DJ103_WVT0W64H"] -check_command = "sshmon" -"vars.sshmon_command" = "ST20000NM007D-3DJ103_WVT0W64H" - -[metadata.icinga2_api.smartd.services."SMART STATUS ST18000NM0092-3CX103_ZVV0686W"] -check_command = "sshmon" -"vars.sshmon_command" = "ST18000NM0092-3CX103_ZVV0686W" - -[metadata.icinga2_api.smartd.services."SMART STATUS ST18000NM0092-3CX103_ZVV06JV7"] -check_command = "sshmon" -"vars.sshmon_command" = "ST18000NM0092-3CX103_ZVV06JV7" - -[metadata.icinga2_api.smartd.services."SMART STATUS ST18000NM0092-3CX103_ZVV06SLR"] -check_command = "sshmon" -"vars.sshmon_command" = "ST18000NM0092-3CX103_ZVV06SLR" - -[metadata.icinga2_api.smartd.services."SMART STATUS ST8000NM0045-1RL112_ZA1EYQWR"] -check_command = "sshmon" -"vars.sshmon_command" = "ST8000NM0045-1RL112_ZA1EYQWR" - -[metadata.icinga2_api.smartd.services."SMART STATUS ST8000NM0045-1RL112_ZA1EYZQF"] -check_command = "sshmon" -"vars.sshmon_command" = "ST8000NM0045-1RL112_ZA1EYZQF" - -[metadata.icinga2_api.smartd.services."SMART STATUS ST8000NM0045-1RL112_ZA1EZ0X5"] -check_command = "sshmon" -"vars.sshmon_command" = "ST8000NM0045-1RL112_ZA1EZ0X5" diff --git a/nodes/revision-dect-vpn.toml b/nodes/revision-dect-vpn.toml deleted file mode 100644 index 1340297..0000000 --- a/nodes/revision-dect-vpn.toml +++ /dev/null @@ -1,27 +0,0 @@ -hostname = "10.1.3.252" -bundles = ["bird", "wireguard"] -groups = ["debian-bookworm"] - -[metadata] -location = "revision" -backups.exclude_from_backups = true -icinga_options.exclude_from_monitoring = true - -[metadata.bird] -static_routes = [ - "10.1.3.0/24", -] - -[metadata.interfaces.ens18] -ips = ["10.1.3.252/24"] -gateway4 = "10.1.3.1" - -[metadata.nftables.postrouting] -"50-router" = [ - "oifname ens18 masquerade", -] - -[metadata.wireguard.peers."htz-cloud.wireguard"] -my_port = 51804 -my_ip = "172.19.136.67" -their_ip = "172.19.136.66" diff --git a/nodes/rottenraptor-server.toml b/nodes/rottenraptor-server.toml deleted file mode 100644 index dadc232..0000000 --- a/nodes/rottenraptor-server.toml +++ /dev/null @@ -1,92 +0,0 @@ -hostname = "91.198.192.207" -groups = [ - "debian-bookworm", - "webserver", -] -bundles = [ - "docker-engine", - "docker-goauthentik", - "docker-immich", - "ipmitool", - "php", - "smartd", - "zfs", -] - -ipmi_hostname = "192.168.100.27" -ipmi_username = "Administrator" -ipmi_password = "!bwpass:bw/rottenraptor-server/ipmi" -ipmi_interface = "lanplus" - -[metadata.docker-immich] -enable_auto_album_share = true - -[metadata.icinga_options] -period = "daytime" - -[metadata.interfaces.eno4] -ips = [ - "91.198.192.207/27", - "2001:67c:b54:1::e/64", -] -gateway4 = "91.198.192.193" -gateway6 = "2001:67c:b54:1::1" - -[metadata.nginx.vhosts.'rotten.city'.locations.'/'] -redirect = "https://www.rottenraptor.com/" -mode = 302 - -[metadata.nginx.vhosts.dokuwiki] -domain = "wiki.rotten.city" -php = true -extras = true -webroot_config.owner = "www-data" - -[metadata.nginx.vhosts.goauthentik] -domain = "sso.rotten.city" - -[metadata.nginx.vhosts.immich] -domain = "immich.rotten.city" - -[metadata.php] -packages = [ - "xml", -] - -[metadata.smartd] -disks = [ - "/dev/disk/by-id/ata-HUH721008ALN600_7SGH125C", - "/dev/disk/by-id/ata-HUH721008ALN600_7SGH726C", - "/dev/disk/by-id/ata-WDC_WDS100T1R0A-68A4W0_21133V800321", - "/dev/disk/by-id/ata-WDC_WDS100T1R0A-68A4W0_21283J446103", - "/dev/disk/by-id/nvme-TOSHIBA-RC100_58UPC29HPW5S", -] - -[metadata.vm] -cpu = 4 -ram = 8 - -[metadata.zfs.pools.tank.when_creating] -ashift = 12 - -[[metadata.zfs.pools.tank.when_creating.config]] -type = "mirror" -devices = [ - "/dev/disk/by-id/ata-HUH721008ALN600_7SGH125C", - "/dev/disk/by-id/ata-HUH721008ALN600_7SGH726C", -] - -[[metadata.zfs.pools.tank.when_creating.config]] -type = "log" -devices = [ - "/dev/disk/by-id/ata-WDC_WDS100T1R0A-68A4W0_21133V800321-part1", - "/dev/disk/by-id/ata-WDC_WDS100T1R0A-68A4W0_21283J446103-part1", -] - -[[metadata.zfs.pools.tank.when_creating.config]] -type = "cache" -devices = [ - "/dev/disk/by-id/ata-WDC_WDS100T1R0A-68A4W0_21133V800321-part2", - "/dev/disk/by-id/ata-WDC_WDS100T1R0A-68A4W0_21283J446103-part2", -] - diff --git a/nodes/rottenraptor-stromdisplay.toml b/nodes/rottenraptor-stromdisplay.toml deleted file mode 100644 index a111bef..0000000 --- a/nodes/rottenraptor-stromdisplay.toml +++ /dev/null @@ -1,40 +0,0 @@ -hostname = "192.168.1.252" -os = "debian" -os_version = [12,] -bundles = [ - "apt", - "basic", - "kernel-modules", - "openssh", - "raspberrypi", - "sdm630_mqtt", - "sudo", - "sysctl", - "systemd", - "systemd-networkd", - "users", -] - -[metadata.apt.unattended-upgrades] -enabled = false - -[metadata.icinga_options] -exclude_from_monitoring = true - -[metadata.interfaces.eth0] -ips = [ - "192.168.1.252/24", -] -dhcp = true - -[metadata.raspberrypi] -enable_display = true - -[metadata.sdm630_mqtt] -enable_stats_collection = false -enable_local_printout = true -config.mqtt.host = "192.168.1.253" - -[metadata.users.kutscher] -password = "!decrypt:encrypt$gAAAAABmqQgvrVuPqFJWJSu8Yxd9NV4ppo5STfCPFqUWn0KepLRdFCktEMla0EJPPxZR5HbNnD6K2Vp-c63raeWwahFUT24SUrAoBFeWfToYWaRDi5WeXJU=" -sudo_commands = ["ALL"] diff --git a/nodes/rottenraptor-stromzaehler.toml b/nodes/rottenraptor-stromzaehler.toml deleted file mode 100644 index c04d6a4..0000000 --- a/nodes/rottenraptor-stromzaehler.toml +++ /dev/null @@ -1,46 +0,0 @@ -hostname = "192.168.1.253" -os = "debian" -os_version = [12,] -bundles = [ - "apt", - "basic", - "kernel-modules", - "mosquitto", - "openssh", - "raspberrypi", - "sdm630_mqtt", - "sudo", - "sysctl", - "systemd", - "systemd-networkd", - "telegraf", - "users", -] - -[metadata.apt.unattended-upgrades] -enabled = false - -[metadata.icinga_options] -exclude_from_monitoring = true - -[metadata.interfaces.eth0] -ips = [ - "192.168.1.253/24", -] -dhcp = true - -[metadata.sdm630_mqtt] -enable_local_printout = true -config.modbus.host = "192.168.1.254" -config.modbus.port = 4196 -config.telegraf.identifier = 'rottenraptor_truck' - -[metadata.sysctl.options] -'net.ipv6.conf.all.disable_ipv6' = '1' - -[metadata.telegraf] -collect_default_metrics = false - -[metadata.users.kutscher] -password = "!decrypt:encrypt$gAAAAABmqQgvrVuPqFJWJSu8Yxd9NV4ppo5STfCPFqUWn0KepLRdFCktEMla0EJPPxZR5HbNnD6K2Vp-c63raeWwahFUT24SUrAoBFeWfToYWaRDi5WeXJU=" -sudo_commands = ["ALL"] diff --git a/nodes/rottenraptor-vpn.toml b/nodes/rottenraptor-vpn.toml deleted file mode 100644 index 342ce1c..0000000 --- a/nodes/rottenraptor-vpn.toml +++ /dev/null @@ -1,27 +0,0 @@ -hostname = "172.30.17.53" -bundles = ["bird", "wireguard"] -groups = ["debian-bookworm"] - -[metadata] -location = "rottenraptor" -backups.exclude_from_backups = true -icinga_options.exclude_from_monitoring = true - -[metadata.bird] -static_routes = [ - "172.30.17.0/24", -] - -[metadata.interfaces.ens18] -ips = ["172.30.17.53/24"] -gateway4 = "172.30.17.1" - -[metadata.nftables.postrouting] -"50-router" = [ - "oifname ens18 masquerade", -] - -[metadata.wireguard.peers."htz-cloud.wireguard"] -my_port = 51804 -my_ip = "172.19.136.69" -their_ip = "172.19.136.68" diff --git a/nodes/rx300.py b/nodes/rx300.py new file mode 100644 index 0000000..cd5ea0a --- /dev/null +++ b/nodes/rx300.py @@ -0,0 +1,578 @@ +# To use the serial console in iRMC, set up grub as follows: +# GRUB_TIMEOUT=30 +# GRUB_CMDLINE_LINUX_DEFAULT="console=ttyS0,115200 console=tty0" +# GRUB_TERMINAL=serial +# GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1" + +nodes['rx300'] = { + 'hostname': '31.47.232.106', + 'bundles': { + 'check-mail-received', + 'dovecot', + 'element-web', + 'gitea', + 'ipmitool', + 'jenkins-ci', + 'lm-sensors', + 'matrix-dimension', + 'matrix-media-repo', + 'matrix-synapse', + 'mautrix-telegram', + 'mautrix-whatsapp', + 'miniflux', + 'minecraft', + 'mx-puppet-discord', + 'netbox', + 'nodejs', + 'oidentd', + 'php', + 'postfixadmin', + 'postgresql', + 'radicale', + 'redis', + 'rspamd', + 'smartd', + 'travelynx', + 'unbound', + 'vmhost', + 'zfs', + }, + 'groups': { + 'debian-bullseye', + 'webserver', + }, + 'metadata': { + 'interfaces': { + 'br0': { + 'ips': { + '31.47.232.106/29', + '2a00:f820:528::2/64', + }, + 'gateway4': '31.47.232.105', + 'gateway6': '2a00:f820:528::1', + }, + }, + 'apt': { + 'packages': { + # for franzi.business deployment + 'ruby': {}, + 'ruby-dev': {}, + 'ruby-bundler': {}, + + # for `bw test` on jenkins + 'bind9utils': {}, + + # used by user:kunsi + 'mosh': {}, + 'weechat': {}, + 'weechat-core': {}, + 'weechat-curses': {}, + 'weechat-perl': {}, + 'weechat-plugins': {}, + 'weechat-python': {}, + 'weechat-ruby': {}, + + # for weechat scripts + 'libpod-parser-perl': {}, + }, + 'repos': { + 'weechat': { + 'items': { + 'deb https://weechat.org/debian {os_release} main', + }, + }, + }, + }, + 'backup-client': { + 'pre-hooks': { + 'kunsi-weechat': \ + 'echo \'core.weechat */layout store\' >> /home/kunsi/.weechat/weechat_fifo\n' \ + 'echo \'core.weechat */save\' >> /home/kunsi/.weechat/weechat_fifo\n', + }, + }, + 'backups': { + 'paths': { + '/home/kunsi/.weechat', + }, + }, + 'check-mail-received': { + 't-online': { + 'email': 'franzi.kunsmann@t-online.de', + 'imap_host': 'secureimap.t-online.de', + 'imap_pass': bwpass.attr('t-online.de/franzi.kunsmann@t-online.de', 'imap'), + }, + }, + 'element-web': { + 'url': 'chat.franzi.business', + 'version': 'v1.11.16', + 'config': { + 'default_server_config': { + 'm.homeserver': { + 'base_url': 'https://matrix.franzi.business', + 'server_name': 'franzi.business', + }, + }, + 'brand': 'franzi.business', + 'showLabsSettings': True, + 'integrations_ui_url': 'https://dimension.franzi.business/riot', + 'integrations_rest_url': 'https://dimension.franzi.business/api/v1/scalar', + 'integrations_widgets_urls': { + 'https://dimension.franzi.business/widgets' + }, + 'default_theme': 'dark', + 'defaultCountryCode': 'DE', + 'jitsi': { + 'preferredDomain': 'meet.ffmuc.net', + }, + }, + }, + 'gitea': { + 'version': '1.17.3', + 'sha1': 'a78611a3e799150fbae3d45d2bd276d95ccffcd8', + 'domain': 'git.franzi.business', + 'email_domain_blocklist': { + 'aol.com', + 'bamibi.com', + 'beezom.buzz', + 'block521.com', + 'cloud-mail.top', + 'comcast.net', + 'cox.net', + 'cupbest.com', + 'dakcans.com', + 'fitshot.xyz', + 'gmail.co', + 'gmail.com', + 'grabmail.club', + 'hbehs.com', + 'hotmail.com', + 'msn.com', + 'nycexercise.com', + 'oceore.com', + 'popcornfly.com', + 'qqhow.com', + 'runqx.com', + 'spicethainj.com', + 'spruzme.com', + 'syswift.com', + 'tagbert.com', + 'teleg.eu', + 'tempinbox.xyz', + 'verizon.net', + 'vusra.com', + 'yahoo.com', + }, + 'enable_git_hooks': True, + 'install_ssh_key': True, + 'internal_token': vault.decrypt('encrypt$gAAAAABfPncYwCX-NdBr9LdxLyGqmjRJqhmwMnWsdZy6kVOWdKrScW78xaqbJ1tpL1J4qa2hcZ7TQj3l-2mkyJNJOenGzU3TsI-gYMj9vC4m8Bhur5zboxjD4dQXaJbD1WSyHJ9sPJYsWP3Gjg6I19xeq9xMlAI6xaS9vOfuoI8nZnnQPx1NjfQEj03Jxf8a0-3F20sfICst1xRa5K48bpq1PFkK_oRojg=='), + 'lfs_secret_key': vault.decrypt('encrypt$gAAAAABfPnd1vgNDt86-91YhviQw8Z0djSp4f_tBt76klDv-ZcwxP1ryJzqJ7qnfaTe_6DYCfc82gEzvVDsyBlCoAkGpt1AI2_LCKetuSCnDPjtGvwdQl3A53lFEdG2UJl1uUiR7f8Vr'), + 'oauth_secret_key': vault.decrypt('encrypt$gAAAAABfPnbfTISbldhS0WyxVKBHVVoOMcar7Kxmh1kkmiUGd-RzbbnNzzhEER_owjttPQcACPfGKZ6WklaSsXjLq8km4P6A9QmPbC06GmHbc91m0odCb1KiY7SZeUD35PiRiGSq50dz'), + 'security_secret_key': vault.decrypt('encrypt$gAAAAABfPnc-R7pkDj4pQgHDb6pzlNYNJgiWdeBFsX7IsHSnCtNPbZxCdtSL8cHtQzVO1KbSxS7zCwssmgiR8Kj54Z-koD-FQbjpbKWoIPw8SsyeqBVlZhIeEzhw_1t7_7ZTvv1O8AePdNYel9JJb_TaAZ8Vx46ZfsEPy8zaaHrqOekHC6RAnB4='), + }, + 'icinga_options': { + 'pretty_name': 'franzi.business', + }, + 'jenkins-ci': { + 'install_ssh_key': True, + 'domain': 'jenkins.franzi.business', + 'writeable_paths': { + '/var/www/franzi.business', # for deployment task + }, + }, + 'letsencrypt': { + 'concat_and_deploy': { + 'kunsi-weechat': { + 'match_domain': 'rx300.kunbox.net', + 'target': '/home/kunsi/.weechat/ssl/relay.pem', + 'chown': 'kunsi:kunsi', + 'chmod': '0440', + 'commands': [ + 'echo \'core.weechat */relay sslcertkey\' >> /home/kunsi/.weechat/weechat_fifo' + ], + }, + }, + 'domains': { + 'rx300.kunbox.net': set(), + }, + }, + 'matrix-media-repo': { + 'version': 'v1.2.12', + 'sha1': 'c2dfa521c2eea9a0dcde9f1c7803f52ce6d0352e', + 'homeservers': { + 'franzi.business': { + 'domain': 'http://[::1]:20080/', + 'api': 'synapse', + }, + }, + 'admins': { + '@kunsi:franzi.business', + }, + 'upload_max_mb': 500, + }, + 'matrix-dimension': { + 'url': 'dimension.franzi.business', + 'version': 'c6d047c', # XXX master is broken as of 2021-11-27 + 'homeserver': { + 'name': 'franzi.business', + 'clientServerUrl': 'https://matrix.franzi.business', + 'accessToken': vault.decrypt('encrypt$gAAAAABg-wBmGbAy-Ou1mkG2w5UyoqWmWYzDr4ZavyUQdmG_VtrUSmwHjx-qcBGIz_7NniD3zKm9GGvzRZItDu5zYiojcudYr74TkWJKhdDrgFbcWlfJJ_m3bWzrSORaTYzBGRckp2Vz_8xHgDk1W03vpT6mdIPMDzjuINssIcPs0YDth25W942tMfPA2csvLADY50qVRMJpdBOVIWba55o0g6-mAAQLOz6Ld4cCvYqZsqXsxjT8JUytJv_uSG4zgCS_aX20JlAyJWpJgT8FQF5HzIbsko_-Z9-TwtY7yllJp5Ri3n0WaDaWoMmUfhLvkMJeymmOc32A4WJBAePQ_2F-_oUDE7t97A-m3ZiMVAEefDnH5MkoiQEJTfHrJsXRkdBT_BnJlY1CoAuXpRYDdvbVDwN_qZHHHtqsno437l9S6GgDK_-sKBiojYkYsfHcJCdSEqeFGuxT'), + }, + 'admins': [ + '@kunsi:franzi.business', + ], + 'telegram': { + # same as for mautrix-telegram + 'botToken': vault.decrypt('encrypt$gAAAAABfVK51ErJ6gfsOOkbRxSHDnVYmf7EihAQf7Uwj9og3TlAw64WRsA6ZVEgTSvOdLB3SMKZ-cTEhwkCOpbymq-_WLhes-hZALhN-H_oXHaxTQErJ0lARynKmjM-4ZhoGlUWlfh4Q'), + }, + }, + 'matrix-synapse': { + 'server_name': 'franzi.business', + 'baseurl': 'matrix.franzi.business', + 'admin_contact': 'mailto:hostmaster@kunbox.net', + 'trusted_key_servers': { + 'matrix.org', + 'finallycoffee.eu', + 'nyantec.com', + }, + 'additional_client_config': { + 'im.vector.riot.jitsi': { + 'preferredDomain': 'meet.ffmuc.net', + }, + }, + 'wellknown_also_on_vhosts': { + 'franzi.business', + }, + }, + 'mautrix-telegram': { + 'version': 'v0.12.2', + 'homeserver': { + 'domain': 'franzi.business', + 'url': 'https://matrix.franzi.business', + }, + 'provisioning': { + 'enabled': True, + 'shared_secret': vault.decrypt('encrypt$gAAAAABfVKflEMAi07C_QGP8cy97hF-4gGPym0oF6p4WSMdAveTpx-hFsZd2s7v9ubw99yIsyKx0dHOJI0UND7hV1rKZdvjy4Qa642abZ2wwW7SWTqvuP_qVtrf6-klc2QKTzeD9c_LVsyZ2dqz_JxRPq3MRXgkubZuWOZ6FmFlAlteTffoGfWE='), + }, + 'permissions': { + "'*'": 'relaybot', + 'nyantec.com': 'full', + 'franzi.business': 'full', + "'@kunsi:franzi.business'": 'admin', + }, + 'telegram': { + 'api_id': vault.decrypt('encrypt$gAAAAABfVK5SmDDru-UQxitkE5VhPArnUBhaRbAqQPvAW2Fh3fd1XDrWxa3Qn4BSnJAPNWglH5wil_SXUMcIm95FMhPe8dVeMQ=='), + 'api_token': vault.decrypt('encrypt$gAAAAABfVK5jHuUly1xr9Iku362k7oF4ZYRhLGzNJh3aJpiNrLfAy_DJpTwucx4FV_g45dyQF5boqG2rgdDfwsJN_Ab95es6T4SPGiXIxJOBlvIln1Torwh16pXKchhUTn_PQ077Ll1W'), + # same as for matrix-dimension + 'bot_token': vault.decrypt('encrypt$gAAAAABfVK51ErJ6gfsOOkbRxSHDnVYmf7EihAQf7Uwj9og3TlAw64WRsA6ZVEgTSvOdLB3SMKZ-cTEhwkCOpbymq-_WLhes-hZALhN-H_oXHaxTQErJ0lARynKmjM-4ZhoGlUWlfh4Q'), + }, + }, + 'mautrix-whatsapp': { + 'version': 'v0.8.0', + 'sha1': '4e561a96c8fae61edd8dee9abdd52b5146fa98b2', + 'homeserver': { + 'domain': 'franzi.business', + 'url': 'https://matrix.franzi.business', + }, + 'permissions': { + "'@kunsi:franzi.business'": 'admin', + }, + }, + 'miniflux': { + 'domain': 'rss.franzi.business', + }, + 'minecraft': { + 'heap_mb': 16*1024, + 'sha1': '82be5e1bbdfd1bcb001644780562282fd42ee5a9', + 'version': ('1.19.2', '261'), + 'allowlist': { + # use https://mcuuid.net/ + 'kunsi': 'a2b93640-9dff-4c3c-a6c7-bd75329d8997', + 'sophie': '7e593cbb-9d61-4d46-a416-6edbcf8a2109', + }, + 'ops': { + 'kunsi': 'a2b93640-9dff-4c3c-a6c7-bd75329d8997', + }, + 'restrict-to': {'*'}, + }, + 'mx-puppet-discord': { + 'homeserver': { + 'domain': 'franzi.business', + 'url': 'https://matrix.franzi.business', + }, + 'allowed-users': { + '@.*:franzi\\\\.business', + }, + }, + 'netbox': { + 'domain': 'netbox.franzi.business', + 'version': 'v3.4.1', + 'changelog_retention_days': 360, + 'admins': { + 'kunsi': 'hostmaster@kunbox.net', + }, + }, + 'nftables': { + 'rules': { + '50-kunsi-weechat': [ + 'inet filter input udp dport { 60000-61000 } accept', + 'inet filter input tcp dport 9001 accept', + ], + }, + }, + 'nginx': { + 'security.txt': { + 'contact': 'mailto:security@kunsmann.eu', + 'Encryption': 'https://franzi.business/gpg_hi-kunsmann.eu.asc', + }, + 'vhosts': { + 'element-web': {'ssl': '_.franzi.business'}, + 'gitea': {'ssl': '_.franzi.business'}, + 'jenkins-ci': {'ssl': '_.franzi.business'}, + 'matrix-dimension': {'ssl': '_.franzi.business'}, + 'matrix-synapse': {'ssl': '_.franzi.business'}, + 'miniflux': {'ssl': '_.franzi.business'}, + 'netbox': {'ssl': '_.franzi.business'}, + 'radicale': {'ssl': '_.franzi.business'}, + 'travelynx': {'ssl': '_.franzi.business'}, + 'daskritzelt-redirect': { + 'domain': 'die-brontosaurier-waren-es.org', + 'ssl': None, + 'locations': { + '/': { + 'redirect': 'https://twitter.com/daskritzelt/status/1259167444373028864', + 'mode': 302, + }, + }, + }, + 'franzi.business': { + 'webroot': '/var/www/franzi.business/_site/', + 'ssl': '_.franzi.business', + 'extras': True, + }, + 'git.kunsmann.eu': { + 'locations': { + '/': { + 'redirect': 'https://git.franzi.business$request_uri', + }, + }, + }, + 'kunbox.net': {}, + 'kunsmann.eu': { + 'locations': { + '/': { + 'redirect': 'https://franzi.business$request_uri', + }, + '/.well-known/openpgpkey': { + 'alias': '/var/www/kunsmann.eu/.well-known/openpgpkey/', + 'additional_config': { + 'default_type application/octet-stream', + 'add_header Access-Control-Allow-Origin *', + }, + }, + }, + }, + 'mta-sts': { + 'domain': 'mta-sts.kunbox.net', + 'domain_aliases': { + 'mta-sts.franzi.business', + 'mta-sts.kunsmann.eu', + 'mta-sts.trans-agenda.eu', + }, + }, + 'paste.franzi.business': { + 'ssl': '_.franzi.business', + 'extras': True, + 'webroot_config': { + 'owner': 'kunsi', + }, + }, + 'postfixadmin': { + 'domain': 'postfixadmin.franzi.business', + 'ssl': '_.franzi.business', + 'webroot': '/opt/postfixadmin/public/', + 'php': True, + 'locations': { + '/rspamd/': { + 'target': 'http://localhost:11334/', + 'websockets': True, + }, + } + }, + 'wiki.franzi.business': { + 'ssl': '_.franzi.business', + 'extras': True, + 'php': True, + 'webroot_config': { + 'owner': 'www-data', + 'group': 'www-data', + }, + 'website_check_path': '/start?do=login', + 'website_check_string': 'Username', + }, + }, + 'worker_processes': 8, + }, + 'oidentd': { + 'allows': { + 'kunsi': { + 'spoof', + 'spoof_all', + }, + }, + }, + 'php': { + 'version': '8.0', + 'packages': { + 'gd', + 'imagick', + 'imap', + 'intl', + 'mbstring', + 'opcache', + 'pgsql', + 'readline', + 'xml', + 'yaml', + }, + }, + 'postfix': { + 'message_size_limit_mb': 50, + 'mynetworks': { + 'gce', + 'ovh', + }, + }, + 'postfixadmin': { + 'version': '3.3.13', + 'setup_password': vault.decrypt('encrypt$gAAAAABgnNGpAqUs--qBXII9ZPcHtxaELy9e2Dx9O44n4l0O4nMHPoIyaPW5HkvpQ2zWTlh5OfjjOgunRtE_voJuY0Kdtji37ixAnuL9ErOJ0LDY5QfMkNPUgPs5alwz1baqYq6rqJ7NDmB0gHraY46v5eG79R2EyQ=='), + }, + 'postgresql': { + 'version': '13', + }, + 'radicale': { + 'domain': 'radicale.franzi.business', + 'users': { + 'kunsi': bwpass.password('radicale.franzi.business/kunsi'), + }, + }, + 'rspamd': { + 'ignore_spam_check_for_ips': { + # entropia + '45.140.180.32/27', # Entropia e. V. + '45.140.180.112/28', # MicroPOC + '2a0e:c5c0:0:201::/64', # Entropia e. V. + '2a0e:c5c0:0:307::/64', # MicroPOC + + # c3kl + '116.202.19.236', + '2a01:4f8:1c17:cc52::/64', + + # ccc + '212.12.55.65', + '212.12.55.67', + '2a00:14b0:4200:3000:23:55:0:65', + + # IN-Berlin mailman + '130.133.8.35', + '192.109.42.28', + '192.109.42.122', + '193.29.188.9', + '217.197.80.23', + '217.197.80.134', + '2001:bf0:c000:a::2:134', + + # c3voc + '185.106.84.32/26', + '2001:67c:20a0:e::/64', + + # DENOG + '195.20.121.100', + '2001:1440:201:101::5', + }, + 'password': bwpass.password('bw/rx300/rspamd'), + 'dkim': 'uO4aNejDvVdw8BKne3KJIqAvCQMJ0416', + }, + 'smartd': { + 'disks': { + '/dev/nvme0', + }, + }, + 'systemd': { + 'journal': { + 'maxuse': '4G', + }, + }, + 'systemd-networkd': { + 'bridges': { + 'br0': { + 'match': { + 'eno1', + }, + }, + }, + }, + 'systemd-timers': { + 'timers': { + 'cleanup-paste.franzi.business': { + 'command': '/usr/bin/find /var/www/paste.franzi.business/ -maxdepth 1 -type d -mtime +60 -exec rm -r {} \;', + 'user': 'kunsi', + 'when': 'daily', + }, + }, + }, + 'travelynx': { + 'version': '1.23.12', + 'mail_from': 'travelynx@franzi.business', + 'domain': 'travelynx.franzi.business', + }, + 'unbound': { + 'threads': 8, + 'cache_slabs': 8, + }, + 'users': { + 'kunsi': { + 'enable_linger': True, + }, + }, + 'zfs': { + 'module_options': { + 'zfs_arc_max_gb': 16, + }, + 'pools': { + 'tank': { + 'when_creating': { + 'config': [{ + 'type': 'raidz', + 'devices': { + '/dev/sda', + '/dev/sdb', + '/dev/sdc', + '/dev/sdd', + }, + }], + 'ashift': 12, + }, + }, + }, + 'datasets': { + 'tank/libvirt': { + 'mountpoint': '/var/lib/libvirt', + 'compression': 'on', + 'needed_by': { + 'bundle:vmhost', + }, + }, + 'tank/home-kunsi': { + 'mountpoint': '/home/kunsi', + 'needed_by': { + 'directory:/home/kunsi', + }, + }, + }, + }, + 'vm': { + 'cpu': 32, + 'ram': 256, + }, + }, +} diff --git a/nodes/sophie/miniserver.py b/nodes/sophie/miniserver.py deleted file mode 100644 index b852a35..0000000 --- a/nodes/sophie/miniserver.py +++ /dev/null @@ -1,263 +0,0 @@ -# sophie's miniserver - -nodes["htz-cloud.miniserver"] = { - "bundles": { - "element-web", - "hedgedoc", - "matrix-media-repo", - "matrix-synapse", - "matrix-stickerpicker", - "nodejs", - "ntfy", - "mautrix-telegram", - "postgresql", - "zfs", - }, - "groups": { - "debian-bookworm", - "sophie", - "webserver", - }, - "metadata": { - "interfaces": { - "eth0": { - "ips": { - "157.90.20.62", - "2a01:4f8:c2c:840f::1/64", - }, - "gateway4": "172.31.1.1", - "gateway6": "fe80::1", - }, - }, - "apt": { - "packages": { - "mosh": {}, - "weechat": {}, - "weechat-core": {}, - "weechat-curses": {}, - "weechat-perl": {}, - "weechat-plugins": {}, - "weechat-python": {}, - "weechat-ruby": {}, - }, - "repos": { - "weechat": { - "items": { - "deb https://weechat.org/debian {os_release} main", - }, - }, - }, - }, - "backup-client": { - "pre-hooks": { - "sophie-weechat": "echo 'core.weechat */layout store' >> /home/sophie/.weechat/weechat_fifo\n" - "echo 'core.weechat */save' >> /home/sophie/.weechat/weechat_fifo\n", - }, - }, - "backups": { - "paths": { - "/home/sophie/.weechat", - }, - }, - "element-web": { - "url": "chat.sophies-kitchen.eu", - "version": "v1.11.96", - "config": { - "default_server_config": { - "m.homeserver": { - "base_url": "https://matrix.sophies-kitchen.eu", - "server_name": "sophies-kitchen.eu", - }, - }, - "brand": "sophies-kitchen.eu", - "showLabsSettings": True, - "default_theme": "dark", - "defaultCountryCode": "DE", - "jitsi": { - "preferredDomain": "meet.ffmuc.net", - }, - "map_style_url": "https://api.maptiler.com/maps/openstreetmap/style.json?key=fU3vlMsMn4Jb6dnEIFsx", - }, - }, - "hedgedoc": { - "version": "1.10.0", - "config": { - "production": { - "allowAnonymousEdits": True, - "domain": "pad.sophies-kitchen.eu", - }, - }, - }, - "letsencrypt": { - "concat_and_deploy": { - "sophie-weechat": { - "match_domain": "i.sophies-kitchen.eu", - "target": "/home/sophie/.weechat/ssl/relay.pem", - "chown": "sophie:sophie", - "chmod": "0440", - "commands": [ - "echo 'core.weechat */relay sslcertkey' >> /home/sophie/.weechat/weechat_fifo" - ], - }, - }, - "domains": { - "i.sophies-kitchen.eu": set(), - "webdump.sophies-kitchen.eu": set(), - "matrix.sophies-kitchen.eu": { - "sophies-kitchen.eu", - }, - }, - }, - "matrix-media-repo": { - "version": "v1.3.7", - "datastore_id": "99c09e24edc4e9be6c4c9486bc147e385bc87044", - "sha1": "3e2bb7089b0898b86000243a82cc58ae998dc9d9", - "homeservers": { - "sophies-kitchen.eu": { - "domain": "http://[::1]:20080/", - "api": "synapse", - "signing_key_path": "/etc/matrix-synapse/mmr.signing.key", - }, - }, - "admins": { - "@sophie:sophies-kitchen.eu", - }, - "upload_max_mb": 500, - }, - "matrix-stickerpicker": { - # use this bot token for telegram import: encrypt$gAAAAABg4bcQVzBF_iXdDtjRQD-O37GHdbHwWXyhCLPOuJLbv3ezUeXKR203hkCXkjfItSHi4NiTEgQPadDZTRkavaRpvAoaQV1a4srCS_Y-NU4RiOmkrVFJ_Xhw6UZvwjQUQ0QPOx9t - "domain": "matrix-stickers.sophies-kitchen.eu", - "config": { - "access_token": vault.decrypt( - "encrypt$gAAAAABg4btB0KGk068ahGZzR0w_Lm1bj1wUbB2WfNNs2bp3PwM4Ftp6MjQnrF-CejZfrF0NjPJw9Z4MrgileHP0sVw04mvgKSHfTf8gv4kTB6WuCIxHeMWHUDx00LTWL73fSlhCK0o1" - ), - "homeserver": "https://matrix.sophies-kitchen.eu", - "user_id": "@dimension:sophies-kitchen.eu", - }, - }, - "matrix-synapse": { - "server_name": "sophies-kitchen.eu", - "baseurl": "matrix.sophies-kitchen.eu", - "admin_contact": "mailto:foobar@sophies-kitchen.eu", - "trusted_key_servers": { - "matrix.org", - }, - }, - "mautrix-telegram": { - "version": "v0.15.2", - "homeserver": { - "domain": "sophies-kitchen.eu", - "url": "https://matrix.sophies-kitchen.eu", - }, - "provisioning": { - "enabled": False, - "shared_secret": '""', - }, - "permissions": { - "sophies-kitchen.eu": "full", - "'@sophie:sophies-kitchen.eu'": "admin", - }, - "telegram": { - "api_id": vault.decrypt( - "encrypt$gAAAAABgnqdXhCTwtCXJhSaCZsiNfHPtjwlYtV1sUAux7JZdejN3xItU9RJLeNu4gUniv36XbBoxKwVtqqyV3RcAs-PgumcfYQ==" - ), - "api_token": vault.decrypt( - "encrypt$gAAAAABgnqd5IdpYRmW-C4ONBSXQfiJrpTVQX0rP0eKoDnLnVTLg-5olSjcw2gVvEKWLnsGEZIgVcG7yEs-sqYRxeiQLFFpSn-Z4We0mhj0CUeFoD-eXJsp-bAgLv9PJoMv5Gjb8r9i6" - ), - "bot_token": '""', - }, - }, - "nameservers": { - "213.133.98.98", - "213.133.99.99", - "213.133.100.100", - "2a01:4f8:0:1::add:1010", - "2a01:4f8:0:1::add:9999", - "2a01:4f8:0:1::add:9898", - }, - "nftables": { - "input": { - "50-sophie-weechat": [ - "udp dport { 60000-61000 } accept", - "tcp dport 9001 accept", - ], - }, - }, - "nginx": { - "vhosts": { - "sophies-kitchen.eu": { - "webroot": "/var/www/sophies-kitchen.eu/_site/", - "extras": True, - }, - "matrix-synapse": { - "domain": "matrix.sophies-kitchen.eu", - }, - "webdump.sophies-kitchen.eu": { - "webroot_config": { - "owner": "sophie", - "group": "sophie", - "mode": "0755", - }, - "extras": True, - }, - "recipes.sophies-kitchen.eu": { - "webroot_config": { - "owner": "sophie", - "group": "sophie", - "mode": "0755", - }, - }, - }, - }, - "nodejs": { - "version": 20, - }, - "ntfy": { - "domain": "ntfy.sophies-kitchen.eu", - "allow_unauthorized_write": True, - }, - "postgresql": { - "version": "13", - }, - "sysctl": { - "options": { - # XXX find out if this is really needed - "net.ipv4.conf.all.forwarding": "1", - "net.ipv6.conf.all.forwarding": "1", - }, - }, - "vm": { - "cpu": 2, - "ram": 4, - }, - "users": { - "sophie": { - "enable_linger": True, - "ssh_pubkey": [ - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDILcYrMQNRVXAm5L+7No1ZumqfCyRc1QZmTY3O7Q8hsE4+fCAvwsWm2aSMfLL3NnIl8Nm1Rixzic5jdYKYNIY3SlX1wvTB+MhGb2eyVSd7c/Y98aCLSlDkQ2sebjpdA1FoJOeGD3qxqDwj0+KckXU2ZaSSQY7CxVsjH65UxCHqVAg+6uLdNbj7j850s1B9NXVXef+sBQ5jUngXxnqQWwNh2Mn8auwumkeEG4SYf96wyFkLvmBitOng/GyLWl9YPnXXHHDnatcVipy7y34qw4CQ4P84anecbA+Bqr9IcxBW6qYmYgRKEnAcmEfjQd+BI1gCLB1BBEmb/qp+mVLd4tOh sophie@carbon" - ], - }, - }, - "zfs": { - "datasets": { - "tank/webdump": { - "mountpoint": "/var/www/webdump.sophies-kitchen.eu", - "needed_by": ["directory:/var/www/webdump.sophies-kitchen.eu"], - } - }, - "pools": { - "tank": { - "when_creating": { - "config": [ - { - "devices": { - "/dev/disk/by-id/scsi-0HC_Volume_23952298", - }, - } - ] - }, - }, - }, - }, - }, -} diff --git a/nodes/sophie/sophie.homeassistant.toml b/nodes/sophie/sophie.homeassistant.toml deleted file mode 100644 index 42e25d0..0000000 --- a/nodes/sophie/sophie.homeassistant.toml +++ /dev/null @@ -1,36 +0,0 @@ -hostname = "172.19.164.3" -bundles = [ - 'homeassistant', - 'nginx', - 'pyenv', -] -groups = [ - "debian-bookworm", -] - -[metadata.interfaces.enp7s0] -ips = [ - "172.19.164.3/24", -] -gateway4 = "172.19.164.1" -ipv6_accept_ra = true - -[metadata.vm] -cpu = 2 -ram = 4 - -[metadata.homeassistant] -domain = 'homeassistant.home.sophies-kitchen.eu' -api_secret = 'encrypt$gAAAAABjpyuqXLoilokQW5c0zV8shHcOzN1zkEbS-I6WAAX-xDO_OF33YbjbkpELU2HGBzqiWX40J0hsaEbYJOnCHFk8gJ-Xt0vdqqbQ5vca_TGPNQHZPAS4qZoPTcUhmX_I-0EdT6ukhxejXFYBiYRZikTLjH3lcNM5qnckCm-H9NbRdjLb9hbCDIjbEglHmBl_g08S1_ukvX3dDSCIHIxgXXGsdK_Go1KxPJd8G22FL_MMhCfsTW-6ioIqoHSeSA1NGk3MZHEIM2errckiopKBxoBaROsacO9Uqk1zrrgXOs2NsgiTRtrbV1TNlFVaIX9mZdsUnMGZ' - -[metadata.nginx] -restrict-to = [ - '172.19.164.0/22', -] - -[metadata.pyenv] -version = 'v2.3.36' -python_versions = ["3.12.2"] - -[metadata.nginx.vhosts.homeassistant] -ssl = '_.home.sophies-kitchen.eu' diff --git a/nodes/sophie/unbound.py b/nodes/sophie/unbound.py deleted file mode 100644 index e0cb10d..0000000 --- a/nodes/sophie/unbound.py +++ /dev/null @@ -1,32 +0,0 @@ -nodes["sophie.unbound"] = { - "hostname": "172.19.164.4", - "bundles": { - "unbound", - }, - "groups": { - "debian-bookworm", - }, - "metadata": { - "interfaces": { - "enp1s0": { - "ips": { - "172.19.164.4/24", - "fe80::4/64", - }, - "gateway4": "172.19.164.1", - "ipv6_accept_ra": True, - }, - }, - "vm": { - "cpu": 2, - "ram": 2, - }, - "unbound": { - "dns64": False, - "restrict-to": { - "172.19.164.0/24", - "fe80::/64", - }, - }, - }, -} diff --git a/nodes/sophie/vmhost.py b/nodes/sophie/vmhost.py deleted file mode 100644 index aca520c..0000000 --- a/nodes/sophie/vmhost.py +++ /dev/null @@ -1,145 +0,0 @@ -nodes['sophie.vmhost'] = { - 'hostname': '172.19.164.2', - 'bundles': { - 'backup-client', - 'lm-sensors', - 'nfs-server', - 'mosquitto', - 'smartd', - 'vmhost', - 'zfs', - }, - 'groups': { - 'debian-bookworm', - }, - 'metadata': { - 'apt': { - 'packages': { - 'irqbalance': {}, - }, - }, - 'groups': { - 'nas': {}, - }, - 'interfaces': { - 'br1': { - 'ips': { - '172.19.164.2/24', - }, - 'gateway4': '172.19.164.1', - 'ipv6_accept_ra': True, - }, - }, - 'mosquitto': { - 'bridges': { - 'c3voc': { - 'peer': 'mqtt.c3voc.de', - 'client_id': 'sophie-vm-host', - 'auth': { - 'username': vault.decrypt('encrypt$gAAAAABgaBa5UZyZlsMM9TV5pa-VyOieFWYzAslxWVnXjOeXHvF4kMHHSHSMOrv-U9k7Ec3mMCDuJFO3ybpOsZSeFQDL7GgEfw=='), - 'password': vault.decrypt('encrypt$gAAAAABgaBbfm65cYBuod0UehWNmY0NfeUH9xsrP2kENYNF_LWP2iV5a8db_cqMoITwyjjBsHpvjaeDq07Z5K5nQ_BLZG6zPqapL-Qvp20wyck49Dy2R4V4='), - }, - 'topics': [ - { - 'pattern': '#', - 'remote_prefix': '/voc/', - 'local_prefix': 'voc' - }, - ], - }, - }, - 'listeners': { - '8083': { - 'protocol': 'websockets', - }, - }, - 'tasmota-telegraf-topic': '/switch/#', - 'restrict-to': { - '172.19.164.0/24', - }, - }, - 'nfs-server': { - 'version': 4, - 'shares': { - '/srv/nas': { - '172.19.164.0/24': 'ro,all_squash,anonuid=65534,anongid=65534,no_subtree_check', - }, - }, - }, - 'smartd': { - 'disks': { - '/dev/nvme0', - - # nas disks - '/dev/disk/by-id/ata-ST20000NM007D-3DJ103_ZVT7BHBQ', - '/dev/disk/by-id/ata-ST20000NM007D-3DJ103_ZVT7D6JP', - }, - }, - 'systemd-networkd': { - 'bridges': { - 'br0': { - 'match': { - 'enp1s0', - }, - }, - 'br1': { - 'match': { - 'br0.1', - }, - }, - }, - }, - 'systemd-timers': { - 'timers': { - # Ensure every user is able to read and write to the NAS dataset. - 'nas_permissions': { - 'command': [ - 'chown -R :nas /srv/nas/', - r'find /srv/nas/ -type d -exec chmod 0775 {} \;', - r'find /srv/nas/ -type f -exec chmod 0664 {} \;', - ], - 'when': '*-*-* 02:00:00', - }, - }, - }, - 'users': { - 'sophie': { - 'groups': { - 'nas', - }, - }, - }, - 'zfs': { - 'pools': { - 'storage': { - 'when_creating': { - 'config': [{ - 'devices': { - '/dev/disk/by-id/nvme-SAMSUNG_MZVLB256HAHQ-000L7_S41GNX0M481966-part3', - }, - }] - } - }, - 'nas': { - 'when_creating': { - 'config': [{ - 'type': 'mirror', - 'devices': { - '/dev/disk/by-id/ata-ST20000NM007D-3DJ103_ZVT7BHBQ', - '/dev/disk/by-id/ata-ST20000NM007D-3DJ103_ZVT7D6JP', - }, - }] - } - } - }, - "datasets": { - "storage/libvirt": { - "mountpoint": "/var/lib/libvirt", - }, - "nas": { - "mountpoint": "/srv/nas", - }, - }, - }, - }, -} diff --git a/nodes/voc/infobeamer-cms.py b/nodes/voc/infobeamer-cms.py index 55949e2..ef285c8 100644 --- a/nodes/voc/infobeamer-cms.py +++ b/nodes/voc/infobeamer-cms.py @@ -1,12 +1,11 @@ nodes['voc.infobeamer-cms'] = { - 'hostname': 'infobeamer.c3voc.de', + 'hostname': 'infobeamer-cms.c3voc.de', 'bundles': { 'infobeamer-cms', - 'infobeamer-monitor', 'redis', }, 'groups': { - 'debian-bookworm', + 'debian-bullseye', 'webserver', }, 'metadata': { @@ -23,106 +22,32 @@ nodes['voc.infobeamer-cms'] = { 'gateway6': '2001:67c:20a0:e::1', }, }, + 'icinga_options': { + 'pretty_name': 'infobeamer-cms.c3voc.de', + }, 'infobeamer-cms': { - 'domain': 'infobeamer.c3voc.de', - 'event_start_date': '2025-02-28', - 'event_duration_days': 3, + 'domain': 'infobeamer-cms.c3voc.de', + 'event_start_date': '2022-07-22', + 'event_duration_days': 5, 'config': { - 'ADMIN_USERS': [], - 'NO_LIMIT_USERS': [], - 'HOSTED_API_KEY': vault.decrypt('encrypt$gAAAAABhxJPH2sIGMAibU2Us1HoCVlNfF0SQQnVl0eiod48Zu8webL_-xk3wDw3yXw1Hkglj-2usl-D3Yd095yTSq0vZMCv2fh-JWwSPdJewQ45x9Ai4vXVD4CNz5vuJBESKS9xQWXTc'), - 'INTERRUPT_KEY': vault.human_password_for('infobeamer-cms interrupt key 38c3', words=1), - 'SETUP_IDS': [ - 258552, + 'ADMIN_USERS': [ + 'kunsi', + 'sophieschi', + 'hexchen', ], -# 'EXTRA_ASSETS': [{ -# 'type': "image", -# 'asset': 1316000, -# # bottom left, 10px from border -# 'x1': 10, -# 'y1': 970, -# 'x2': 110, -# 'y2': 1070, -# }], - 'NOTIFIER': { - 'MQTT_PASSWORD': vault.decrypt('encrypt$gAAAAABhxakfhhwWn0vxhoO1FiMEpdCkomWvo0dHIuBrqDKav8WDpI6dXpb0hoXiWRsPV6p5m-8RlbfFbjPhz47AY-nFOOAAW6Yis3-IVD-U-InKJo9dvms='), - 'MQTT_HOST': 'mqtt.c3voc.de', - 'MQTT_TOPIC': '/voc/alert', - 'MQTT_USERNAME': vault.decrypt('encrypt$gAAAAABhxakKHC_kHmHP2mFHorb4niuNTH4F24w1D6m5JUxl117N7znlZA6fpMmY3_NcmBr2Ihw4hL3FjZr9Fm_1oUZ1ZQdADA=='), - 'NTFY': [ - vault.decrypt('encrypt$gAAAAABm_RXKqIgRfe24frA_uvUMwJECr0TmL6TWPOmrPlS0CJuuBlpN6vGHrMkm5pjD5c5h1brC-aqQavsTk_AHXwq8bHG1QiZtQwqPxGuD_fEVP4-xOZ3t-RjqG3kPLz6ebqPoqyPl'), - ], - }, - 'FAQ': { - 'SOURCE': 'https://github.com/voc/infobeamer-cms', - 'CONTACT': ''' - Please use the IRC - Channel #infobeamer on irc.hackint.org (also - bridged to matrix) - or #info-beamer on the cccv rocketchat instance. - '''.strip(), - }, - 'DEFAULT_SSO_PROVIDER': 'github', - 'DEFAULT_ADMIN_SSO_PROVIDER': 'c3voc', - 'oauth2_providers': { - 'github': { - 'client_id': vault.decrypt('encrypt$gAAAAABiNwHfIu9PYFfJrF7qirn_9vdvvUlEhJnadoNSS5XlCDbI_aMyj21_ZYQxaCkc6_eVX6Cj1jEHZ7Vs6wM-XyQdW0nUOahtqG4uvnYCiM3GFKHW_wQ='), - 'client_secret': vault.decrypt('encrypt$gAAAAABiNwHtdZC2XQ8IjosL7vsmrxZMwDIM6AD5dUlLo996tJs4qV7KJETHgYYZil2aMzClwhcE6JmxdhARRp7IJQ4rQQibelTNmyYSzj_V4puVpvma7SU0UZkTIG95SdPpoHY--Zba'), - }, - 'c3voc': { - 'client_id': 'uqzN2mYeMq4vxnHL6HNmBC80hsvYcfhzniiczdqV', - 'client_secret': vault.decrypt('encrypt$gAAAAABnaZ0z-hQ3yYf8P1g4gyLLvNHcNkiXVtIq7M11qswbzcVM4upfgtxCWBlCgwLN3v7CxwDFQbJnosEq0hbX4c0TEoOausV4upJD0-5zP_1U18gbMGicpZ0TCzYyEhOqvCye7UmFOWzOmplSX1fz43Pf7peDeaPxHjqmxjw0khyExzWw4JPOd1V7LhnesJmPCfGKXn5YHMDicrdYeqFf0FySN1yA5gfLNo7y-S1QMJ6-n6Jct7uuifF9t2OV-zyOj3cKK13B'), - }, - #'c3hub': { - # 'client_id': '16oHBcVstcOKwt3EuX9E2urpYeVC0Dfo3Gzn2XhS', - # 'client_secret': vault.decrypt('encrypt$gAAAAABnaoRKbORUcceyKu3tda3lgMIFC-e0cG0AeMdDYJ--EnTRxp8QcULOTf2oBtKQUk17hgwfsafTFi4eZq1FrjNgq1h5gm83oJYWLQ6pp8Rsp9kjwgtAXf72jIU-AOQxx02SoFMU8r5pdEFEX4FkU_ksbU6s7xgBW8oxq_WO2CXAppTUX61TeB9me2nSLFdJc5-v6RDpQfDvVAm7yNS_PhMvMgVzfEZrFM-EWF_bl0S_q0ejf88o9zaXHIMJpzMruVZOXD0T'), - #}, - }, + 'GITHUB_CLIENT_ID': vault.decrypt('encrypt$gAAAAABiNwHfIu9PYFfJrF7qirn_9vdvvUlEhJnadoNSS5XlCDbI_aMyj21_ZYQxaCkc6_eVX6Cj1jEHZ7Vs6wM-XyQdW0nUOahtqG4uvnYCiM3GFKHW_wQ='), + 'GITHUB_CLIENT_SECRET': vault.decrypt('encrypt$gAAAAABiNwHtdZC2XQ8IjosL7vsmrxZMwDIM6AD5dUlLo996tJs4qV7KJETHgYYZil2aMzClwhcE6JmxdhARRp7IJQ4rQQibelTNmyYSzj_V4puVpvma7SU0UZkTIG95SdPpoHY--Zba'), + 'HOSTED_API_KEY': vault.decrypt('encrypt$gAAAAABhxJPH2sIGMAibU2Us1HoCVlNfF0SQQnVl0eiod48Zu8webL_-xk3wDw3yXw1Hkglj-2usl-D3Yd095yTSq0vZMCv2fh-JWwSPdJewQ45x9Ai4vXVD4CNz5vuJBESKS9xQWXTc'), + 'MQTT_MESSAGE': '{{"level":"info","component":"infobeamer-cms","msg":"{asset} uploaded by {user}. Check it at {url}"}}', + 'MQTT_PASSWORD': vault.decrypt('encrypt$gAAAAABhxakfhhwWn0vxhoO1FiMEpdCkomWvo0dHIuBrqDKav8WDpI6dXpb0hoXiWRsPV6p5m-8RlbfFbjPhz47AY-nFOOAAW6Yis3-IVD-U-InKJo9dvms='), + 'MQTT_SERVER': 'mqtt.c3voc.de', + 'MQTT_TOPIC': '/voc/alert', + 'MQTT_USERNAME': vault.decrypt('encrypt$gAAAAABhxakKHC_kHmHP2mFHorb4niuNTH4F24w1D6m5JUxl117N7znlZA6fpMmY3_NcmBr2Ihw4hL3FjZr9Fm_1oUZ1ZQdADA=='), + 'SETUP_IDS': [220674], }, 'rooms': { - 'Saal 1': 34430, # s1 - 'Saal GLITCH': 37731, # s2 - 'Saal ZIGZAG': 26610, # s3 - 'Sendezentrum': 38641, # s4 - 'Stage YELL': 38642, # s5 - 'Stage HUFF': 35042, # s6 + 'infobeamer stream': 23541, }, - 'interrupts': { - 'Questions': 'questions', - 'Translations': 'translations', - }, - }, - 'infobeamer-monitor': { - 'api_key': vault.decrypt('encrypt$gAAAAABlitmDR1duKo_4KuMJBF_HbPO2GFo_gdoT1rvUKQ2kkugPbe2RljM4bxW5bmwhs5avjxiaSAvjnOBte9ioyPEr7cIh79WFEfMnsHeexlCHwMt6NV_t-8EAhuuEQEf3Py93g8zQ'), - 'mqtt': { - 'password': vault.decrypt('encrypt$gAAAAABhxakfhhwWn0vxhoO1FiMEpdCkomWvo0dHIuBrqDKav8WDpI6dXpb0hoXiWRsPV6p5m-8RlbfFbjPhz47AY-nFOOAAW6Yis3-IVD-U-InKJo9dvms='), - 'host': 'mqtt.c3voc.de', - 'topic': '/voc/alert', - 'user': vault.decrypt('encrypt$gAAAAABhxakKHC_kHmHP2mFHorb4niuNTH4F24w1D6m5JUxl117N7znlZA6fpMmY3_NcmBr2Ihw4hL3FjZr9Fm_1oUZ1ZQdADA=='), - }, - }, - 'nginx': { - 'vhosts': { - 'redirect': { - 'domain': 'infobeamer-cms.c3voc.de', - 'locations': { - '/': { - 'redirect': 'https://infobeamer.c3voc.de', - }, - }, - }, - }, - }, - 'users': { - 'hexchen': { - 'ssh_pubkey': { - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINJ0tCxsEilAzV6LaNpUpcjzyEn4ptw8kFz3R+Z3YjEF", - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDI3T1eFS77URHZ/HVWkMOqx7W1U54zJtn9C7QWsHOtyH72i/4EVj8SxYqLllElh1kuKUXSUipPeEzVsipFVvfH0wEuTDgFffiSQ3a8lfUgdEBuoySwceEoPgc5deapkOmiDIDeeWlrRe3nqspLRrSWU1DirMxoFPbwqJXRvpl6qJPxRg+2IolDcXlZ6yxB4Vv48vzRfVzZNUz7Pjmy2ebU8PbDoFWL/S3m7yOzQpv3L7KYBz7+rkjuF3AU2vy6CAfIySkVpspZZLtkTGCIJF228ev0e8NvhuN6ZnjzXxVTQOy32HCdPdbBbicu0uHfZ5O7JX9DjGd8kk1r2dnZwwy/", - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC4CLJ+mFfq5XiBXROKewmN9WYmj+79bj/AoaR6Iud2pirulot3tkrrLe2cMjiNWFX8CGVqrsAELKUA8EyUTJfStlcTE0/QNESTRmdDaC+lZL41pWUO9KOiD6/0axAhHXrSJ0ScvbqtD0CtpnCKKxtuOflVPoUGZsH9cLKJNRKfEka0H0GgeKb5Tp618R/WNAQOwaCcXzg/nG4Bgv3gJW4Nm9IKy/MwRZqtILi8Mtd+2diTqpMwyNRmbenmRHCQ1vRw46joYkledVqrmSlfSMFgIHI1zRSBXb/JkG2IvIyB5TGbTkC4N2fqJNpH8wnCKuOvs46xmgdiRA26P48C2em3", - }, - 'sudo_commands': {'ALL'}, - }, - 'sophie': {}, }, }, } diff --git a/nodes/voc/pretalx.py b/nodes/voc/pretalx.py index f37a29c..7e84aed 100644 --- a/nodes/voc/pretalx.py +++ b/nodes/voc/pretalx.py @@ -5,10 +5,8 @@ nodes['voc.pretalx'] = { 'hostname': 'pretalx.c3voc.de', 'bundles': { - 'backup-client', 'check-mail-received', 'c3voc-addons', - 'nodejs', 'pretalx', 'postfix', 'postgresql', @@ -16,9 +14,6 @@ nodes['voc.pretalx'] = { 'sshmon', }, 'metadata': { - 'backup-client': { - 'target': 'backup-kunsi', - }, 'check-mail-received': { 't-online': { 'email': 'franzi.kunsmann@t-online.de', @@ -36,6 +31,9 @@ nodes['voc.pretalx'] = { 'gateway6': '2a01:a700:48d1::1', }, }, + 'icinga_options': { + 'pretty_name': 'pretalx.c3voc.de', + }, 'nginx': { 'vhosts': { 'pretalx': { @@ -49,23 +47,18 @@ nodes['voc.pretalx'] = { }, }, 'pretalx': { - # 2023.3.1 with some bugfixes - 'version': '05e377398cecdd45d3ca6013040c5857bbe225d6', + 'version': '7c3f8861a0ced94ffb4745c071a6ca3359dc1047', 'domain': 'pretalx.c3voc.de', 'mail_from': 'pretalx@c3voc.de', 'administrators-from-group-id': 1, 'plugins': { - 'broadcast_tools': { - 'repo': 'https://github.com/Kunsi/pretalx-plugin-broadcast-tools.git', - 'rev': '2.4.0', - }, 'downstream': { 'repo': 'https://github.com/pretalx/pretalx-downstream.git', - 'rev': 'main', + 'rev': 'v1.1.0', }, - 'halfnarp': { - 'repo': 'https://github.com/seibert-media/pretalx-halfnarp.git', - 'rev': '1.1.2', + 'broadcast_tools': { + 'repo': 'https://github.com/Kunsi/pretalx-plugin-broadcast-tools.git', + 'rev': '1.0.1', }, 'media.ccc.de': { 'repo': 'https://github.com/pretalx/pretalx-media-ccc-de.git', @@ -78,10 +71,10 @@ nodes['voc.pretalx'] = { 'relayhost': 'mng.c3voc.de', }, 'postgresql': { - 'version': '13', + 'version': '11', }, }, 'os': 'debian', - 'os_version': (12,), + 'os_version': (10,), 'pip_command': 'pip3', } diff --git a/requirements.txt b/requirements.txt index 6b2227f..8c04545 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -bundlewrap>=4.22.0 +bundlewrap~=4.16.0 PyNaCl bundlewrap-pass -semver +pynetbox==7.0.0 diff --git a/scripts/encrypt_file b/scripts/encrypt_file new file mode 100755 index 0000000..8fa272e --- /dev/null +++ b/scripts/encrypt_file @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +from os import environ +from os.path import abspath, isfile, join, relpath +from sys import argv + +from bundlewrap.repo import Repository + + +path = environ.get('BW_REPO_PATH', '.') +repo = Repository(path) + +if len(argv) < 3: + print('Usage: {} [encryption key, default \'encrypt\']'.format(argv[0])) + exit(1) + +target = abspath(argv[2]) +datapath = join(abspath(path), 'data') + +if not isfile(argv[1]): + print('ERROR: Source file \'{}\' does not exist.'.format(argv[1])) + exit(1) + +if not target.endswith('.vault'): + print('ERROR: Target file \'{}\' does not end in .vault'.format(argv[2])) + exit(1) +elif not target.startswith(datapath): + print('ERROR: Target file \'{}\' is not in BW_REPO_PATH/data/'.format(argv[2])) + exit(1) + +if isfile(target): + if input('ERROR: Target file \'{}\' already exists, overwrite? [yN]'.format(argv[2])) not in ['y', 'Y']: + print('Abort') + exit(2) + +if len(argv) > 3: + key = argv[3] +else: + key = 'encrypt' + +repo.vault.encrypt_file(argv[1], relpath(target, start=datapath), key) + +print('encryption successful') diff --git a/scripts/junos-update-config b/scripts/junos-update-config new file mode 100755 index 0000000..74191cf --- /dev/null +++ b/scripts/junos-update-config @@ -0,0 +1,137 @@ +#!/usr/bin/env python3 + +from json import load +from os import environ +from os.path import join +from sys import argv, exit +from tempfile import gettempdir + +from mako.template import Template + +from bundlewrap.repo import Repository +from bundlewrap.utils.text import bold +from bundlewrap.utils.ui import io + +NTP_SERVERS = { +# pool.ntp.org + '148.251.54.81', + '162.159.200.123', + '213.209.109.44', + '54.36.110.36', +} + +try: + node_name = argv[1] +except Exception: + print(f'Usage: {argv[0]} ') + exit(1) + +path = environ.get('BW_REPO_PATH', '.') +repo = Repository(path) +node = repo.get_node(node_name) + +try: + io.activate() + + interfaces = {} + users = {} + vlans = { + 'default': { + 'id': None, + 'ip_address': '169.254.254.254/24', + }, + } + + tmpfile = join(gettempdir(), f'{node.name}.conf') + + gw_split = node.hostname.split('.') + gw_split[3] = '1' + gateway = '.'.join(gw_split) + + with io.job('reading netbox_dump.json'): + with open(join(repo.path, 'netbox_dump.json'), 'r') as f: + json = load(f)[node.metadata.get('location')] + + for vlan, vid in json['vlans'].items(): + vlans[vlan] = { + 'id': vid, + 'ip_address': None, + } + + for iface, iconfig in json['devices'][node.name].items(): + if iface in vlans: + # If the interface name is the same as a vlan name, this + # means the ip assigned to this interface should get + # assigned to that vlan. + vlans[iface]['ip_address'] = iconfig['ip_addresses'][0] + else: + interfaces[iface] = { + 'enabled': bool( + iconfig['enabled'] + and iconfig['mode'] + and ( + iconfig['vlans']['tagged'] + or iconfig['vlans']['untagged'] + ) + ), + 'description': iconfig['description'], + 'untagged_vlan': iconfig['vlans']['untagged'], + } + + if iconfig['mode'] and iconfig['mode'].startswith('tagged'): + interfaces[iface]['mode'] = 'trunk' + else: + interfaces[iface]['mode'] = 'access' + + tagged_vlans = set() + for vlan in iconfig['vlans']['tagged']: + tagged_vlans.add(str(vlans[vlan]['id'])) + interfaces[iface]['tagged_vlans'] = tagged_vlans + + with io.job('reading users.json'): + with open(join(repo.path, 'users.json'), 'r') as f: + json = load(f) + + users = {} + for uname, config in json.items(): + if config.get('is_admin', False): + users[uname] = { + 'password': repo.vault.password_for(f'{node.name} {uname} login'), + 'ssh_pubkey': set(config['ssh_pubkey']), + } + + + with io.job(f'{bold(node.name)} rendering config template to {tmpfile}'): + with open(join(repo.path, 'configs', 'junos-template.conf')) as f: + template = Template( + f.read().encode('utf-8'), + input_encoding='utf-8', + output_encoding='utf-8', + ) + content = template.render( + gateway=gateway, + interfaces=interfaces, + node=node, + ntp_servers=NTP_SERVERS, + repo=repo, + users=users, + vlans=vlans, + ) + with open(tmpfile, 'w+') as f: + f.write(content.decode('utf-8')) + + with io.job(f'{bold(node.name)} updating configuration on device'): + node.upload(tmpfile, '/tmp/bundlewrap.conf') + + result = node.run( + 'configure exclusive ; load override /tmp/bundlewrap.conf ; commit', + log_output=True, + ) + + if 'commit complete' in result.stdout.decode(): + node.run( + 'request system configuration rescue save', + log_output=True, + ) +finally: + io.deactivate() diff --git a/scripts/letsencrypt-wildcard b/scripts/letsencrypt-wildcard index 3d90231..98eca7a 100755 --- a/scripts/letsencrypt-wildcard +++ b/scripts/letsencrypt-wildcard @@ -39,7 +39,7 @@ then echo echo You must now provide this DNS record: - echo "$(tput bold)_acme-challenge.$domain IN TXT $token_value$(tput sgr0)" + echo "$(tput bold)_acme-challenge.$domain. IN TXT $token_value$(tput sgr0)" echo echo "Hit ENTER once it's available." read diff --git a/scripts/list-all-ips b/scripts/list-all-ips new file mode 100755 index 0000000..f5f2bc5 --- /dev/null +++ b/scripts/list-all-ips @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +from os import environ +from sys import argv + +from bundlewrap.repo import Repository +from bundlewrap.utils.dicts import merge_dict + + +path = environ.get('BW_REPO_PATH', '.') +repo = Repository(path) + + +if len(argv) > 1: + ips = {} + for i in argv[1:]: + ips = merge_dict(ips, repo.libs.tools.resolve_identifier(repo, i)) +else: + ips = repo.libs.tools.resolve_identifier(repo, 'all') + + +if ips['ipv4']: + # editorconfig-checker-disable + print(''' ________ __ __ + / _/ __ \\_ __/ // / + / // /_/ / | / / // /_ + _/ // ____/| |/ /__ __/ +/___/_/ |___/ /_/''') + # editorconfig-checker-enable + + for ip in sorted(ips['ipv4']): + print(ip) + +if ips['ipv4'] and ips['ipv6']: + # some space inbetween + print() + +if ips['ipv6']: + # editorconfig-checker-disable + print(''' ________ _____ + / _/ __ \\_ __/ ___/ + / // /_/ / | / / __ \\ + _/ // ____/| |/ / /_/ / +/___/_/ |___/\\____/''') + # editorconfig-checker-enable + + for ip in sorted(ips['ipv6']): + print(ip) diff --git a/scripts/netbox-dump b/scripts/netbox-dump index 8486653..779b143 100755 --- a/scripts/netbox-dump +++ b/scripts/netbox-dump @@ -1,240 +1,117 @@ #!/usr/bin/env python3 -from argparse import ArgumentParser from json import dump -from os import environ, makedirs, remove, scandir -from os.path import abspath, dirname, join +from os import environ +from os.path import join from sys import exit -import bwpass -from requests import post - -from bundlewrap.utils.text import bold, red, validate_name -from bundlewrap.utils.ui import io - -TOKEN = environ.get("NETBOX_AUTH_TOKEN") -if not TOKEN: - try: - TOKEN = bwpass.attr("netbox.franzi.business/kunsi", "token") - except Exception: - print("NETBOX_AUTH_TOKEN missing") - exit(1) - -TARGET_PATH = join(dirname(dirname(abspath(__file__))), "configs", "netbox") - -QUERY_SITES = """{ - site_list { - name - id - vlans { - name - vid - } - } -}""" - -QUERY_DEVICES = """{ - device_list(filters: {tag: "bundlewrap", site_id: "SITE_ID"}) { - name - id - } -}""" - -QUERY_DEVICE_DETAILS = """{ - device(id: DEVICE_ID) { - name - interfaces { - id - name - enabled - description - mode - type - ip_addresses { - address - } - untagged_vlan { - name - } - tagged_vlans { - name - } - link_peers { - ... on InterfaceType { - name - device { - name - } - } - ... on FrontPortType { - name - device { - name - } - } - } - connected_endpoints { - ... on InterfaceType { - name - device { - name - } - } - } - } - } -}""" +from bundlewrap.utils.ui import QUIT_EVENT, io +from bundlewrap.utils.text import bold, yellow, validate_name +from pynetbox import api as netbox_api -def graphql(query): - r = post( - "https://netbox.franzi.business/graphql/", - headers={ - "Accept": "application/json", - "Authorization": f"Token {TOKEN}", - }, - json={ - "query": query, - }, - ) - r.raise_for_status() - return r.json()["data"] +BW_REPO_PATH = environ.get('BW_REPO_PATH', '.') +netbox = netbox_api( + environ.get('NETBOX_HOST', 'https://netbox.franzi.business'), + token=environ.get('NETBOX_TOKEN', None), +) +result = { +# 'my_site_name': { +# 'vlans': { +# 'my_vlan_name': 10, +# 'other_vlan_name': 11, +# 'yet_another_vlan_name': 12, +# }, +# 'devices': { +# 'my_switch': { +# 'port1': { +# 'description': 'foo', +# 'type': '1000base-t', # or 'lag' +# 'mode': None, # or 'access', 'tagged', 'tagged-all' +# 'lag': 'none', # or 'LAG1' +# 'vlan': { +# 'untagged': 'my_vlan_name', +# 'tagged': [ +# 'other_vlan_name', +# 'yet_another_vlan_name', +# ], +# }, +# }, +# }, +# }, +# }, +} -def filter_results(results, filter_by): - if filter_by is None: - return results - - out = [] - for result in results: - if str(result["id"]) in filter_by or result["name"] in filter_by: - out.append(result) - return out - - -parser = ArgumentParser() -parser.add_argument("--only-site", nargs="+", type=str) -parser.add_argument("--only-device", nargs="+", type=str) -args = parser.parse_args() - +errors = False try: io.activate() - filenames_used = set() - with io.job("getting sites"): - sites = filter_results( - graphql(QUERY_SITES).get("site_list", []), args.only_site - ) + for site in netbox.dcim.sites.all(): + site_name = site.name.lower() - io.stdout(f"Processing {len(sites)} sites in total") + result[site_name] = { + 'vlans': {}, + 'devices': {}, + } - for site in sites: - with io.job(f"{bold(site['name'])} getting devices"): - devices = filter_results( - graphql(QUERY_DEVICES.replace("SITE_ID", site["id"])).get( - "device_list", [] - ), - args.only_device, - ) - io.stdout(f"Site {bold(site['name'])} has {len(devices)} devices to process") + with io.job(f'{bold(site_name)} getting vlans'): + for vlan in netbox.ipam.vlans.filter(site_id=site.id): + if vlan.name in result[site_name]['vlans'].keys() and result[site_name]['vlans'][vlan.name] != vlan.id: + raise Exception(f"vlan {result[site_name]['vlans'][vlan.name]} and {vlan.id} both have the name {vlan.name}") - for device in devices: - if not device["name"] or not validate_name(device["name"]): - # invalid node name, ignore - continue + result[site_name]['vlans'][vlan.name] = vlan.vid - with io.job( - f"{bold(site['name'])} {bold(device['name'])} getting interfaces" - ): - details = graphql( - QUERY_DEVICE_DETAILS.replace("DEVICE_ID", device["id"]) - )["device"] + for interface in netbox.dcim.interfaces.filter(site_id=site.id): + if QUIT_EVENT.is_set(): + exit(0) - result = { - "interfaces": {}, - "vlans": site["vlans"], + with io.job(f'{bold(site_name)} {bold(interface.device.name)} interface {yellow(interface.name)}'): + if not interface.device.name: + # Unnamed device. Probably not managed by bw. + continue + elif not validate_name(interface.device.name): + # bundlewrap does not consider this device name to be a valid + # node name. Ignore it, we don't manage it + continue + + has_valid_description = False + if interface.description: + description = interface.description + has_valid_description = True + elif interface.connected_endpoints: + description = f'{sorted(interface.connected_endpoints)[0].device.display} ({sorted(interface.connected_endpoints)[0].display})' + has_valid_description = True + elif interface.link_peers: + description = f'{sorted(interface.link_peers)[0].device.display} ({sorted(interface.link_peers)[0].display})' + else: + description = '' + + if not description.isascii(): + errors = True + io.stderr(f'{bold(interface.device.name)} {bold(interface.name)} description "{description}" contains non-ascii characters, this isn\'t supported') + + result[site_name]['devices'].setdefault(interface.device.name, {})[interface.name] = { + 'description': description, + 'enabled': interface.enabled, + 'ip_addresses': sorted(set() if interface.count_ipaddresses == 0 else { + ip.address for ip in + netbox.ipam.ip_addresses.filter(interface_id=interface.id) + }), + 'mode': interface.mode.value if interface.mode else None, + 'type': interface.type.value, + 'lag': interface.lag.name if interface.lag else None, + 'vlans': { + 'untagged': interface.untagged_vlan.name if interface.untagged_vlan else None, + 'tagged': sorted(vlan.name for vlan in interface.tagged_vlans), + }, } - for interface in details["interfaces"]: - peers = None + if errors: + exit(1) - if interface["connected_endpoints"]: - peers = interface["connected_endpoints"] - elif interface["link_peers"]: - peers = interface["link_peers"] - - if interface["description"]: - description = interface["description"] - elif peers: - peer_list = set() - - for i in peers: - peer_list.add( - "{} ({})".format( - i["device"]["name"], - i["name"], - ) - ) - - description = "; ".join(sorted(peer_list)) - else: - description = "" - - assert description.isascii() - - result["interfaces"][interface["name"]] = { - "description": description, - "enabled": interface["enabled"], - "mode": interface["mode"], - "type": interface["type"], - "ips": sorted( - {i["address"] for i in interface["ip_addresses"]} - ), - "untagged_vlan": ( - interface["untagged_vlan"]["name"] - if interface["untagged_vlan"] - else None - ), - "tagged_vlans": sorted( - {v["name"] for v in interface["tagged_vlans"]} - ), - } - - if result["interfaces"]: - filename = f"{device['name']}.json" - filenames_used.add(filename) - file_with_path = join(TARGET_PATH, filename) - - with io.job( - f"{bold(site['name'])} {bold(device['name'])} writing to {file_with_path}" - ): - with open( - file_with_path, - "w+", - ) as f: - dump( - result, - f, - indent=4, - sort_keys=True, - ) - else: - io.stdout( - f"device {bold(device['name'])} has no interfaces, {red('not')} dumping!" - ) - - if not args.only_site and not args.only_device and filenames_used: - with io.job(f"cleaning leftover files from {TARGET_PATH}"): - for direntry in scandir(TARGET_PATH): - filename = direntry.name - if filename.startswith("."): - continue - if not direntry.is_file(): - io.stderr( - f"found non-file {filename} in {TARGET_PATH}, please check what's going on!" - ) - continue - if filename not in filenames_used: - remove(join(TARGET_PATH, filename)) + with io.job('dumping result to netbox_dump.json'): + with open(join(BW_REPO_PATH, 'netbox_dump.json'), 'w') as f: + dump(result, f, indent=4, sort_keys=True) finally: io.deactivate() diff --git a/scripts/passwords-for b/scripts/passwords-for index d019e74..3aa0d53 100755 --- a/scripts/passwords-for +++ b/scripts/passwords-for @@ -1,21 +1,17 @@ #!/usr/bin/env python3 - from os import environ -from os.path import abspath, dirname from sys import argv -from bundlewrap.exceptions import FaultUnavailable -from bundlewrap.metagen import NodeMetadataProxy from bundlewrap.repo import Repository from bundlewrap.utils import Fault +from bundlewrap.exceptions import FaultUnavailable -repo = Repository( - dirname(dirname(abspath(__file__))) -) + +path = environ.get('BW_REPO_PATH', '.') +repo = Repository(path) def print_faults(dictionary, keypath=[]): for key, value in sorted(dictionary.items()): - key = str(key) if isinstance(value, Fault): try: resolved_fault = value.value @@ -24,9 +20,7 @@ def print_faults(dictionary, keypath=[]): else: if '\n' not in resolved_fault: print('{}/{}: {}'.format('/'.join(keypath), key, value)) - elif isinstance(value, (list, set, tuple)): - print_faults(dict(enumerate(value)), keypath=keypath+[key]) - elif isinstance(value, (dict, NodeMetadataProxy)): + elif isinstance(value, dict): print_faults(value, keypath=keypath+[key]) @@ -35,16 +29,4 @@ if len(argv) == 1: exit(1) node = repo.get_node(argv[1]) -if node.username or node.password: - print_faults({ - 'username': node.username, - 'password': node.password, - }) -#if node.ipmi_username or node.ipmi_password: -# print_faults({ -# 'ipmi_username': node.ipmi_username, -# 'ipmi_password': node.ipmi_password, -# }) -print_faults({ - 'metadata': node.metadata, -}) +print_faults(node.metadata) diff --git a/scripts/update-ssh-client-config b/scripts/update-ssh-client-config index ba5acde..0c2f7fd 100755 --- a/scripts/update-ssh-client-config +++ b/scripts/update-ssh-client-config @@ -12,20 +12,10 @@ BW_TABLE_STYLE=grep bw nodes -a hostname -- "lambda:not node.dummy" | \ while read node addr do - if [[ -n "$BW_SSH_HOOK_EXTRA_LINE" ]] - then - echo "Host $addr" >>"$tmpfile" - echo "$BW_SSH_HOOK_EXTRA_LINE" >>"$tmpfile" - echo "" >>"$tmpfile" - fi echo "Host $node" >>"$tmpfile" echo "HostName $addr" >>"$tmpfile" - if [[ -n "$BW_SSH_HOOK_EXTRA_LINE" ]] - then - echo "$BW_SSH_HOOK_EXTRA_LINE" >>"$tmpfile" - fi echo "" >>"$tmpfile" done - mv "$tmpfile" ~/.ssh/config.d/bwnodes + mv "$tmpfile" ~/.ssh/bwnodes ) & diff --git a/users.json b/users.json index 0dab537..7769c17 100644 --- a/users.json +++ b/users.json @@ -1,18 +1,17 @@ { + "autojenkins": { + "ssh_pubkey": [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHZnYhsdtGUYJiFcvfqTLljGkInnFTOoDF/WZniLtPjH" + ] + }, "fkunsmann": { "ssh_pubkey": [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICYst1HK+gJYhNxzqJGnz4iB73pa89Xz2yH+8wufOcsA" ] }, - "forgejo-carlene": { - "ssh_pubkey": [ - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA3aj7Ij9aIgSBgIAyIPAQa/w++7eVKIxbK0iFuVvjeH" - ] - }, "kunsi": { "ssh_pubkey": [ - "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBLpRRSFhzPC8xNorYiNDG37JivSSER+oUNjSFwJ+4Gn8QdcM5sjQZsokAEFs5AsAWl1i7d/qceA2JGG4jCwDBx0=", - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC+ja1z5VRQzaKCCePsUM14qMr9QR94qlWc7Je5Poki9UmC1t/TyxRVzcCBL1ZdIfBGx6QKtfkEbvhgb3nxVt3PvXjoJrc6wwGLmNrVsU6B88y35g7nzupQiPKYJwkNzJ9j6Dmkgj1F5Q+aY2SitDaX6vqICLJ4Al/ZFw2IQxVJfC7JXRJ9jRMG5o9gWoE3gWDYEAmw+HU2mNzyeuaD12qJw9DHUimAlgkOWzll3gh9WclsYnnXGrCCn5fyHFUCJl+XXAIy519z7YTpKih02rsIOw5dnaGClBZD/YQu2ZKVFZiwIVH7aBiqHOmtgRyWTQgjbh/fMpIN0ar2f/iZsWYUjd6et48TOmXZYIPCQ5FivXNvxt9oo1XZfq76UHBwlmypLJIWROMbz375n2M6hr3hECuxuPjKEUXAv05KiC1aJ4xc6pFoVhqwAR99hvHw5U4o7/ko2NVjNpTu6Jr5DT5VaQLIdDDjC/93kUjMpdD/8P72bEn7454+WexU6OE6uvNiHj1fetrptr2UAuzVfnCoaV8pBqY7X95gk+lnSENdpr8ltJYMg8s0Z7Pzz0OxsZtzzDY5VmWfC9TCdJkN5lT8IbnaixsYlWdjQl1lMmZGElmelfU3K7YQLAbZiHmHKe4hTl9ZoCcWdTQ3d4y2t1DBos+N2HZNdtFCyOS8esDdMw==" + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC+ja1z5VRQzaKCCePsUM14qMr9QR94qlWc7Je5Poki9UmC1t/TyxRVzcCBL1ZdIfBGx6QKtfkEbvhgb3nxVt3PvXjoJrc6wwGLmNrVsU6B88y35g7nzupQiPKYJwkNzJ9j6Dmkgj1F5Q+aY2SitDaX6vqICLJ4Al/ZFw2IQxVJfC7JXRJ9jRMG5o9gWoE3gWDYEAmw+HU2mNzyeuaD12qJw9DHUimAlgkOWzll3gh9WclsYnnXGrCCn5fyHFUCJl+XXAIy519z7YTpKih02rsIOw5dnaGClBZD/YQu2ZKVFZiwIVH7aBiqHOmtgRyWTQgjbh/fMpIN0ar2f/iZsWYUjd6et48TOmXZYIPCQ5FivXNvxt9oo1XZfq76UHBwlmypLJIWROMbz375n2M6hr3hECuxuPjKEUXAv05KiC1aJ4xc6pFoVhqwAR99hvHw5U4o7/ko2NVjNpTu6Jr5DT5VaQLIdDDjC/93kUjMpdD/8P72bEn7454+WexU6OE6uvNiHj1fetrptr2UAuzVfnCoaV8pBqY7X95gk+lnSENdpr8ltJYMg8s0Z7Pzz0OxsZtzzDY5VmWfC9TCdJkN5lT8IbnaixsYlWdjQl1lMmZGElmelfU3K7YQLAbZiHmHKe4hTl9ZoCcWdTQ3d4y2t1DBos+N2HZNdtFCyOS8esDdMw== cardno:000609506971" ], "email": "encrypt$gAAAAABfuXj1DQ3yUn0rEdN2koT1hzgHwCwNp00a0KkWoT_FTsild1zIBpfIiI07AmgIZ5FpyhKH5bSdCVLKc0p4rQuxLrLWpw==", "phone": "encrypt$gAAAAABfuXkP2GetSvTd9JJFz4V2v5r5NubihFRg2AB91mtvXpUVUiflzy1VHQJ_qbp6Rke5LEXbtlluNkAa3OOAr_c9L6Pstw==", @@ -20,7 +19,8 @@ }, "sophie": { "ssh_pubkey": [ - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDU7XmpX4w+rGQDi+dF6M0q65K2iHVgD1wHBoHREjyqCzmPGZgrnLIv6EN9WWJXjCgRdLEUXgPn7PNJnAgBs3U8G8MsF55yrPNUIsEeg6v+Y6zibEujMrwmeDSk0XAn8iSZcy+4cnqykIMk9Hd5WXW7ZhSHGs4MftWn3Z/q15qPHl/w9OyaKDJAjk8yEsD1sZoAQMhomKliKjJ5a6jNyf7otS3HdbZx4KXABJNuWn/IvmwkcaIU8ljyuPkPkiMn5JWhcUK2kE81Y4a5zJxxusSXSF6Ip7W2Rhv+4gnScTjhTPsG70HlSF/LAB2ytKo0F0N/ZB2hJk+Jq6cAwNBzuST7" - ] + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDU7XmpX4w+rGQDi+dF6M0q65K2iHVgD1wHBoHREjyqCzmPGZgrnLIv6EN9WWJXjCgRdLEUXgPn7PNJnAgBs3U8G8MsF55yrPNUIsEeg6v+Y6zibEujMrwmeDSk0XAn8iSZcy+4cnqykIMk9Hd5WXW7ZhSHGs4MftWn3Z/q15qPHl/w9OyaKDJAjk8yEsD1sZoAQMhomKliKjJ5a6jNyf7otS3HdbZx4KXABJNuWn/IvmwkcaIU8ljyuPkPkiMn5JWhcUK2kE81Y4a5zJxxusSXSF6Ip7W2Rhv+4gnScTjhTPsG70HlSF/LAB2ytKo0F0N/ZB2hJk+Jq6cAwNBzuST7 sophie@ejgwmobile" + ], + "is_admin": true } }