Compare commits

...

65 commits

Author SHA1 Message Date
Sophie Schiller
7aaa47ccb2 jh toolz from original source 2024-07-22 21:32:57 +02:00
Sophie Schiller
0f07357ebe revive jhtoolz 2024-07-22 21:32:57 +02:00
Sophie Schiller
6d9e2e2663 jhtoolz static 2024-07-22 21:32:57 +02:00
Sophie Schiller
dc0d745842 htz-cloud.jugendhackt: add new node 2024-07-22 21:32:57 +02:00
95bb7c52fe
bundles/apt: add bissing default for update commands 2024-07-22 21:31:27 +02:00
2a8c1ef84b
update mautrix-whatsapp to 0.10.9 2024-07-19 19:22:05 +02:00
c1fc942b1d
update mautrix-telegram to 0.15.2 2024-07-19 19:21:50 +02:00
c4bf96482f
update element-web to 1.11.71 2024-07-19 19:21:37 +02:00
69691f75c5
data/apt: new gpg key for nodesource 2024-07-19 19:20:40 +02:00
263440296d
bundles: no default for nodejs version anymore 2024-07-19 19:20:23 +02:00
55a3e6675f
bundles/nodejs: everything changed, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 2024-07-19 19:19:45 +02:00
350c436e4d
bundles/apt: add action to execute additional_update_commands 2024-07-19 19:19:14 +02:00
205fea377a
update paperless to 2.11.0 2024-07-12 19:06:55 +02:00
fb46d81f97
update netbox to 4.0.7 2024-07-12 19:06:43 +02:00
466a620bca
update element-web to 1.11.70 2024-07-12 19:06:28 +02:00
04094df418
update matrix-media-repo to 1.3.6 2024-07-12 18:46:10 +02:00
c348953611
bundles/sshmon: even more letsencrypt shenanigans 2024-07-12 18:45:43 +02:00
e4dfd17bb6
bundles/matrix-media-repo: has live config reload 2024-07-12 18:42:31 +02:00
08f2c46c31
bundles/matrix-synapse: media-repo needs more paths now 2024-07-12 18:39:09 +02:00
b2028855d1
bundles/sshmon: new issuer hash for letsencrypt 2024-07-12 18:24:27 +02:00
a472ca4657
bw/bundles/matrix-media-repo: adjust config for 1.3.6 2024-07-12 18:20:53 +02:00
d08e9f12ab
add icinga_options.also_affected_by to systems running in vm on home.nas 2024-07-12 18:13:43 +02:00
2fddd57ed8
bundles/backup-client: only log to logfile when not running in debug mode 2024-07-07 10:23:20 +02:00
5a86e657ff
bundles/mixcloud-downloader: add login via netrc 2024-07-07 10:22:26 +02:00
52b68d6e42
home.nas: clean up smartd config 2024-07-06 10:59:46 +02:00
fbe2197055
add home.r630 2024-07-06 10:56:13 +02:00
ced6479b8e
home.nas: clean up zfs datasets 2024-07-06 09:49:22 +02:00
6e677a7a0b
update paperless-ngx to 2.10.2 2024-07-06 09:45:41 +02:00
c0b3db55ec
update travelynx to 2.7.7 2024-07-06 09:45:18 +02:00
fc4aaf4abb
update netbox to 4.0.6 2024-07-06 09:44:57 +02:00
ce44926920
update forgejo to 7.0.5 2024-07-06 09:44:41 +02:00
4736e3b281
update travelynx to 2.7.6 2024-07-04 11:43:43 +02:00
b3ab18a32c
bundles/nginx: don't cache stuff when running through php 2024-07-01 17:17:30 +02:00
79bb4169a7
ns-mephisto: new ip config 2024-07-01 11:34:36 +02:00
101928339f
bundles/powerdns: fix SyntaxWarning 2024-06-26 07:11:44 +02:00
67198c5fd9
bundles/grafana: needs websockets 2024-06-25 17:32:24 +02:00
791eb8d1a9
bump netbox-dump 2024-06-25 17:10:32 +02:00
0ce0e34382 Merge pull request 'sophiesheomenetwork' (#68) from sophiesheomenetwork into main
Reviewed-on: #68
2024-06-23 12:54:01 +00:00
668ae0432b
htz-hel.backup-kunsi: remove backup target for kunsi-t470 2024-06-23 14:52:09 +02:00
b72d82b894
bundles/routeros: this does not need to be a metadata reactor 2024-06-22 20:39:04 +02:00
d1f182607d
rework netbox-dump script and routeros bundle for better usability 2024-06-22 20:04:51 +02:00
Sophie Schiller
9be31b8850 homeassistant: use correct network interface 2024-06-22 00:51:33 +02:00
Sophie Schiller
182cdada22 homeassistant metadata reshuffle 2024-06-21 21:25:48 +02:00
Sophie Schiller
2c51caa524 update nginx signing key 2024-06-21 20:58:17 +02:00
Sophie Schiller
263301b265 add homeassistant in sophies home 2024-06-21 20:32:06 +02:00
Sophie Schiller
2f4b90c147 miniserver: element update 2024-06-21 19:32:43 +02:00
Sophie Schiller
e5c5672554 add vmhost for sophies home 2024-06-21 19:32:28 +02:00
c47b412cf3
update forgejo to 7.0.4 2024-06-18 20:43:55 +02:00
cda7e3b7fd
update paperless to 2.10.0 2024-06-18 20:43:41 +02:00
e876d39002
update netbox to 4.0.5 2024-06-18 20:43:25 +02:00
b9583d9a64
update element-web to 1.11.69 2024-06-18 20:43:10 +02:00
60a0737187
bundles/jellyfin: fix firewall defaults 2024-06-18 20:40:09 +02:00
52c093427f
ssl: bump _.home.kunbox.net 2024-06-11 17:42:43 +02:00
Sophie Schiller
658acbd12b rechenmonster: add dataset 2024-06-09 10:21:08 +02:00
56df06e981
clean up some nodefiles 2024-06-08 18:50:55 +02:00
d1e28c3f0c
sophie gets her own group 2024-06-08 18:46:51 +02:00
Sophie Schiller
1c2127437c voc.infobeamer-cms: gpn22 2024-05-30 21:44:07 +02:00
Sophie Schiller
768ae0a37a htz-cloud.miniserver: backlinks to social media 2024-05-29 00:02:29 +02:00
bebc603c43
update paperless-ngx to 2.8.6 2024-05-24 17:07:21 +02:00
43fe831395
update netbox to 4.0.3 2024-05-24 17:07:10 +02:00
5b8784e916
update forgejo to 7.0.3 2024-05-24 17:06:53 +02:00
ea21e4b119
update element-web to 1.11.67 2024-05-24 17:06:38 +02:00
a6c1d67b55
remove entropia-jira 2024-05-24 17:03:18 +02:00
a8ef19f4ff
bundles/icinga2: add check_omm 2024-05-24 15:26:35 +02:00
8c42c9411a
bundles/postfix: fix typo 2024-05-24 15:24:14 +02:00
66 changed files with 1212 additions and 728 deletions

View file

@ -27,6 +27,10 @@ actions = {
'triggered': True, 'triggered': True,
'cascade_skip': False, 'cascade_skip': False,
}, },
'apt_execute_update_commands': {
'command': ' && '.join(sorted(node.metadata.get('apt/additional_update_commands', {'true'}))),
'triggered': True,
},
} }
files = { files = {

View file

@ -62,10 +62,13 @@ trap "on_exit" EXIT
# redirect stdout and stderr to logfile # redirect stdout and stderr to logfile
prepare_and_cleanup_logdir prepare_and_cleanup_logdir
logfile="$logdir/backup--$(date '+%F--%H-%M-%S')--$$.log.gz" if [[ -z "$DEBUG" ]]
echo "All log output will go to $logfile" | logger -it backup-client then
exec > >(gzip >"$logfile") logfile="$logdir/backup--$(date '+%F--%H-%M-%S')--$$.log.gz"
exec 2>&1 echo "All log output will go to $logfile" | logger -it backup-client
exec > >(gzip >"$logfile")
exec 2>&1
fi
# this is where the real work starts # this is where the real work starts
ts_begin=$(date +%s) ts_begin=$(date +%s)

View file

@ -33,7 +33,7 @@ actions = {
'yarn build', 'yarn build',
]), ]),
'needs': { 'needs': {
'action:nodejs_install_yarn', 'action:apt_execute_update_commands',
'pkg_apt:nodejs', 'pkg_apt:nodejs',
}, },
'triggered': True, 'triggered': True,

View file

@ -11,6 +11,26 @@ 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': 20,
},
}
else:
return {
'nodejs': {
'version': 18,
},
}
@metadata_reactor.provides( @metadata_reactor.provides(
'nginx/vhosts/element-web', 'nginx/vhosts/element-web',
) )

View file

@ -43,6 +43,7 @@ def nginx(metadata):
'locations': { 'locations': {
'/': { '/': {
'target': 'http://127.0.0.1:21010', 'target': 'http://127.0.0.1:21010',
'websockets': True,
}, },
'/api/ds/query': { '/api/ds/query': {
'target': 'http://127.0.0.1:21010', 'target': 'http://127.0.0.1:21010',

View file

@ -7,6 +7,7 @@ else:
users = { users = {
'homeassistant': { 'homeassistant': {
'home': '/var/opt/homeassistant', 'home': '/var/opt/homeassistant',
"groups": ["dialout"],
}, },
} }

View file

@ -0,0 +1,132 @@
#!/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()

View file

@ -63,7 +63,7 @@ def firewall(metadata):
return { return {
'firewall': { 'firewall': {
'port_rules': { 'port_rules': {
'8096/tcp': atomic(metadata.get('jellyfin/restrict-to', {'*'})), '8096/tcp': atomic(metadata.get('jellyfin/restrict-to', set())),
}, },
}, },
} }

View file

@ -1,7 +1,7 @@
directories['/opt/jugendhackt_tools/src'] = {} directories['/opt/jugendhackt_tools/src'] = {}
git_deploy['/opt/jugendhackt_tools/src'] = { git_deploy['/opt/jugendhackt_tools/src'] = {
'repo': 'https://github.com/kunsi/jugendhackt_schedule.git', 'repo': 'https://github.com/Kunsi/jugendhackt_schedule.git',
'rev': 'main', 'rev': 'main',
'triggers': { 'triggers': {
'action:jugendhackt_tools_install', 'action:jugendhackt_tools_install',
@ -16,6 +16,7 @@ actions['jugendhackt_tools_create_virtualenv'] = {
'needs': { 'needs': {
# actually /opt/jugendhackt_tools, but we don't create that # actually /opt/jugendhackt_tools, but we don't create that
'directory:/opt/jugendhackt_tools/src', 'directory:/opt/jugendhackt_tools/src',
'pkg_apt:python3-virtualenv',
}, },
} }
@ -27,6 +28,7 @@ actions['jugendhackt_tools_install'] = {
]), ]),
'needs': { 'needs': {
'action:jugendhackt_tools_create_virtualenv', 'action:jugendhackt_tools_create_virtualenv',
'pkg_apt:python3-pip',
}, },
'triggered': True, 'triggered': True,
} }

View file

@ -3,6 +3,9 @@ repo:
bindAddress: '${node.metadata.get('matrix-media-repo/listen-addr', '127.0.0.1')}' bindAddress: '${node.metadata.get('matrix-media-repo/listen-addr', '127.0.0.1')}'
port: ${node.metadata.get('matrix-media-repo/port', 20090)} port: ${node.metadata.get('matrix-media-repo/port', 20090)}
logDirectory: '-' logDirectory: '-'
logColors: false
jsonLogs: false
logLevel: 'info'
trustAnyForwardedAddress: false trustAnyForwardedAddress: false
useForwardedHost: true useForwardedHost: true
@ -22,6 +25,9 @@ homeservers:
csApi: "${config['domain']}" csApi: "${config['domain']}"
backoffAt: ${config.get('backoff_at', 10)} backoffAt: ${config.get('backoff_at', 10)}
adminApiKind: "${config.get('api', 'matrix')}" adminApiKind: "${config.get('api', 'matrix')}"
% if config.get('signing_key_path'):
signingKeyPath: "${config['signing_key_path']}"
% endif
% endfor % endfor
accessTokens: accessTokens:
@ -53,7 +59,9 @@ archiving:
uploads: uploads:
maxBytes: ${node.metadata.get('matrix-media-repo/upload_max_mb')*1024*1024} maxBytes: ${node.metadata.get('matrix-media-repo/upload_max_mb')*1024*1024}
minBytes: 100 minBytes: 100
reportedMaxBytes: 0 #reportedMaxBytes: 0
maxPending: 5
maxAgeSeconds: 1800
quotas: quotas:
enabled: false enabled: false
@ -61,14 +69,6 @@ downloads:
maxBytes: ${node.metadata.get('matrix-media-repo/download_max_mb')*1024*1024} maxBytes: ${node.metadata.get('matrix-media-repo/download_max_mb')*1024*1024}
numWorkers: ${node.metadata.get('matrix-media-repo/workers')} numWorkers: ${node.metadata.get('matrix-media-repo/workers')}
failureCacheMinutes: 5 failureCacheMinutes: 5
cache:
enabled: true
maxSizeBytes: ${node.metadata.get('matrix-media-repo/download_max_mb')*10*1024*1024}
maxFileSizeBytes: ${node.metadata.get('matrix-media-repo/download_max_mb')*1024*1024}
trackedMinutes: 30
minDownloads: 5
minCacheTimeSeconds: 300
minEvictedTimeSeconds: 60
expireAfterDays: 0 expireAfterDays: 0
urlPreviews: urlPreviews:

View file

@ -19,9 +19,6 @@ files = {
'/opt/matrix-media-repo/config.yaml': { '/opt/matrix-media-repo/config.yaml': {
'owner': 'matrix-media-repo', 'owner': 'matrix-media-repo',
'content_type': 'mako', 'content_type': 'mako',
'triggers': {
'svc_systemd:matrix-media-repo:restart',
},
}, },
'/etc/systemd/system/matrix-media-repo.service': { '/etc/systemd/system/matrix-media-repo.service': {
'triggers': { 'triggers': {

View file

@ -144,13 +144,14 @@ def nginx(metadata):
} }
if node.has_bundle('matrix-media-repo'): if node.has_bundle('matrix-media-repo'):
locations['/_matrix/media'] = { for path in ('/_matrix/media', '/_matrix/client/v1/media', '/_matrix/federation/v1/media'):
'target': 'http://localhost:20090', locations[path] = {
'max_body_size': '{}M'.format(metadata.get('matrix-media-repo/upload_max_mb')), 'target': 'http://localhost:20090',
# matrix-media-repo needs this to be the 'max_body_size': '{}M'.format(metadata.get('matrix-media-repo/upload_max_mb')),
# homeserver address. # matrix-media-repo needs this to be the
'x_forwarded_host': metadata.get('matrix-synapse/server_name'), # homeserver address.
} 'x_forwarded_host': metadata.get('matrix-synapse/server_name'),
}
vhosts = { vhosts = {
'matrix-synapse': { 'matrix-synapse': {

View file

@ -1,11 +1,15 @@
#!/bin/bash #!/bin/bash
OPTS="" 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"
if [[ -n "$DEBUG" ]] if [[ -n "$DEBUG" ]]
then then
set -x set -x
else else
OPTS="-q" OPTS="$OPTS -q"
fi fi
set -euo pipefail set -euo pipefail

View file

@ -0,0 +1,3 @@
% for domain, data in sorted(node.metadata.get('mixcloud-downloader/netrc', {}).items()):
machine ${domain} login ${data['username']} password ${data['password']}
% endfor

View file

@ -6,3 +6,9 @@ files['/opt/mixcloud-downloader/download.sh'] = {
directories['/opt/mixcloud-downloader'] = { directories['/opt/mixcloud-downloader'] = {
'owner': 'kunsi', 'owner': 'kunsi',
} }
files['/opt/mixcloud-downloader/netrc'] = {
'content_type': 'mako',
'mode': '0400',
'owner': 'kunsi',
}

View file

@ -201,6 +201,8 @@ server {
fastcgi_hide_header X-XSS-Protection; fastcgi_hide_header X-XSS-Protection;
% endif % endif
fastcgi_hide_header Permissions-Policy; fastcgi_hide_header Permissions-Policy;
fastcgi_request_buffering off;
proxy_buffering off;
} }
% if not max_body_size: % if not max_body_size:
client_max_body_size 5M; client_max_body_size 5M;

View file

@ -1,9 +0,0 @@
actions = {
'nodejs_install_yarn': {
'command': 'npm install -g yarn@latest',
'unless': 'test -e /usr/lib/node_modules/yarn',
'after': {
'pkg_apt:',
},
},
}

View file

@ -1,54 +1,41 @@
defaults = { defaults = {
'apt': { 'apt': {
'additional_update_commands': { 'additional_update_commands': {
# update npm to latest version # update npm and yarn to latest version
'npm install -g npm@latest',
'npm install -g yarn@latest', 'npm install -g yarn@latest',
}, },
'packages': { 'packages': {
'nodejs': {}, 'nodejs': {
'triggers': {
'action:apt_execute_update_commands',
},
},
'npm': {
'installed': False,
'triggers': {
'action:apt_execute_update_commands',
},
},
}, },
}, },
'nodejs': {
'version': 18,
},
}
VERSIONS_SHIPPED_BY_DEBIAN = {
10: 10,
11: 12,
12: 18,
13: 18,
} }
@metadata_reactor.provides( @metadata_reactor.provides(
'apt/repos/nodejs/items', 'apt/repos/nodejs/items',
'apt/additional_update_commands',
) )
def nodejs_from_version(metadata): def nodejs_from_version(metadata):
version = metadata.get('nodejs/version') version = metadata.get('nodejs/version')
if version != VERSIONS_SHIPPED_BY_DEBIAN[node.os_version[0]]: return {
return { 'apt': {
'apt': { 'repos': {
'additional_update_commands': { 'nodejs': {
# update npm to latest version 'items': {
'npm install -g npm@latest', f'deb https://deb.nodesource.com/node_{version}.x nodistro main',
}, f'deb-src https://deb.nodesource.com/node_{version}.x nodistro main',
'repos': {
'nodejs': {
'items': {
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',
},
}, },
}, },
}, },
} },
else: }
return {
'apt': {
'packages': {
'npm': {},
},
},
}

View file

@ -33,6 +33,9 @@ defaults = {
'/mnt/paperless', '/mnt/paperless',
}, },
}, },
'nodejs': {
'version': 18,
},
'postgresql': { 'postgresql': {
'roles': { 'roles': {
'paperless': { 'paperless': {

View file

@ -57,7 +57,7 @@ smtpd_tls_auth_only = yes
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1 smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1 smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
smtpd_tls_mandatory_ciphers = medium smtpd_tls_mandatory_ciphers = medium
smtpd_tls_dh1024_param_file = /etc/ssl/certs/dhparam.pem; 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_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_preempt_cipherlist = no
</%text> </%text>

View file

@ -65,7 +65,7 @@ svc_systemd = {
actions = { actions = {
'powerdns_reload_zones': { 'powerdns_reload_zones': {
'triggered': True, 'triggered': True,
'command': 'pdns_control rediscover; pdns_control reload; pdns_control notify \*', 'command': r'pdns_control rediscover; pdns_control reload; pdns_control notify \*',
'after': { 'after': {
'svc_systemd:pdns', 'svc_systemd:pdns',
}, },
@ -160,7 +160,7 @@ if node.metadata.get('powerdns/features/pgsql', node.has_bundle('postgresql')):
actions['powerdns_load_pgsql_schema'] = { 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'), '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': 'sudo -u postgres psql -d powerdns -c "\dt" | grep domains 2>&1 >/dev/null', 'unless': r'sudo -u postgres psql -d powerdns -c "\dt" | grep domains 2>&1 >/dev/null',
'needs': { 'needs': {
'bundle:postgresql', 'bundle:postgresql',
'pkg_apt:pdns-backend-pgsql', 'pkg_apt:pdns-backend-pgsql',

View file

@ -13,6 +13,9 @@ defaults = {
'python3-wheel': {}, 'python3-wheel': {},
}, },
}, },
'nodejs': {
'version': 18,
},
'users': { 'users': {
'powerdnsadmin': { 'powerdnsadmin': {
'home': '/opt/powerdnsadmin', 'home': '/opt/powerdnsadmin',

View file

@ -26,6 +26,9 @@ defaults = {
}, },
}, },
}, },
'nodejs': {
'version': 18,
},
'pretalx': { 'pretalx': {
'database': { 'database': {
'user': 'pretalx', 'user': 'pretalx',

View file

@ -2,6 +2,85 @@ import re
from json import load from json import load
from os.path import join 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 = { defaults = {
'icinga2_api': { 'icinga2_api': {
'routeros': { 'routeros': {
@ -17,100 +96,14 @@ defaults = {
}, },
}, },
}, },
'routeros': {
'ips': ips,
'ports': ports,
'vlans': vlans,
},
} }
@metadata_reactor.provides(
'routeros/ips',
'routeros/ports',
'routeros/vlans',
)
def get_ports_from_netbox_dump(metadata):
with open(join(repo.path, 'configs', f'netbox_device_{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'] == '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 (
'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'] == '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')
return {
'routeros': {
'ips': ips,
'ports': ports,
'vlans': vlans,
}
}
@metadata_reactor.provides('routeros/gateway') @metadata_reactor.provides('routeros/gateway')
def gateway(metadata): def gateway(metadata):
ip_pattern = re.compile(r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.)\d{1,3}') ip_pattern = re.compile(r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.)\d{1,3}')

View file

@ -19,7 +19,9 @@ crit_days=30
case "$issuer_hash" in case "$issuer_hash" in
# 4f06f81d: issuer=C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3 # 4f06f81d: issuer=C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
# 8d33f237: issuer=C = US, O = Let's Encrypt, CN = R3 # 8d33f237: issuer=C = US, O = Let's Encrypt, CN = R3
4f06f81d|8d33f237) # 462422cf: issuer=C = US, O = Let's Encrypt, CN = E5
# 9aad238c: issuer=C = US, O = Let's Encrypt, CN = E6
4f06f81d|8d33f237|462422cf|9aad238c)
warn_days=10 warn_days=10
crit_days=3 crit_days=3
;; ;;

View file

@ -11,8 +11,9 @@ fi
if systemctl is-active wide-dhcpv6-client; if systemctl is-active wide-dhcpv6-client;
then then
systemctl stop wide-dhcpv6-client systemctl stop wide-dhcpv6-client
sleep 1 sleep 60
systemctl start wide-dhcpv6-client systemctl start wide-dhcpv6-client
else else
sleep 60
systemctl start wide-dhcpv6-client systemctl start wide-dhcpv6-client
fi fi

View file

@ -4,225 +4,225 @@
"description": "home.router (enp1s0)", "description": "home.router (enp1s0)",
"enabled": true, "enabled": true,
"ips": [], "ips": [],
"mode": "TAGGED_ALL", "mode": "tagged-all",
"tagged_vlans": [], "tagged_vlans": [],
"type": "A_1000BASE_T", "type": "1000base-t",
"untagged_vlan": null "untagged_vlan": null
}, },
"ether10": { "ether10": {
"description": "home.mitel-rfp35 (LAN)", "description": "home.mitel-rfp35 (LAN)",
"enabled": true, "enabled": true,
"ips": [], "ips": [],
"mode": "ACCESS", "mode": "access",
"tagged_vlans": [], "tagged_vlans": [],
"type": "A_1000BASE_T", "type": "1000base-t",
"untagged_vlan": "home.clients" "untagged_vlan": "home.clients"
}, },
"ether11": { "ether11": {
"description": "home.usv01 (LAN)", "description": "home.usv01 (LAN)",
"enabled": true, "enabled": true,
"ips": [], "ips": [],
"mode": "ACCESS", "mode": "access",
"tagged_vlans": [], "tagged_vlans": [],
"type": "A_1000BASE_T", "type": "1000base-t",
"untagged_vlan": "home.clients" "untagged_vlan": "home.clients"
}, },
"ether12": { "ether12": {
"description": "home.rechenmonster (IPMI)", "description": "",
"enabled": true, "enabled": true,
"ips": [], "ips": [],
"mode": "ACCESS", "mode": "access",
"tagged_vlans": [], "tagged_vlans": [],
"type": "A_1000BASE_T", "type": "1000base-t",
"untagged_vlan": "home.clients" "untagged_vlan": "home.clients"
}, },
"ether13": { "ether13": {
"description": "", "description": "",
"enabled": true, "enabled": true,
"ips": [], "ips": [],
"mode": "ACCESS", "mode": "access",
"tagged_vlans": [], "tagged_vlans": [],
"type": "A_1000BASE_T", "type": "1000base-t",
"untagged_vlan": "home.clients" "untagged_vlan": "home.clients"
}, },
"ether14": { "ether14": {
"description": "home.rechenmonster (LAN)", "description": "",
"enabled": true, "enabled": true,
"ips": [], "ips": [],
"mode": "ACCESS", "mode": "access",
"tagged_vlans": [], "tagged_vlans": [],
"type": "A_1000BASE_T", "type": "1000base-t",
"untagged_vlan": "home.clients" "untagged_vlan": "home.clients"
}, },
"ether15": { "ether15": {
"description": "", "description": "",
"enabled": true, "enabled": true,
"ips": [], "ips": [],
"mode": "ACCESS", "mode": "access",
"tagged_vlans": [], "tagged_vlans": [],
"type": "A_1000BASE_T", "type": "1000base-t",
"untagged_vlan": "home.clients" "untagged_vlan": "home.clients"
}, },
"ether16": { "ether16": {
"description": "", "description": "",
"enabled": true, "enabled": true,
"ips": [], "ips": [],
"mode": "ACCESS", "mode": "access",
"tagged_vlans": [], "tagged_vlans": [],
"type": "A_1000BASE_T", "type": "1000base-t",
"untagged_vlan": "home.clients" "untagged_vlan": "home.clients"
}, },
"ether17": { "ether17": {
"description": "", "description": "",
"enabled": true, "enabled": true,
"ips": [], "ips": [],
"mode": "ACCESS", "mode": "access",
"tagged_vlans": [], "tagged_vlans": [],
"type": "A_1000BASE_T", "type": "1000base-t",
"untagged_vlan": "home.clients" "untagged_vlan": "home.clients"
}, },
"ether18": { "ether18": {
"description": "", "description": "",
"enabled": true, "enabled": true,
"ips": [], "ips": [],
"mode": "ACCESS", "mode": "access",
"tagged_vlans": [], "tagged_vlans": [],
"type": "A_1000BASE_T", "type": "1000base-t",
"untagged_vlan": "home.clients" "untagged_vlan": "home.clients"
}, },
"ether19": { "ether19": {
"description": "home.lgtv-wohnzimmer", "description": "home.lgtv-wohnzimmer",
"enabled": true, "enabled": true,
"ips": [], "ips": [],
"mode": "ACCESS", "mode": "access",
"tagged_vlans": [], "tagged_vlans": [],
"type": "A_1000BASE_T", "type": "1000base-t",
"untagged_vlan": "home.clients" "untagged_vlan": "home.clients"
}, },
"ether2": { "ether2": {
"description": "Fritz!Box (LAN1)", "description": "Fritz!Box (LAN1)",
"enabled": true, "enabled": true,
"ips": [], "ips": [],
"mode": "ACCESS", "mode": "access",
"tagged_vlans": [], "tagged_vlans": [],
"type": "A_1000BASE_T", "type": "1000base-t",
"untagged_vlan": "home.wan" "untagged_vlan": "home.wan"
}, },
"ether20": { "ether20": {
"description": "Franzi Laptop", "description": "Franzi Laptop",
"enabled": true, "enabled": true,
"ips": [], "ips": [],
"mode": "ACCESS", "mode": "access",
"tagged_vlans": [], "tagged_vlans": [],
"type": "A_1000BASE_T", "type": "1000base-t",
"untagged_vlan": "home.clients" "untagged_vlan": "home.clients"
}, },
"ether21": { "ether21": {
"description": "Sophie Laptop", "description": "",
"enabled": true, "enabled": true,
"ips": [], "ips": [],
"mode": "ACCESS", "mode": "access",
"tagged_vlans": [], "tagged_vlans": [],
"type": "A_1000BASE_T", "type": "1000base-t",
"untagged_vlan": "home.clients" "untagged_vlan": "home.clients"
}, },
"ether22": { "ether22": {
"description": "Sophie Desktop", "description": "Arbeitsplatz Regal",
"enabled": true, "enabled": true,
"ips": [], "ips": [],
"mode": "ACCESS", "mode": "access",
"tagged_vlans": [], "tagged_vlans": [],
"type": "A_1000BASE_T", "type": "1000base-t",
"untagged_vlan": "home.clients" "untagged_vlan": "home.clients"
}, },
"ether23": { "ether23": {
"description": "Wohnzimmer Kabel", "description": "Wohnzimmer Kabel",
"enabled": true, "enabled": true,
"ips": [], "ips": [],
"mode": "ACCESS", "mode": "access",
"tagged_vlans": [], "tagged_vlans": [],
"type": "A_1000BASE_T", "type": "1000base-t",
"untagged_vlan": "home.clients" "untagged_vlan": "home.clients"
}, },
"ether24": { "ether24": {
"description": "home.snom-wohnzimmer", "description": "home.snom-wohnzimmer",
"enabled": true, "enabled": true,
"ips": [], "ips": [],
"mode": "ACCESS", "mode": "access",
"tagged_vlans": [], "tagged_vlans": [],
"type": "A_1000BASE_T", "type": "1000base-t",
"untagged_vlan": "home.clients" "untagged_vlan": "home.clients"
}, },
"ether3": { "ether3": {
"description": "home.aruba325-schlafzimmer", "description": "home.aruba325-schlafzimmer",
"enabled": true, "enabled": true,
"ips": [], "ips": [],
"mode": "TAGGED", "mode": "tagged",
"tagged_vlans": [ "tagged_vlans": [
"ffwi.client", "ffwi.client",
"home.v6only" "home.v6only"
], ],
"type": "A_1000BASE_T", "type": "1000base-t",
"untagged_vlan": "home.clients" "untagged_vlan": "home.clients"
}, },
"ether4": { "ether4": {
"description": "home.aruba325-wohnzimmer", "description": "home.aruba325-wohnzimmer",
"enabled": true, "enabled": true,
"ips": [], "ips": [],
"mode": "TAGGED", "mode": "tagged",
"tagged_vlans": [ "tagged_vlans": [
"ffwi.client", "ffwi.client",
"home.v6only" "home.v6only"
], ],
"type": "A_1000BASE_T", "type": "1000base-t",
"untagged_vlan": "home.clients" "untagged_vlan": "home.clients"
}, },
"ether5": { "ether5": {
"description": "home.nas (eno1)", "description": "home.nas (eno1)",
"enabled": true, "enabled": true,
"ips": [], "ips": [],
"mode": "TAGGED_ALL", "mode": "tagged-all",
"tagged_vlans": [], "tagged_vlans": [],
"type": "A_1000BASE_T", "type": "1000base-t",
"untagged_vlan": null "untagged_vlan": null
}, },
"ether6": { "ether6": {
"description": "home.aruba325-office", "description": "home.aruba325-office",
"enabled": true, "enabled": true,
"ips": [], "ips": [],
"mode": "TAGGED", "mode": "tagged",
"tagged_vlans": [ "tagged_vlans": [
"ffwi.client", "ffwi.client",
"home.v6only" "home.v6only"
], ],
"type": "A_1000BASE_T", "type": "1000base-t",
"untagged_vlan": "home.clients" "untagged_vlan": "home.clients"
}, },
"ether7": { "ether7": {
"description": "RIPE-Probe #28280 (LAN)", "description": "RIPE-Probe #28280 (LAN)",
"enabled": true, "enabled": true,
"ips": [], "ips": [],
"mode": "ACCESS", "mode": "access",
"tagged_vlans": [], "tagged_vlans": [],
"type": "A_1000BASE_T", "type": "1000base-t",
"untagged_vlan": "home.dmz" "untagged_vlan": "home.dmz"
}, },
"ether8": { "ether8": {
"description": "home.drucker-sophie", "description": "home.drucker-franzi",
"enabled": true, "enabled": true,
"ips": [], "ips": [],
"mode": "ACCESS", "mode": "access",
"tagged_vlans": [], "tagged_vlans": [],
"type": "A_1000BASE_T", "type": "1000base-t",
"untagged_vlan": "home.clients" "untagged_vlan": "home.clients"
}, },
"ether9": { "ether9": {
"description": "info-beamer 12199 (LAN)", "description": "info-beamer 12199 (LAN)",
"enabled": true, "enabled": true,
"ips": [], "ips": [],
"mode": "ACCESS", "mode": "access",
"tagged_vlans": [], "tagged_vlans": [],
"type": "A_1000BASE_T", "type": "1000base-t",
"untagged_vlan": "home.clients" "untagged_vlan": "home.clients"
}, },
"home.clients": { "home.clients": {
@ -231,27 +231,27 @@
"ips": [ "ips": [
"172.19.138.4/24" "172.19.138.4/24"
], ],
"mode": null, "mode": "",
"tagged_vlans": [], "tagged_vlans": [],
"type": "VIRTUAL", "type": "virtual",
"untagged_vlan": null "untagged_vlan": null
}, },
"sfp-sfpplus1": { "sfp-sfpplus1": {
"description": "", "description": "",
"enabled": true, "enabled": true,
"ips": [], "ips": [],
"mode": null, "mode": "",
"tagged_vlans": [], "tagged_vlans": [],
"type": "A_10GBASE_X_SFPP", "type": "10gbase-x-sfpp",
"untagged_vlan": null "untagged_vlan": null
}, },
"sfp-sfpplus2": { "sfp-sfpplus2": {
"description": "", "description": "",
"enabled": true, "enabled": true,
"ips": [], "ips": [],
"mode": null, "mode": "",
"tagged_vlans": [], "tagged_vlans": [],
"type": "A_10GBASE_X_SFPP", "type": "10gbase-x-sfpp",
"untagged_vlan": null "untagged_vlan": null
} }
}, },

View file

@ -1,5 +1,66 @@
-----BEGIN PGP PUBLIC KEY BLOCK----- -----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2.0.22 (GNU/Linux)
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
vcV0wl+DODz9hw==
=oWlI
-----END PGP PUBLIC KEY BLOCK-----
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQENBE5OMmIBCAD+FPYKGriGGf7NqwKfWC83cBV01gabgVWQmZbMcFzeW+hMsgxH mQENBE5OMmIBCAD+FPYKGriGGf7NqwKfWC83cBV01gabgVWQmZbMcFzeW+hMsgxH
W6iimD0RsfZ9oEbfJCPG0CRSZ7ppq5pKamYs2+EJ8Q2ysOFHHwpGrA2C8zyNAs4I W6iimD0RsfZ9oEbfJCPG0CRSZ7ppq5pKamYs2+EJ8Q2ysOFHHwpGrA2C8zyNAs4I
@ -7,22 +68,125 @@ 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
Va3l3WuB+rgKjsQ= U4wUpuJbAAxImJ9uNKKaH+cmvoshkWTSUBXTvNjAQW3SM9oW+V3G7wicUtH+7cnd
=EWWI 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
ozw9yNdOZmnk2Prj7+mBuchbT3BJOQ==
=AgHy
-----END PGP PUBLIC KEY BLOCK-----
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
UYda9m8fOnaIew==
=TEOn
-----END PGP PUBLIC KEY BLOCK----- -----END PGP PUBLIC KEY BLOCK-----

View file

@ -1,52 +1,29 @@
-----BEGIN PGP PUBLIC KEY BLOCK----- -----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1
Comment: GPGTools - https://gpgtools.org
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 =MARt
41nuxZDSuBJhDeFIp0ccnN2Lp1o6XfIeDYPegyEPSSZqrudfqLrSZhStDlJgXjea
JjW6UP6txPtYaaila9/Hn6vF87AQ5bR2dEWB/xRJzgNwRiax7KSU0xca6xAuf+TD
xCjZ5pp2JwdCjquXLTmUnbIZ9LGV54UZ/MeiG8yVu6pxbiGnXo4Ekbk6xgi1ewLi
vGmz4QRfVklV0dba3Zj0fRozfZ22qUHxCfDM7ad0eBXMFmHiN8hg3IUHTO+UdlX/
aH3gADFAvSVDv0v8t6dGc6XE9Dr7mGEFnQMHO4zhM1HaS2Nh0TiL2tFLttLbfG5o
QlxCfXX9/nasj3K9qnlEg9G3+4T7lpdPmZRRe1O8cHCI5imVg6cLIiBLPO16e0fK
yHIgYswLdrJFfaHNYM/SWJxHpX795zn+iCwyvZSlLfH9mlegOeVmj9cyhN/VOmS3
QRhlYXoA2z7WZTNoC6iAIlyIpMTcZr+ntaGVtFOLS6fwdBqDXjmSQu66mDKwU5Ek
fNlbyrpzZMyFCDWEYo4AIR/18aGZBYUAEQEAAYkCHwQYAQIACQUCU5sktgIbDAAK
CRAWVaCraFdigIPQEACcYh8rR19wMZZ/hgYv5so6Y1HcJNARuzmffQKozS/rxqec
0xM3wceL1AIMuGhlXFeGd0wRv/RVzeZjnTGwhN1DnCDy1I66hUTgehONsfVanuP1
PZKoL38EAxsMzdYgkYH6T9a4wJH/IPt+uuFTFFy3o8TKMvKaJk98+Jsp2X/QuNxh
qpcIGaVbtQ1bn7m+k5Qe/fz+bFuUeXPivafLLlGc6KbdgMvSW9EVMO7yBy/2JE15
ZJgl7lXKLQ31VQPAHT3an5IV2C/ie12eEqZWlnCiHV/wT+zhOkSpWdrheWfBT+ac
hR4jDH80AS3F8jo3byQATJb3RoCYUCVc3u1ouhNZa5yLgYZ/iZkpk5gKjxHPudFb
DdWjbGflN9k17VCf4Z9yAb9QMqHzHwIGXrb7ryFcuROMCLLVUp07PrTrRxnO9A/4
xxECi0l/BzNxeU1gK88hEaNjIfviPR/h6Gq6KOcNKZ8rVFdwFpjbvwHMQBWhrqfu
G3KaePvbnObKHXpfIKoAM7X2qfO+IFnLGTPyhFTcrl6vZBTMZTfZiC1XDQLuGUnd
sckuXINIU3DFWzZGr0QrqkuE/jyr7FXeUJj9B7cLo+s/TXo+RaVfi3kOc9BoxIvy
/qiNGs/TKy2/Ujqp/affmIMoMXSozKmga81JSwkADO1JMgUy6dApXz9kP4EE3g==
=CLGF
-----END PGP PUBLIC KEY BLOCK----- -----END PGP PUBLIC KEY BLOCK-----

View file

@ -8,3 +8,13 @@ location /.well-known/matrix/server {
default_type application/json; default_type application/json;
add_header Access-Control-Allow-Origin *; 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 '<!doctype html><html><body><a rel="me" href="https://chaos.social/@sophie">Mastodon</a></body></html>';
default_type text/html;
add_header Access-Control-Allow-Origin *;
}

View file

@ -1,26 +1,22 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIETzCCAzegAwIBAgISBGnv4i5cZkqMTZ6E2W9oY145MA0GCSqGSIb3DQEBCwUA MIIDsDCCAzWgAwIBAgISBMRgrLMPa1cucom1daU3fmCaMAoGCCqGSM49BAMDMDIx
MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQDEwJF
EwJSMzAeFw0yNDAzMTYwOTAxNDdaFw0yNDA2MTQwOTAxNDZaMBoxGDAWBgNVBAMT NTAeFw0yNDA2MTExNDQyMzdaFw0yNDA5MDkxNDQyMzZaMBoxGDAWBgNVBAMTD2hv
D2hvbWUua3VuYm94Lm5ldDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNjknNF3eIBR bWUua3VuYm94Lm5ldDB2MBAGByqGSM49AgEGBSuBBAAiA2IABGlCPITmq729xoLb
7bzqJEfvTTmGnw9nCDa/VY2l+POYFhrBryT9pCgO7lcSK3raynAu3yNjVSSK4KdB DkSn6SYxnP7Mns9dBSqUv1WktnYjwbavlbXKN3Bz0yCGcXSCZA+Nq576DBK9L9X6
p2fEu8SytoRPp6Hjz5epjIQvdaYaWsg7gjPe1GoFU8YG6KrX7y6DNaOCAiMwggIf tTeIvqG1akyNxY+1eDK3vhH4FKmZE6oOyh1jqfG2LY7dvLYCQKOCAiQwggIgMA4G
MA4GA1UdDwEB/wQEAwIHgDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw A1UdDwEB/wQEAwIHgDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYD
DAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUkioReLB1H6GooNGezjbwLZ0dTBwwHwYD VR0TAQH/BAIwADAdBgNVHQ4EFgQUt6i+27R0AAj+AUgSNg3Gmm5GzLYwHwYDVR0j
VR0jBBgwFoAUFC6zF7dYVsuuUAlA5h+vnYsUwsYwVQYIKwYBBQUHAQEESTBHMCEG BBgwFoAUnytfzzwhT50Et+0rLMTGcIvS1w0wVQYIKwYBBQUHAQEESTBHMCEGCCsG
CCsGAQUFBzABhhVodHRwOi8vcjMuby5sZW5jci5vcmcwIgYIKwYBBQUHMAKGFmh0 AQUFBzABhhVodHRwOi8vZTUuby5sZW5jci5vcmcwIgYIKwYBBQUHMAKGFmh0dHA6
dHA6Ly9yMy5pLmxlbmNyLm9yZy8wLQYDVR0RBCYwJIIRKi5ob21lLmt1bmJveC5u Ly9lNS5pLmxlbmNyLm9yZy8wLQYDVR0RBCYwJIIRKi5ob21lLmt1bmJveC5uZXSC
ZXSCD2hvbWUua3VuYm94Lm5ldDATBgNVHSAEDDAKMAgGBmeBDAECATCCAQMGCisG D2hvbWUua3VuYm94Lm5ldDATBgNVHSAEDDAKMAgGBmeBDAECATCCAQQGCisGAQQB
AQQB1nkCBAIEgfQEgfEA7wB1AO7N0GTV2xrOxVy3nbTNE6Iyh0Z8vOzew1FIWUZx 1nkCBAIEgfUEgfIA8AB2AO7N0GTV2xrOxVy3nbTNE6Iyh0Z8vOzew1FIWUZxH7Wb
H7WbAAABjka13wQAAAQDAEYwRAIgK0+HX4aRu8J69wpybX8ExvOSDT4GTFhQGz1t AAABkAf3K9YAAAQDAEcwRQIhAPFpuj8ZoOmqhDNJDSuJ3BWyUuOUyY2QXjIVRHop
RBm8WJMCICs/8Nj65/IEUp7AaBPruyrUFvbfhZ2pNxwQIy03fn3GAHYAO1N3dT4t dKyPAiAa2cwsyBFOjWOEYRCZ/7UgBA5axt8ZCrRYseefFwpvSQB2AN/hVuuqBa+1
uYBOizBbBv5AO2fYT8P0x70ADS1yb+H61BcAAAGORrXg5wAABAMARzBFAiEAvSxW nA+GcY2owDJOrlbZbqf1pWoB0cE7vlJcAAABkAf3LJ8AAAQDAEcwRQIhAL9+dxTj
MJIsOZei1W3J1C1hkMQwodZC/9ucFicCWXkX7UUCIFzShY5chEVFurxRDKSYLgV1 34moGhk32PnQZg2+nVNiVxLxYjDL9fk1R+bXAiAA7EjWqcZgktinTpt1pVQMmuUn
R820vp8F9ilwp465IeE+MA0GCSqGSIb3DQEBCwUAA4IBAQCMEbmFNXyfSwczdrf9 FQ1IRh5AdycNn0lL2jAKBggqhkjOPQQDAwNpADBmAjEAubnofDBEyrcSJAiGxlqc
0SOFEVEP8guf6JHmlSL2hNI2cWp+08fyxIEHhvNtyyyLZ57lBvtE6Q8h8WNkKayz EpUndlnkT/irfl/As8EUt0KMSPhnV3i7oEq89bi0KDghAjEA+XHccaWUi7BJEoV7
wBUdrHbl9HMnznURX95uofgI/6GZKv1RHyxQd6KxJZCatIhxnsVfFfoDwJmzzg80 nCUOCct64mb2LmXkvYiFVicsV9ubp4kVbziWjLgng6TC3HoM
/aoHksxbQzzJWLcm8fJTqsE95Alc1W4u+bDkHjj+OrvNYaHsQLjxedt++jN3o4at
bkOY3zEQyg5mspykq7DjxNpPIC9mSeH6dKZAzsOc6KRWVj91Ol68GYM35TWXUp+3
kYkU828fznJQc77u9BysTGlyc4iYLzzb0Xus6McqOVPDVnNbeLxdHCQfF8A9Hh6F
o4UX
-----END CERTIFICATE----- -----END CERTIFICATE-----

View file

@ -1,31 +1,27 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw MIIEVzCCAj+gAwIBAgIRAIOPbGPOsTmMYgZigxXJ/d4wDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjQwMzEzMDAwMDAw
WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg WhcNMjcwMzEyMjM1OTU5WjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg
RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK RW5jcnlwdDELMAkGA1UEAxMCRTUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNCzqK
AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP a2GOtu/cX1jnxkJFVKtj9mZhSAouWXW0gQI3ULc/FnncmOyhKJdyIBwsz9V8UiBO
R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx VHhbhBRrwJCuhezAUUE8Wod/Bk3U/mDR+mwt4X2VEIiiCFQPmRpM5uoKrNijgfgw
sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm gfUwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD
NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg ATASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSfK1/PPCFPnQS37SssxMZw
Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG i9LXDTAfBgNVHSMEGDAWgBR5tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcB
/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC AQQmMCQwIgYIKwYBBQUHMAKGFmh0dHA6Ly94MS5pLmxlbmNyLm9yZy8wEwYDVR0g
AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB BAwwCjAIBgZngQwBAgEwJwYDVR0fBCAwHjAcoBqgGIYWaHR0cDovL3gxLmMubGVu
Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA Y3Iub3JnLzANBgkqhkiG9w0BAQsFAAOCAgEAH3KdNEVCQdqk0LKyuNImTKdRJY1C
FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw 2uw2SJajuhqkyGPY8C+zzsufZ+mgnhnq1A2KVQOSykOEnUbx1cy637rBAihx97r+
AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw bcwbZM6sTDIaEriR/PLk6LKs9Be0uoVxgOKDcpG9svD33J+G9Lcfv1K9luDmSTgG
Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB 6XNFIN5vfI5gs/lMPyojEMdIzK9blcl2/1vKxO8WGCcjvsQ1nJ/Pwt8LQZBfOFyV
gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W XP8ubAp/au3dc4EKWG9MO5zcx1qT9+NXRGdVWxGvmBFRAajciMfXME1ZuGmk3/GO
PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl koAM7ZkjZmleyokP1LGzmfJcUd9s7eeu1/9/eg5XlXd/55GtYjAM+C4DG5i7eaNq
ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz cm2F+yxYIPt6cbbtYVNJCGfHWqHEQ4FYStUyFnv8sjyqU8ypgZaNJ9aVcWSICLOI
CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm E1/Qv/7oKsnZCWJ926wU6RqG1OYPGOi1zuABhLw61cuPVDT28nQS/e6z95cJXq0e
lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4 K1BcaJ6fJZsmbjRgD5p3mvEf5vdQM7MCEvU0tHbsx2I5mHHJoABHb8KVBgWp/lcX
avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2 GWiWaeOyB7RP+OfDtvi2OsapxXiV7vNVs7fMlrRjY1joKaqmmycnBvAq14AEbtyL
yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O sVfOS66B8apkeFX2NY4XPEYV4ZSCe8VHPrdrERk2wILG3T/EGmSIkCYVUMSnjmJd
yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids VQD9F6Na/+zmXCc=
hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+
HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv
MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX
nLRbwHOoq7hHwg==
-----END CERTIFICATE----- -----END CERTIFICATE-----

View file

@ -1 +1 @@
encrypt$gAAAAABl9W4O5LekyB_15MB30WObrH9t9ew-irVSO5PnG5C6neXdHFTtiun46guBfuqqJo99a-jXkdXrCMmmi_qmPylw625w27fh_jpV6imyJejUTNV5LZKJJ8-jgX43dsWZHdX29TgjLDl8ebVPOoeWv6GPZ2u0-88Aylr5d_T6A0c5NB0WG7481PiR8Obu-T8uMXJRTgQwMdwWJ8mIzceJ_lD1YeF3PBNSXJatcwRqmLRB_7YfQfFCOZEUutZHRUuIsvmyPwuql0bAoV9dfgQjdsGtuPmE2i58CCKtTuweb6sq-FsF6v6pvj7Joq9hStx9lYN3l36-Zl7OvwxWkMSjcrvQvbaAO7h7Aws8fkgFOEO5cBeN9x30nhSOdmYjqvSyRAFFdJu0PEFPdu6Ft9v_g_NnARRnvDokWEEKee_NRsEuKsct2kbu05pPOHerEpNjtPEwqKnTe387Z2K2wlnYfev6LSHSDw== encrypt$gAAAAABmaHBwHXKZDN_8bEa47lNIX25-wvvW1RcC689Hod4HAsY2tT6fd9k7zdnbK8KWedRNopdRIlhQUkU0xBVh5J5maiYfn5R8Kp_VpkXiWY0LVY3XMWjB4oHmU29VEbl490oesAhUUH6hb7lwfvsbV4WTM_7aL0_sPfF1udxO89gg-9z2nbl-7zmTdSBY651fZQngd4SlwK17N1fedkHgYamGLdgE10oPZiRsOJKrUGv-Pxi4ICQ7J_AF6bO05PyZkeNqqUP19g2f5EsKNnT0bxQHCP5sbofvYzli-fU2bW-leuvm-VU8lV27t39lQZyF-WcWnB7626w0semrg7cCJ4qoHJVekEFWzJBLhagSNdCDWHAwdV2_MHzSgbXvyXz0maga8-1wBoa8Ueinp2oPQMPaUsVzy6NVX7mAsB6Rw9CXDSEf8WPSKWaz7324qhxKmhMHt0r68z0qM28mHb98F_vbS6geCw==

View file

@ -0,0 +1,23 @@
-----BEGIN CERTIFICATE-----
MIIDxzCCA02gAwIBAgISBDW3AazQEdYbYaSrLIoUKbvsMAoGCCqGSM49BAMDMDIx
CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQDEwJF
NjAeFw0yNDA2MjExNjUzNDBaFw0yNDA5MTkxNjUzMzlaMCIxIDAeBgNVBAMTF2hv
bWUuc29waGllcy1raXRjaGVuLmV1MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEQDuO
QacqKUrKWbwBWgSqPkaBIb4t6f4kiRMvCyY8KiZmIvJadVD6iKnbcGzFQ0LRI+vt
+O6ZVpwsUOXvgF3PB7o7OfODlVsKRc4pYJPvoRRaz1VlK6eZW20GGivBVgl0o4IC
NDCCAjAwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEF
BQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBRScRdoEyCVXr1PC0yvKusaOO5i
dTAfBgNVHSMEGDAWgBSTJ0aYA6lRaI6Y1sRCSNsjv1iU0jBVBggrBgEFBQcBAQRJ
MEcwIQYIKwYBBQUHMAGGFWh0dHA6Ly9lNi5vLmxlbmNyLm9yZzAiBggrBgEFBQcw
AoYWaHR0cDovL2U2LmkubGVuY3Iub3JnLzA9BgNVHREENjA0ghkqLmhvbWUuc29w
aGllcy1raXRjaGVuLmV1ghdob21lLnNvcGhpZXMta2l0Y2hlbi5ldTATBgNVHSAE
DDAKMAgGBmeBDAECATCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB1AEiw42vapkc0
D+VqAvqdMOscUgHLVt0sgdm7v6s52IRzAAABkDvuwaIAAAQDAEYwRAIgP3lyMqvr
+a7XWoRLxzQzhv6umJ/hiQPTWen3qqTao34CIGLq9y9ZPZUuo2smf49h9v9I9B4t
o6ihFaHoOB68q37DAHcA3+FW66oFr7WcD4ZxjajAMk6uVtlup/WlagHRwTu+UlwA
AAGQO+7CZAAABAMASDBGAiEAjl1f87koOUNfTNL4IRO+BBEVeHCxPvYRaztVJoC0
x6ECIQDblc+Snmea3OSqydLcyi8xgdtMySyQgPElXLtM7H+RUjAKBggqhkjOPQQD
AwNoADBlAjA0FOSmTiYrA9Hd2T5DkI2TMOH2akk8SxXprkei6H37bI8O3br7ke8t
jwHWVtvN4d8CMQDohhdWUQ3G8Fl4ektN34oX6U3NcywBm96U3RVt5JYcfnn8ea68
Qboj263s/g0Ciqs=
-----END CERTIFICATE-----

View file

@ -0,0 +1,27 @@
-----BEGIN CERTIFICATE-----
MIIEVzCCAj+gAwIBAgIRALBXPpFzlydw27SHyzpFKzgwDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjQwMzEzMDAwMDAw
WhcNMjcwMzEyMjM1OTU5WjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg
RW5jcnlwdDELMAkGA1UEAxMCRTYwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATZ8Z5G
h/ghcWCoJuuj+rnq2h25EqfUJtlRFLFhfHWWvyILOR/VvtEKRqotPEoJhC6+QJVV
6RlAN2Z17TJOdwRJ+HB7wxjnzvdxEP6sdNgA1O1tHHMWMxCcOrLqbGL0vbijgfgw
gfUwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD
ATASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSTJ0aYA6lRaI6Y1sRCSNsj
v1iU0jAfBgNVHSMEGDAWgBR5tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcB
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=
-----END CERTIFICATE-----

View file

@ -0,0 +1 @@
encrypt$gAAAAABmdb4pdFakOuqHPRpEu_RjEPVVS9Ef0kuvWKKT3Gr3056e0nhinh_THX1w7CqiZ4CQlvSIH7vlDNUORFWlqDuZJOh8FYPSzjr78aK1MqVGZHxQBK8VVNd0K5m1U3z9_4W_pB7Zr_5fLXDqtIW-t68GQPEfxCwy2h2eBepQ2zJiLupWa7JwuqiXH6QyB4gD5Y-9F30RjH52WtJLrx6XtgClPG0p-6FrHcNHqmMYqgpt11zvLa88lOBUoDGFrrqqFRbY039ay2b1jrQOAhTQLDxnAMsbr5jTSbST1modE-1u_Wis-Km-jcMwkiViZpK-HC6Ce_TNdt1NDarBat6nRhTrpqHXENlroVixHmGl1_-Y6mc75tJ-KHQKRRzwK8V_X62iA3vfSz1Xps8B1FZqxJWA2EdM0JkQecCuC-bnpedEoumYnif3vLhe91NV8SQ5FBlkd3NFT8vBAWCgnqT_jDf5YQW70w==

View file

@ -60,6 +60,20 @@ groups['home'] = {
}, },
} }
groups['sophie'] = {
'member_patterns': {
r"sophie\..*",
},
'metadata': {
'icinga_options': {
'exclude_from_monitoring': True,
},
'users': {
'sophie': {},
},
},
}
groups['voc'] = { groups['voc'] = {
'member_patterns': { 'member_patterns': {
r"voc\..*", r"voc\..*",

View file

@ -40,7 +40,7 @@ imap_pass = "!bwpass_attr:t-online.de/franzi.kunsmann@t-online.de:imap"
[metadata.element-web] [metadata.element-web]
url = "chat.franzi.business" url = "chat.franzi.business"
version = "v1.11.66" version = "v1.11.71"
[metadata.element-web.config] [metadata.element-web.config]
default_server_config.'m.homeserver'.base_url = "https://matrix.franzi.business" default_server_config.'m.homeserver'.base_url = "https://matrix.franzi.business"
default_server_config.'m.homeserver'.server_name = "franzi.business" default_server_config.'m.homeserver'.server_name = "franzi.business"
@ -49,8 +49,8 @@ defaultCountryCode = "DE"
jitsi.preferredDomain = "meet.ffmuc.net" jitsi.preferredDomain = "meet.ffmuc.net"
[metadata.forgejo] [metadata.forgejo]
version = "7.0.2" version = "7.0.5"
sha1 = "8d8f463b875a114012d688b413b11501aaba2eee" sha1 = "8dc0526cdd886d5bc96ce96841202c2800029e68"
domain = "git.franzi.business" domain = "git.franzi.business"
enable_git_hooks = true enable_git_hooks = true
install_ssh_key = true install_ssh_key = true
@ -70,12 +70,13 @@ gateway6 = "2a0a:51c0:0:225::1"
[metadata.matrix-media-repo] [metadata.matrix-media-repo]
admins = ["@kunsi:franzi.business"] admins = ["@kunsi:franzi.business"]
datastore_id = "3fff5da324ed784c771d638bb6be5917" datastore_id = "3fff5da324ed784c771d638bb6be5917"
sha1 = "55d353b472894547c61b11567089eb2cf40ce5ba" sha1 = "ef9e8624e70714e4d421ece0c27f2974f55c0e59"
upload_max_mb = 500 upload_max_mb = 500
version = "v1.3.4" version = "v1.3.6"
[metadata.matrix-media-repo.homeservers.'franzi.business'] [metadata.matrix-media-repo.homeservers.'franzi.business']
api = "synapse" api = "synapse"
domain = "http://[::1]:20080/" domain = "http://[::1]:20080/"
signing_key_path = "/etc/matrix-synapse/mmr.signing.key"
[metadata.matrix-stickerpicker] [metadata.matrix-stickerpicker]
# use this bot token: encrypt$gAAAAABfVK51ErJ6gfsOOkbRxSHDnVYmf7EihAQf7Uwj9og3TlAw64WRsA6ZVEgTSvOdLB3SMKZ-cTEhwkCOpbymq-_WLhes-hZALhN-H_oXHaxTQErJ0lARynKmjM-4ZhoGlUWlfh4Q # use this bot token: encrypt$gAAAAABfVK51ErJ6gfsOOkbRxSHDnVYmf7EihAQf7Uwj9og3TlAw64WRsA6ZVEgTSvOdLB3SMKZ-cTEhwkCOpbymq-_WLhes-hZALhN-H_oXHaxTQErJ0lARynKmjM-4ZhoGlUWlfh4Q
@ -98,7 +99,7 @@ sha1 = "cecb371ff5f1dd528cfc490484a0967dcc28cd82"
secret = "!decrypt:encrypt$gAAAAABl9yJlbEZafJ2mumtg03rW0-440NIgFcgdWGMo3Axrypugwctacy9Cq7MYtCBGjnDyNvVLI5B2QMJ9ssCD46NCsFRN3-X4u9rDtxPhRZV7rls_LQ_Csc_GsffJfvpmHbn_wsljd3I74h4ouWlYhhEQUIKwb3eErSZ_VTZhu_bC4jTa0FY=" secret = "!decrypt:encrypt$gAAAAABl9yJlbEZafJ2mumtg03rW0-440NIgFcgdWGMo3Axrypugwctacy9Cq7MYtCBGjnDyNvVLI5B2QMJ9ssCD46NCsFRN3-X4u9rDtxPhRZV7rls_LQ_Csc_GsffJfvpmHbn_wsljd3I74h4ouWlYhhEQUIKwb3eErSZ_VTZhu_bC4jTa0FY="
[metadata.mautrix-telegram] [metadata.mautrix-telegram]
version = "v0.15.1" version = "v0.15.2"
homeserver.domain = "franzi.business" homeserver.domain = "franzi.business"
homeserver.url = "https://matrix.franzi.business" homeserver.url = "https://matrix.franzi.business"
telegram.api_id = "!decrypt:encrypt$gAAAAABfVK5SmDDru-UQxitkE5VhPArnUBhaRbAqQPvAW2Fh3fd1XDrWxa3Qn4BSnJAPNWglH5wil_SXUMcIm95FMhPe8dVeMQ==" telegram.api_id = "!decrypt:encrypt$gAAAAABfVK5SmDDru-UQxitkE5VhPArnUBhaRbAqQPvAW2Fh3fd1XDrWxa3Qn4BSnJAPNWglH5wil_SXUMcIm95FMhPe8dVeMQ=="
@ -113,8 +114,8 @@ provisioning.shared_secret = "!decrypt:encrypt$gAAAAABfVKflEMAi07C_QGP8cy97hF-4g
"'@kunsi:franzi.business'" = "admin" "'@kunsi:franzi.business'" = "admin"
[metadata.mautrix-whatsapp] [metadata.mautrix-whatsapp]
version = "v0.10.7" version = "v0.10.9"
sha1 = "7ebfadc247c3fb4c6c9503f7c48234fcc976cadf" sha1 = "1619579ec6b9fca84fec085a94842d309d3f730c"
permissions."'@kunsi:franzi.business'" = "admin" permissions."'@kunsi:franzi.business'" = "admin"
[metadata.mautrix-whatsapp.homeserver] [metadata.mautrix-whatsapp.homeserver]
domain = "franzi.business" domain = "franzi.business"
@ -125,7 +126,7 @@ domain = "rss.franzi.business"
[metadata.netbox] [metadata.netbox]
domain = "netbox.franzi.business" domain = "netbox.franzi.business"
version = "v4.0.1" version = "v4.0.7"
admins.kunsi = "hostmaster@kunbox.net" admins.kunsi = "hostmaster@kunbox.net"
[metadata.nextcloud] [metadata.nextcloud]
@ -255,7 +256,7 @@ disks = [
] ]
[metadata.travelynx] [metadata.travelynx]
version = "2.6.9" version = "2.7.7"
mail_from = "travelynx@franzi.business" mail_from = "travelynx@franzi.business"
domain = "travelynx.franzi.business" domain = "travelynx.franzi.business"

View file

@ -1,34 +0,0 @@
hostname = "45.140.180.45"
dummy = true
[metadata.icinga_options]
period = "daytime"
show_on_statuspage = false
[metadata.icinga2_api.nginx.services."NGINX VHOST ticket-redirect 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 CERTIFICATE"]
check_command = "check_https_cert_at_url"
"vars.domain" = "jira.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://jira.gulas.ch/secure/Dashboard.jspa"
"vars.notification.sms" = true
[metadata.icinga2_api.custom.services]
# these checks do not get deployed onto the actual host by us, we only
# execute those checks
'DISK SPACE'.'vars.sshmon_command' = 'DISK_SPACE'
'JIRA HEAP'.'vars.sshmon_command' = 'JIRA_HEAP'
'JIRA THREADS'.'vars.sshmon_command' = 'JIRA_THREADS'
'LOAD'.'vars.sshmon_command' = 'LOAD'
'OOM KILLER'.'vars.sshmon_command' = 'OOM_KILLER'
'RAM'.'vars.sshmon_command' = 'RAM'
'USER PROCESS SECURITY jira'.'vars.sshmon_command' = 'USER_PROCESS_SECURITY_jira'
'ZPOOL SPACE tank'.'vars.sshmon_command' = 'check_zpool_space_tank'

View file

@ -121,12 +121,6 @@ nodes['fkusei-locutus'] = {
'fkunsmann': { 'fkunsmann': {
'password': vault.decrypt('encrypt$gAAAAABgLmmuQGRUStrQawoPee-758emIYn2u8-8ebrgzNAFSp7ifeFDdXXvs-zL3QogwNYlCtBHboH2xfy1rSj6OF5bbNO-tg=='), 'password': vault.decrypt('encrypt$gAAAAABgLmmuQGRUStrQawoPee-758emIYn2u8-8ebrgzNAFSp7ifeFDdXXvs-zL3QogwNYlCtBHboH2xfy1rSj6OF5bbNO-tg=='),
'shell': '/usr/bin/fish', 'shell': '/usr/bin/fish',
'sudo_commands': {
'ALL',
},
},
'sophie': {
'delete': True,
}, },
}, },
'voc-tracker-worker': { 'voc-tracker-worker': {

View file

@ -1,6 +0,0 @@
dummy = true
[metadata.interfaces.default]
ips = ["172.19.138.61"]
dhcp = true
mac = "00:14:38:9E:29:E3"

View file

@ -6,6 +6,9 @@ bundles = [
] ]
groups = ["debian-bookworm"] groups = ["debian-bookworm"]
[metadata.icinga_options]
also_affected_by = ['home.nas']
[metadata.interfaces.enp1s0] [metadata.interfaces.enp1s0]
ips = [ ips = [
"172.19.138.25/24", "172.19.138.25/24",

View file

@ -1,35 +0,0 @@
hostname = "172.19.138.24"
bundles = ["kodi", "lm-sensors", "nfs-client", "smartd"]
groups = ["debian-bullseye"]
# is powered off
dummy = true
[metadata.apt.packages.intel-media-va-driver-non-free]
[metadata.apt.unattended-upgrades]
day = 6
hour = 2
# needs powered on display to detect HDMI audio correctly
reboot_enabled = false
[metadata.icinga_options]
# is powered off
exclude_from_monitoring = true
[metadata.interfaces.eno1]
ips = ["172.19.138.24/24"]
gateway4 = "172.19.138.1"
ipv6_accept_ra = true
[metadata.nfs-client.mounts.nas-storage]
mountpoint = "/mnt/nas"
serverpath = "172.19.138.20:/storage/nas"
mount_options = ["retry=0", "ro"]
[metadata.smartd]
disks = ["/dev/nvme0"]
[metadata.vm]
cpu = 2
ram = 4

View file

@ -0,0 +1,6 @@
dummy = true
[metadata.interfaces.eth0]
ips = ["172.19.138.23"]
dhcp = true
mac = "50:9a:4c:ad:f9:c4"

19
nodes/home.r630.toml Normal file
View file

@ -0,0 +1,19 @@
hostname = "172.19.138.22"
groups = ["debian-bookworm"]
[metadata]
icinga_options.exclude_from_monitoring = true
[metadata.interfaces.eno3]
ips = [
"172.19.138.22/24",
]
gateway4 = "172.19.138.1"
ipv6_accept_ra = true
[metadata.users.molly]
password = "!decrypt:dummy$no"
[metadata.vm]
cpu = 56
ram = 128

View file

@ -1,5 +1,8 @@
dummy = true dummy = true
[metadata.icinga_options]
also_affected_by = ['home.nas']
[metadata.interfaces.default] [metadata.interfaces.default]
ips = ["172.19.138.10"] ips = ["172.19.138.10"]
dhcp = true dhcp = true

View file

@ -1,9 +0,0 @@
dummy = true
[metadata.interfaces.default]
ips = ["172.19.138.73"]
dhcp = true
mac = "7c:87:ce:b6:54:cd"
[metadata.icinga_options]
exclude_from_monitoring = true

View file

@ -1,9 +0,0 @@
dummy = true
[metadata.interfaces.default]
ips = ["172.19.138.70"]
dhcp = true
mac = "3c:61:05:d0:f2:b9"
[metadata.icinga_options]
exclude_from_monitoring = true

View file

@ -8,6 +8,11 @@ nodes['home.downloadhelper'] = {
'debian-bullseye', 'debian-bullseye',
}, },
'metadata': { 'metadata': {
'icinga_options': {
'also_affected_by': {
'home.nas',
},
},
'interfaces': { 'interfaces': {
'enp1s0.3001': { 'enp1s0.3001': {
'dhcp': True, 'dhcp': True,

View file

@ -67,26 +67,6 @@ nodes['home.nas'] = {
'/storage/nas/normen', '/storage/nas/normen',
}, },
}, },
'dm-crypt': {
'encrypted-devices': {
'/dev/disk/by-id/ata-ST18000NM0092-3CX103_ZVV06JV7-part1': {
'dm-name': 'sg-ZVV06JV7-1',
'passphrase': bwpass.password('bw/home.nas/dmcrypt/sg-ZVV06JV7-1'),
},
'/dev/disk/by-id/ata-ST18000NM0092-3CX103_ZVV06JV7-part2': {
'dm-name': 'sg-ZVV06JV7-2',
'passphrase': bwpass.password('bw/home.nas/dmcrypt/sg-ZVV06JV7-2'),
},
'/dev/disk/by-id/ata-ST18000NM0092-3CX103_ZVV06SLR-part1': {
'dm-name': 'sg-ZVV06SLR-1',
'passphrase': bwpass.password('bw/home.nas/dmcrypt/sg-ZVV06SLR-1'),
},
'/dev/disk/by-id/ata-ST18000NM0092-3CX103_ZVV06SLR-part2': {
'dm-name': 'sg-ZVV06SLR-2',
'passphrase': bwpass.password('bw/home.nas/dmcrypt/sg-ZVV06SLR-2'),
},
},
},
'groups': { 'groups': {
'nas': {}, 'nas': {},
}, },
@ -121,6 +101,14 @@ nodes['home.nas'] = {
'home.lgtv-wohnzimmer', 'home.lgtv-wohnzimmer',
}, },
}, },
'mixcloud-downloader': {
'netrc': {
'soundcloud': {
'username': 'oauth',
'password': bwpass.attr('soundcloud.com/hi@kunsmann.eu', 'oauth_token'),
},
},
},
'mosquitto': { 'mosquitto': {
'bridges': { 'bridges': {
'c3voc': { 'c3voc': {
@ -183,10 +171,6 @@ nodes['home.nas'] = {
'disks': { 'disks': {
'/dev/nvme0', '/dev/nvme0',
# encrypted disks
'/dev/disk/by-id/ata-ST18000NM0092-3CX103_ZVV06JV7',
'/dev/disk/by-id/ata-ST18000NM0092-3CX103_ZVV06SLR',
# ZFS cache disks # ZFS cache disks
#'/dev/disk/by-id/ata-TS64GSSD370_B807810503', #'/dev/disk/by-id/ata-TS64GSSD370_B807810503',
#'/dev/disk/by-id/ata-TS64GSSD370_B807810527', #'/dev/disk/by-id/ata-TS64GSSD370_B807810527',
@ -223,9 +207,6 @@ nodes['home.nas'] = {
'enable_x_forwarding_for_admins': True, 'enable_x_forwarding_for_admins': True,
}, },
'users': { 'users': {
'f2k1de': {
'delete': True,
},
'inbox': { 'inbox': {
'ssh_pubkey': { '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 ',
@ -236,14 +217,6 @@ nodes['home.nas'] = {
'nas', 'nas',
}, },
}, },
'sophie': {
'groups': {
'nas',
},
},
'qcn': {
'delete': True,
},
}, },
'zfs': { 'zfs': {
'module_options': { 'module_options': {
@ -282,58 +255,14 @@ nodes['home.nas'] = {
'ashift': 12, 'ashift': 12,
}, },
}, },
'encrypted': {
'when_creating': {
'config': [
# These are new and fancy "dual actuator"
# drives, partitioned into two partitions
# taking 50% of the disk each.
{
'type': 'mirror',
'devices': {
'/dev/mapper/sg-ZVV06JV7-1',
'/dev/mapper/sg-ZVV06SLR-1',
},
},
{
'type': 'mirror',
'devices': {
'/dev/mapper/sg-ZVV06JV7-2',
'/dev/mapper/sg-ZVV06SLR-2',
},
},
],
'ashift': 12
},
'needs': {
'action:dm-crypt_open_sg-ZVV06JV7-1',
'action:dm-crypt_open_sg-ZVV06JV7-2',
'action:dm-crypt_open_sg-ZVV06SLR-1',
'action:dm-crypt_open_sg-ZVV06SLR-2',
},
# see comment in bundle:backup-server
'unless': 'zpool import encrypted',
},
}, },
'datasets': { 'datasets': {
'encrypted': {
'primarycache': 'metadata',
},
'encrypted/nas': {
'acltype': 'off',
'atime': 'off',
'compression': 'off',
'mountpoint': '/media/nas',
},
'storage': { 'storage': {
'primarycache': 'metadata', 'primarycache': 'metadata',
}, },
'storage/opt-yate': { 'storage/opt-yate': {
'mountpoint': '/opt/yate', 'mountpoint': '/opt/yate',
}, },
'storage/f2k1de': {
'mountpoint': '/storage/f2k1de',
},
'storage/download': { 'storage/download': {
'mountpoint': '/storage/download', 'mountpoint': '/storage/download',
}, },
@ -342,6 +271,9 @@ nodes['home.nas'] = {
'mountpoint': '/storage/inbox', 'mountpoint': '/storage/inbox',
}, },
'storage/nas': { 'storage/nas': {
'acltype': 'off',
'atime': 'off',
'compression': 'off',
'mountpoint': '/storage/nas', 'mountpoint': '/storage/nas',
}, },
'storage/paperless': { 'storage/paperless': {

View file

@ -12,6 +12,11 @@ nodes['home.paperless'] = {
'webserver', 'webserver',
}, },
'metadata': { 'metadata': {
'icinga_options': {
'also_affected_by': {
'home.nas',
},
},
'interfaces': { 'interfaces': {
'enp1s0': { 'enp1s0': {
'ips': { 'ips': {
@ -42,7 +47,7 @@ nodes['home.paperless'] = {
}, },
'paperless': { 'paperless': {
'domain': 'paperless.home.kunbox.net', 'domain': 'paperless.home.kunbox.net',
'version': 'v2.8.3', 'version': 'v2.11.0',
'timezone': 'Europe/Berlin', 'timezone': 'Europe/Berlin',
}, },
'postgresql': { 'postgresql': {

View file

@ -146,11 +146,7 @@ nodes['home.router'] = {
}, },
}, },
'users': { 'users': {
'f2k1de': {
'delete': True,
},
'fkunsmann': {}, 'fkunsmann': {},
'sophie': {},
}, },
'vnstat': { 'vnstat': {
'interface': 'enp1s0.7', 'interface': 'enp1s0.7',

View file

@ -32,7 +32,7 @@ routes.'172.19.128.0/20'.via = "172.19.137.1"
[metadata.element-web] [metadata.element-web]
url = "element.afra.berlin" url = "element.afra.berlin"
version = "v1.11.66" version = "v1.11.71"
[metadata.element-web.config] [metadata.element-web.config]
default_server_config.'m.homeserver'.base_url = "https://matrix.afra.berlin" default_server_config.'m.homeserver'.base_url = "https://matrix.afra.berlin"
@ -44,13 +44,14 @@ jitsi.preferredDomain = "meet.ffmuc.net"
[metadata.matrix-media-repo] [metadata.matrix-media-repo]
admins = ['@administress:afra.berlin'] admins = ['@administress:afra.berlin']
datastore_id = "e33b50474021fba9977f912414cdd7fe8890ed57" datastore_id = "e33b50474021fba9977f912414cdd7fe8890ed57"
sha1 = "55d353b472894547c61b11567089eb2cf40ce5ba" sha1 = "ef9e8624e70714e4d421ece0c27f2974f55c0e59"
upload_max_mb = 50 upload_max_mb = 50
version = "v1.3.4" version = "v1.3.6"
[metadata.matrix-media-repo.homeservers.'afra.berlin'] [metadata.matrix-media-repo.homeservers.'afra.berlin']
domain = "http://[::1]:20080/" domain = "http://[::1]:20080/"
api = "synapse" api = "synapse"
signing_key_path = "/etc/matrix-synapse/mmr.signing.key"
[metadata.matrix-registration] [metadata.matrix-registration]
base_path = "/matrix" base_path = "/matrix"

View file

@ -0,0 +1,79 @@
# jugend hackt toolz
nodes['htz-cloud.jugendhackt'] = {
'bundles': {
'jugendhackt_tools',
'postgresql',
'zfs',
},
'groups': {
'debian-bookworm',
'webserver',
},
'metadata': {
'interfaces': {
'eth0': {
'ips': {
'65.21.106.160',
'2a01:4f9:c012:cfd9::/64',
},
'gateway4': '172.31.1.1',
'gateway6': 'fe80::1',
},
},
'jugendhackt_tools': {
'allowed_hosts': ['jh.sophies-kitchen.eu'],
'timezone': 'Europe/Berlin',
},
'nginx': {
'vhosts': {
'jugendhackt_tools': {
'domain': 'jh.sophies-kitchen.eu',
'locations': {
'/': {
'target': 'http://127.0.0.1:22090/',
},
'/static/': {
'alias': '/opt/jugendhackt_tools/src/static/',
},
},
},
},
},
'postgresql': {
'version': '16',
},
'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/sdb',
},
}]
},
},
},
},
},
}

View file

@ -83,9 +83,6 @@ nodes['htz-cloud.pirmasens'] = {
'users': { 'users': {
'forgejo-carlene': {}, 'forgejo-carlene': {},
'frank': {}, 'frank': {},
'sophie': {
'delete': True,
},
}, },
'vm': { 'vm': {
'cpu': 2, 'cpu': 2,

View file

@ -32,22 +32,6 @@ nodes['htz-hel.backup-kunsi'] = {
'encrypted-devices': { 'encrypted-devices': {
'/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi1-part1': bwpass.password('bw/backup-kunsi/encryption-passphrase'), '/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
},
}, },
}, },
} }

View file

@ -162,9 +162,6 @@ nodes['kunsi-p14s'] = {
'password': vault.decrypt('encrypt$gAAAAABgLmmuQGRUStrQawoPee-758emIYn2u8-8ebrgzNAFSp7ifeFDdXXvs-zL3QogwNYlCtBHboH2xfy1rSj6OF5bbNO-tg=='), 'password': vault.decrypt('encrypt$gAAAAABgLmmuQGRUStrQawoPee-758emIYn2u8-8ebrgzNAFSp7ifeFDdXXvs-zL3QogwNYlCtBHboH2xfy1rSj6OF5bbNO-tg=='),
'shell': '/usr/bin/fish', 'shell': '/usr/bin/fish',
}, },
'sophie': {
'delete': True,
},
}, },
'wireguard': { 'wireguard': {
'peers': { 'peers': {

View file

@ -11,11 +11,11 @@ groups = [
[metadata.interfaces.ens192] [metadata.interfaces.ens192]
ips = [ ips = [
"82.165.52.168", "82.165.52.168/32",
"2001:8d8:1801:7d4::1/64", "2a01:239:31c:9b00::1/80"
] ]
gateway4 = "10.255.255.1" gateway4 = "82.165.52.1"
gateway6 = "fe80::250:56ff:fea8:628f" gateway6 = "fe80::1"
[metadata.nginx.vhosts.powerdnsadmin] [metadata.nginx.vhosts.powerdnsadmin]
domain = "ns-mephisto.kunbox.net" domain = "ns-mephisto.kunbox.net"

View file

@ -6,6 +6,7 @@ nodes['htz-hel.backup-sophie'] = {
}, },
'groups': { 'groups': {
'debian-bullseye', 'debian-bullseye',
'sophie',
}, },
'metadata': { 'metadata': {
'apt': { 'apt': {
@ -30,9 +31,6 @@ nodes['htz-hel.backup-sophie'] = {
'gateway6': '2a01:4f9:6b:2d99::2', 'gateway6': '2a01:4f9:6b:2d99::2',
}, },
}, },
'icinga_options': {
'pretty_name': 'backup.sophies-kitchen.eu',
},
'vm': { 'vm': {
'cpu': 4, 'cpu': 4,
'ram': 8, 'ram': 8,
@ -48,9 +46,6 @@ nodes['htz-hel.backup-sophie'] = {
], ],
}, },
}, },
'users': {
'sophie': {},
},
'zfs': { 'zfs': {
'datasets': { 'datasets': {
'tank/ejgwthink': { 'tank/ejgwthink': {

View file

@ -15,6 +15,7 @@ nodes['htz-cloud.miniserver'] = {
}, },
'groups': { 'groups': {
'debian-bookworm', 'debian-bookworm',
'sophie',
'webserver', 'webserver',
}, },
'metadata': { 'metadata': {
@ -62,7 +63,7 @@ nodes['htz-cloud.miniserver'] = {
}, },
'element-web': { 'element-web': {
'url': 'chat.sophies-kitchen.eu', 'url': 'chat.sophies-kitchen.eu',
'version': 'v1.11.66', 'version': 'v1.11.69',
'config': { 'config': {
'default_server_config': { 'default_server_config': {
'm.homeserver': { 'm.homeserver': {
@ -89,10 +90,6 @@ nodes['htz-cloud.miniserver'] = {
}, },
}, },
}, },
'icinga_options': {
'pretty_name': 'sophies-kitchen.eu',
'vars.notification.sms': False,
},
'letsencrypt': { 'letsencrypt': {
'concat_and_deploy': { 'concat_and_deploy': {
'sophie-weechat': { 'sophie-weechat': {

View file

@ -1,4 +1,4 @@
nodes['home.paperless-sophie'] = { nodes['sophie.paperless'] = {
'hostname': '172.19.138.30', 'hostname': '172.19.138.30',
'bundles': { 'bundles': {
'nfs-client', 'nfs-client',
@ -61,13 +61,6 @@ nodes['home.paperless-sophie'] = {
'postgresql': { 'postgresql': {
'version': '11', 'version': '11',
}, },
'users': {
'sophie': {
'sudo_commands': {
'ALL',
},
},
},
'vm': { 'vm': {
'cpu': 2, 'cpu': 2,
'ram': 2, 'ram': 2,

View file

@ -1,4 +1,4 @@
nodes['home.rechenmonster'] = { nodes['sophie.rechenmonster'] = {
'hostname': '172.19.138.98', 'hostname': '172.19.138.98',
'bundles': { 'bundles': {
'basic', 'basic',
@ -54,9 +54,6 @@ nodes['home.rechenmonster'] = {
}, },
}, },
'users': { 'users': {
'kunsi': {
'password': vault.decrypt('encrypt$gAAAAABgLmmuQGRUStrQawoPee-758emIYn2u8-8ebrgzNAFSp7ifeFDdXXvs-zL3QogwNYlCtBHboH2xfy1rSj6OF5bbNO-tg=='),
},
'sophie': { 'sophie': {
'password': vault.decrypt('encrypt$gAAAAABiEAyiedXL6ZnvelOMumhcB73X72SXZhjS_G0EDYVK5-NQ3_J_0h1W1HkFBNe5tShGNmg88jUiULRBn5u2IoiRGiDrYg=='), 'password': vault.decrypt('encrypt$gAAAAABiEAyiedXL6ZnvelOMumhcB73X72SXZhjS_G0EDYVK5-NQ3_J_0h1W1HkFBNe5tShGNmg88jUiULRBn5u2IoiRGiDrYg=='),
}, },
@ -91,6 +88,9 @@ nodes['home.rechenmonster'] = {
'storage/video': { 'storage/video': {
'mountpoint': '/video', 'mountpoint': '/video',
}, },
'storage/nas': {
'mountpoint': '/nas',
},
}, },
}, },
}, },

View file

@ -0,0 +1,36 @@
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'

85
nodes/sophie/vmhost.py Normal file
View file

@ -0,0 +1,85 @@
nodes['sophie.vmhost'] = {
'hostname': '172.19.164.2',
'bundles': {
'backup-client',
'lm-sensors',
'mosquitto',
'smartd',
'vmhost',
'zfs',
},
'groups': {
'debian-bookworm',
},
'metadata': {
'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',
},
},
'systemd-networkd': {
'bridges': {
'br0': {
'match': {
'eno2',
},
},
'br1': {
'match': {
'br0.1',
},
},
},
},
'zfs': {
'pools': {
'storage': {
'when_creating': {
'config': [{
'devices': {
'/dev/disk/by-id/nvme-SAMSUNG_MZVLB256HAHQ-000L7_S41GNX0M481966-part3',
},
}]
}
}
},
"datasets": {
"storage/libvirt": {
"mountpoint": "/var/lib/libvirt",
},
},
},
},
}

View file

@ -25,7 +25,7 @@ nodes['voc.infobeamer-cms'] = {
}, },
'infobeamer-cms': { 'infobeamer-cms': {
'domain': 'infobeamer.c3voc.de', 'domain': 'infobeamer.c3voc.de',
'event_start_date': '2023-12-26', 'event_start_date': '2024-05-29',
'event_duration_days': 5, 'event_duration_days': 5,
'config': { 'config': {
'ADMIN_USERS': [ 'ADMIN_USERS': [
@ -45,7 +45,7 @@ nodes['voc.infobeamer-cms'] = {
'MQTT_TOPIC': '/voc/alert', 'MQTT_TOPIC': '/voc/alert',
'MQTT_USERNAME': vault.decrypt('encrypt$gAAAAABhxakKHC_kHmHP2mFHorb4niuNTH4F24w1D6m5JUxl117N7znlZA6fpMmY3_NcmBr2Ihw4hL3FjZr9Fm_1oUZ1ZQdADA=='), 'MQTT_USERNAME': vault.decrypt('encrypt$gAAAAABhxakKHC_kHmHP2mFHorb4niuNTH4F24w1D6m5JUxl117N7znlZA6fpMmY3_NcmBr2Ihw4hL3FjZr9Fm_1oUZ1ZQdADA=='),
'SETUP_IDS': [ 'SETUP_IDS': [
245793, 250294,
], ],
# 'EXTRA_ASSETS': [{ # 'EXTRA_ASSETS': [{
# 'type': "image", # 'type': "image",

View file

@ -1,158 +1,240 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from argparse import ArgumentParser
from json import dump from json import dump
from os import environ from os import environ, makedirs, remove, scandir
from os.path import dirname, join from os.path import abspath, dirname, join
from sys import exit from sys import exit
import bwpass import bwpass
from requests import post from requests import post
from bundlewrap.utils.text import validate_name from bundlewrap.utils.text import bold, red, validate_name
from bundlewrap.utils.ui import io
TOKEN = environ.get("NETBOX_AUTH_TOKEN") TOKEN = environ.get("NETBOX_AUTH_TOKEN")
# editorconfig-checker-disable
QUERY = """{
device_list(tag: "bundlewrap") {
name
site {
id
}
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
}
}
}
}
}
site_list {
id
vlans {
name
vid
}
}
}"""
# editorconfig-checker-enable
if not TOKEN: if not TOKEN:
try: try:
TOKEN = bwpass.attr("netbox.franzi.business/kunsi", "token") TOKEN = bwpass.attr("netbox.franzi.business/kunsi", "token")
except Exception: except Exception:
print("NETBOX_AUTH_TOKEN is missing") print("NETBOX_AUTH_TOKEN missing")
exit(1) exit(1)
r = post( TARGET_PATH = join(dirname(dirname(abspath(__file__))), "configs", "netbox")
"https://netbox.franzi.business/graphql/",
headers={
"Accept": "application/json",
"Authorization": f"Token {TOKEN}",
},
json={
"query": QUERY,
},
)
r.raise_for_status()
data = r.json()["data"] QUERY_SITES = """{
site_list {
site_vlans = {site["id"]: site["vlans"] for site in data["site_list"]} name
id
for device in data["device_list"]: vlans {
if not device["name"] or not validate_name(device["name"]): name
# invalid node name, ignore vid
continue }
result = {
"interfaces": {},
"vlans": site_vlans[device["site"]["id"]],
} }
}"""
for interface in device["interfaces"]: QUERY_DEVICES = """{
description = "" device_list(filters: {tag: "bundlewrap", site_id: "SITE_ID"}) {
peers = None name
id
}
}"""
if interface["connected_endpoints"]: QUERY_DEVICE_DETAILS = """{
peers = interface["connected_endpoints"] device(id: DEVICE_ID) {
elif interface["link_peers"]: name
peers = interface["link_peers"] 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
}
}
}
}
}
}"""
if interface["description"]:
description = interface["description"]
elif peers:
peer_list = set()
for i in peers: def graphql(query):
peer_list.add( r = post(
"{} ({})".format( "https://netbox.franzi.business/graphql/",
i["device"]["name"], headers={
i["name"], "Accept": "application/json",
) "Authorization": f"Token {TOKEN}",
},
json={
"query": query,
},
)
r.raise_for_status()
return r.json()["data"]
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()
try:
io.activate()
filenames_used = set()
with io.job("getting sites"):
sites = filter_results(
graphql(QUERY_SITES).get("site_list", []), args.only_site
)
io.stdout(f"Processing {len(sites)} sites in total")
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")
for device in devices:
if not device["name"] or not validate_name(device["name"]):
# invalid node name, ignore
continue
with io.job(
f"{bold(site['name'])} {bold(device['name'])} getting interfaces"
):
details = graphql(
QUERY_DEVICE_DETAILS.replace("DEVICE_ID", device["id"])
)["device"]
result = {
"interfaces": {},
"vlans": site["vlans"],
}
for interface in details["interfaces"]:
peers = None
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!"
) )
description = "; ".join(sorted(peer_list)) if not args.only_site and not args.only_device and filenames_used:
else: with io.job(f"cleaning leftover files from {TARGET_PATH}"):
description = "" for direntry in scandir(TARGET_PATH):
filename = direntry.name
assert description.isascii() if filename.startswith("."):
continue
result["interfaces"][interface["name"]] = { if not direntry.is_file():
"description": description, io.stderr(
"enabled": interface["enabled"], f"found non-file {filename} in {TARGET_PATH}, please check what's going on!"
"mode": interface["mode"], )
"type": interface["type"], continue
"ips": sorted({i['address'] for i in interface['ip_addresses']}), if filename not in filenames_used:
"untagged_vlan": interface["untagged_vlan"]["name"] remove(join(TARGET_PATH, filename))
if interface["untagged_vlan"] finally:
else None, io.deactivate()
"tagged_vlans": sorted({v["name"] for v in interface["tagged_vlans"]}),
}
with open(
join(
dirname(dirname(__file__)),
"configs",
"netbox_device_{}.json".format(device["name"]),
),
"w+",
) as f:
dump(
result,
f,
indent=4,
sort_keys=True,
)