Compare commits

..

No commits in common. "main" and "unbound-sophie" have entirely different histories.

89 changed files with 1700 additions and 389 deletions

3
.envrc
View file

@ -1,3 +0,0 @@
layout python3
source_env_if_exists .envrc.local

2
.gitignore vendored
View file

@ -1,5 +1,3 @@
.secrets.cfg*
__pycache__
*.swp
.direnv
.envrc.local

View file

@ -0,0 +1,5 @@
context.exec = [
{ path = "pactl" args = "load-module module-native-protocol-tcp" }
{ path = "pactl" args = "load-module module-zeroconf-discover" }
{ path = "pactl" args = "load-module module-zeroconf-publish" }
]

View file

@ -0,0 +1,3 @@
[Autologin]
User=${user}
Session=i3.desktop

View file

@ -0,0 +1,110 @@
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 = {
'avahi-daemon': {
'needs': {
'pkg_pacman:avahi',
},
},
'sddm': {
'needs': {
'pkg_pacman:sddm',
},
},
}
git_deploy = {
'/opt/i3pystatus/src': {
'repo': 'https://github.com/enkore/i3pystatus.git',
'rev': 'current',
'triggers': {
'action:i3pystatus_install',
},
},
}
files['/etc/pipewire/pipewire-pulse.conf.d/50-network.conf'] = {}
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',
},
}

View file

@ -0,0 +1,124 @@
assert node.os == 'arch'
defaults = {
'backups': {
'paths': {
'/etc/netctl',
},
},
'icinga_options': {
'exclude_from_monitoring': True,
},
'nftables': {
'input': {
'50-avahi': {
'udp dport 5353 accept',
'udp sport 5353 accept',
},
},
},
'pacman': {
'packages': {
# fonts
'fontconfig': {},
'ttf-dejavu': {
'needed_by': {
'pkg_pacman:sddm',
},
},
# login management
'sddm': {},
# networking
'avahi': {},
'netctl': {},
'util-linux': {}, # provides rfkill
'wpa_supplicant': {},
'wpa_actiond': {},
# shell and other gui stuff
'dunst': {},
'fish': {},
'kitty': {},
'libnotify': {}, # provides notify-send
'light': {},
'redshift': {},
'rofi': {},
# sound
'calf': {},
'easyeffects': {},
'lsp-plugins': {},
'pavucontrol': {},
'pipewire': {},
'pipewire-jack': {},
'pipewire-pulse': {},
'pipewire-zeroconf': {},
'qpwgraph': {},
# window management
'i3-wm': {},
'i3lock': {},
'xss-lock': {},
# i3pystatus dependencies
'iw': {},
'wireless_tools': {},
# Xorg
'xf86-input-libinput': {},
'xf86-input-wacom': {},
'xorg-server': {},
'xorg-setxkbmap': {},
'xorg-xev': {},
'xorg-xinput': {},
'xorg-xset': {},
# all them apps
'browserpass': {},
'browserpass-firefox': {},
'ffmpeg': {},
'firefox': {},
'gimp': {},
'imagemagick': {},
'inkscape': {},
'kdenlive': {},
'maim': {},
'mosh': {},
'mosquitto': {},
'mpv': {},
'pass': {},
'pass-otp': {},
'pdftk': {},
'pwgen': {},
'qpdfview': {},
'samba': {},
'shotcut': {},
'sipcalc': {},
'the_silver_searcher': {},
'tlp': {},
'virt-manager': {},
'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,
},
}

View file

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

View file

@ -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',
},
}

View file

@ -1,11 +0,0 @@
defaults = {
'apt': {
'packages': {
'avahi-daemon': {},
'libnss-mdns': {},
},
},
'avahi-daemon': {
'use-ipv6': True,
}
}

View file

@ -24,6 +24,7 @@ files = {
'before': {
'action:',
'pkg_apt:',
'pkg_pacman:',
},
},
}

View file

@ -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}',
},
},
}

View file

@ -13,6 +13,15 @@ defaults = {
},
},
},
'pacman': {
'packages': {
'bird': {
'needed_by': {
'svc_systemd:bird',
},
},
},
},
'sysctl': {
'options': {
'net.ipv4.conf.all.forwarding': '1',

View file

@ -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',
@ -17,9 +24,9 @@ directories = {
}
svc_systemd = {
'cron': {
service_name: {
'needs': {
'pkg_apt:cron',
package_name,
},
},
}

View file

@ -4,4 +4,9 @@ defaults = {
'cron': {},
},
},
'pacman': {
'packages': {
'cronie': {},
},
},
}

View file

@ -20,7 +20,7 @@ def nodejs(metadata):
if version >= (1, 11, 71):
return {
'nodejs': {
'version': 22,
'version': 20,
},
}
else:

View file

@ -401,6 +401,22 @@ for rnode in sorted(repo.nodes):
DAYS_TO_STRING[day%7]: f'{hour}:{minute}-{hour}:{minute+15}',
},
})
elif (
rnode.has_bundle('pacman')
and rnode.metadata.get('pacman/unattended-upgrades/is_enabled', False)
):
day = rnode.metadata.get('pacman/unattended-upgrades/day')
hour = rnode.metadata.get('pacman/unattended-upgrades/hour')
minute = rnode.magic_number%30
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',

View file

@ -1,13 +1,10 @@
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'),
@ -52,7 +49,7 @@ def nginx(metadata):
'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)

View file

@ -40,10 +40,7 @@ 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}"
message = f"[{device['description']}] {message}"
client.publish(
CONFIG["mqtt"]["topic"],
@ -93,7 +90,7 @@ while True:
)
else:
new_state = {}
for device in sorted(ib_state, key=lambda x: x["id"]):
for device in ib_state:
did = str(device["id"])
if did in new_state:

View file

@ -19,4 +19,9 @@ defaults = {
'/usr/bin/ipmitool *',
},
},
'pacman': {
'packages': {
'ipmitool': {},
},
},
}

View file

@ -13,6 +13,15 @@ defaults = {
},
},
},
'pacman': {
'packages': {
'dehydrated': {
'needed_by': {
'action:letsencrypt_update_certificates',
},
},
},
},
}

View file

@ -10,4 +10,15 @@ defaults = {
},
},
},
'pacman': {
'packages': {
'lldpd': {
'needed_by': {
'directory:/etc/lldpd.d',
'file:/etc/lldpd.conf',
'svc_systemd:lldpd',
},
},
},
},
}

View file

@ -4,6 +4,11 @@ defaults = {
'lm-sensors': {},
},
},
'pacman': {
'packages': {
'lm_sensors': {},
},
},
'telegraf': {
'input_plugins': {
'builtin': {

View file

@ -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,
},
}

View file

@ -4,6 +4,11 @@ defaults = {
'nfs-common': {},
},
},
'pacman': {
'packages': {
'nfs-utils': {},
},
},
}
if node.has_bundle('telegraf'):

View file

@ -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': {
@ -37,7 +42,7 @@ svc_systemd = {
'nftables': {
'needs': {
'file:/etc/nftables.conf',
'pkg_apt:nftables',
package,
},
},
}

View file

@ -10,6 +10,23 @@ defaults = {
'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'):

View file

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

View file

@ -1,4 +1,4 @@
user www-data;
user ${username};
worker_processes ${worker_processes};
pid /var/run/nginx.pid;

View file

@ -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': {},
@ -33,6 +40,7 @@ files = {
'/etc/nginx/nginx.conf': {
'content_type': 'mako',
'context': {
'username': username,
**node.metadata['nginx'],
},
'triggers': {
@ -61,13 +69,21 @@ 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',
},
}
svc_systemd = {
'nginx': {
'needs': {
'action:generate-dhparam',
'directory:/var/log/nginx-timing',
'pkg_apt:nginx',
package,
},
},
}

View file

@ -33,6 +33,11 @@ defaults = {
'nginx': {
'worker_connections': 768,
},
'pacman': {
'packages': {
'nginx': {},
},
},
}
if node.has_bundle('telegraf'):

View file

@ -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,
},
},
}

View file

@ -8,6 +8,11 @@ defaults = {
'openssh-sftp-server': {},
},
},
'pacman': {
'packages': {
'openssh': {},
},
},
}
@metadata_reactor.provides(

View file

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

View file

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

View file

@ -0,0 +1,2 @@
# just disable faillock.
deny = 0

View file

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

View file

@ -0,0 +1,49 @@
#!/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" && $1 != "nobody"')
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
systemctl reboot
echo "upgrade-and-reboot for node $nodename is DONE"

View file

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

113
bundles/pacman/items.py Normal file
View file

@ -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': {},
'bind': {},
'binutils': {},
'bison': {},
'bzip2': {},
'curl': {},
'dialog': {},
'diffutils': {},
'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

View file

@ -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',
},
},
},
},
}

View file

@ -34,7 +34,7 @@ defaults = {
},
},
'nodejs': {
'version': 22,
'version': 18,
},
'postgresql': {
'roles': {

View file

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

View file

@ -21,12 +21,13 @@ 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',
my_package,
},
'triggers': {
'svc_systemd:postfix:restart',
@ -81,7 +82,7 @@ actions = {
'command': 'newaliases',
'triggered': True,
'needs': {
'pkg_apt:postfix',
my_package,
},
'before': {
'svc_systemd:postfix',
@ -91,7 +92,7 @@ actions = {
'command': 'postmap hash:/etc/postfix/blocked_recipients',
'triggered': True,
'needs': {
'pkg_apt:postfix',
my_package,
},
'before': {
'svc_systemd:postfix',
@ -104,7 +105,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',
},
}

View file

@ -14,7 +14,7 @@ defaults = {
'postfix': {
'services': {
'POSTFIX PROCESS': {
'command_on_monitored_host': '/usr/local/share/icinga/plugins/check_systemd_unit postfix@-',
'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'):

View file

@ -14,7 +14,7 @@ defaults = {
},
},
'nodejs': {
'version': 22,
'version': 18,
},
'users': {
'powerdnsadmin': {

View file

@ -116,7 +116,7 @@ svc_systemd = {
'pretalx-worker': {
'needs': {
'action:pretalx_install',
'action:pretalx_migrate',
'action:pretalx_migrate',,
'action:pretalx_rebuild',
'file:/etc/systemd/system/pretalx-worker.service',
'file:/opt/pretalx/pretalx.cfg',

View file

@ -27,7 +27,7 @@ defaults = {
},
},
'nodejs': {
'version': 22,
'version': 18,
},
'pretalx': {
'database': {

View file

@ -96,7 +96,7 @@ 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': {

View file

@ -13,13 +13,6 @@ 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}]
@ -44,24 +37,3 @@ 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

View file

@ -1,21 +0,0 @@
<?xml version="1.0" standalone='no'?>
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
<name replace-wildcards="yes">%h</name>
<service>
<type>_smb._tcp</type>
<port>445</port>
</service>
<service>
<type>_device-info._tcp</type>
<port>0</port>
<txt-record>model=RackMac1,2</txt-record>
</service>
<service>
<type>_adisk._tcp</type>
% for idx, share_name in enumerate(sorted(shares)):
<txt-record>dk${idx}=adVN=timemachine-${share_name},adVF=0x82</txt-record>
% endfor
<txt-record>sys=waMa=0,adVF=0x100</txt-record>
</service>
</service-group>

View file

@ -11,14 +11,9 @@ svc_systemd = {
},
}
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',
@ -62,24 +57,3 @@ for user, uconfig in node.metadata.get('users', {}).items():
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'
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',
}

View file

@ -24,30 +24,3 @@ def firewall(metadata):
},
},
}
@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,
},
}

View file

@ -64,3 +64,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',
},
}

View file

@ -36,6 +36,14 @@ defaults = {
'sshmon',
},
},
'pacman': {
'packages': {
'gawk': {},
'perl-libwww': {},
'monitoring-plugins': {},
'python-requests': {},
},
},
}

View file

@ -4,4 +4,9 @@ defaults = {
'sudo': {},
},
},
'pacman': {
'packages': {
'sudo': {},
},
},
}

View file

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

View file

@ -0,0 +1,5 @@
auto-entries no
auto-firmware yes
console-mode keep
default ${config['default']}
timeout ${config.get('timeout', 5)}

View file

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

View file

@ -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,
}

View file

@ -25,4 +25,14 @@ defaults = {
},
},
},
'pacman': {
'packages': {
'telegraf-bin': {
'needed_by': {
'svc_systemd:telegraf',
'user:telegraf',
},
},
},
},
}

View file

@ -7,6 +7,11 @@ defaults = {
'kitty-terminfo': {},
},
},
'pacman': {
'packages': {
'kitty-terminfo': {},
},
},
'users': {
'root': {
'home': '/root',

View file

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

View file

@ -21,6 +21,12 @@ defaults = {
},
},
},
'pacman': {
'packages': {
'edk2-ovmf': {},
'libvirt': {},
},
},
}
if node.os == 'debian' and node.os_version[0] < 11:
@ -36,6 +42,9 @@ if node.has_bundle('nftables'):
},
}
if node.has_bundle('arch-with-gui'):
defaults['pacman']['packages']['virt-manager'] = {}
@metadata_reactor.provides(
'users',

View file

@ -0,0 +1,16 @@
[Unit]
Description=CRS runner for ${script}
After=network.target
[Service]
User=voc
Group=voc
EnvironmentFile=/etc/default/crs-worker
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

View file

@ -0,0 +1,6 @@
CRS_TRACKER=${url}
CRS_TOKEN=${token}
CRS_SECRET=${secret}
% if use_vaapi:
CRS_USE_VAAPI=yes
% endif

View file

@ -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',
},
}

View file

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

View file

@ -283,7 +283,7 @@ def interface_ips(metadata):
'nftables/postrouting/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)

View file

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

View file

@ -43,6 +43,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': {
@ -109,6 +121,27 @@ if node.has_bundle('telegraf'):
}
@metadata_reactor.provides(
'pacman/packages',
)
def packages(metadata):
if node.metadata.get('pacman/linux-lts', False):
pkgname = 'zfs-linux-lts'
else:
pkgname = 'zfs-linux'
return {
'pacman': {
'packages': {
pkgname: {
'needed_by': {
'zfs_dataset:',
'zfs_pool:',
},
},
},
},
}
@metadata_reactor.provides(
'apt/packages',
)

View file

@ -1,4 +1,3 @@
109.203.176.0/21
109.237.176.0/20
109.72.116.0/24
116.50.16.0/21
@ -20,6 +19,7 @@
141.77.0.0/16
143.99.213.0/24
145.225.16.0/23
146.247.58.0/24
147.161.22.0/24
147.78.17.0/24
147.79.8.0/21
@ -31,13 +31,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
@ -49,13 +46,12 @@
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
160.211.126.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
164.133.10.0/24
164.133.11.0/24
@ -100,7 +96,6 @@
185.202.32.0/21
185.207.46.0/24
185.21.247.0/24
185.224.0.0/24
185.237.0.0/24
185.237.1.0/24
185.237.2.0/24
@ -113,16 +108,11 @@
185.28.208.0/22
185.39.12.0/22
185.48.0.0/22
185.57.231.0/24
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
192.109.121.0/24
192.109.122.0/24
192.109.124.0/24
192.109.129.0/24
@ -163,6 +153,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
@ -294,7 +285,6 @@
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
@ -329,6 +319,7 @@
194.180.64.0/20
194.25.0.0/16
194.25.1.5/32
194.26.191.0/24
194.31.142.0/24
194.31.208.0/24
194.31.209.0/24
@ -339,11 +330,6 @@
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
@ -443,9 +429,6 @@
205.142.63.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
@ -454,7 +437,7 @@
213.209.156.0/24
217.0.0.0/13
217.117.96.0/24
217.177.33.0/24
217.198.189.0/24
217.224.0.0/11
217.24.32.0/20
217.24.33.0/24
@ -464,22 +447,17 @@
31.224.0.0/11
31.6.56.0/23
37.143.0.0/22
37.230.61.0/24
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.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
46.78.0.0/15
@ -496,7 +474,6 @@
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
@ -539,9 +516,7 @@
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
@ -552,19 +527,13 @@
85.116.30.0/24
85.116.31.0/24
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
86.38.248.0/21
86.38.37.0/24
87.128.0.0/10
@ -576,6 +545,7 @@
89.116.64.0/22
89.213.186.0/23
89.39.97.0/24
89.43.34.0/24
91.0.0.0/10
91.103.240.0/21
91.124.135.0/24
@ -589,6 +559,7 @@
91.124.27.0/24
91.124.28.0/24
91.124.31.0/24
91.124.32.0/24
91.124.33.0/24
91.124.34.0/24
91.124.36.0/24
@ -635,15 +606,27 @@
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.128.0/24
92.112.155.0/24
92.112.157.0/24
92.112.16.0/22
92.112.160.0/24
92.112.162.0/24
92.112.165.0/24
92.112.167.0/24
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.112.49.0/24
92.112.52.0/24
92.112.54.0/24
92.112.59.0/24
92.112.63.0/24
92.112.64.0/24
92.112.67.0/24
92.112.79.0/24
92.112.81.0/24
92.112.83.0/24
92.112.94.0/24
92.114.44.0/22
92.119.164.0/22
92.119.208.0/24
@ -652,12 +635,8 @@
92.119.211.0/24
93.113.70.0/24
93.119.201.0/24
93.119.232.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

View file

@ -6,7 +6,6 @@
109.250.192.0/19
109.250.224.0/19
109.250.64.0/18
109.72.113.0/24
134.101.0.0/21
14.102.90.0/24
143.58.64.0/18
@ -122,7 +121,6 @@
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
@ -154,8 +152,6 @@
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
61.8.128.0/19
61.8.128.0/22
61.8.132.0/22
@ -168,7 +164,6 @@
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
@ -229,7 +224,6 @@
88.130.0.0/16
88.130.136.0/21
88.130.144.0/20
88.130.172.0/22
88.130.176.0/21
88.130.192.0/23
88.130.194.0/23
@ -248,16 +242,14 @@
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
89.244.0.0/14
89.244.120.0/21
89.244.160.0/21
89.244.176.0/20
89.244.192.0/19
89.244.224.0/19
89.244.76.0/22
89.244.224.0/20
89.244.76.0/24
89.244.78.0/23
89.244.80.0/20
89.244.96.0/22
@ -274,6 +266,7 @@
89.245.64.0/19
89.245.96.0/20
89.246.0.0/19
89.246.112.0/22
89.246.122.0/24
89.246.124.0/22
89.246.160.0/21
@ -332,8 +325,6 @@
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
@ -359,7 +350,6 @@
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:16b8:1000::/40

View file

@ -1,23 +1,23 @@
-----BEGIN CERTIFICATE-----
MIIDxzCCA02gAwIBAgISA1HOrGT03Yk2QXIKpt4i5P2mMAoGCCqGSM49BAMDMDIx
MIIDxjCCA0ygAwIBAgISBIbwgyWchKDri2pD+Lk46M3eMAoGCCqGSM49BAMDMDIx
CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQDEwJF
NjAeFw0yNDEyMTkwMTE2MTdaFw0yNTAzMTkwMTE2MTZaMCIxIDAeBgNVBAMTF2hv
bWUuc29waGllcy1raXRjaGVuLmV1MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEKI2X
YK5pxQUcBjOYQwH6OQBEaj2kVhtj1BgRXXrap/U3Zi9M1oKpDk22husbUDS4fACo
IFAsNYbFi15ayAwvkkcWEe4VkgYEdPVJes3XnkL1YOGzUpT9+eC6VbjCxjfdo4IC
NDCCAjAwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEF
BQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBRQB7GGtPhw9dPLCx28NgPOq+Wa
jjAfBgNVHSMEGDAWgBSTJ0aYA6lRaI6Y1sRCSNsjv1iU0jBVBggrBgEFBQcBAQRJ
MEcwIQYIKwYBBQUHMAGGFWh0dHA6Ly9lNi5vLmxlbmNyLm9yZzAiBggrBgEFBQcw
AoYWaHR0cDovL2U2LmkubGVuY3Iub3JnLzA9BgNVHREENjA0ghkqLmhvbWUuc29w
NTAeFw0yNDA5MTkxOTQ5NDFaFw0yNDEyMTgxOTQ5NDBaMCIxIDAeBgNVBAMTF2hv
bWUuc29waGllcy1raXRjaGVuLmV1MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE4rKd
PfAtfQts90WjdnsscizZzlUF/HZBx97kT4/eWgyU/MNOFGF4WqGA92OX0ymZVJ7l
D4CnHq96odx0LqHBQ+W+MXNlsWnwBTUOPKp8XyUeDhZbkgNJDR8nGtHje9a8o4IC
MzCCAi8wDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEF
BQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBSONIAWFPI0mqJYBqnWk1J0Ea27
sDAfBgNVHSMEGDAWgBSfK1/PPCFPnQS37SssxMZwi9LXDTBVBggrBgEFBQcBAQRJ
MEcwIQYIKwYBBQUHMAGGFWh0dHA6Ly9lNS5vLmxlbmNyLm9yZzAiBggrBgEFBQcw
AoYWaHR0cDovL2U1LmkubGVuY3Iub3JnLzA9BgNVHREENjA0ghkqLmhvbWUuc29w
aGllcy1raXRjaGVuLmV1ghdob21lLnNvcGhpZXMta2l0Y2hlbi5ldTATBgNVHSAE
DDAKMAgGBmeBDAECATCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB3AKLjCuRF772t
m3447Udnd1PXgluElNcrXhssxLlQpEfnAAABk9yyNhIAAAQDAEgwRgIhAOsCeRvZ
GUN1z2lGajkrKcCtffuDhwNRPAIN2we+oXuzAiEA7XeLDROcGGcOYUMin5xKE+qr
XwitlCEyUejC5xKJm1QAdQDM+w9qhXEJZf6Vm1PO6bJ8IumFXA2XjbapflTA/kwN
sAAAAZPcsjYwAAAEAwBGMEQCIFRahCu7PZCNkSF6+oyB3MAWoLQYmjlDXxeI91E0
QfOkAiBGaToUTmM1n16nkX0hMVhNm7icCFojHkNCUzfSJ0wk8zAKBggqhkjOPQQD
AwNoADBlAjAgbshjfMt0K8pG2NzhVW1m/es3HJEtK4QGAe/BR5lgjLy1bJG/iLr9
eXPh4xACg5wCMQDx7cF2C2T06e9ogshtJGODQSM9tGHbtt2rpAbUAzWNZgu+F3XL
mwaSjFAL7mBYSMM=
DDAKMAgGBmeBDAECATCCAQMGCisGAQQB1nkCBAIEgfQEgfEA7wB1AEiw42vapkc0
D+VqAvqdMOscUgHLVt0sgdm7v6s52IRzAAABkgwK350AAAQDAEYwRAIga5zPs7YZ
mJqbxhinEJKKQ9XCe1w/MhBzFMzwHFGbaPgCIHeprkwET14Y3h5dmUF7szwTg1Ey
zqLM+GQL3t7EAX2cAHYAPxdLT9ciR1iUHWUchL4NEu2QN38fhWrrwb8ohez4ZG4A
AAGSDArfogAABAMARzBFAiEA0faR1cyqpmCyHo/0KCv04fkpwgzWdMY+WopJXDLD
zz8CIEBKANatmiRstc5D69jKhq2beHldLZB3jRfm1WlWqmxJMAoGCCqGSM49BAMD
A2gAMGUCMCrpe2jxoTH410jNJPOnbN4ae0Ng54JtRNcFWHlcwpk07NrByJSTPWDd
zr7AYsbbVQIxAOGboJcIxsuf+rN30iWoe5KwCY3sd5XW8bEKFQnugIVHxAQKnHNc
0InWz2sVWYKNBA==
-----END CERTIFICATE-----

View file

@ -1,27 +1,27 @@
-----BEGIN CERTIFICATE-----
MIIEVzCCAj+gAwIBAgIRALBXPpFzlydw27SHyzpFKzgwDQYJKoZIhvcNAQELBQAw
MIIEVzCCAj+gAwIBAgIRAIOPbGPOsTmMYgZigxXJ/d4wDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjQwMzEzMDAwMDAw
WhcNMjcwMzEyMjM1OTU5WjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg
RW5jcnlwdDELMAkGA1UEAxMCRTYwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATZ8Z5G
h/ghcWCoJuuj+rnq2h25EqfUJtlRFLFhfHWWvyILOR/VvtEKRqotPEoJhC6+QJVV
6RlAN2Z17TJOdwRJ+HB7wxjnzvdxEP6sdNgA1O1tHHMWMxCcOrLqbGL0vbijgfgw
RW5jcnlwdDELMAkGA1UEAxMCRTUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNCzqK
a2GOtu/cX1jnxkJFVKtj9mZhSAouWXW0gQI3ULc/FnncmOyhKJdyIBwsz9V8UiBO
VHhbhBRrwJCuhezAUUE8Wod/Bk3U/mDR+mwt4X2VEIiiCFQPmRpM5uoKrNijgfgw
gfUwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD
ATASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSTJ0aYA6lRaI6Y1sRCSNsj
v1iU0jAfBgNVHSMEGDAWgBR5tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcB
ATASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSfK1/PPCFPnQS37SssxMZw
i9LXDTAfBgNVHSMEGDAWgBR5tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcB
AQQmMCQwIgYIKwYBBQUHMAKGFmh0dHA6Ly94MS5pLmxlbmNyLm9yZy8wEwYDVR0g
BAwwCjAIBgZngQwBAgEwJwYDVR0fBCAwHjAcoBqgGIYWaHR0cDovL3gxLmMubGVu
Y3Iub3JnLzANBgkqhkiG9w0BAQsFAAOCAgEAfYt7SiA1sgWGCIpunk46r4AExIRc
MxkKgUhNlrrv1B21hOaXN/5miE+LOTbrcmU/M9yvC6MVY730GNFoL8IhJ8j8vrOL
pMY22OP6baS1k9YMrtDTlwJHoGby04ThTUeBDksS9RiuHvicZqBedQdIF65pZuhp
eDcGBcLiYasQr/EO5gxxtLyTmgsHSOVSBcFOn9lgv7LECPq9i7mfH3mpxgrRKSxH
pOoZ0KXMcB+hHuvlklHntvcI0mMMQ0mhYj6qtMFStkF1RpCG3IPdIwpVCQqu8GV7
s8ubknRzs+3C/Bm19RFOoiPpDkwvyNfvmQ14XkyqqKK5oZ8zhD32kFRQkxa8uZSu
h4aTImFxknu39waBxIRXE4jKxlAmQc4QjFZoq1KmQqQg0J/1JF8RlFvJas1VcjLv
YlvUB2t6npO6oQjB3l+PNf0DpQH7iUx3Wz5AjQCi6L25FjyE06q6BZ/QlmtYdl/8
ZYao4SRqPEs/6cAiF+Qf5zg2UkaWtDphl1LKMuTNLotvsX99HP69V2faNyegodQ0
LyTApr/vT01YPE46vNsDLgK+4cL6TrzC/a4WcmF5SRJ938zrv/duJHLXQIku5v0+
EwOy59Hdm0PT/Er/84dDV0CSjdR/2XuZM3kpysSKLgD1cKiDA+IRguODCxfO9cyY
Ig46v9mFmBvyH04=
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-----

View file

@ -1 +1 @@
encrypt$gAAAAABnY4Ga6MmpudhHnOVKVh3j6R071y-Bs6es3e3hNHkZP7Tfj6IomEhTSxWb_oG9HYZmhkadw66cmVRQcxp1wGChWWLye-ykadgy0xUCxGW3YmBWp4t--Yesvbjamaa5OlvDFWQVG5Zt4fsY7BloXRdio8XUdPKBkbi2MV0quvpqsFfOqr_ZmIOOkjLlZojfw9HQ7odM9lSAm8cVS5NXimOhA1ks_gK6CzJbzwhpbekCOcx5_sGhdb8XFUxLN-VBtmQ2HGIncou66rE1P3mBg2hDSyqiXapVMkqMjNoVM71V_5lUnAF7Lxce3nG72SnOe2oITnxRNcnaavxDEgd0ffM5revuCd-XWlaUW1iQrgSyQzJyD6Ukv-mM2IRpuoq79JdTZK_LNJkAmJozrGBT0c5ZwGVNLmZEcjQ1dk8jyYslF5s7rK1lmNvcTUaHGpFToXc1p-qFY8NNWj_Iu-MLE8PNrIscDg==
encrypt$gAAAAABm7I7N50TwtCs2LUt_MArRJnLQ-xLFVhr-zDtdWUVMejViIN2O9h5d_RP45jWt5BpxIkTORarcULXprEXp7zbb-CR5CTwbsNK6HnvSHPwuwXuxJQKRJtT4wWfYEFOxY9aUR9gxvXc3arsYHwVsGyLOeWA_6YzjO5IpL1LfQrsJuUE_1p9sKRyPpslmOJtD5OihMtIfAJNzBDwOSE_gdtLa8iae3DHtSvmKbGKSvwQEZ0pkJxVTVXJY4wddQmdsuV0ky04ls_tUINH8t6IMTJCt_5_ELzpTSdcHgV6W4yh8r_LTEH38n2boYnz3fKgieHnDHDWxFW1EYA2JWjkamH7hQ8iOMl8bqQieFAENnYjF41iz6tSCjfxVyKt_OfJUAwMScVMhPsuaI_i_ZB0Ge6BLsMwkw0d3yw06CwRQ3N7PcPPJLhL_eQS3EuV7Y-7Vv64secplJJIkcFfm1t5zcGkkm4-pDw==

View file

@ -13,6 +13,7 @@ groups['raspberry'] = {
groups['linux'] = {
'subgroups': {
'arch',
'debian',
'raspberry',
},
@ -47,6 +48,13 @@ groups['linux'] = {
'pip_command': 'pip3',
}
groups['arch'] = {
'bundles': {
'pacman',
},
'os': 'arch',
}
groups['debian'] = {
'subgroup_patterns': {
'^debian-[a-z]+$',

View file

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

View file

@ -5,7 +5,7 @@ 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, linklocal=False, only_physical=False):
"""
Try to resolve an identifier (group or node). Return a set of ip
addresses valid for this identifier.
@ -62,15 +62,10 @@ 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:

View file

@ -40,7 +40,7 @@ imap_pass = "!bwpass_attr:t-online.de/franzi.kunsmann@t-online.de:imap"
[metadata.element-web]
url = "chat.franzi.business"
version = "v1.11.89"
version = "v1.11.86"
[metadata.element-web.config]
default_server_config.'m.homeserver'.base_url = "https://matrix.franzi.business"
default_server_config.'m.homeserver'.server_name = "franzi.business"
@ -49,8 +49,8 @@ defaultCountryCode = "DE"
jitsi.preferredDomain = "meet.ffmuc.net"
[metadata.forgejo]
version = "9.0.3"
sha1 = "a04a8d5bee7321610d91da780a24e18f7407403c"
version = "9.0.2"
sha1 = "5aecc64f93e8ef05c6d6f83d4b647bdb2c831d9f"
domain = "git.franzi.business"
enable_git_hooks = true
install_ssh_key = true
@ -114,8 +114,8 @@ provisioning.shared_secret = "!decrypt:encrypt$gAAAAABfVKflEMAi07C_QGP8cy97hF-4g
"'@kunsi:franzi.business'" = "admin"
[metadata.mautrix-whatsapp]
version = "v0.11.2"
sha1 = "0bd8ebef237473989c4e9658c72595e9f7c09d44"
version = "v0.11.1"
sha1 = "ada2dc6acfd5cb15fae341266b383d3f6e8b42bd"
permissions."'@kunsi:franzi.business'" = "admin"
[metadata.mautrix-whatsapp.homeserver]
domain = "franzi.business"
@ -126,7 +126,7 @@ domain = "rss.franzi.business"
[metadata.netbox]
domain = "netbox.franzi.business"
version = "v4.1.10"
version = "v4.1.7"
admins.kunsi = "hostmaster@kunbox.net"
[metadata.nextcloud]
@ -213,7 +213,7 @@ blocked_recipients = [
[metadata.postfixadmin]
domain = "postfixadmin.franzi.business"
setup_password = "!decrypt:encrypt$gAAAAABgnNGpAqUs--qBXII9ZPcHtxaELy9e2Dx9O44n4l0O4nMHPoIyaPW5HkvpQ2zWTlh5OfjjOgunRtE_voJuY0Kdtji37ixAnuL9ErOJ0LDY5QfMkNPUgPs5alwz1baqYq6rqJ7NDmB0gHraY46v5eG79R2EyQ=="
version = "3.3.15"
version = "3.3.14"
[metadata.postgresql]
version = 15
@ -262,7 +262,7 @@ disks = [
]
[metadata.travelynx]
version = "2.9.8"
version = "2.9.2"
mail_from = "travelynx@franzi.business"
domain = "travelynx.franzi.business"

190
nodes/fkusei-locutus.py Normal file
View file

@ -0,0 +1,190 @@
nodes['fkusei-locutus'] = {
'dummy': True,
'hostname': '10.5.99.29',
'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/tcp': {'*'},
},
},
'interfaces': {
'eth*': {
'dhcp': True,
},
# there is also wlan0, 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',
},
},
'pacman': {
'packages': {
'amd-ucode': {},
'xf86-video-amdgpu': {},
# all that other random stuff one needs
'apachedirectorystudio': {},
'direnv': {},
'freerdp': {},
'sdl_ttf': {}, # for compiling testcard
'thermald': {},
},
},
'sysctl': {
'options': {
# accept RA even though forwarding is enabled
'net.ipv4.conf.all.accept_ra': '2',
'net.ipv4.conf.wlan0.accept_ra': '2',
},
},
'systemd-boot': {
'default': 'arch',
'entries': {
'arch': {
'title': 'Arch Linux',
'linux': '/vmlinuz-linux',
'initrd': [
'/amd-ucode.img',
'/initramfs-linux.img',
],
'options': {
'net.ifnames=0',
'rw',
'zfs=zroot/system/root',
},
},
'arch-fallback': {
'title': 'Arch Linux (no ucode, fallback initramfs)',
'linux': '/vmlinuz-linux',
'initrd': [
'/initramfs-linux-fallback.img',
],
'options': {
'net.ifnames=0',
'rw',
'zfs=zroot/system/root',
},
},
},
},
'timezone': 'Europe/Berlin',
'users': {
'fkunsmann': {
'password': vault.decrypt('encrypt$gAAAAABgLmmuQGRUStrQawoPee-758emIYn2u8-8ebrgzNAFSp7ifeFDdXXvs-zL3QogwNYlCtBHboH2xfy1rSj6OF5bbNO-tg=='),
'shell': '/usr/bin/fish',
},
},
'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': {
'endpoint': 'wireguard.htz-cloud.kunbox.net:1194',
'their_ip': '10.200.128.1',
'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': {
'pools': {
'zroot': {
'when_creating': {
'config': [],
},
},
},
'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',
}

View file

@ -25,8 +25,8 @@ 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"]
version = 'v2.3.36'
python_versions = ["3.12.2"]
[metadata.nginx.vhosts.homeassistant]
ssl = '_.home.kunbox.net'

View file

@ -3,7 +3,6 @@
nodes['home.nas'] = {
'hostname': '172.19.138.20',
'bundles': {
'avahi-daemon',
'backup-client',
'dm-crypt',
'jellyfin',
@ -56,9 +55,6 @@ nodes['home.nas'] = {
# systemctl start yate
},
},
'avahi-daemon': {
'use-ipv6': False, # because having a dynamic address confuses the network somehow
},
'backups': {
'paths': {
'/storage/nas/Audiobooks',
@ -71,11 +67,6 @@ nodes['home.nas'] = {
'/storage/nas/normen',
},
},
'cron': {
'jobs': {
'avahi-aruba-fixup': '17,47 * * * * root /usr/bin/systemctl restart avahi-daemon.service',
},
},
'dm-crypt': {
'encrypted-devices': {
'/dev/disk/by-id/ata-Samsung_SSD_870_QVO_8TB_S5SSNJ0X409404K': {
@ -156,7 +147,6 @@ nodes['home.nas'] = {
'restrict-to': {
'172.19.136.0/25',
'172.19.138.0/24',
'htz-cloud.molly-connector',
},
},
'nfs-server': {
@ -187,10 +177,6 @@ nodes['home.nas'] = {
},
'samba': {
'shares': {
'TV': {
'path': '/storage/nas/TV',
'force_group': 'nas',
},
'music': {
'path': '/storage/nas/Musik',
'force_group': 'nas',
@ -203,9 +189,6 @@ nodes['home.nas'] = {
'restrict-to': {
'172.19.138.0/24',
},
'timemachine-shares': {
'apfelcomputer',
},
},
'smartd': {
'disks': {
@ -261,11 +244,11 @@ 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 ',
# },
#},
'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 ',
},
},
'kunsi': {
'groups': {
'nas',
@ -277,7 +260,7 @@ nodes['home.nas'] = {
'zfs_arc_max_gb': 8,
},
'pools': {
'tank': {
'storage': {
'when_creating': {
'config': [
{
@ -322,40 +305,69 @@ nodes['home.nas'] = {
'encrypted': {
'primarycache': 'metadata',
},
'encrypted/download': {
'mountpoint': '/media/download',
},
'encrypted/nas': {
'acltype': 'off',
'atime': 'off',
'compression': 'off',
'mountpoint': '/storage/nas',
},
'tank': {
'encrypted/paperless': {
'mountpoint': '/media/paperless',
},
'storage': {
'primarycache': 'metadata',
},
'tank/opt-yate': {
'storage/opt-yate': {
'mountpoint': '/opt/yate',
},
'tank/download': {
'storage/download': {
'mountpoint': '/storage/download',
},
'tank/paperless': {
'storage/nas': {
'acltype': 'off',
'atime': 'off',
'compression': 'off',
'mountpoint': '/media/nas_old',
},
'storage/paperless': {
'mountpoint': '/srv/paperless',
},
},
'snapshots': {
'retain_per_dataset': {
'encrypted/download': {
'hourly': 6,
'daily': 0,
'weekly': 0,
'monthly': 0,
},
'encrypted/nas': {
# juuuuuuuust to be sure.
'daily': 14,
'weekly': 6,
'monthly': 12,
},
'tank/download': {
'encrypted/paperless': {
'daily': 14,
'weekly': 6,
'monthly': 24,
},
'storage/download': {
'hourly': 48,
'daily': 0,
'weekly': 0,
'monthly': 0,
},
'tank/paperless': {
'storage/nas': {
# juuuuuuuust to be sure.
'daily': 14,
'weekly': 6,
'monthly': 12,
},
'storage/paperless': {
'daily': 14,
'weekly': 6,
'monthly': 24,

View file

@ -0,0 +1,59 @@
hostname = "2a01:4f9:c010:95fa::2"
bundles = ["backup-client"]
groups = [
"arch",
"webserver",
]
[metadata]
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",
]
[metadata.icinga_options]
period = "daytime"
[metadata.backups]
paths = [
"/var/cache/pacman/aurto",
]
[metadata.interfaces.enp1s0]
ips = ["2a01:4f9:c010:95fa::2/64"]
gateway6 = "fe80::1"
[metadata.interfaces.enp7s0]
ips = ["172.19.137.4/32"]
gateway4 = "172.19.137.1"
[metadata.nginx.vhosts.aurto]
domain = "aurto.kunbox.net"
webroot = "/var/cache/pacman/aurto"
extras = true
[metadata.pacman]
enable_aurto = false
additional_config = [
"Include = /etc/pacman.d/aurto",
]
[metadata.pacman.unattended-upgrades]
is_enabled = true
[metadata.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",
]
[metadata.users.aurto]
groups = ["wheel"]
ssh_pubkey = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICYst1HK+gJYhNxzqJGnz4iB73pa89Xz2yH+8wufOcsA", # kunsi work
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC+ja1z5VRQzaKCCePsUM14qMr9QR94qlWc7Je5Poki9UmC1t/TyxRVzcCBL1ZdIfBGx6QKtfkEbvhgb3nxVt3PvXjoJrc6wwGLmNrVsU6B88y35g7nzupQiPKYJwkNzJ9j6Dmkgj1F5Q+aY2SitDaX6vqICLJ4Al/ZFw2IQxVJfC7JXRJ9jRMG5o9gWoE3gWDYEAmw+HU2mNzyeuaD12qJw9DHUimAlgkOWzll3gh9WclsYnnXGrCCn5fyHFUCJl+XXAIy519z7YTpKih02rsIOw5dnaGClBZD/YQu2ZKVFZiwIVH7aBiqHOmtgRyWTQgjbh/fMpIN0ar2f/iZsWYUjd6et48TOmXZYIPCQ5FivXNvxt9oo1XZfq76UHBwlmypLJIWROMbz375n2M6hr3hECuxuPjKEUXAv05KiC1aJ4xc6pFoVhqwAR99hvHw5U4o7/ko2NVjNpTu6Jr5DT5VaQLIdDDjC/93kUjMpdD/8P72bEn7454+WexU6OE6uvNiHj1fetrptr2UAuzVfnCoaV8pBqY7X95gk+lnSENdpr8ltJYMg8s0Z7Pzz0OxsZtzzDY5VmWfC9TCdJkN5lT8IbnaixsYlWdjQl1lMmZGElmelfU3K7YQLAbZiHmHKe4hTl9ZoCcWdTQ3d4y2t1DBos+N2HZNdtFCyOS8esDdMw==", # kunsi privat
]
[metadata.users.kunsi]
groups = ["wheel"]

View file

@ -71,7 +71,7 @@ nodes['htz-cloud.pirmasens'] = {
},
'postfixadmin': {
'domain': 'mail.kunsmann.info',
'version': '3.3.15',
'version': '3.3.14',
'setup_password': vault.decrypt('encrypt$gAAAAABgnNGpAqUs--qBXII9ZPcHtxaELy9e2Dx9O44n4l0O4nMHPoIyaPW5HkvpQ2zWTlh5OfjjOgunRtE_voJuY0Kdtji37ixAnuL9ErOJ0LDY5QfMkNPUgPs5alwz1baqYq6rqJ7NDmB0gHraY46v5eG79R2EyQ=='),
},
'postgresql': {

View file

@ -101,21 +101,12 @@ nodes['htz-cloud.wireguard'] = {
'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': {
'kunsi-p14s': {
'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'),
},
},
},

251
nodes/kunsi-p14s.py Normal file
View file

@ -0,0 +1,251 @@
nodes['kunsi-p14s'] = {
'hostname': 'localhost',
'bundles': {
'arch-with-gui',
'backup-client',
'lldp',
'lm-sensors',
'nfs-client',
'systemd-boot',
'telegraf-battery-usage',
'vmhost',
'wireguard',
'zfs',
},
'groups': {
'arch',
},
'metadata': {
'arch-with-gui': {
'autologin_as': 'kunsi',
},
'backup-client': {
'exclude_from_monitoring': False,
# 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/tcp': {'*'},
},
},
'interfaces': {
'br0': {
'ips': {'10.73.100.112/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',
},
},
},
},
'nftables': {
'forward': {
'50-routing': [
'ct state { related, established } accept',
'oifname wlan0 accept',
],
},
'postrouting': {
'50-routing': [
'oifname wlan0 masquerade',
],
},
},
'openssh': {
'restrict-to': {
'rfc1918',
},
},
'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': {},
# all that other random stuff one needs
#'abcde': {},
'claws-mail': {},
'claws-mail-themes': {},
'ferdium-bin': {},
'gumbo-parser': {}, # for claws litehtml
'inkstitch': {}, # for RZL embroidery machine
'obs-studio': {},
#'perl-musicbrainz-discid': {}, # for abcde
#'perl-webservice-musicbrainz': {}, # for abcde
'sdl_ttf': {}, # for compiling testcard
'x32edit': {},
},
},
'systemd-boot': {
'default': 'arch',
'entries': {
'arch': {
'title': 'Arch Linux',
'linux': '/vmlinuz-linux',
'initrd': [
'/amd-ucode.img',
'/initramfs-linux.img',
],
'options': {
'net.ifnames=0',
'rw',
'zfs=zroot/system/root',
},
},
'arch-fallback': {
'title': 'Arch Linux (no ucode, fallback initramfs)',
'linux': '/vmlinuz-linux',
'initrd': [
'/initramfs-linux-fallback.img',
],
'options': {
'net.ifnames=0',
'rw',
'zfs=zroot/system/root',
},
},
},
},
'sysctl': {
'options': {
'net.ipv4.conf.all.forwarding': '1',
},
},
'systemd-networkd': {
'bridges': {
'br0': {
'match': {
'en*',
'eth*',
},
},
},
},
'timezone': 'Europe/Berlin',
'users': {
'kunsi': {
'password': vault.decrypt('encrypt$gAAAAABgLmmuQGRUStrQawoPee-758emIYn2u8-8ebrgzNAFSp7ifeFDdXXvs-zL3QogwNYlCtBHboH2xfy1rSj6OF5bbNO-tg=='),
'shell': '/usr/bin/fish',
},
},
'wireguard': {
'peers': {
'htz-cloud.wireguard': {
'auto_connection': False,
'endpoint': 'wireguard.htz-cloud.kunbox.net:1194',
'my_ip': '172.19.136.65',
'my_port': 51819,
'their_ip': '172.19.136.64',
'routes': {
'10.73.0.0/16',
'172.19.128.0/20',
},
},
},
},
'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/nextcloud': {
'mountpoint': '/home/kunsi/nextcloud',
},
'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': 'legacy',
},
'zroot/user/kunsi': {
'mountpoint': '/home/kunsi',
},
},
'snapshots': {
'retain_per_dataset': {
'zroot/user/kunsi': {
# juuuuuuuust to be sure
'hourly': 100,
},
},
'snapshot_never': {
'zroot/movies',
'zroot/nextcloud',
'zroot/system/journal',
'zroot/system/video',
},
},
},
},
'os': 'arch',
}

View file

@ -28,10 +28,16 @@ nodes['voc.infobeamer-cms'] = {
'event_start_date': '2024-12-26',
'event_duration_days': 5,
'config': {
'ADMIN_USERS': [],
'NO_LIMIT_USERS': [
'github:stblassitude',
'ADMIN_USERS': [
'hexchen',
'jbeyerstedt',
'jwacalex',
'kunsi',
'sophieschi',
'v0tti',
],
'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'),
'INTERRUPT_KEY': vault.human_password_for('infobeamer-cms interrupt key 38c3', words=1),
'SETUP_IDS': [
@ -64,30 +70,13 @@ nodes['voc.infobeamer-cms'] = {
or #info-beamer on the cccv rocketchat instance.
'''.strip(),
},
'DEFAULT_SSO_PROVIDER': 'c3hub',
'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'),
},
},
},
'rooms': {
'Saal 1': 34430, # s1
'Saal GLITCH': 37731, # s2
'Saal ZIGZAG': 26610, # s3
'Sendezentrum': 38641, # s4
'Stage YELL': 38642, # s5
'Stage HUFF': 35042, # s6
'Saal 1': 34430,
'Saal G': 26598,
'Saal Z': 26610,
'Saal E (SoS/Lightning-Talks)': 32814,
'Saal F (Sendezentrum/DLF)': 9717,
},
'interrupts': {
'Questions': 'questions',

View file

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

View file

@ -11,8 +11,7 @@
},
"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,7 @@
},
"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"
]
}
}