Mercurial > code > home > repos > infra
changeset 326:5b88b38f2471
huge reorg, reog toplevel functions in preparation of a ui with nice task lists
line wrap: on
line diff
--- a/.vscode/settings.json Mon Jan 20 14:10:19 2025 -0800 +++ b/.vscode/settings.json Mon Jan 20 21:55:08 2025 -0800 @@ -1,12 +1,3 @@ { - "python.linting.pylintEnabled": false, - "python.linting.flake8Enabled": true, - "python.linting.enabled": true, - "python.analysis.extraPaths": ["${workspaceFolder}/__pypackages__/3.11/lib"], - "python.autoComplete.extraPaths": ["${workspaceFolder}/__pypackages__/3.11/lib"], - "python.formatting.provider": "yapf", - "files.watcherExclude": { - "_darcs_old/**": true - }, - "python.linting.mypyEnabled": false + }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/all_operations.py Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,32 @@ +import importlib +import os +from pyinfra.context import host + + +def gatherFuncs(): + for opGroup in [ + 'users', + 'system', + 'apt', + 'packages', + 'net', + 'dns', + 'wireguard', + 'kube', + 'sync', + 'mail', + 'home', + ]: + if os.environ.get('GROUP') and opGroup != os.environ['GROUP']: + continue + mod = importlib.import_module(f'{opGroup}.{opGroup}') + operations = getattr(mod, 'operations') + for func in operations: + funcFullName = f'{mod.__name__}.{func.__name__}.{host.name}' + yield (funcFullName, func) + + +funcs = list(gatherFuncs()) + +for name, func in funcs: + func()
--- a/apt/apt.py Mon Jan 20 14:10:19 2025 -0800 +++ b/apt/apt.py Mon Jan 20 21:55:08 2025 -0800 @@ -1,32 +1,19 @@ -import shlex +import io -from pyinfra import host +from pyinfra.context import host from pyinfra.facts.server import Arch from pyinfra.operations import apt, files, server TZ = 'America/Los_Angeles' -def pkg_keys(): - files.directory(path='/etc/apt/keyrings/') # for raspi - for url, name in [ - ('https://repo.steampowered.com/steam/archive/stable/steam.gpg', 'steam.gpg'), - ]: - files.download(src=url, dest=f'/usr/share/keyrings/{name}') +def ubuntuReleases(): + if 'pi' not in host.groups: + files.line(path='/etc/update-manager/release-upgrades', line="^Prompt=", replace="Prompt=normal") - apt.packages(packages=['curl', 'gpg']) - server.shell(commands=[ - f"curl -fsSL {shlex.quote(url)} | gpg --dearmor > /etc/apt/keyrings/{name}" for (url, name) in [ - ('https://packages.microsoft.com/keys/microsoft.asc', 'ms.gpg'), - ('https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key', 'nodesource.gpg'), - ('https://dl.google.com/linux/linux_signing_key.pub', 'chrome.gpg'), - ('https://ftp-master.debian.org/keys/archive-key-11.asc', 'bullseye.gpg'), - ('https://ftp-master.debian.org/keys/archive-key-11-security.asc', 'bullseye-security.gpg'), - ('https://packages.cloud.google.com/apt/doc/apt-key.gpg', 'coral.gpg'), - ('https://hub.unity3d.com/linux/keys/public', 'unityhub.gpg'), - ('https://nvidia.github.io/libnvidia-container/gpgkey', 'nvidia.gpg'), - ] - ]) +def pkgKeys(): + files.directory(path='/etc/apt/keyrings/') # for raspi + files.sync(src='apt/keyrings/', dest='/usr/share/keyrings/', delete=False) # also these #-rw-r--r-- 1 root root 2794 Mar 26 2021 /etc/apt/trusted.gpg.d/ubuntu-keyring-2012-cdimage.gpg @@ -36,15 +23,12 @@ def arch386(): + if host.get_fact(Arch) != 'x86_64': + return server.shell(commands=['dpkg --add-architecture i386']) -def old_deleteme_apt_sources(): - files.template(src='apt/templates/sources.list.j2', dest='/etc/apt/sources.list') - apt_update() - - -def apt_update(): +def aptUpdate(): apt.packages(update=True, cache_time=86400, packages=['tzdata'], @@ -59,22 +43,28 @@ # and steam-launcher -def flatpak_sources(): +def flatpakSources(): apt.packages(update=True, cache_time=86400, packages=['flatpak']) server.shell(commands='flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo') -if host.get_fact(Arch) == 'x86_64': - arch386() +def sources(): + files.put(src=io.StringIO("# see .d\n"), dest="/etc/apt/sources.list") + if 'pi' in host.groups: + osName = "pi" + elif host.name == 'pipe': + osName = "odroid" + else: + osName = "ubuntu" + files.template(src=f'apt/templates/{osName}.sources.j2', dest=f'/etc/apt/sources.list.d/{osName}.sources') + files.template(src='apt/templates/more.sources.j2', dest='/etc/apt/sources.list.d/more.sources') -pkg_keys() -using_new_sources = ['tofu'] -if host.name in using_new_sources: - # todo: rm /etc/apt/sources.list.d/*.list - files.template(src='apt/templates/ubuntu.sources.j2', dest='/etc/apt/sources.list.d/ubuntu.sources') - files.template(src='apt/templates/more.sources.j2', dest='/etc/apt/sources.list.d/more.sources') - apt_update() -else: - old_deleteme_apt_sources() -flatpak_sources() +operations = [ + ubuntuReleases, + arch386, + pkgKeys, + sources, + aptUpdate, + flatpakSources, +]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/apt/get_keyrings.sh Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,21 @@ +#!/bin/zsh + + +cd `dirname $0` +rm -f keyrings/* + +for url in \ + https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key \ + https://dl.google.com/linux/linux_signing_key.pub \ + https://ftp-master.debian.org/keys/archive-key-11-security.asc \ + https://ftp-master.debian.org/keys/archive-key-11.asc \ + https://hub.unity3d.com/linux/keys/public \ + https://nvidia.github.io/libnvidia-container/gpgkey + https://packages.cloud.google.com/apt/doc/apt-key.gpg \ + https://packages.microsoft.com/keys/microsoft.asc \ + https://repo.steampowered.com/steam/archive/stable/steam.gpg \ +do + name=`echo ${url:r}.gpg | perl -lpe 's/https:..//; s/\//_/g'` + curl -fsSL $url | gpg --dearmor > keyrings/$name +done +
--- a/apt/templates/more.sources.j2 Mon Jan 20 14:10:19 2025 -0800 +++ b/apt/templates/more.sources.j2 Mon Jan 20 21:55:08 2025 -0800 @@ -6,79 +6,59 @@ Suites: stable Components: main Architectures: amd64 -Signed-By: /etc/apt/keyrings/ms.gpg +Signed-By: /usr/share/keyrings/packages.microsoft.com_keys_microsoft.gpg + Types: deb URIs: http://dl.google.com/linux/chrome/deb/ Suites: stable Components: main Architectures: amd64 -Signed-By: /etc/apt/keyrings/chrome.gpg +Signed-By: /usr/share/keyrings/dl.google.com_linux_linux_signing_key.gpg + Types: deb URIs: https://repo.steampowered.com/steam/ Suites: stable Components: steam Architectures: amd64 i386 -Signed-By: /usr/share/keyrings/steam.gpg +Signed-By: /usr/share/keyrings/repo.steampowered.com_steam_archive_stable_steam.gpg + Types: deb URIs: https://hub.unity3d.com/linux/repos/deb Suites: stable Components: main -Signed-By: /etc/apt/keyrings/unityhub.gpg +Signed-By: /usr/share/keyrings/hub.unity3d.com_linux_keys_public.gpg + Types: deb URIs: https://deb.nodesource.com/node_18.x Suites: nodistro Components: main Architectures: amd64 -Signed-By: /etc/apt/keyrings/nodesource.gpg +Signed-By: /usr/share/keyrings/deb.nodesource.com_gpgkey_nodesource-repo.gpg.gpg + + {% endif %} - {% if host.data.get('gpu') %} -Types: deb -URIs: https://nvidia.github.io/libnvidia-container/stable/deb/$(ARCH) -Suites: / -Components: main -Signed-By: /etc/apt/keyrings/nvidia.gpg + +#TODO fix Suites + +# Types: deb +# URIs: https://nvidia.github.io/libnvidia-container/stable/deb/$(ARCH) +# Suites: / +# Components: main +# Signed-By: /etc/apt/keyrings/nvidia.gpg + + {% endif %} - {% if host.data.get('coral') %} Types: deb URIs: https://packages.cloud.google.com/apt Suites: coral-edgetpu-stable Components: main Signed-By: /etc/apt/keyrings/coral.gpg -{% endif %} -{% if host.name == 'pipe' %} - -todo convert -# seems stuck on jammy since http://deb.odroid.in/n2/ and https://wiki.odroid.com/odroid-n2/os_images/ubuntu don't have anything newer (2023-12-28) -deb [signed-by=/etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg] http://archive.canonical.com/ubuntu jammy partner -deb [signed-by=/etc/apt/trusted.gpg] http://deb.odroid.in/n2/ jammy main -deb [signed-by=/etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg] http://ports.ubuntu.com/ubuntu-ports/ jammy main restricted -deb [signed-by=/etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg] http://ports.ubuntu.com/ubuntu-ports/ jammy multiverse -deb [signed-by=/etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg] http://ports.ubuntu.com/ubuntu-ports/ jammy universe -deb [signed-by=/etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg] http://ports.ubuntu.com/ubuntu-ports/ jammy-backports main restricted universe multiverse -deb [signed-by=/etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg] http://ports.ubuntu.com/ubuntu-ports/ jammy-security main restricted -deb [signed-by=/etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg] http://ports.ubuntu.com/ubuntu-ports/ jammy-security multiverse -deb [signed-by=/etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg] http://ports.ubuntu.com/ubuntu-ports/ jammy-security universe -deb [signed-by=/etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg] http://ports.ubuntu.com/ubuntu-ports/ jammy-updates main restricted -deb [signed-by=/etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg] http://ports.ubuntu.com/ubuntu-ports/ jammy-updates multiverse -deb [signed-by=/etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg] http://ports.ubuntu.com/ubuntu-ports/ jammy-updates universe -# or, if you have to get this, try: https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=index&search=0xABB1931B59A40B968609F153D0392EC59F9583BA -deb [signed-by=/etc/apt/trusted.gpg] http://ppa.launchpad.net/hardkernel/ppa/ubuntu jammy main -{% endif %} - -{% if 'pi' in host.groups %} - -todo convert - -deb http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware -deb http://deb.debian.org/debian-security/ bookworm-security main contrib non-free non-free-firmware -deb http://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware -{% endif %} - +{% endif %} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/apt/templates/odroid.sources.j2 Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,71 @@ +# written by pyinfra + +# seems stuck on jammy since http://deb.odroid.in/n2/ and https://wiki.odroid.com/odroid-n2/os_images/ubuntu don't have anything newer (2023-12-28) +Types: deb +URIs: http://deb.odroid.in/n2/ +Suites: jammy +Components: main +Signed-By: /etc/apt/trusted.gpg + +Types: deb +URIs: http://ports.ubuntu.com/ubuntu-ports/ +Suites: jammy +Components: main restricted +Signed-By: /etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg + +Types: deb +URIs: http://ports.ubuntu.com/ubuntu-ports/ +Suites: jammy +Components: multiverse +Signed-By: /etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg + +Types: deb +URIs: http://ports.ubuntu.com/ubuntu-ports/ +Suites: jammy +Components: universe +Signed-By: /etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg + +Types: deb +URIs: http://ports.ubuntu.com/ubuntu-ports/ +Suites: jammy-backports +Components: main restricted universe multiverse +Signed-By: /etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg + +Types: deb +URIs: http://ports.ubuntu.com/ubuntu-ports/ +Suites: jammy-security +Components: main restricted +Signed-By: /etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg + +Types: deb +URIs: http://ports.ubuntu.com/ubuntu-ports/ +Suites: jammy-security +Components: multiverse +Signed-By: /etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg + +Types: deb +URIs: http://ports.ubuntu.com/ubuntu-ports/ +Suites: jammy-security +Components: universe +Signed-By: /etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg + +Types: deb +URIs: http://ports.ubuntu.com/ubuntu-ports/ +Suites: jammy-updates +Components: main restricted +Signed-By: /etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg + +Types: deb +URIs: http://ports.ubuntu.com/ubuntu-ports/ +Suites: jammy-updates +Components: multiverse +Signed-By: /etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg + +Types: deb +URIs: http://ports.ubuntu.com/ubuntu-ports/ +Suites: jammy-updates +Components: universe +Signed-By: /etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg + +# # or, if you have to get this, try: https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=index&search=0xABB1931B59A40B968609F153D0392EC59F9583BA +# deb [signed-by=/etc/apt/trusted.gpg] http://ppa.launchpad.net/hardkernel/ppa/ubuntu jammy main
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/apt/templates/pi.sources.j2 Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,19 @@ +# written by pyinfra + +Types: deb +URIs: http://deb.debian.org/debian +Suites: bookworm +Components: main contrib non-free non-free-firmware +Signed-By: /usr/share/keyrings/ftp-master.debian.org_keys_archive-key-11.gpg + +Types: deb +URIs: http://deb.debian.org/debian-security/ +Suites: bookworm-security +Components: main contrib non-free non-free-firmware +Signed-By: /usr/share/keyrings/ftp-master.debian.org_keys_archive-key-11-security.gpg + +Types: deb +URIs: http://deb.debian.org/debian +Suites: bookworm-updates +Components: main contrib non-free non-free-firmware +Signed-By: /usr/share/keyrings/ftp-master.debian.org_keys_archive-key-11.gpg
--- a/apt/templates/sources.list.j2 Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -# written by pyinfra - -{% if 'big' in host.groups or 'laptop' in host.groups %} -deb [arch=amd64,arm64,armhf signed-by=/etc/apt/keyrings/ms.gpg] http://packages.microsoft.com/repos/code stable main -deb [arch=amd64 signed-by=/etc/apt/keyrings/chrome.gpg] http://dl.google.com/linux/chrome/deb/ stable main -deb [arch=amd64,i386 signed-by=/usr/share/keyrings/steam.gpg] https://repo.steampowered.com/steam/ stable steam -deb [signed-by=/etc/apt/keyrings/unityhub.gpg] https://hub.unity3d.com/linux/repos/deb stable main -deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_18.x nodistro main -{% endif %} - -{% if host.data.get('gpu') %} -deb [signed-by=/etc/apt/keyrings/nvidia.gpg] https://nvidia.github.io/libnvidia-container/stable/deb/$(ARCH) / -{% endif %} - -{% if host.data.get('coral') %} -deb [signed-by=/etc/apt/keyrings/coral.gpg] https://packages.cloud.google.com/apt coral-edgetpu-stable main -{% endif %} - -{% if host.name == 'pipe' %} -# seems stuck on jammy since http://deb.odroid.in/n2/ and https://wiki.odroid.com/odroid-n2/os_images/ubuntu don't have anything newer (2023-12-28) -deb [signed-by=/etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg] http://archive.canonical.com/ubuntu jammy partner -deb [signed-by=/etc/apt/trusted.gpg] http://deb.odroid.in/n2/ jammy main -deb [signed-by=/etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg] http://ports.ubuntu.com/ubuntu-ports/ jammy main restricted -deb [signed-by=/etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg] http://ports.ubuntu.com/ubuntu-ports/ jammy multiverse -deb [signed-by=/etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg] http://ports.ubuntu.com/ubuntu-ports/ jammy universe -deb [signed-by=/etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg] http://ports.ubuntu.com/ubuntu-ports/ jammy-backports main restricted universe multiverse -deb [signed-by=/etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg] http://ports.ubuntu.com/ubuntu-ports/ jammy-security main restricted -deb [signed-by=/etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg] http://ports.ubuntu.com/ubuntu-ports/ jammy-security multiverse -deb [signed-by=/etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg] http://ports.ubuntu.com/ubuntu-ports/ jammy-security universe -deb [signed-by=/etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg] http://ports.ubuntu.com/ubuntu-ports/ jammy-updates main restricted -deb [signed-by=/etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg] http://ports.ubuntu.com/ubuntu-ports/ jammy-updates multiverse -deb [signed-by=/etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg] http://ports.ubuntu.com/ubuntu-ports/ jammy-updates universe -# or, if you have to get this, try: https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=index&search=0xABB1931B59A40B968609F153D0392EC59F9583BA -deb [signed-by=/etc/apt/trusted.gpg] http://ppa.launchpad.net/hardkernel/ppa/ubuntu jammy main -{% endif %} - -{% if 'pi' in host.groups %} -deb http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware -deb http://deb.debian.org/debian-security/ bookworm-security main contrib non-free non-free-firmware -deb http://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware -{% endif %} -
--- a/coredns_freshen.sh Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -#!/bin/zsh -kubectl apply -f templates/kube/coredns.yaml -kubectl get -n kube-system configmap/coredns -o yaml
--- a/dns.py Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,126 +0,0 @@ -import subprocess -from io import StringIO - -import pyinfra -from pyinfra import host -from pyinfra.operations import files, server, systemd - - -def dnsmasq_instance(net_name, - house_iface, - dhcp_range='10.2.0.10,10.2.0.11', - listen_address='reqd', - dhcp_hosts_filename='/dev/null'): - files.directory(path=f'/opt/dnsmasq/{net_name}') - files.template( - src='templates/dnsmasq/dnsmasq.conf.j2', - dest=f'/opt/dnsmasq/{net_name}/dnsmasq.conf', - net=net_name, - house_iface=house_iface, - dhcp_range=dhcp_range, - listen_address=listen_address, - dhcp_enabled=net_name == '10.2' and host.name == 'pipe', - dns_server=listen_address, - router=listen_address, - ) - files.template(src='templates/dnsmasq/hosts.j2', dest=f'/opt/dnsmasq/{net_name}/hosts', net=net_name) - - dhcp_hosts = subprocess.check_output(['python3', '/my/serv/lanscape/src/public/make_dhcp_hosts.py'], encoding='utf8') - files.put(src=StringIO(dhcp_hosts), dest=f'/opt/dnsmasq/{net_name}/dhcp_hosts') - - files.template(src='templates/dnsmasq/dnsmasq.service.j2', - dest=f'/etc/systemd/system/dnsmasq_{net_name}.service', - net=net_name) - if net_name in ['10.2', '10.2-filtered']: - systemd.service(service=f'dnsmasq_{net_name}', enabled=True, restarted=True, daemon_reload=True) - - -def standard_host_dns(): - files.template(src='templates/hosts.j2', dest='/etc/hosts') - if 'pi' in host.groups: - files.put(dest='/etc/resolv.conf', - src=StringIO(''' -# written by pyinfra -nameserver 10.2.0.3 -search bigasterisk.com - ''')) - else: - files.link(path='/etc/resolv.conf', target='/run/systemd/resolve/resolv.conf', force=True) - files.template(src='templates/resolved.conf.j2', dest='/etc/systemd/resolved.conf') - systemd.service(service='systemd-resolved.service', running=True, restarted=True) - - -def rpi_net_boot(): - files.directory(path='/opt/dnsmasq/tftp') - - -standard_host_dns() - -# no default instance; i'll add some specific ones below -systemd.service(service='dnsmasq', enabled=False, running=False) - - -def watchLeasesFile(): - """summary: - 1. dnsmasq_10.2 leases an address and writes to /opt/dnsmasq/10.2/leases - 2. dhcp_graph_watch.path notices that change - 3. dhcp_graph_update.service posts /opt/dnsmasq/10.2/leases to dhcp_graph (k8s deploy) - 4. dhcp_graph serves the data as rdf - """ - dhcp_graph_url = "http://10.5.0.7:8005" - leases = "/opt/dnsmasq/10.2/leases" - files.put(dest='/etc/systemd/system/dhcp_graph_watch.path', - src=StringIO(f''' -[Unit] -Description=dhcp leases file changed- run dhcp_graph_update -After=localfs.target - -[Path] -PathModified={leases} -Unit=dhcp_graph_update.service - -[Install] -WantedBy=multi-user.target -''')) - - files.put(dest='/etc/systemd/system/dhcp_graph_update.service', - src=StringIO(f''' -[Unit] -Description=Send new dhcp leases content to dhcp_graph -After=network.target - -[Service] -Type=oneshot -ExecStart=/usr/bin/curl -s {dhcp_graph_url}/leases -H "content-type: text/plain" --data-binary "@{leases}" - -[Install] -WantedBy=multi-user.target -''')) - systemd.service(service='dhcp_graph_watch.path', enabled=True, restarted=True, daemon_reload=True) - systemd.service(service='dhcp_graph_update.service', enabled=True, restarted=True, daemon_reload=True) - - -if host.name == 'pipe': - rpi_net_boot() - files.directory(path='/opt/dnsmasq') - dnsmasq_instance('10.2', - house_iface='eth1', - dhcp_range='10.2.0.110,10.2.0.240', - listen_address='10.2.0.3', - dhcp_hosts_filename='templates/dnsmasq/dhcp_hosts.j2') - out = '/opt/dnsmasq/10.2' - # This mtail is for dhcp command counts and errors. - files.put(src='files/dnsmasq/metrics.mtail', dest=f'{out}/metrics.mtail') - files.put(src='files/dnsmasq/run_mtail.sh', dest=f'{out}/run_mtail.sh') - - watchLeasesFile() - - files.put(src='files/dnsmasq/dnsmasq-mtail.service', dest='/etc/systemd/system/dnsmasq-mtail.service') - systemd.service(service='dnsmasq-mtail', enabled=True, restarted=True, daemon_reload=True) - - # Serve another dns, no dhcp, and include the dynamic-blocking file written by net_routes. - dnsmasq_instance( - net_name='10.2-filtered', - house_iface='eth1', - listen_address='10.2.0.4', - )
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dns/dns.py Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,116 @@ +from operator import le +import subprocess +from io import StringIO + +from pyinfra.context import host +from pyinfra.operations import files, systemd + + +def dnsmasq_instance( + net_name, + house_iface, + dhcp_range='10.2.0.10,10.2.0.11', + listen_address='reqd', +): + files.directory(path=f'/opt/dnsmasq/{net_name}') + files.template( + src='dns/templates/dnsmasq/dnsmasq.conf.j2', + dest=f'/opt/dnsmasq/{net_name}/dnsmasq.conf', + net=net_name, + house_iface=house_iface, + dhcp_range=dhcp_range, + listen_address=listen_address, + dhcp_enabled=net_name == '10.2' and host.name == 'pipe', + dns_server=listen_address, + router=listen_address, + ) + files.template(src='dns/templates/dnsmasq/hosts.j2', dest=f'/opt/dnsmasq/{net_name}/hosts', net=net_name) + + dhcp_hosts = subprocess.check_output(['python3', '/my/serv/lanscape/src/public/make_dhcp_hosts.py'], encoding='utf8') + files.put(src=StringIO(dhcp_hosts), dest=f'/opt/dnsmasq/{net_name}/dhcp_hosts') + + files.template(src='dns/templates/dnsmasq/dnsmasq.service.j2', + dest=f'/etc/systemd/system/dnsmasq_{net_name}.service', + net=net_name) + if net_name in ['10.2', '10.2-filtered']: + systemd.service(service=f'dnsmasq_{net_name}', enabled=True, restarted=True, daemon_reload=True) + + +def standard_host_dns(): + files.template(src='dns/templates/hosts.j2', dest='/etc/hosts') + if 'pi' in host.groups: + files.put(dest='/etc/resolv.conf', src='dns/files/resolv.conf') + else: + files.link(path='/etc/resolv.conf', target='/run/systemd/resolve/resolv.conf', force=True) + files.template(src='dns/templates/resolved.conf.j2', dest='/etc/systemd/resolved.conf') + systemd.service(service='systemd-resolved.service', running=True, restarted=True) + + +def rpi_net_boot(): + files.directory(path='/opt/dnsmasq/tftp') + + +def no_default_dnsmasq_instance(): + # no default instance; i'll add some specific ones below + systemd.service(service='dnsmasq', enabled=False, running=False) + + +def watchLeasesFile(): + """summary: + 1. dnsmasq_10.2 leases an address and writes to /opt/dnsmasq/10.2/leases + 2. dhcp_graph_watch.path notices that change + 3. dhcp_graph_update.service posts /opt/dnsmasq/10.2/leases to dhcp_graph (k8s deploy) + 4. dhcp_graph serves the data as rdf + """ + dhcp_graph_url = "http://10.5.0.7:8005" + leases = "/opt/dnsmasq/10.2/leases" + files.template( + src='dns/templates/dhcp_graph_watch.path.j2', + dest='/etc/systemd/system/dhcp_graph_watch.path', + leases=leases, + ) + + files.template( + src='dns/templates/dhcp_graph_update.service.j2', + dest='/etc/systemd/system/dhcp_graph_update.service', + leases=leases, + dhcp_graph_url=dhcp_graph_url, + ) + systemd.service(service='dhcp_graph_watch.path', enabled=True, restarted=True, daemon_reload=True) + systemd.service(service='dhcp_graph_update.service', enabled=True, restarted=True, daemon_reload=True) + + +def dnsmasq_on_pipe(): + if host.name != 'pipe': + return + rpi_net_boot() + files.directory(path='/opt/dnsmasq') + dnsmasq_instance( + '10.2', + house_iface='eth1', + dhcp_range='10.2.0.110,10.2.0.240', + listen_address='10.2.0.3', + ) + out = '/opt/dnsmasq/10.2' + # This mtail is for dhcp command counts and errors. + files.put(src='dns/files/metrics.mtail', dest=f'{out}/metrics.mtail') + files.put(src='dns/files/run_mtail.sh', dest=f'{out}/run_mtail.sh') + + watchLeasesFile() + + files.put(src='dns/files/dnsmasq-mtail.service', dest='/etc/systemd/system/dnsmasq-mtail.service') + systemd.service(service='dnsmasq-mtail', enabled=True, restarted=True, daemon_reload=True) + + # Serve another dns, no dhcp, and include the dynamic-blocking file written by net_routes. + dnsmasq_instance( + net_name='10.2-filtered', + house_iface='eth1', + listen_address='10.2.0.4', + ) + + +operations = [ + standard_host_dns, + no_default_dnsmasq_instance, + dnsmasq_on_pipe, +]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dns/files/dnsmasq-mtail.service Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,13 @@ +# written by pyinfra + +[Unit] +Description=dnsmasq-mtail for 10.2 network +After=dnsmasq_10.2.service + +[Service] +Type=simple + +ExecStart=zsh /opt/dnsmasq/10.2/run_mtail.sh + +[Install] +WantedBy=multi-user.target
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dns/files/metrics.mtail Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,37 @@ +counter dnsmasq_no_addr_errors +/no address available/ { + dnsmasq_no_addr_errors++ +} + +counter dnsmasq_dhcp_requests +/DHCPREQUEST/ { + dnsmasq_dhcp_requests++ +} + +counter dnsmasq_dhcp_acks +/DHCPACK/ { + dnsmasq_dhcp_acks++ +} + +counter dnsmasq_dhcp_discovers +/DHCPDISCOVER/ { + dnsmasq_dhcp_discovers++ +} + +counter dnsmasq_dhcp_offers +/DHCPOFFER/ { + dnsmasq_dhcp_offers++ +} + +gauge dnsmasq_dns_queries_answered_locally +gauge dnsmasq_dns_queries_forwarded by server +gauge dnsmasq_dns_queries_retried_or_failed by server + +/queries forwarded (?P<fwd>\d+), queries answered locally (?P<loc>\d+)/ { + dnsmasq_dns_queries_answered_locally = $loc +} + +/server (?P<svr>\S+)#53: queries sent (?P<sent>\d+), retried or failed (?P<fail>\d+)/ { + dnsmasq_dns_queries_forwarded[$svr] = $sent + dnsmasq_dns_queries_retried_or_failed[$svr] = $fail +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dns/files/resolv.conf Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,6 @@ +# written by pyinfra + +# (used on rpi) + +nameserver 10.2.0.3 +search bigasterisk.com \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dns/files/run_mtail.sh Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,11 @@ +#!/bin/zsh +STATS_PERIOD=2m +while (true) { pkill --signal USR1 --oldest --full /usr/sbin/dnsmasq; sleep ${STATS_PERIOD} } & + +rm -f /tmp/dnsmasq_log_pipe +mkfifo /tmp/dnsmasq_log_pipe + +{ journalctl -fu dnsmasq_10.2.service > /tmp/dnsmasq_log_pipe } & + +mtail -port 9991 -logtostderr -logs /tmp/dnsmasq_log_pipe -progs /opt/dnsmasq/10.2 +#-disable_fsnotify -poll_interval ${STATS_PERIOD} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dns/templates/dhcp_graph_update.service.j2 Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,10 @@ +[Unit] +Description=Send new dhcp leases content to dhcp_graph +After=network.target + +[Service] +Type=oneshot +ExecStart=/usr/bin/curl -s {{dhcp_graph_url}}/leases -H "content-type: text/plain" --data-binary "@{{leases}}" + +[Install] +WantedBy=multi-user.target
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dns/templates/dhcp_graph_watch.path.j2 Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,10 @@ +[Unit] +Description=dhcp leases file changed- run dhcp_graph_update +After=localfs.target + +[Path] +PathModified={{leases}} +Unit=dhcp_graph_update.service + +[Install] +WantedBy=multi-user.target \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dns/templates/dnsmasq/dnsmasq.conf.j2 Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,71 @@ +user=nobody +keep-in-foreground +log-facility=- + +listen-address={{ listen_address }} +{% if net == "10.2" %} +# dnsmasq will not automatically listen on the loopback interface. To achieve +# this, its IP address, 127.0.0.1, must be explicitly given as a +# --listen-address option. +listen-address=127.0.0.1 +{% endif %} +bind-interfaces + +domain-needed +no-resolv +no-hosts +addn-hosts=/opt/dnsmasq/{{ net }}/hosts +local-ttl=30 +mx-host=bigasterisk.com +cache-size=10000 +neg-ttl=60 +dns-forward-max=1000 +domain=bigasterisk.com + +# log-queries +# log-debug + +{% if dhcp_enabled %} +log-dhcp + +dhcp-sequential-ip +dhcp-broadcast +dhcp-authoritative +dhcp-option=option:domain-name,bigasterisk.com +dhcp-script=/opt/dnsmasq_exporter/on_dhcp_change.sh +dhcp-hostsfile=/opt/dnsmasq/{{ net }}/dhcp_hosts +dhcp-leasefile=/opt/dnsmasq/{{ net }}/leases +dhcp-range={{ house_iface }},10.2.0.0,static,infinite +dhcp-range=tag:!known,{{ house_iface }},{{ dhcp_range }},2h +dhcp-option={{ house_iface }},option:dns-server,{{ dns_server }} +dhcp-option={{ house_iface }},option:router,{{ router }} +# hosts are tagged in ./dhcp_hosts.j2 +dhcp-option=tag:filtereddns,option:dns-server,10.2.0.4 + +enable-tftp +tftp-root=/opt/dnsmasq/tftp +pxe-service=0,"Raspberry Pi Boot" + dhcp-mac=set:net-booting-rpi,b8:27:eb:*:*:* + dhcp-reply-delay=tag:net-booting-rpi,2 +{% endif %} + +local=/bigasterisk.com/ +# i didn't say --all-servers, but it was behaving like that +server=208.201.224.11 +#server=208.201.224.33 +#server=8.8.4.4 +#server=8.8.8.8 + +{% if net == "10.5" %} +# net==10.5 is not used for dhcp at all +# use ./hosts, then try the server that knows the dhcp leases +server={{ router }} +{% endif %} + +{% if net == '10.2-filtered' %} +# written by net_routes/dns_blocker.py +addn-hosts=/opt/dnsmasq/10.2-filtered/dynamic-blocking +# but! users of this dns server can't even look up names +# like 'ditto' since those come from dhcp on the 10.2.0.3 +# (nonfiltered) dnsmasq instance +{% endif %}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dns/templates/dnsmasq/dnsmasq.service.j2 Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,52 @@ +# written by pyinfra + +[Unit] +Description=dnsmasq for {{ net }} network + +# this dnsmasq needs to bind to addr 10.2.0.3 +Requires=network-online.target +Requires=sys-subsystem-net-devices-eth1.device + +Wants=nss-lookup.target +Before=nss-lookup.target +After=network.target + +# startup order has to be like this: +# dnsmasq_10.2 +# wg-quick@wg0.service +# dnsmasq_10.5 +{% if net == '10.2' %} +Before=wg-quick@wg0.service +After=house_net.service +{% endif %} +{% if net == '10.5' %} +Requires=wg-quick@wg0.service +{% endif %} + +[Service] +Type=simple + +# 10.5 will not work until wg0 interface is actually up, so just let it retry +# but i think this next line was not the right way to retry. +#SuccessExitStatus=2 +Restart=always +RestartSec=5 + +# Test the config file and refuse starting if it is not valid. +ExecStartPre=/usr/sbin/dnsmasq --conf-file=/opt/dnsmasq/{{ net }}/dnsmasq.conf --test + +ExecStart=/usr/sbin/dnsmasq --conf-file=/opt/dnsmasq/{{ net }}/dnsmasq.conf + +{% if net == '10.2' %} +# The systemd-*-resolvconf functions configure (and deconfigure) +# resolvconf to work with the dnsmasq DNS server. They're called like +# this to get correct error handling (ie don't start-resolvconf if the +# dnsmasq daemon fails to start. +ExecStartPost=/etc/init.d/dnsmasq systemd-start-resolvconf +ExecStop=/etc/init.d/dnsmasq systemd-stop-resolvconf +{% endif %} + +ExecReload=/bin/kill -HUP $MAINPID + +[Install] +WantedBy=multi-user.target
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dns/templates/dnsmasq/hosts.j2 Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,60 @@ +# written by pyinfra + +162.243.138.136 prime-ext.bigasterisk.com public.bigasterisk.com + +# This is the dns trick-- hosts at home should use the local address +# for 'bigasterisk.com' etc instead of taking a trip to prime. +10.2.0.1 bang bang.bigasterisk.com +10.2.0.133 bigasterisk.com cam-int.bigasterisk.com cam-ext.bigasterisk.com imap.bigasterisk.com repo.bigasterisk.com drewp.quickwitretort.com photo.bigasterisk.com projects.bigasterisk.com quickwitretort.com whatsplayingnext.com whopickedthis.com vpn-home.bigasterisk.com file.bigasterisk.com antigen-superset.bigasterisk.com authenticate.bigasterisk.com authenticate2.bigasterisk.com authenticate3.bigasterisk.com megasecond.club hass.bigasterisk.com bitwarden.bigasterisk.com livegrep.bigasterisk.com dev.bigasterisk.com apprise.bigasterisk.com sco-bot-prefect.bigasterisk.com paperless.bigasterisk.com linkwarden.bigasterisk.com jellyfin.bigasterisk.com viseron.bigasterisk.com chat.bigasterisk.com + +# deleteme +162.243.138.136 light9.bigasterisk.com + +# VIPs on ditto +10.2.0.11 mqtt1 mqtt1.bigasterisk.com +10.2.0.12 mqtt2 mqtt2.bigasterisk.com +# might be used for syncthing +10.2.0.13 mqtt3 mqtt3.bigasterisk.com +10.2.0.14 mqtt4 mqtt4.bigasterisk.com + +10.2.0.15 victorialogs.bigasterisk.com + +# sync with /my/proj/infra/inventory.py +# and with templates/wireguard/wg0.conf.j2 +# Hosts with fixed wg0 addresses: +10.5.0.1 bang5.bigasterisk.com local.bigasterisk.com reg +10.5.0.2 prime5.bigasterisk.com prime.bigasterisk.com +10.5.0.5 dash5.bigasterisk.com +10.5.0.6 slash5.bigasterisk.com +10.5.0.7 ditto5.bigasterisk.com +10.5.0.14 ga-iot5.bigasterisk.com +10.5.0.17 frontbed5.bigasterisk.com +10.5.0.30 dot5.bigasterisk.com +10.5.0.31 ws-printer5.bigasterisk.com +10.5.0.32 gn-music5.bigasterisk.com +10.5.0.33 li-drums5.bigasterisk.com +10.5.0.110 plus5.bigasterisk.com +10.5.0.111 pillow.bigasterisk.com pillow5.bigasterisk.com +10.5.0.112 drew-note5.bigasterisk.com +10.5.0.113 tofu.bigasterisk.com tofu5.bigasterisk.com + +{% if net == '10.2' %} +# Hosts with fixed addrs who don't introduce via dhcp: +# 162.243.138.136 prime.bigasterisk.com +10.2.0.3 pipe pipe.bigasterisk.com +# from netdevices.n3 +10.2.0.133 ditto ditto.bigasterisk.com +{% endif %} + +{% if net == '10.5' %} +# Names that should be routed on wg0 when the DNS lookup is on wg0: +10.5.0.1 bang.bigasterisk.com +10.5.0.5 dash.bigasterisk.com +10.5.0.6 slash.bigasterisk.com +10.5.0.7 ditto.bigasterisk.com +10.5.0.14 ga-iot.bigasterisk.com +10.5.0.17 frontbed.bigasterisk.com +10.5.0.30 dot.bigasterisk.com +10.5.0.110 plus.bigasterisk.com +10.5.0.112 drew-note.bigasterisk.com +{% endif %}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dns/templates/hosts.j2 Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,23 @@ +# written by pyinfra + +127.0.0.1 localhost +127.0.1.1 {{ host.name }} + +# The following lines are desirable for IPv6 capable hosts +::1 ip6-localhost ip6-loopback +fe00::0 ip6-localnet +ff00::0 ip6-mcastprefix +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters + + +{% if 'laptop' in host.groups or 'hosted' in host.groups %} +10.5.0.1 bang bang.bigasterisk.com bang5 bang5.bigasterisk.com +10.5.0.7 ditto ditto.bigasterisk.com ditto5 ditto5.bigasterisk.com +10.5.0.5 dash +{% endif %} + +{% if host.name == 'prime' %} +# for wireguard setup: +127.0.0.1 public.bigasterisk.com +{% endif %}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dns/templates/resolved.conf.j2 Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,25 @@ +# written by pyinfra + +# See resolved.conf(5) for details + +{% if host.name == 'prime' %} +[Resolve] +# This list is tried randomly, not in order, so we could have +# some trouble with internal names +DNS=10.5.0.1 8.8.8.8 8.8.4.4 +Domains=bigasterisk.com + +{% else %} +[Resolve] +# worst case- you might get a better one over DHCP, which would get listed AFTER this one so it needs to be the only one. +#DNS=10.2.0.4 +#FallbackDNS= +Domains=bigasterisk.com +#LLMNR=no +#MulticastDNS=no +#DNSSEC=no +#DNSOverTLS=no +#Cache=yes +#DNSStubListener=yes +#ReadEtcHosts=yes +{% endif %} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dnsmasq_exporter.service Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,15 @@ +unused? + +# written by pyinfra + +[Unit] +Description=send updated leases to dnsmasq_exporter +After=dnsmasq_10.2.service + +[Service] +Type=simple + +ExecStart=zsh -c 'print /opt/dnsmasq/10.2/leases | entr curl http://10.5.0.7:9998/leases -H "content-type: text/plain" -d "@/opt/dnsmasq/10.2/leases"' + +[Install] +WantedBy=multi-user.target
--- a/files/dnsmasq/dnsmasq-mtail.service Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -# written by pyinfra - -[Unit] -Description=dnsmasq-mtail for 10.2 network -After=dnsmasq_10.2.service - -[Service] -Type=simple - -ExecStart=zsh /opt/dnsmasq/10.2/run_mtail.sh - -[Install] -WantedBy=multi-user.target
--- a/files/dnsmasq/metrics.mtail Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -counter dnsmasq_no_addr_errors -/no address available/ { - dnsmasq_no_addr_errors++ -} - -counter dnsmasq_dhcp_requests -/DHCPREQUEST/ { - dnsmasq_dhcp_requests++ -} - -counter dnsmasq_dhcp_acks -/DHCPACK/ { - dnsmasq_dhcp_acks++ -} - -counter dnsmasq_dhcp_discovers -/DHCPDISCOVER/ { - dnsmasq_dhcp_discovers++ -} - -counter dnsmasq_dhcp_offers -/DHCPOFFER/ { - dnsmasq_dhcp_offers++ -} - -gauge dnsmasq_dns_queries_answered_locally -gauge dnsmasq_dns_queries_forwarded by server -gauge dnsmasq_dns_queries_retried_or_failed by server - -/queries forwarded (?P<fwd>\d+), queries answered locally (?P<loc>\d+)/ { - dnsmasq_dns_queries_answered_locally = $loc -} - -/server (?P<svr>\S+)#53: queries sent (?P<sent>\d+), retried or failed (?P<fail>\d+)/ { - dnsmasq_dns_queries_forwarded[$svr] = $sent - dnsmasq_dns_queries_retried_or_failed[$svr] = $fail -} \ No newline at end of file
--- a/files/dnsmasq/run_mtail.sh Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -#!/bin/zsh -STATS_PERIOD=2m -while (true) { pkill --signal USR1 --oldest --full /usr/sbin/dnsmasq; sleep ${STATS_PERIOD} } & - -rm -f /tmp/dnsmasq_log_pipe -mkfifo /tmp/dnsmasq_log_pipe - -{ journalctl -fu dnsmasq_10.2.service > /tmp/dnsmasq_log_pipe } & - -mtail -port 9991 -logtostderr -logs /tmp/dnsmasq_log_pipe -progs /opt/dnsmasq/10.2 -#-disable_fsnotify -poll_interval ${STATS_PERIOD} \ No newline at end of file
--- a/files/fstab/bang Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -# written by pyinfra - -# <file system> <mount point> <type> <options> <dump> <pass> -/dev/disk/by-uuid/8c7a2d08-60d1-486a-8136-d9f43d83a064 / ext4 relatime 0 0 -/dev/disk/by-uuid/d9a1e1e4-9eba-4988-8b01-c5f6732a2972 /d3 ext4 noatime 0 0 -/dev/disk/by-partuuid/77687eec-15bf-9345-b420-bb83659e6a6b /d4 ext4 noatime 0 0 - -ditto5:/my /my nfs rw,noatime 0 0
--- a/files/fstab/dash Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -# written by pyinfra - -# <file system> <mount point> <type> <options> <dump> <pass> -/dev/disk/by-uuid/d8d23ff1-7c37-4a7d-9fc4-55fc61f912a0 / ext4 defaults 0 1 -/dev/disk/by-uuid/CB55-821E /boot/efi vfat defaults 0 1 - -UUID=73bcd201-5f77-4f68-9fba-47835c3c1692 /d2 ext4 defaults 0 0 -UUID=6cae1c30-3c91-4aa7-9e9f-fcbd7ff706fe /d3 ext4 defaults 0 0 -UUID=3b6780e0-ec86-43be-8d09-e462dbad762e /d4 ext4 defaults 0 0 - -ditto5:/my /my nfs rw,noatime 0 0
--- a/files/fstab/ditto Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -# written by pyinfra - - -# -# Use 'blkid' to print the universally unique identifier for a -# device; this may be used with UUID= as a more robust way to name devices -# that works even if disks are added and removed. See fstab(5). -# -# <file system> <mount point> <type> <options> <dump> <pass> -/dev/disk/by-uuid/6e64ce62-34db-4084-9385-d001e99ad38b / ext4 defaults 0 1 -/dev/disk/by-uuid/3F95-42F4 /boot/efi vfat defaults 0 1 -/dev/disk/by-uuid/74795c77-ed20-417d-988a-abc09c3dfc27 /d2 ext4 defaults 0 1 - -
--- a/files/fstab/dot Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -# written by pyinfra - -# <file system> <mount point> <type> <options> <dump> <pass> - - - -/dev/disk/by-uuid/a9403f0b-aa16-4096-ab0d-2e2069d3f18a / ext4 defaults 0 1 - -/dev/mapper/ubuntu--vg-ubuntu--lv /d2 ext4 defaults 0 1 -/dev/disk/by-uuid/5a6ce8db-cde0-4c26-b6a4-08faef2e01a2 /d3 ext4 defaults 0 1
--- a/files/fstab/slash Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -# written by pyinfra - -# <file system> <mount point> <type> <options> <dump> <pass> -UUID=df079890-9431-4e17-940c-d9ed8ce4e149 / ext4 errors=remount-ro 0 1 -UUID=1CFA-995B /boot/efi vfat umask=0077 0 1 - -ditto5:/my /my nfs rw,noatime 0 0
--- a/files/fstab/tofu Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -# written by pyinfra - -# <file system> <mount point> <type> <options> <dump> <pass> -/dev/nvme0n1p6 / ext4 rw,relatime 0 0
--- a/files/kube/k3s-killall.sh Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -#!/bin/sh -[ $(id -u) -eq 0 ] || exec sudo $0 $@ - -for bin in /var/lib/rancher/k3s/data/**/bin/; do - [ -d $bin ] && export PATH=$PATH:$bin:$bin/aux -done - -set -x - -for service in /etc/systemd/system/k3s*.service; do - [ -s $service ] && systemctl stop $(basename $service) -done - -for service in /etc/init.d/k3s*; do - [ -x $service ] && $service stop -done - -pschildren() { - ps -e -o ppid= -o pid= | \ - sed -e 's/^\s*//g; s/\s\s*/\t/g;' | \ - grep -w "^$1" | \ - cut -f2 -} - -pstree() { - for pid in $@; do - echo $pid - for child in $(pschildren $pid); do - pstree $child - done - done -} - -killtree() { - kill -9 $( - { set +x; } 2>/dev/null; - pstree $@; - set -x; - ) 2>/dev/null -} - -getshims() { - ps -e -o pid= -o args= | sed -e 's/^ *//; s/\s\s*/\t/;' | grep -w 'k3s/data/[^/]*/bin/containerd-shim' | cut -f1 -} - -killtree $({ set +x; } 2>/dev/null; getshims; set -x) - -do_unmount_and_remove() { - set +x - while read -r _ path _; do - case "$path" in $1*) echo "$path" ;; esac - done < /proc/self/mounts | sort -r | xargs -r -t -n 1 sh -c 'umount "$0" && rm -rf "$0"' - set -x -} - -do_unmount_and_remove '/run/k3s' -do_unmount_and_remove '/var/lib/rancher/k3s' -do_unmount_and_remove '/var/lib/kubelet/pods' -do_unmount_and_remove '/var/lib/kubelet/plugins' -do_unmount_and_remove '/run/netns/cni-' - -# Remove CNI namespaces -ip netns show 2>/dev/null | grep cni- | xargs -r -t -n 1 ip netns delete - -# Delete network interface(s) that match 'master cni0' -ip link show 2>/dev/null | grep 'master cni0' | while read ignore iface ignore; do - iface=${iface%%@*} - [ -z "$iface" ] || ip link delete $iface -done -ip link delete cni0 -ip link delete flannel.1 -ip link delete flannel-v6.1 -ip link delete kube-ipvs0 -rm -rf /var/lib/cni/ -iptables-save | grep -v KUBE- | grep -v CNI- | grep -v flannel | iptables-restore -ip6tables-save | grep -v KUBE- | grep -v CNI- | grep -v flannel | ip6tables-restore
--- a/files/kube/k3s-uninstall.sh Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -#!/bin/sh -set -x -[ $(id -u) -eq 0 ] || exec sudo $0 $@ - -/usr/local/bin/k3s-killall.sh - -if command -v systemctl; then - systemctl disable k3s - systemctl reset-failed k3s - systemctl daemon-reload -fi -if command -v rc-update; then - rc-update delete k3s default -fi - -rm -f /etc/systemd/system/k3s.service -rm -f /etc/systemd/system/k3s.service.env - -remove_uninstall() { - rm -f /usr/local/bin/k3s-uninstall.sh -} -trap remove_uninstall EXIT - -if (ls /etc/systemd/system/k3s*.service || ls /etc/init.d/k3s*) >/dev/null 2>&1; then - set +x; echo 'Additional k3s services installed, skipping uninstall of k3s'; set -x - exit -fi - -for cmd in kubectl crictl ctr; do - if [ -L /usr/local/bin/$cmd ]; then - rm -f /usr/local/bin/$cmd - fi -done - -rm -rf /etc/rancher/k3s -rm -rf /run/k3s -rm -rf /run/flannel -rm -rf /var/lib/rancher/k3s -rm -rf /var/lib/kubelet -rm -f /usr/local/bin/k3s -rm -f /usr/local/bin/k3s-killall.sh - -if type yum >/dev/null 2>&1; then - yum remove -y k3s-selinux - rm -f /etc/yum.repos.d/rancher-k3s-common*.repo -elif type zypper >/dev/null 2>&1; then - uninstall_cmd="zypper remove -y k3s-selinux" - if [ "${TRANSACTIONAL_UPDATE=false}" != "true" ] && [ -x /usr/sbin/transactional-update ]; then - uninstall_cmd="transactional-update --no-selfupdate -d run $uninstall_cmd" - fi - $uninstall_cmd - rm -f /etc/zypp/repos.d/rancher-k3s-common*.repo -fi
--- a/files/kube/kubelet.config Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -apiVersion: kubelet.config.k8s.io/v1beta1 -kind: KubeletConfiguration -maxPods: 250
--- a/files/net/ditto-netplan.yaml Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -# written by pyinfra -network: - ethernets: - eno1: - addresses: - # name=ditto - - 10.2.0.133/16 - # name=mqtt1 etc - - 10.2.0.11/16 - - 10.2.0.12/16 - - 10.2.0.13/16 - - 10.2.0.14/16 - routes: - - to: default - via: 10.2.0.3 - nameservers: - addresses: [10.2.0.3] - enp5s0: - dhcp4: true - ens3: - dhcp4: true - version: 2
--- a/files/net/house_net.service Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -# written by pyinfra - -[Unit] -After=network-online.target nss-lookup.target -Wants=network-online.target nss-lookup.target - -[Service] -Type=oneshot -ExecStart=sh -c "sysctl net.ipv4.ip_forward=1 && /usr/sbin/iptables -A POSTROUTING --table nat --out-interface eth0 --jump MASQUERADE" -RemainAfterExit=yes - - -[Install] -WantedBy=multi-user.target
--- a/files/net/pipe_10.2.network Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -# written by pyinfra - -[Match] -# usb dongle -MACAddress=00:05:1b:33:3e:81 - -[Network] -DHCP=no -Address=10.2.0.3/16 -# vip for the filtered dns server we give clients who are to have sometimes-filtered domains -Address=10.2.0.4/16 -DNS=10.2.0.3 -Domains=bigasterisk.com -
--- a/files/net/pipe_isp.network Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -# written by pyinfra - -[Match] -# onboard eth -MACAddress=00:1e:06:43:20:d0 - -[Network] -DHCP=no -Address=192.168.42.3/24 -Gateway=192.168.42.1 -DNS=10.2.0.1 -Domains=bigasterisk.com \ No newline at end of file
--- a/files/net/prime.network Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -# written by pyinfra - -# see systemd.network(5) - -[Match] -MACAddress=04:01:09:7f:89:01 - -[Network] -Address=162.243.138.136/24 -Gateway=162.243.138.1 -DNS=10.5.0.1%wg0 -DNS=8.8.8.8 -DNS=8.8.4.4 -Domains=bigasterisk.com \ No newline at end of file
--- a/files/net/singlenic.network Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -# written by pyinfra - -[Match] -Name=* - -[Network] -DHCP=yes -# this sauce may or may not help with k3s -LinkLocalAddressing=yes -IPForward=yes \ No newline at end of file
--- a/files/pi_wlan0_powersave Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -# written by pyinfra - -auto wlan0 -iface wlan0 inet dhcp - post-up iw wlan0 set power_save off
--- a/files/pigpiod.service Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -# written by pyinfra - -[Unit] -Description=Daemon required to control GPIO pins via pigpio - -[Service] -Type=simple -ExecStart=/usr/bin/pigpiod -g -p 8888 - -[Install] -WantedBy=multi-user.target
--- a/home.py Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -from pyinfra import host -from pyinfra.operations import files, server - -if host.data.get('drewp_home'): - # maybe bring sync.py in here too - - server.shell(commands=['chsh -s /bin/zsh drewp']) - files.link(path='/home/drewp/.aptitude/config', target='../own/config/aptitude-config', force=True) - files.link(path='/home/drewp/.config/blender', target='../own/config/blender', force=True) - files.link(path='/home/drewp/.config/i3', target='../own/config/i3', force=True) - files.link(path='/home/drewp/.emacs.d', target='own/config/emacs-d', force=True) - files.link(path='/home/drewp/.fonts', target='own/config/fonts', force=True) - files.link(path='/home/drewp/.fvwm2rc', target='own/config/fvwm2rc', force=True) - files.link(path='/home/drewp/.hgrc', target='own/config/hgrc', force=True) - files.link(path='/home/drewp/.kitty', target='own/config/kitty', force=True) - files.link(path='/home/drewp/.zshrc', target='own/config/zshrc', force=True) - files.link(path='/home/drewp/bin', target='own/config/bin/', force=True) - files.link(path='/home/drewp/blenderkit_data', target='own/gfx-lib/blenderkit_data/', force=True) - -#drwx------ 3 drewp drewp 4096 Jul 31 15:07 .config/syncthing -#npm.rc? -# run on bang: pnpm server --background start
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/home/home.py Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,27 @@ +from pyinfra.context import host +from pyinfra.operations import files, server + +def drewp_home_sync_links(): + if host.data.get('drewp_home'): + # maybe bring sync.py in here too + + server.shell(commands=['chsh -s /bin/zsh drewp']) + files.link(path='/home/drewp/.aptitude/config', target='../own/config/aptitude-config', force=True) + files.link(path='/home/drewp/.config/blender', target='../own/config/blender', force=True) + files.link(path='/home/drewp/.config/i3', target='../own/config/i3', force=True) + files.link(path='/home/drewp/.emacs.d', target='own/config/emacs-d', force=True) + files.link(path='/home/drewp/.fonts', target='own/config/fonts', force=True) + files.link(path='/home/drewp/.fvwm2rc', target='own/config/fvwm2rc', force=True) + files.link(path='/home/drewp/.hgrc', target='own/config/hgrc', force=True) + files.link(path='/home/drewp/.kitty', target='own/config/kitty', force=True) + files.link(path='/home/drewp/.zshrc', target='own/config/zshrc', force=True) + files.link(path='/home/drewp/bin', target='own/config/bin/', force=True) + files.link(path='/home/drewp/blenderkit_data', target='own/gfx-lib/blenderkit_data/', force=True) + +#drwx------ 3 drewp drewp 4096 Jul 31 15:07 .config/syncthing +#npm.rc? +# run on bang: pnpm server --background start + +operations = [ + drewp_home_sync_links, +] \ No newline at end of file
--- a/k8s_reserve/deploy.yaml Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: reserve-cpu-dash -spec: - replicas: 1 - selector: - matchLabels: - app.kubernetes.io/name: reserve-cpu-dash - template: - metadata: - labels: - app.kubernetes.io/name: reserve-cpu-dash - annotations: { prometheus.io/scrape: "false" } - spec: - containers: - - name: sleep - image: "docker.io/rancher/pause:3.6" - resources: {requests: {cpu: "3"}} - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: "kubernetes.io/hostname" - operator: In - values: ["dash"]
--- a/k8s_reserve/readme Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -It's ok for k8s to use dash's ram, but it can also tie up so much cpu (notably with frigate) that I notice stalls on my desktop. - -The plan is to make a sleeper job with required.cpu=N to reserve N cpus from getting scheduled with real work.
--- a/kube.py Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,192 +0,0 @@ -import io -import os -import subprocess -from tempfile import NamedTemporaryFile - -from pyinfra import host -from pyinfra.facts.files import FindInFile -from pyinfra.facts.server import Arch, LinuxDistribution -from pyinfra.operations import files, server, systemd, apt - -# https://github.com/GoogleContainerTools/skaffold/releases -skaffold_version = 'v2.13.2' - - -def download_k3s(k3s_version): - tail = 'k3s' if host.get_fact(Arch) == 'x86_64' else 'k3s-armhf' - if host.get_fact(Arch) == 'aarch64': - tail = 'k3s-arm64' - files.download( - src=f'https://github.com/rancher/k3s/releases/download/{k3s_version}/{tail}', - dest='/usr/local/bin/k3s', - user='root', - group='root', - mode='755', - cache_time=43000, - # force=True, # to get a new version - ) - - -def install_skaffold(reg): - files.download(src=f'https://storage.googleapis.com/skaffold/releases/{skaffold_version}/skaffold-linux-amd64', - dest='/usr/local/bin/skaffold', - user='root', - group='root', - mode='755', - cache_time=1000) - # one time; writes to $HOME - server.shell(commands=f"skaffold config set --global insecure-registries {reg}") - - -def host_prep(): - server.sysctl(key='net.ipv4.ip_forward', value="1", persist=True) - server.sysctl(key='net.ipv6.conf.all.forwarding', value="1", persist=True) - server.sysctl(key='fs.inotify.max_user_instances', value='8192', persist=True) - server.sysctl(key='fs.inotify.max_user_watches', value='524288', persist=True) - - # https://sysctl-explorer.net/net/ipv4/rp_filter/ - none, strict, loose = 0, 1, 2 - server.sysctl(key='net.ipv4.conf.default.rp_filter', value=loose, persist=True) - - -# don't try to get aufs-dkms on rpi-- https://github.com/docker/for-linux/issues/709 -def podman_insecure_registry(reg): - # docs: https://rancher.com/docs/k3s/latest/en/installation/private-registry/ - # user confusions: https://github.com/rancher/k3s/issues/1802 - files.template(src='templates/kube/registries.yaml.j2', dest='/etc/rancher/k3s/registries.yaml', reg=reg) - - files.template(src='templates/kube/podman_registries.conf.j2', dest='/etc/containers/registries.conf.d/reg.conf', reg=reg) - if host.data.get('k8s_admin'): - systemd.service(service='podman', user_mode=True) - systemd.service(service='podman.socket', user_mode=True) - # and maybe edit /etc/containers/policy.json - - -def config_and_run_service(k3s_version, server_node, server_ip): - download_k3s(k3s_version) - service_name = 'k3s.service' if host.name == server_node else 'k3s-node.service' - role = 'server' if host.name == server_node else 'agent' - which_conf = 'config-server.yaml.j2' if host.name == server_node else 'config-agent.yaml.j2' - - files.put(src="files/kube/kubelet.config", dest="/etc/rancher/k3s/kubelet.config") - - # /var/lib/rancher/k3s/server/node-token is the source of the string in secrets/k3s_token, - # so this presumes a previous run - if host.name == server_node: - token = "ununsed" - else: - # this assumes localhost is the k3s server. - if not os.path.exists('/var/lib/rancher/k3s/server/node-token'): - print("first pass is for server only- skipping other nodes") - return - token = open('/var/lib/rancher/k3s/server/node-token', 'rt').read().strip() - files.template( - src=f'templates/kube/{which_conf}', - dest='/etc/k3s_config.yaml', - server_ip=server_ip, - token=token, - wg_ip=host.host_data['wireguard_address'], - ) - files.template( - src='templates/kube/k3s.service.j2', - dest=f'/etc/systemd/system/{service_name}', - role=role, - ) - if not host.data.get('gpu'): - # no supported gpu - ''' - kubectl label --overwrite node bang nvidia.com/gpu.deploy.gpu-feature-discovery=false - kubectl label --overwrite node bang nvidia.com/gpu.deploy.container-toolkit=false - kubectl label --overwrite node bang nvidia.com/gpu.deploy.dcgm-exporter=false - kubectl label --overwrite node bang nvidia.com/gpu.deploy.device-plugin=false - kubectl label --overwrite node bang nvidia.com/gpu.deploy.driver=false - kubectl label --overwrite node bang nvidia.com/gpu.deploy.mig-manager=false - kubectl label --overwrite node bang nvidia.com/gpu.deploy.operator-validator=false - ''' - systemd.service(service=service_name, daemon_reload=True, enabled=True, restarted=True) - - -def setupNvidiaToolkit(): - # guides: - # https://github.com/NVIDIA/k8s-device-plugin#prerequisites - # https://docs.k3s.io/advanced#nvidia-container-runtime-support - # apply this once to kube-system: https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.14.3/nvidia-device-plugin.yml - # apply this once: https://raw.githubusercontent.com/NVIDIA/gpu-feature-discovery/v0.8.2/deployments/static/nfd.yaml - # and: kubectl apply -f https://raw.githubusercontent.com/NVIDIA/gpu-feature-discovery/v0.8.2/deployments/static/gpu-feature-discovery-daemonset.yaml - - # k3s says they do this: - #server.shell('nvidia-ctk runtime configure --runtime=containerd --config /var/lib/rancher/k3s/agent/etc/containerd/config.toml') - - # then caller restarts k3s which includes containerd - - # tried https://github.com/k3s-io/k3s/discussions/9231#discussioncomment-8114243 - pass - - -def make_cluster( - server_ip, - server_node, - nodes, - # https://github.com/k3s-io/k3s/releases - # 1.23.6 per https://github.com/cilium/cilium/issues/20331 - k3s_version, -): - if host.name in nodes + [server_node]: - host_prep() - files.directory(path='/etc/rancher/k3s') - - podman_insecure_registry(reg='reg:5000') - # also note that podman dropped the default `docker.io/` prefix on image names (see https://unix.stackexchange.com/a/701785/419418) - config_and_run_service(k3s_version, server_node, server_ip) - - if host.data.get('k8s_admin'): - files.directory(path='/etc/rancher/k3s') - install_skaffold("reg:5000") - files.link(path='/usr/local/bin/kubectl', target='/usr/local/bin/k3s') - files.directory(path='/home/drewp/.kube', user='drewp', group='drewp') - - # assumes our pyinfra process is running on server_node - files.put( - src='/etc/rancher/k3s/k3s.yaml', - dest='/etc/rancher/k3s/k3s.yaml', # - user='root', - group='drewp', - mode='640') - server.shell( - commands=f"kubectl config set-cluster default --server=https://{server_ip}:6443 --kubeconfig=/etc/rancher/k3s/k3s.yaml" - ) - - -def run_non_k8s_telegraf(node): - if host.name != node: - return - # this CM is written by /my/serv/telegraf/tasks.py - conf = io.BytesIO(subprocess.check_output(["kubectl", "get", "cm", "telegraf-config", "-o", "jsonpath={.data." + node + "}"])) - apt.packages(packages=['telegraf']) - files.put(src=conf, dest="/etc/telegraf/telegraf.conf", create_remote_dir=True, assume_exists=True) - systemd.service( - service='telegraf', - running=True, - enabled=True, - restarted=True, - ) - - -make_cluster( - server_ip="10.5.0.7", - server_node='ditto', - nodes=[ - 'bang', - 'slash', - 'dash', - 'ws-printer', - 'ga-iot', - 'li-drums', - # 'gn-music', - ], - k3s_version='v1.29.1+k3s1') - -run_non_k8s_telegraf('pipe') -# consider https://github.com/derailed/k9s/releases/download/v0.32.4/k9s_Linux_amd64.tar.gz - -# k label node ws-printer unschedulable=octoprint-allowed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kube/coredns/coredns.yaml Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,228 @@ +unused? needs server ip fixes + + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: coredns + namespace: kube-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + kubernetes.io/bootstrapping: rbac-defaults + name: system:coredns +rules: +- apiGroups: + - "" + resources: + - endpoints + - services + - pods + - namespaces + verbs: + - list + - watch +- apiGroups: + - discovery.k8s.io + resources: + - endpointslices + verbs: + - list + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + annotations: + rbac.authorization.kubernetes.io/autoupdate: "true" + labels: + kubernetes.io/bootstrapping: rbac-defaults + name: system:coredns +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:coredns +subjects: +- kind: ServiceAccount + name: coredns + namespace: kube-system +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: coredns + namespace: kube-system +data: + Corefile: | + # update 2022-11-26T23:47 + .:53 { + errors + health + ready + kubernetes cluster.local in-addr.arpa ip6.arpa { + pods insecure + fallthrough in-addr.arpa ip6.arpa + } + hosts /etc/coredns/NodeHosts { + ttl 60 + reload 15s + fallthrough + } + prometheus :9153 + forward . dns://10.2.0.3 + cache 30 + loop + reload + loadbalance + log + } +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: coredns + namespace: kube-system + labels: + k8s-app: kube-dns + kubernetes.io/name: "CoreDNS" +spec: + #replicas: 1 + strategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + selector: + matchLabels: + k8s-app: kube-dns + template: + metadata: + labels: + k8s-app: kube-dns + spec: + priorityClassName: "system-cluster-critical" + serviceAccountName: coredns + tolerations: + - key: "CriticalAddonsOnly" + operator: "Exists" + - key: "node-role.kubernetes.io/control-plane" + operator: "Exists" + effect: "NoSchedule" + - key: "node-role.kubernetes.io/master" + operator: "Exists" + effect: "NoSchedule" + nodeSelector: + kubernetes.io/os: linux + affinity: # because dns is broken so often, and it might be a circular config that can't start unless this is on bang + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: "kubernetes.io/hostname" + operator: In + values: ["bang"] + topologySpreadConstraints: + - maxSkew: 1 + topologyKey: kubernetes.io/hostname + whenUnsatisfiable: DoNotSchedule + labelSelector: + matchLabels: + k8s-app: kube-dns + containers: + - name: coredns + image: rancher/mirrored-coredns-coredns:1.9.1 + imagePullPolicy: IfNotPresent + resources: + limits: + memory: 170Mi + requests: + cpu: 100m + memory: 70Mi + args: [ "-conf", "/etc/coredns/Corefile" ] + volumeMounts: + - name: config-volume + mountPath: /etc/coredns + readOnly: true + - name: custom-config-volume + mountPath: /etc/coredns/custom + readOnly: true + ports: + - containerPort: 53 + name: dns + protocol: UDP + - containerPort: 53 + name: dns-tcp + protocol: TCP + - containerPort: 9153 + name: metrics + protocol: TCP + securityContext: + allowPrivilegeEscalation: false + capabilities: + add: + - NET_BIND_SERVICE + drop: + - all + readOnlyRootFilesystem: true + livenessProbe: + httpGet: + path: /health + port: 8080 + scheme: HTTP + initialDelaySeconds: 60 + periodSeconds: 10 + timeoutSeconds: 1 + successThreshold: 1 + failureThreshold: 3 + readinessProbe: + httpGet: + path: /ready + port: 8181 + scheme: HTTP + initialDelaySeconds: 0 + periodSeconds: 2 + timeoutSeconds: 1 + successThreshold: 1 + failureThreshold: 3 + dnsPolicy: Default + volumes: + - name: config-volume + configMap: + name: coredns + items: + - key: Corefile + path: Corefile + - key: NodeHosts + path: NodeHosts + - name: custom-config-volume + configMap: + name: coredns-custom + optional: true +--- +apiVersion: v1 +kind: Service +metadata: + name: kube-dns + namespace: kube-system + annotations: + prometheus.io/port: "9153" + prometheus.io/scrape: "true" + labels: + k8s-app: kube-dns + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" +spec: + selector: + k8s-app: kube-dns + clusterIP: '10.5.0.1' + ports: + - name: dns + port: 53 + protocol: UDP + - name: dns-tcp + port: 53 + protocol: TCP + - name: metrics + port: 9153 + protocol: TCP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kube/coredns/coredns_freshen.sh Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,3 @@ +#!/bin/zsh +kubectl apply -f ./coredns.yaml +kubectl get -n kube-system configmap/coredns -o yaml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kube/files/kubelet.config Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,3 @@ +apiVersion: kubelet.config.k8s.io/v1beta1 +kind: KubeletConfiguration +maxPods: 250
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kube/k3s-killall.sh Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,76 @@ +#!/bin/sh +[ $(id -u) -eq 0 ] || exec sudo $0 $@ + +for bin in /var/lib/rancher/k3s/data/**/bin/; do + [ -d $bin ] && export PATH=$PATH:$bin:$bin/aux +done + +set -x + +for service in /etc/systemd/system/k3s*.service; do + [ -s $service ] && systemctl stop $(basename $service) +done + +for service in /etc/init.d/k3s*; do + [ -x $service ] && $service stop +done + +pschildren() { + ps -e -o ppid= -o pid= | \ + sed -e 's/^\s*//g; s/\s\s*/\t/g;' | \ + grep -w "^$1" | \ + cut -f2 +} + +pstree() { + for pid in $@; do + echo $pid + for child in $(pschildren $pid); do + pstree $child + done + done +} + +killtree() { + kill -9 $( + { set +x; } 2>/dev/null; + pstree $@; + set -x; + ) 2>/dev/null +} + +getshims() { + ps -e -o pid= -o args= | sed -e 's/^ *//; s/\s\s*/\t/;' | grep -w 'k3s/data/[^/]*/bin/containerd-shim' | cut -f1 +} + +killtree $({ set +x; } 2>/dev/null; getshims; set -x) + +do_unmount_and_remove() { + set +x + while read -r _ path _; do + case "$path" in $1*) echo "$path" ;; esac + done < /proc/self/mounts | sort -r | xargs -r -t -n 1 sh -c 'umount "$0" && rm -rf "$0"' + set -x +} + +do_unmount_and_remove '/run/k3s' +do_unmount_and_remove '/var/lib/rancher/k3s' +do_unmount_and_remove '/var/lib/kubelet/pods' +do_unmount_and_remove '/var/lib/kubelet/plugins' +do_unmount_and_remove '/run/netns/cni-' + +# Remove CNI namespaces +ip netns show 2>/dev/null | grep cni- | xargs -r -t -n 1 ip netns delete + +# Delete network interface(s) that match 'master cni0' +ip link show 2>/dev/null | grep 'master cni0' | while read ignore iface ignore; do + iface=${iface%%@*} + [ -z "$iface" ] || ip link delete $iface +done +ip link delete cni0 +ip link delete flannel.1 +ip link delete flannel-v6.1 +ip link delete kube-ipvs0 +rm -rf /var/lib/cni/ +iptables-save | grep -v KUBE- | grep -v CNI- | grep -v flannel | iptables-restore +ip6tables-save | grep -v KUBE- | grep -v CNI- | grep -v flannel | ip6tables-restore
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kube/k3s-uninstall.sh Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,53 @@ +#!/bin/sh +set -x +[ $(id -u) -eq 0 ] || exec sudo $0 $@ + +/usr/local/bin/k3s-killall.sh + +if command -v systemctl; then + systemctl disable k3s + systemctl reset-failed k3s + systemctl daemon-reload +fi +if command -v rc-update; then + rc-update delete k3s default +fi + +rm -f /etc/systemd/system/k3s.service +rm -f /etc/systemd/system/k3s.service.env + +remove_uninstall() { + rm -f /usr/local/bin/k3s-uninstall.sh +} +trap remove_uninstall EXIT + +if (ls /etc/systemd/system/k3s*.service || ls /etc/init.d/k3s*) >/dev/null 2>&1; then + set +x; echo 'Additional k3s services installed, skipping uninstall of k3s'; set -x + exit +fi + +for cmd in kubectl crictl ctr; do + if [ -L /usr/local/bin/$cmd ]; then + rm -f /usr/local/bin/$cmd + fi +done + +rm -rf /etc/rancher/k3s +rm -rf /run/k3s +rm -rf /run/flannel +rm -rf /var/lib/rancher/k3s +rm -rf /var/lib/kubelet +rm -f /usr/local/bin/k3s +rm -f /usr/local/bin/k3s-killall.sh + +if type yum >/dev/null 2>&1; then + yum remove -y k3s-selinux + rm -f /etc/yum.repos.d/rancher-k3s-common*.repo +elif type zypper >/dev/null 2>&1; then + uninstall_cmd="zypper remove -y k3s-selinux" + if [ "${TRANSACTIONAL_UPDATE=false}" != "true" ] && [ -x /usr/sbin/transactional-update ]; then + uninstall_cmd="transactional-update --no-selfupdate -d run $uninstall_cmd" + fi + $uninstall_cmd + rm -f /etc/zypp/repos.d/rancher-k3s-common*.repo +fi
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kube/k8s_reserve/deploy.yaml Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,27 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: reserve-cpu-dash +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: reserve-cpu-dash + template: + metadata: + labels: + app.kubernetes.io/name: reserve-cpu-dash + annotations: { prometheus.io/scrape: "false" } + spec: + containers: + - name: sleep + image: "docker.io/rancher/pause:3.6" + resources: {requests: {cpu: "3"}} + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: "kubernetes.io/hostname" + operator: In + values: ["dash"]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kube/k8s_reserve/readme Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,3 @@ +It's ok for k8s to use dash's ram, but it can also tie up so much cpu (notably with frigate) that I notice stalls on my desktop. + +The plan is to make a sleeper job with required.cpu=N to reserve N cpus from getting scheduled with real work.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kube/kube.py Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,203 @@ +import io +import os +import subprocess +from tempfile import NamedTemporaryFile + +from pyinfra.context import host +from pyinfra.facts.files import FindInFile +from pyinfra.facts.server import Arch, LinuxDistribution +from pyinfra.operations import files, server, systemd, apt + +# https://github.com/GoogleContainerTools/skaffold/releases +skaffold_version = 'v2.13.2' + + +def download_k3s(k3s_version): + match host.get_fact(Arch): + case 'x86_64': + tail,sha = 'k3s','dd320550cb32b053f78fb6442a1cd2c0188428c5c817482763a7fb32ea3b87b8' + case 'aarch64': + tail,sha = 'k3s-arm64','9c4cc7586c4999650edbb5312f114d4e9c6517143b1234206a32464397c77c41' + case _: + raise ValueError(f"unknown arch: {host.get_fact(Arch)}") + files.download( + src=f'https://github.com/rancher/k3s/releases/download/{k3s_version}/{tail}', + dest='/usr/local/bin/k3s', + user='root', + group='root', + mode='755', + sha256sum=sha, + cache_time=1000, + ) + + +def install_skaffold(reg): + files.download(src=f'https://storage.googleapis.com/skaffold/releases/{skaffold_version}/skaffold-linux-amd64', + dest='/usr/local/bin/skaffold', + user='root', + group='root', + mode='755', + cache_time=1000) + # one time; writes to $HOME + server.shell(commands=f"skaffold config set --global insecure-registries {reg}") + + +def host_prep(): + server.sysctl(key='net.ipv4.ip_forward', value="1", persist=True) + server.sysctl(key='net.ipv6.conf.all.forwarding', value="1", persist=True) + server.sysctl(key='fs.inotify.max_user_instances', value='8192', persist=True) + server.sysctl(key='fs.inotify.max_user_watches', value='524288', persist=True) + + # https://sysctl-explorer.net/net/ipv4/rp_filter/ + none, strict, loose = 0, 1, 2 + server.sysctl(key='net.ipv4.conf.default.rp_filter', value=loose, persist=True) + + +# don't try to get aufs-dkms on rpi-- https://github.com/docker/for-linux/issues/709 +def podman_insecure_registry(reg): + # docs: https://rancher.com/docs/k3s/latest/en/installation/private-registry/ + # user confusions: https://github.com/rancher/k3s/issues/1802 + files.template(src='kube/templates/registries.yaml.j2', dest='/etc/rancher/k3s/registries.yaml', reg=reg) + + files.template(src='kube/templates/podman_registries.conf.j2', dest='/etc/containers/registries.conf.d/reg.conf', reg=reg) + if host.data.get('k8s_admin'): + systemd.service(service='podman', user_mode=True) + systemd.service(service='podman.socket', user_mode=True) + # and maybe edit /etc/containers/policy.json + + +def config_and_run_service(k3s_version, server_node, server_ip): + download_k3s(k3s_version) + service_name = 'k3s.service' if host.name == server_node else 'k3s-node.service' + role = 'server' if host.name == server_node else 'agent' + which_conf = 'config-server.yaml.j2' if host.name == server_node else 'config-agent.yaml.j2' + + files.put(src="kube/files/kubelet.config", dest="/etc/rancher/k3s/kubelet.config") + + # /var/lib/rancher/k3s/server/node-token is the source of the string in secrets/k3s_token, + # so this presumes a previous run + if host.name == server_node: + token = "ununsed" + else: + # this assumes localhost is the k3s server. + if not os.path.exists('/var/lib/rancher/k3s/server/node-token'): + print("first pass is for server only- skipping other nodes") + return + token = open('/var/lib/rancher/k3s/server/node-token', 'rt').read().strip() + files.template( + src=f'kube/templates/{which_conf}', + dest='/etc/k3s_config.yaml', + server_ip=server_ip, + token=token, + wg_ip=host.host_data['wireguard_address'], + ) + files.template( + src='kube/templates/k3s.service.j2', + dest=f'/etc/systemd/system/{service_name}', + role=role, + ) + if not host.data.get('gpu'): + # no supported gpu + ''' + kubectl label --overwrite node bang nvidia.com/gpu.deploy.gpu-feature-discovery=false + kubectl label --overwrite node bang nvidia.com/gpu.deploy.container-toolkit=false + kubectl label --overwrite node bang nvidia.com/gpu.deploy.dcgm-exporter=false + kubectl label --overwrite node bang nvidia.com/gpu.deploy.device-plugin=false + kubectl label --overwrite node bang nvidia.com/gpu.deploy.driver=false + kubectl label --overwrite node bang nvidia.com/gpu.deploy.mig-manager=false + kubectl label --overwrite node bang nvidia.com/gpu.deploy.operator-validator=false + ''' + systemd.service(service=service_name, daemon_reload=True, enabled=True, restarted=True) + + +def setupNvidiaToolkit(): + # guides: + # https://github.com/NVIDIA/k8s-device-plugin#prerequisites + # https://docs.k3s.io/advanced#nvidia-container-runtime-support + # apply this once to kube-system: https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.14.3/nvidia-device-plugin.yml + # apply this once: https://raw.githubusercontent.com/NVIDIA/gpu-feature-discovery/v0.8.2/deployments/static/nfd.yaml + # and: kubectl apply -f https://raw.githubusercontent.com/NVIDIA/gpu-feature-discovery/v0.8.2/deployments/static/gpu-feature-discovery-daemonset.yaml + + # k3s says they do this: + #server.shell('nvidia-ctk runtime configure --runtime=containerd --config /var/lib/rancher/k3s/agent/etc/containerd/config.toml') + + # then caller restarts k3s which includes containerd + + # tried https://github.com/k3s-io/k3s/discussions/9231#discussioncomment-8114243 + pass + + +def make_cluster( + server_ip, + server_node, + nodes, + # https://github.com/k3s-io/k3s/releases + # 1.23.6 per https://github.com/cilium/cilium/issues/20331 + k3s_version, +): + if host.name in nodes + [server_node]: + host_prep() + files.directory(path='/etc/rancher/k3s') + + podman_insecure_registry(reg='reg:5000') + # also note that podman dropped the default `docker.io/` prefix on image names (see https://unix.stackexchange.com/a/701785/419418) + config_and_run_service(k3s_version, server_node, server_ip) + + if host.data.get('k8s_admin'): + files.directory(path='/etc/rancher/k3s') + install_skaffold("reg:5000") + files.link(path='/usr/local/bin/kubectl', target='/usr/local/bin/k3s') + files.directory(path='/home/drewp/.kube', user='drewp', group='drewp') + + # assumes our pyinfra process is running on server_node + files.put( + src='/etc/rancher/k3s/k3s.yaml', + dest='/etc/rancher/k3s/k3s.yaml', # + user='root', + group='drewp', + mode='640') + server.shell( + commands=f"kubectl config set-cluster default --server=https://{server_ip}:6443 --kubeconfig=/etc/rancher/k3s/k3s.yaml" + ) + + +def run_non_k8s_telegraf(node): + if host.name != node: + return + # this CM is written by /my/serv/telegraf/tasks.py + conf = io.BytesIO(subprocess.check_output(["kubectl", "get", "cm", "telegraf-config", "-o", "jsonpath={.data." + node + "}"])) + apt.packages(packages=['telegraf']) + files.put(src=conf, dest="/etc/telegraf/telegraf.conf", create_remote_dir=True, assume_exists=True) + systemd.service( + service='telegraf', + running=True, + enabled=True, + restarted=True, + ) + + +def main_cluster(): + make_cluster( + server_ip="10.5.0.7", + server_node='ditto', + nodes=[ + 'bang', + 'slash', + 'dash', + 'ws-printer', + 'ga-iot', + 'li-drums', + # 'gn-music', + ], + k3s_version='v1.29.1+k3s1') + + run_non_k8s_telegraf('pipe') + + +operations = [ + main_cluster, +] + +# consider https://github.com/derailed/k9s/releases/download/v0.32.4/k9s_Linux_amd64.tar.gz + +# k label node ws-printer unschedulable=octoprint-allowed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kube/templates/config-agent.yaml.j2 Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,3 @@ +node-ip: {{ wg_ip }} +token: {{ token }} +server: https://{{ server_ip }}:6443
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kube/templates/config-server.yaml.j2 Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,4 @@ +write-kubeconfig-mode: '640' +node-ip: {{ wg_ip }} +disable: + - traefik
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kube/templates/k3s.service.j2 Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,26 @@ +# written by pyinfra + +[Unit] +Description=Lightweight Kubernetes +Documentation=https://k3s.io +After=network-online.target + +[Service] +Type=notify +ExecStartPre=-/sbin/modprobe br_netfilter +ExecStartPre=-/sbin/modprobe overlay +ExecStart=/usr/local/bin/k3s {{ role }} --config /etc/k3s_config.yaml --kubelet-arg=config=/etc/rancher/k3s/kubelet.config +KillMode=process +Delegate=yes +# Having non-zero Limit*s causes performance problems due to accounting overhead +# in the kernel. We recommend using cgroups to do container-local accounting. +LimitNOFILE=1048576 +LimitNPROC=infinity +LimitCORE=infinity +TasksMax=infinity +TimeoutStartSec=0 +Restart=always +RestartSec=5s + +[Install] +WantedBy=multi-user.target
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kube/templates/podman_registries.conf.j2 Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,3 @@ +[[registry]] +location = "{{reg}}" +insecure = true
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kube/templates/registries.yaml.j2 Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,10 @@ +# written by pyinfra + + +# docs: https://rancher.com/docs/k3s/latest/en/installation/private-registry/ + + +mirrors: + "{{reg}}": + endpoint: + - "http://{{reg}}"
--- a/mail.py Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -from pyinfra import host -from pyinfra.operations import apt, files, server, systemd - -if host.name == 'prime': - apt.packages(packages=['postfix', 'isync', 'opendkim', 'opendkim-tools']) - ''' - per domain keygen: - prime(pts/4):~# mkdir /etc/opendkim/keys/chat.bigasterisk.com - prime(pts/4):~# opendkim-genkey -b 1024 -d chat.bigasterisk.com -D /etc/opendkim/keys/chat.bigasterisk.com -s default -v - opendkim-genkey: generating private key - opendkim-genkey: private key written to default.private - opendkim-genkey: extracting public key - opendkim-genkey: DNS TXT record written to default.txt - prime(pts/4):~# chown opendkim /etc/opendkim/keys/*/* - ''' - - files.template(src='templates/mail/opendkim-KeyTable.j2', dest='/etc/opendkim/KeyTable') - files.template(src='templates/mail/opendkim-SigningTable.j2', dest='/etc/opendkim/SigningTable') - files.template(src='templates/mail/opendkim-TrustedHosts.j2', dest='/etc/opendkim/TrustedHosts') - files.template(src='templates/mail/opendkim.conf.j2', dest='/etc/opendkim.conf') - files.put(src='secrets/mail/bigasterisk.com-default.private', - dest='/etc/opendkim/keys/bigasterisk.com/default.private', - mode='0600', user='opendkim') - - files.template(src='templates/mail/opendkim.service.j2', dest='/usr/lib/systemd/system/opendkim.service') - systemd.service(service='opendkim.service', enabled=True, running=True, restarted=True, daemon_reload=True) - - files.template(src='templates/mail/main.cf.j2', dest='/etc/postfix/main.cf') - files.template(src='templates/mail/mydestination.j2', dest='/etc/postfix/mydestination') - files.put(src='secrets/mail/aliases', dest='/etc/postfix/aliases') - files.put(src='secrets/mail/sender_access', dest='/etc/postfix/sender_access') - files.put(src='secrets/mail/virtual', dest='/etc/postfix/virtual') - - server.shell(commands=[ - 'postmap /etc/postfix/sender_access', - 'postmap /etc/postfix/virtual', - 'postmap /etc/postfix/aliases', # broken - 'postfix reload', - ]) - systemd.service(service='postfix@-.service', enabled=True, running=True) - - # something to run ~drewp/mbsync/go at startup - - server.shell(commands=[ - "cd /home/drewp/mbsync; /usr/bin/mbsync-get-cert 10.5.0.1 > servercert", - ]) - - files.put(src='templates/file-count/file_count.py', dest='/opt/file_count.py') - files.template(src='templates/file-count/file-count.service.j2', dest='/etc/systemd/system/maildir-count.service') - systemd.service(service='maildir-count.service', enabled=True, running=True, daemon_reload=True) - - -# other machines, route mail to bang or prime for delivery - -if host.name == 'bang': - apt.packages(packages=['postfix']) - files.template(src='templates/mail/main.cf.j2', dest='/etc/postfix/main.cf') - files.template(src='templates/mail/mydestination.j2', dest='/etc/postfix/mydestination') - files.put(src='secrets/mail/aliases', dest='/etc/postfix/aliases') - files.put(src='secrets/mail/sender_access', dest='/etc/postfix/sender_access') - files.put(src='secrets/mail/virtual', dest='/etc/postfix/virtual') - - server.shell(commands=[ - 'postmap /etc/postfix/sender_access', - 'postmap /etc/postfix/virtual', - 'postmap /etc/postfix/aliases', - 'postfix reload', - ]) - systemd.service(service='postfix@-.service', enabled=True, running=True) - - # server.shell(commands=[ - # # not working - # "cd /my/serv/dovecot; runuser -u drewp -- invoke certs", - # ])
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mail/dkim/opendkim-KeyTable Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,2 @@ +default._domainkey.bigasterisk.com bigasterisk.com:default:/etc/opendkim/keys/bigasterisk.com/default.private +default._domainkey.chat.bigasterisk.com chat.bigasterisk.com:default:/etc/opendkim/keys/chat.bigasterisk.com/default.private
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mail/dkim/opendkim-SigningTable Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,2 @@ +*@bigasterisk.com default._domainkey.bigasterisk.com +*@chat.bigasterisk.com default._domainkey.chat.bigasterisk.com
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mail/dkim/opendkim-TrustedHosts Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,4 @@ +127.0.0.1 +::1 +*.bigasterisk.com +10.5.0.0/16
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mail/dkim/opendkim.conf Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,772 @@ +## +## opendkim.conf -- configuration file for OpenDKIM filter +## +## Copyright (c) 2010-2015, 2018, The Trusted Domain Project. +## All rights reserved. +## + +## +## For settings that refer to a "dataset", see the opendkim(8) man page. +## + +## DEPRECATED CONFIGURATION OPTIONS +## +## The following configuration options are no longer valid. They should be +## removed from your existing configuration file to prevent potential issues. +## Failure to do so may result in opendkim being unable to start. +## +## Removed in 2.10.0: +## AddAllSignatureResults +## ADSPAction +## ADSPNoSuchDomain +## BogusPolicy +## DisableADSP +## LDAPSoftStart +## LocalADSP +## NoDiscardableMailTo +## On-PolicyError +## SendADSPReports +## UnprotectedPolicy + +## CONFIGURATION OPTIONS + +## AllowSHA1Only { yes | no } +## default "no" +## +## By default, the filter will refuse to start if support for SHA256 is +## not available since this violates the strong recommendations of +## RFC6376 Section 3.3, which says: +## +## "Verifiers MUST implement both rsa-sha1 and rsa-sha256. Signers MUST +## implement and SHOULD sign using rsa-sha256." +## +## This forces that violation to be explicitly selected by the administrator. + +# AllowSHA1Only no + +## AlwaysAddARHeader { yes | no } +## default "no" +## +## Add an "Authentication-Results:" header even to unsigned messages +## from domains with no "signs all" policy. The reported DKIM result +## will be "none" in such cases. Normally unsigned mail from non-strict +## domains does not cause the results header to be added. + +# AlwaysAddARHeader no + +## AuthservID string +## default (local host name) +## +## Defines the "authserv-id" token to be used when generating +## Authentication-Results headers after message verification. + +# AuthservID example.com + +## AuthservIDWithJobID +## default "no" +## +## Appends a "/" followed by the MTA's job ID to the "authserv-id" token +## when generating Authentication-Results headers after message verification. + +# AuthservIDWithJobId no + +## AutoRestart { yes | no } +## default "no" +## +## Indicate whether or not the filter should arrange to restart automatically +## if it crashes. + +# AutoRestart No + +## AutoRestartCount n +## default 0 +## +## Sets the maximum automatic restart count. After this number of +## automatic restarts, the filter will give up and terminate. A value of 0 +## implies no limit. + +# AutoRestartCount 0 + +## AutoRestartRate n/t[u] +## default (none) +## +## Sets the maximum automatic restart rate. See the opendkim.conf(5) +## man page for the format of this parameter. + +# AutoRestartRate n/tu + +## Background { yes | no } +## default "yes" +## +## Indicate whether or not the filter should run in the background. + +# Background Yes + +## BaseDirectory path +## default (none) +## +## Causes the filter to change to the named directory before beginning +## operation. Thus, cores will be dumped here and configuration files +## are read relative to this location. + +# BaseDirectory /var/run/opendkim + +## BodyLengthDB dataset +## default (none) +## +## A data set that is checked against envelope recipients to see if a +## body length tag should be included in the generated signature. +## This has security implications; see opendkim.conf(5) for details. + +# BodyLengthDB dataset + +## Canonicalization hdrcanon[/bodycanon] +## default "simple/simple" +## +## Select canonicalizations to use when signing. If the "bodycanon" is +## omitted, "simple" is used. Valid values for each are "simple" and +## "relaxed". + +# Canonicalization simple/simple + +## ClockDrift n +## default 300 +## +## Specify the tolerance range for expired signatures or signatures +## which appear to have timestamps in the future, allowing for clock +## drift. + +# ClockDrift 300 + +## Diagnostics { yes | no } +## default "no" +## +## Specifies whether or not signatures with header diagnostic tags should +## be generated. + +# Diagnostics No + +## DNSTimeout n +## default 10 +## +## Specify the time in seconds to wait for replies from the nameserver when +## requesting keys or signing policies. + +# DNSTimeout 10 + +## Domain dataset +## default (none) +## +## Specify for which domain(s) signing should be done. No default; must +## be specified for signing. + +Domain bigasterisk.com,chat.bigasterisk.com + +## DomainKeysCompat { yes | no } +## default "no" +## +## When enabled, backward compatibility with DomainKeys (RFC4870) key +## records is enabled. Otherwise, such key records are considered to be +## syntactically invalid. + +# DomainKeysCompat no + +## DontSignMailTo dataset +## default (none) +## +## Gives a list of recipient addresses or address patterns whose mail should +## not be signed. + +# DontSignMailTo addr1,addr2,... + +## EnableCoredumps { yes | no } +## default "no" +## +## On systems which have support for such, requests that the kernel dump +## core even though the process may change user ID during its execution. + +# EnableCoredumps no + +## ExemptDomains dataset +## default (none) +## +## A data set of domain names that are checked against the message sender's +## domain. If a match is found, the message is ignored by the filter. + +# ExemptDomains domain1,domain2,... + +## ExternalIgnoreList filename +## +## Names a file from which a list of externally-trusted hosts is read. +## These are hosts which are allowed to send mail through you for signing. +## Automatically contains 127.0.0.1. See man page for file format. + +ExternalIgnoreList refile:/etc/opendkim/TrustedHosts + +## FixCRLF { yes | no } +## +## Requests that the library convert "naked" CR and LF characters to +## CRLFs during canonicalization. The default is "no". + +# FixCRLF no + +## IgnoreMalformedMail { yes | no } +## default "no" +## +## Silently passes malformed messages without alteration. This includes +## messages that fail the RequiredHeaders check, if enabled. The default is +## to pass those messages but add an Authentication-Results field indicating +## that they were malformed. + +# IgnoreMalformedMail no + +## InternalHosts dataset +## default "127.0.0.1" +## +## Names a file from which a list of internal hosts is read. These are +## hosts from which mail should be signed rather than verified. +## Automatically contains 127.0.0.1. + +InternalHosts refile:/etc/opendkim/TrustedHosts + +## KeepTemporaryFiles { yes | no } +## default "no" +## +## If set, causes temporary files generated during message signing or +## verifying to be left behind for debugging use. Not for normal operation; +## can fill your disks quite fast on busy systems. + +# KeepTemporaryFiles no + +## KeyFile filename +## default (none) +## +## Specifies the path to the private key to use when signing. Ignored if +## SigningTable and KeyTable are used. No default; must be specified for +## signing if SigningTable/KeyTable are not in use. + +KeyFile /etc/opendkim/keys/default.private + +## KeyTable dataset +## default (none) +## +## Defines a table that will be queried to convert key names to +## sets of data of the form (signing domain, signing selector, private key). +## The private key can either contain a PEM-formatted private key, +## a base64-encoded DER format private key, or a path to a file containing +## one of those. + +KeyTable /etc/opendkim/KeyTable + +## LogWhy { yes | no } +## default "no" +## +## If logging is enabled (see Syslog below), issues very detailed logging +## about the logic behind the filter's decision to either sign a message +## or verify it. The logic behind the decision is non-trivial and can be +## confusing to administrators not familiar with its operation. A +## description of how the decision is made can be found in the OPERATIONS +## section of the opendkim(8) man page. This causes a large increase +## in the amount of log data generated for each message, so it should be +## limited to debugging use and not enabled for general operation. + +LogWhy yes + +## MacroList macro[=value][,...] +## +## Gives a set of MTA-provided macros which should be checked to see +## if the sender has been determined to be a local user and therefore +## whether or not signing should be done. See opendkim.conf(5) for +## more information. + +# MacroList foo=bar,baz=blivit + +## MaximumHeaders n +## +## Disallow messages whose header blocks are bigger than "n" bytes. +## Intended to detect and block a denial-of-service attack. The default +## is 65536. A value of 0 disables this test. + +# MaximumHeaders n + +## MaximumSignaturesToVerify n +## (default 3) +## +## Verify no more than "n" signatures on an arriving message. +## A value of 0 means "no limit". + +# MaximumSignaturesToVerify n + +## MaximumSignedBytes n +## +## Don't sign more than "n" bytes of the message. The default is to +## sign the entire message. Setting this implies "BodyLengths". + +# MaximumSignedBytes n + +## MilterDebug n +## +## Request a debug level of "n" from the milter library. The default is 0. + +# MilterDebug 0 + +## Minimum n[% | +] +## default 0 +## +## Sets a minimum signing volume; one of the following formats: +## n at least n bytes (or the whole message, whichever is less) +## must be signed +## n% at least n% of the message must be signed +## n+ if a length limit was presented in the signature, no more than +## n bytes may have been added + +# Minimum n + +## MinimumKeyBits n +## default 1024 +## +## Causes the library not to accept signatures matching keys made of fewer +## than the specified number of bits, even if they would otherwise pass +## DKIM signing. + +# MinimumKeyBits 1024 + +## Mode [sv] +## default sv +## +## Indicates which mode(s) of operation should be provided. "s" means +## "sign", "v" means "verify". + +Mode sv + +## MTA dataset +## default (none) +## +## Specifies a list of MTAs whos mail should always be signed rather than +## verified. The "mtaname" is extracted from the DaemonPortOptions line +## in effect. + +# MTA name + +## MultipleSignatures { yes | no } +## default no +## +## Allows multiple signatures to be added. If set to "true" and a SigningTable +## is in use, all SigningTable entries that match the candidate message will +## cause a signature to be added. Otherwise, only the first matching +## SigningTable entry will be added, or only the key defined by Domain, +## Selector and KeyFile will be added. + +# MultipleSignatures no + +## MustBeSigned dataset +## default (none) +## +## Defines a list of headers which, if present on a message, must be +## signed for the signature to be considered acceptable. + +# MustBeSigned header1,header2,... + +## Nameservers addr1[,addr2[,...]] +## default (none) +## +## Provides a comma-separated list of IP addresses that are to be used when +## doing DNS queries to retrieve DKIM keys, VBR records, etc. +## These override any local defaults built in to the resolver in use, which +## may be defined in /etc/resolv.conf or hard-coded into the software. + +# Nameservers addr1,addr2,... + +## NoHeaderB { yes | no } +## default "no" +## +## Suppresses addition of "header.b" tags on Authentication-Results +## header fields. + +# NoHeaderB no + +## OmitHeaders dataset +## default (none) +## +## Specifies a list of headers that should always be omitted when signing. +## Header names should be separated by commas. + +# OmitHeaders header1,header2,... + +## On-... +## +## Specifies what to do when certain error conditions are encountered. +## +## See opendkim.conf(5) for more information. + +# On-Default +# On-BadSignature +# On-DNSError +# On-InternalError +# On-NoSignature +# On-Security +# On-SignatureError + +## OversignHeaders dataset +## default (none) +## +## Specifies a set of header fields that should be included in all signature +## header lists (the "h=" tag) once more than the number of times they were +## actually present in the signed message. See opendkim.conf(5) for more +## information. + +# OverSignHeaders header1,header2,... + +## PeerList dataset +## default (none) +## +## Contains a list of IP addresses, CIDR blocks, hostnames or domain names +## whose mail should be neither signed nor verified by this filter. See man +## page for file format. + +# PeerList filename + +## PidFile filename +## default (none) +## +## Name of the file where the filter should write its pid before beginning +## normal operations. + +# PidFile filename + +## POPDBFile dataset +## default (none) +## +## Names a database which should be checked for "POP before SMTP" records +## as a form of authentication of users who may be sending mail through +## the MTA for signing. Requires special compilation of the filter. +## See opendkim.conf(5) for more information. + +# POPDBFile filename + +## Quarantine { yes | no } +## default "no" +## +## Indicates whether or not the filter should arrange to quarantine mail +## which fails verification. Intended for diagnostic use only. + +# Quarantine No + +## QueryCache { yes | no } +## default "no" +## +## Instructs the DKIM library to maintain its own local cache of keys and +## policies retrieved from DNS, rather than relying on the nameserver for +## caching service. Useful if the nameserver being used by the filter is +## not local. The filter must be compiled with the QUERY_CACHE flag to enable +## this feature, since it adds a library dependency. + +# QueryCache No + +## RedirectFailuresTo address +## default (none) +## +## Redirects signed messages to the specified address if none of the +## signatures present failed to verify. + +# RedirectFailuresTo postmaster@example.com + +## RemoveARAll { yes | no } +## default "no" +## +## Remove all Authentication-Results: headers on all arriving mail. + +# RemoveARAll No + +## RemoveARFrom dataset +## default (none) +## +## Remove all Authentication-Results: headers on all arriving mail that +## claim to have been added by hosts listed in this parameter. The list +## should be comma-separated. Entire domains may be specified by preceding +## the dopmain name by a single dot (".") character. + +# RemoveARFrom host1,host2,.domain1,.domain2,... + +## RemoveOldSignatures { yes | no } +## default "no" +## +## Remove old signatures on messages, if any, when generating a signature. + +# RemoveOldSignatures No + +## ReportAddress addr +## default (executing user)@(hostname) +## +## Specifies the sending address to be used on From: headers of outgoing +## failure reports. By default, the e-mail address of the user executing +## the filter is used. + +# ReportAddress "DKIM Error Postmaster" <postmaster@example.com> + +## ReportBccAddress addr +## default (none) +## +## Specifies additional recipient address(es) to receive outgoing failure +## reports. + +# ReportBccAddress postmaster@example.com, john@example.com + +## RequiredHeaders { yes | no } +## default no +## +## Rejects messages which don't conform to RFC5322 header count requirements. + +# RequiredHeaders No + +## RequireSafeKeys { yes | no } +## default yes +## +## Refuses to use key files that appear to have unsafe permissions. + +# RequireSafeKeys Yes +RequireSafeKeys false + +## ResignAll { yes | no } +## default no +## +## Where ResignMailTo triggers a re-signing action, this flag indicates +## whether or not all mail should be signed (if set) versus only verified +## mail being signed (if not set). + +# ResignAll No + +## ResignMailTo dataset +## default (none) +## +## Checks each message recipient against the specified dataset for a +## matching record. The full address is checked in each case, then the +## hostname, then each domain preceded by ".". If there is a match, the +## value returned is presumed to be the name of a key in the KeyTable +## (if defined) to be used to re-sign the message in addition to +## verifying it. If there is a match without a KeyTable, the default key +## is applied. + +# ResignMailTo dataset + +## ResolverConfiguration string +## +## Passes arbitrary configuration data to the resolver. For the stock UNIX +## resolver, this is ignored; for Unbound, it names a resolv.conf(5)-style +## file that should be read for configuration information. + +# ResolverConfiguration string + +## ResolverTracing { yes | no } +## +## Requests enabling of resolver trace features, if available. The effect +## of setting this flag depends on how trace features, if any, are implemented +## in the resolver in use. Currently only effective when used with the +## OpenDKIM asynchronous resolver. + +# ResolverTracing no + +## Selector name +## +## The name of the selector to use when signing. No default; must be +## specified for signing. + +Selector default + +## SenderHeaders dataset +## default (none) +## +## Overrides the default list of headers that will be used to determine +## the sending domain when deciding whether to sign the message and with +## with which key(s). See opendkim.conf(5) for details. + +# SenderHeaders From + +## SendReports { yes | no } +## default "no" +## +## Specifies whether or not the filter should generate report mail back +## to senders when verification fails and an address for such a purpose +## is provided. See opendkim.conf(5) for details. + +# SendReports No + +## SignatureAlgorithm signalg +## default "rsa-sha256" +## +## Signature algorithm to use when generating signatures. Must be one of +## "rsa-sha1", "rsa-sha256", or "ed25519-sha256". + +# SignatureAlgorithm rsa-sha256 + +## SignatureTTL seconds +## default "0" +## +## Specifies the lifetime in seconds of signatures generated by the +## filter. A value of 0 means no expiration time is included in the +## signature. + +# SignatureTTL 0 + +## SignHeaders dataset +## default (none) +## +## Specifies the list of headers which should be included when generating +## signatures. The string should be a comma-separated list of header names. +## See the opendkim.conf(5) man page for more information. + +# SignHeaders header1,header2,... + +## SigningTable dataset +## default (none) +## +## Defines a dataset that will be queried for the message sender's address +## to determine which private key(s) (if any) should be used to sign the +## message. The sender is determined from the value of the sender +## header fields as described with SenderHeaders above. The key for this +## lookup should be an address or address pattern that matches senders; +## see the opendkim.conf(5) man page for more information. The value +## of the lookup should return the name of a key found in the KeyTable +## that should be used to sign the message. If MultipleSignatures +## is set, all possible lookup keys will be attempted which may result +## in multiple signatures being applied. + +SigningTable refile:/etc/opendkim/SigningTable + +## SingleAuthResult { yes | no} +## default "no" +## +## When DomainKeys verification is enabled, multiple Authentication-Results +## will be added, one for DK and one for DKIM. With this enabled, only +## a DKIM result will be reported unless DKIM failed but DK passed, in which +## case only a DK result will be reported. + +# SingleAuthResult no + +## SMTPURI uri +## +## Specifies a URI (e.g., "smtp://localhost") to which mail should be sent +## via SMTP when notifications are generated. + +# Socket smtp://localhost + +## Socket socketspec +## +## Names the socket where this filter should listen for milter connections +## from the MTA. Required. Should be in one of these forms: +## +## inet:port@address to listen on a specific interface +## inet:port to listen on all interfaces +## local:/path/to/socket to listen on a UNIX domain socket + +Socket inet:8891@localhost + +## SoftwareHeader { yes | no } +## default "no" +## +## Add a DKIM-Filter header field to messages passing through this filter +## to identify messages it has processed. + +# SoftwareHeader no + +## StrictHeaders { yes | no } +## default "no" +## +## Requests that the DKIM library refuse to process a message whose +## header fields do not conform to the standards, in particular Section 3.6 +## of RFC5322. + +# StrictHeaders no + +## StrictTestMode { yes | no } +## default "no" +## +## Selects strict CRLF mode during testing (see the "-t" command line +## flag in the opendkim(8) man page). Messages for which all header +## fields and body lines are not CRLF-terminated are considered malformed +## and will produce an error. + +# StrictTestMode no + +## SubDomains { yes | no } +## default "no" +## +## Sign for subdomains as well? + +# SubDomains No + +## Syslog { yes | no } +## default "yes" +## +## Log informational and error activity to syslog? + +Syslog Yes + +## SyslogFacility facility +## default "mail" +## +## Valid values are : +## auth cron daemon kern lpr mail news security syslog user uucp +## local0 local1 local2 local3 local4 local5 local6 local7 +## +## syslog facility to be used + +# SyslogFacility mail + +## SyslogName ident +## default "opendkim" (or the name of the executable) +## +## Identifier to be prepended to all generated log entries. + +# SyslogName opendkim + +## SyslogSuccess { yes | no } +## default "no" +## +## Log success activity to syslog? + +# SyslogSuccess No + +## TemporaryDirectory path +## default /tmp +## +## Specifies which directory will be used for creating temporary files +## during message processing. + +# TemporaryDirectory /tmp + +## TestPublicKeys filename +## default (none) +## +## Names a file from which public keys should be read. Intended for use +## only during automated testing. + +# TestPublicKeys /tmp/testkeys + +## TrustAnchorFile filename +## default (none) +## +## Specifies a file from which trust anchor data should be read when doing +## DNS queries and applying the DNSSEC protocol. See the Unbound documentation +## at http://unbound.net for the expected format of this file. + +# TrustAnchorFile /var/named/trustanchor + +## UMask mask +## default (none) +## +## Change the process umask for file creation to the specified value. +## The system has its own default which will be used (usually 022). +## See the umask(2) man page for more information. + +# UMask 022 + +# UnboundConfigFile /var/named/unbound.conf + +## Userid userid +## default (none) +## +## Change to user "userid" before starting normal operation? May include +## a group ID as well, separated from the userid by a colon. + +UserID opendkim
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mail/file-count/file-count.service Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,15 @@ +# written by pyinfra + +[Unit] +After=wg-quick@wg0.service + +[Service] +Type=exec +KillMode=process +# port 2500 is used in victoriametrics/config/scrape_main.yaml +ExecStart=runuser -u drewp /usr/bin/python3 /opt/file_count.py 10.5.0.2 2500 /home/drewp/Maildir/new maildir_count +Restart=always +RestartSec=5s + +[Install] +WantedBy=multi-user.target
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mail/file-count/file_count.py Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,20 @@ +import http.server +import socketserver +import os +import sys + +interface, port, dir, metric_name = sys.argv[1:] + + +class Web(http.server.SimpleHTTPRequestHandler): + + def do_GET(self): + files_count = len(os.listdir(dir)) + self.send_response(200) + self.send_header('Content-type', 'text/plain') + self.end_headers() + self.wfile.write(f'{metric_name} {files_count}'.encode()) + + +with socketserver.TCPServer((interface, int(port)), Web) as httpd: + httpd.serve_forever()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mail/mail.py Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,99 @@ +from pyinfra.context import host +from pyinfra.operations import apt, files, server, systemd + +# ditto (and others?) might also run postfix; not sure how + + +def dkim(): + if host.name != 'prime': + return + ''' + per domain keygen: + prime(pts/4):~# mkdir /etc/opendkim/keys/chat.bigasterisk.com + prime(pts/4):~# opendkim-genkey -b 1024 -d chat.bigasterisk.com -D /etc/opendkim/keys/chat.bigasterisk.com -s default -v + opendkim-genkey: generating private key + opendkim-genkey: private key written to default.private + opendkim-genkey: extracting public key + opendkim-genkey: DNS TXT record written to default.txt + prime(pts/4):~# chown opendkim /etc/opendkim/keys/*/* + ''' + apt.packages(packages=['opendkim', 'opendkim-tools']) + + files.template(src='mail/dkim/opendkim-KeyTable', dest='/etc/opendkim/KeyTable') + files.template(src='mail/dkim/opendkim-SigningTable', dest='/etc/opendkim/SigningTable') + files.template(src='mail/dkim/opendkim-TrustedHosts', dest='/etc/opendkim/TrustedHosts') + files.template(src='mail/dkim/opendkim.conf', dest='/etc/opendkim.conf') + + for domain in ['bigasterisk.com', 'chat.bigasterisk.com']: + files.put(src=f'secrets/mail/{domain}-default.private', + dest=f'/etc/opendkim/keys/{domain}/default.private', + mode='0600', + user='opendkim') + + files.template(src='mail/opendkim.service', dest='/usr/lib/systemd/system/opendkim.service') + systemd.service(service='opendkim.service', enabled=True, running=True, restarted=True, daemon_reload=True) + + +def postfix(): + if host.name != 'prime': + return + apt.packages(packages=['postfix', 'isync']) + + files.template(src='mail/main.cf.j2', dest='/etc/postfix/main.cf') + files.put(src='mail/mydestination', dest='/etc/postfix/mydestination') + files.put(src='secrets/mail/aliases', dest='/etc/postfix/aliases') + files.put(src='secrets/mail/sender_access', dest='/etc/postfix/sender_access') + files.put(src='secrets/mail/virtual', dest='/etc/postfix/virtual') + + server.shell(commands=[ + 'postmap /etc/postfix/sender_access', + 'postmap /etc/postfix/virtual', + 'postmap /etc/postfix/aliases', # broken + 'postfix reload', + ]) + systemd.service(service='postfix@-.service', enabled=True, running=True) + + +def mbsync(): + if host.name != 'prime': + return + + # todo: something to run ~drewp/mbsync/go at startup + + server.shell(commands=[ + "cd /home/drewp/mbsync; /usr/bin/mbsync-get-cert 10.5.0.1 > servercert", + ]) + + files.put(src='mail/file-count/file_count.py', dest='/opt/file_count.py') + files.put(src='mail/file-count/file-count.service', dest='/etc/systemd/system/maildir-count.service') + systemd.service(service='maildir-count.service', enabled=True, running=True, daemon_reload=True) + + +# other machines, route mail to bang or prime for delivery + +# if host.name == 'bang': +# apt.packages(packages=['postfix']) +# files.template(src='templates/mail/main.cf.j2', dest='/etc/postfix/main.cf') +# files.template(src='templates/mail/mydestination.j2', dest='/etc/postfix/mydestination') +# files.put(src='secrets/mail/aliases', dest='/etc/postfix/aliases') +# files.put(src='secrets/mail/sender_access', dest='/etc/postfix/sender_access') +# files.put(src='secrets/mail/virtual', dest='/etc/postfix/virtual') + +# server.shell(commands=[ +# 'postmap /etc/postfix/sender_access', +# 'postmap /etc/postfix/virtual', +# 'postmap /etc/postfix/aliases', +# 'postfix reload', +# ]) +# systemd.service(service='postfix@-.service', enabled=True, running=True) + +# # server.shell(commands=[ +# # # not working +# # "cd /my/serv/dovecot; runuser -u drewp -- invoke certs", +# # ]) + +operations = [ + dkim, + postfix, + mbsync, +]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mail/main.cf.j2 Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,104 @@ +# written by pyinfra + +compatibility_level = 3 + +smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu) + +readme_directory = /usr/share/doc/postfix +html_directory = /usr/share/doc/postfix/html + +inet_interfaces = all + +# TLS parameters +smtpd_tls_cert_file=/etc/ssl/certs/self1-ca.crt +smtpd_tls_key_file=/etc/ssl/certs/self1-ca.key +smtpd_use_tls=yes +smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache +smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache +smtpd_tls_loglevel = 0 +smtpd_tls_security_level = may +smtpd_tls_received_header = yes +smtpd_relay_before_recipient_restrictions = yes +smtp_address_preference = ipv4 + +# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for +# information on enabling SSL in the smtp client. + +relayhost = {{ 'prime.bigasterisk.com' if host.name != 'prime' else '' }} + +alias_maps = hash:/etc/postfix/aliases +alias_database = hash:/etc/postfix/aliases + +{% if host.name == 'prime' %} +myhostname = bigasterisk.com +mydestination = /etc/postfix/mydestination +{% else %} +myhostname = {{ host.name }}.bigasterisk.com +# must relay, even if you think you're the destination name is correct +mydestination = +{% endif %} + +relay_domains = $mydestination +mynetworks_style = subnet +mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 10.1.0.0/16 10.3.0.0/16 10.5.0.0/24 192.168.0.3/32 [fc7b:54e8:69a9:e165:86c8:9d42:6cc5:b2a1]/128 [fcc8:29d:5660:ec63:754f:37af:de4a:a9df]/128 + +# allow realuser+fakepart@bigasterisk.com +recipient_delimiter = + + +{% if host.name == 'prime' %} +# mail can only deliver on prime +mailbox_size_limit = 0 +home_mailbox = Maildir/ +biff = no +message_size_limit = 50000000 +#mailbox_command = procmail -a "$EXTENSION" +{% endif %} + + +# http://www.spamcop.net/fom-serve/cache/349.html +# upgraded, per http://www.wrightthisway.com/Articles/000062.html + +smtpd_recipient_restrictions = + permit_mynetworks, + permit_sasl_authenticated, +# check_client_access /etc/passwd somehow? + reject_invalid_hostname, + reject_non_fqdn_sender, + reject_non_fqdn_recipient, + reject_unknown_sender_domain, + reject_unknown_recipient_domain, + reject_unauth_pipelining, + permit_tls_clientcerts, + reject_unauth_destination, + check_sender_access hash:/etc/postfix/sender_access, + reject_rbl_client bl.spamcop.net, + permit + +smtpd_tls_ask_ccert = yes + +# no dovecot +smtpd_sasl_type = cyrus +cyrus_sasl_config_path = /etc/postfix/sasl/ + +# yes dovecot +#smtpd_sasl_type = dovecot +#smtpd_sasl_path = private/auth + +smtpd_sasl_auth_enable = yes +smtpd_sasl_security_options = noanonymous +smtpd_sasl_tls_security_options = $smtpd_sasl_security_options +smtpd_tls_auth_only = yes + +queue_directory = /var/spool/postfix + +# Postfix is the final destination for the specified list +{% if host.name == 'prime' %} +virtual_alias_domains = adkinslawgroup.com iveseenyoubefore.com fantasyfamegame.com maxradi.us whopickedthis.com quickwitretort.com drewp.quickwitretort.com kelsi.quickwitretort.com photo.bigasterisk.com whatsplayingnext.com williamperttula.com + +# Optional lookup tables that alias specific mail addresses or domains to other local or remote addresses +virtual_alias_maps = hash:/etc/postfix/virtual +{% endif %} + +smtpd_milters = inet:127.0.0.1:8891 +non_smtpd_milters = $smtpd_milters +milter_default_action = accept
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mail/mydestination Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,20 @@ +localhost +localhost.bigasterisk.com +10.2.0.1 +a.mx.bigasterisk.com +bang.bigasterisk.com +bigast.com +bigasterisk.com +dash.bigasterisk.com +mail.bigasterisk.com +www.bigasterisk.com +chitty.bigasterisk.com +cuisine.bigasterisk.com +dot.bigasterisk.com +drewp.quickwitretort.com +kelsi.quickwitretort.com +maxradi.us +williamperttula.com +ditto.bigasterisk.com +chat.bigasterisk.com +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mail/opendkim.service Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,15 @@ +[Unit] +Description=OpenDKIM Milter +Documentation=man:opendkim(8) man:opendkim.conf(5) man:opendkim-lua(3) man:opendkim-genkey(8) man:opendkim-genzone(8) man:opendkim-testkey(8) http://www.opendkim.org/docs.html +After=network-online.target nss-lookup.target +Wants=network-online.target + +[Service] +Type=forking +#PIDFile=/run/opendkim/opendkim.pid +ExecStart=/usr/sbin/opendkim -vv +#ExecReload=/bin/kill -USR1 $MAINPID +Restart=on-failure + +[Install] +WantedBy=multi-user.target \ No newline at end of file
--- a/multikube.py Mon Jan 20 14:10:19 2025 -0800 +++ b/multikube.py Mon Jan 20 21:55:08 2025 -0800 @@ -1,5 +1,5 @@ # leave kube.py running single-host and try again -from pyinfra import host +from pyinfra.context import host from pyinfra.facts.server import Arch from pyinfra.operations import files, server, systemd
--- a/net.py Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -from pyinfra import host -from pyinfra.operations import apt, files, server, systemd - - -def cleanup(): - # past attempts - files.file(path='/etc/network/interfaces', present=False) - - for search_dir in [ - # search path per `man systemd.network`: - # /lib/systemd/network # These OS files are ok. - '/usr/local/lib/systemd/network/', # Probably no such dir. - '/run/systemd/network/', # Previous netplan attempts dumped in here. - # '/etc/systemd/network/', # I'm going to work in here. - ]: - files.sync( - src="files/empty_dir/", - dest=search_dir, - delete=True, - ) - - # On pipe: - # Now using a HW router for this firewall. No incoming connections. - # test connections from the outside: - # http://www.t1shopper.com/tools/port-scanner/ - # On prime: - # using digitalocean network config: - # https://cloud.digitalocean.com/networking/firewalls/f68899ae-1aac-4469-b379-59ce2bbc988f/droplets?i=7c5072 - apt.packages(packages=['ufw'], present=False) - - -def iptables_version(): - # https://github.com/k3s-io/k3s/issues/1812 unclear, but more importantly, this has to be set - # on pipe in a way that works with the commands in house_net.service (and net_routes) - server.shell(commands=[ - 'update-alternatives --set iptables /usr/sbin/iptables-legacy', - 'update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy', - ]) - # needs reboot if this changed - - -iptables_version() -server.sysctl(key='net.ipv6.conf.all.disable_ipv6', value=1, persist=True) - -if host.name == 'prime': - cleanup() - - files.template( - src="files/net/prime.network", - dest="/etc/systemd/network/99-prime.network", - ) - systemd.service(service='systemd-networkd.service', enabled=True, running=True, restarted=True) - -if host.name == 'pipe': - cleanup() - - files.template(src="files/net/pipe_10.2.network", dest="/etc/systemd/network/99-10.2.network") - files.template(src="files/net/pipe_isp.network", dest="/etc/systemd/network/99-isp.network") - server.sysctl(key='net.ipv4.ip_forward', value=1, persist=True) - files.template(src="files/net/house_net.service", dest="/etc/systemd/system/house_net.service", out_interface='eth0') - systemd.service(service='house_net.service', daemon_reload=True, enabled=True, running=True, restarted=True) - systemd.service(service='systemd-networkd.service', enabled=True, running=True, restarted=True) - -if host.name == 'ditto': - files.template( - src="files/net/ditto-netplan.yaml", - dest="/etc/netplan/00-installer-config.yaml", - create_remote_dir=True, - ) - - systemd.service(service='systemd-networkd.service', enabled=True, running=True, restarted=True)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/net/files/ditto-netplan.yaml Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,22 @@ +# written by pyinfra +network: + ethernets: + eno1: + addresses: + # name=ditto + - 10.2.0.133/16 + # name=mqtt1 etc + - 10.2.0.11/16 + - 10.2.0.12/16 + - 10.2.0.13/16 + - 10.2.0.14/16 + routes: + - to: default + via: 10.2.0.3 + nameservers: + addresses: [10.2.0.3] + enp5s0: + dhcp4: true + ens3: + dhcp4: true + version: 2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/net/files/house_net.service Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,14 @@ +# written by pyinfra + +[Unit] +After=network-online.target nss-lookup.target +Wants=network-online.target nss-lookup.target + +[Service] +Type=oneshot +ExecStart=sh -c "sysctl net.ipv4.ip_forward=1 && /usr/sbin/iptables -A POSTROUTING --table nat --out-interface eth0 --jump MASQUERADE" +RemainAfterExit=yes + + +[Install] +WantedBy=multi-user.target
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/net/files/pipe_10.2.network Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,14 @@ +# written by pyinfra + +[Match] +# usb dongle +MACAddress=00:05:1b:33:3e:81 + +[Network] +DHCP=no +Address=10.2.0.3/16 +# vip for the filtered dns server we give clients who are to have sometimes-filtered domains +Address=10.2.0.4/16 +DNS=10.2.0.3 +Domains=bigasterisk.com +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/net/files/pipe_isp.network Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,12 @@ +# written by pyinfra + +[Match] +# onboard eth +MACAddress=00:1e:06:43:20:d0 + +[Network] +DHCP=no +Address=192.168.42.3/24 +Gateway=192.168.42.1 +DNS=10.2.0.1 +Domains=bigasterisk.com \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/net/files/prime.network Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,14 @@ +# written by pyinfra + +# see systemd.network(5) + +[Match] +MACAddress=04:01:09:7f:89:01 + +[Network] +Address=162.243.138.136/24 +Gateway=162.243.138.1 +DNS=10.5.0.1%wg0 +DNS=8.8.8.8 +DNS=8.8.4.4 +Domains=bigasterisk.com \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/net/net.py Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,61 @@ +from pyinfra.context import host +from pyinfra.operations import apt, files, server, systemd + + +def no_ufw(): + # On pipe: + # Now using a HW router for this firewall. No incoming connections. + # test connections from the outside: + # http://www.t1shopper.com/tools/port-scanner/ + # On prime: + # using digitalocean network config: + # https://cloud.digitalocean.com/networking/firewalls/f68899ae-1aac-4469-b379-59ce2bbc988f/droplets?i=7c5072 + apt.packages(packages=['ufw'], present=False) + + +def iptables_version(): + # https://github.com/k3s-io/k3s/issues/1812 unclear, but more importantly, this has to be set + # on pipe in a way that works with the commands in house_net.service (and net_routes) + server.shell(commands=[ + 'update-alternatives --set iptables /usr/sbin/iptables-legacy', + 'update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy', + ]) + # needs reboot if this changed + + +def no_ipv6(): + server.sysctl(key='net.ipv6.conf.all.disable_ipv6', value=1, persist=True) + + +def special_configs(): + if host.name == 'prime': + files.template( + src="net/files/prime.network", + dest="/etc/systemd/network/99-prime.network", + ) + + elif host.name == 'pipe': + files.template(src="net/files/pipe_10.2.network", dest="/etc/systemd/network/99-10.2.network") + files.template(src="net/files/pipe_isp.network", dest="/etc/systemd/network/99-isp.network") + server.sysctl(key='net.ipv4.ip_forward', value=1, persist=True) + files.template(src="net/files/house_net.service", dest="/etc/systemd/system/house_net.service", out_interface='eth0') + systemd.service(service='house_net.service', daemon_reload=True, enabled=True, running=True, restarted=True) + + elif host.name == 'ditto': + files.template( + src="net/files/ditto-netplan.yaml", + dest="/etc/netplan/00-installer-config.yaml", + create_remote_dir=True, + ) + + else: + return + systemd.service(service='systemd-networkd.service', enabled=True, running=True, restarted=True) + + +operations = [ + no_ufw, + iptables_version, + no_ipv6, + special_configs, +]
--- a/package_lists.py Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,312 +0,0 @@ -# nodejs+friends are handled outside this file - -setup = [ - 'atool', - 'build-essential', - 'curl', - 'iproute2', # needed for wireguard - 'iptables', - 'mosquitto-clients', - 'mtail', - 'rsync', - 'udns-utils', - 'vim-tiny', - 'wireguard-tools', -] - -pi_setup = [ - 'apt-utils', - 'dirmngr', - 'gnupg2', - 'pigpiod', -] -# something in here tries to get libflac8 & libpulse0 on pipe, which it doesn't have -general = [ - 'apt-listchanges', - 'aptitude', - 'atool', - 'bsd-mailx', - 'fdisk', - 'flatpak', - 'hdparm', - 'isc-dhcp-client', - 'jq', - 'keychain', - 'kitty-terminfo', - 'less', - 'libgraphviz-dev', - 'links', - 'lua5.3', - 'mercurial', - 'moreutils', - 'netcat-openbsd', - 'ntpdate', - 'rename', - 'sshfs', - 'vim-nox', - 'wakeonlan', - 'wget', - 'wireguard', - 'xosview', - 'zsh', -] - -non_pi = [ - 'emacs', - 'lpr', - 'nfs-client', - 'python3-dulwich', # desired, but it may depend on an old python3 - 'python3-atomicwrites', - 'python3-invoke', - 'python3-pip', - 'python3-venv', - 'python3-virtualenv', - 'rclone', -] - -debug = [ - 'debian-goodies', - 'dmidecode', - 'dstat', - 'ethtool', - 'gdb', - 'hdparm', - 'htop', - 'ifstat', - 'iotop', - 'iproute2', - 'lshw', - 'lsof', - 'mtr-tiny', - 'ncdu', - 'net-tools', - 'nmap', - 'oping', - 'screen', - 'smartmontools', - 'speedtest-cli', - 'strace', - 'sysstat', - 'tcpdump', - 'wakeonlan', -] - -for_ditto = [ - 'dnsmasq', - 'nfs-common', - 'openntpd', - 'zfs-auto-snapshot', - 'zfs-zed', - 'zfsutils-linux', - 'tgt', - #'libedgetpu1-std', # for coral? not working on bang -] - -for_pipe = [ - 'dnsmasq', - 'python3-iptables', - 'open-iscsi', -] - -for_prime = [ - 'opendkim', - 'opendkim-tools', -] - -laptop = [ - 'brightnessctl', - 'i3', - 'network-manager', - 'xserver-xorg-input-synaptics', - 'tlp', -] - -audio_plugins = [ - 'amb-plugins', - 'ambdec', - 'autotalent', - 'blepvco', - 'blop', - 'bs2b-ladspa', - 'caps', - 'cmt', - 'csladspa', - 'dpf-plugins-ladspa', - 'fil-plugins', - 'guitarix-ladspa', - 'invada-studio-plugins-ladspa', - 'ladspa-sdk', - 'lsp-plugins-ladspa', - 'mcp-plugins', - 'omins', - 'rev-plugins', - 'ste-plugins', - 'swh-plugins', - 'tap-plugins', - 'vco-plugins', - 'wah-plugins', -] - -desktop = [ - 'adwaita-icon-theme-full', - 'alsa-utils', - 'apache2-utils', - 'arandr', - 'ardour', - 'audacity', - 'brasero', - 'breeze', - 'brightnessctl', - 'checkinstall', - 'cmake', - 'code', - 'cups', - 'dclock', - 'dolphin', - 'eog', - 'evtest', - 'eye', - 'fatrace', - 'firefox', - 'flameshot', - 'fontmatrix', - 'fonts-dejavu-core', - 'fonts-dejavu-extra', - 'fonts-dejavu', - 'fonts-droid-fallback', - 'fonts-emojione', - 'fonts-font-awesome', - 'fonts-freefont-ttf', - 'fonts-lato', - 'fonts-liberation2', - 'fonts-noto', - 'fonts-opensymbol', - 'fonts-quicksand', - 'fonts-texgyre', - 'fonts-ubuntu-console', - 'fonts-ubuntu', - 'fonts-urw-base35', - 'fvwm3', - 'gdb', - 'gedit', - 'gimp-data-extras', - 'gimp-gmic', - 'gimp-plugin-registry', - 'gimp-texturize', - 'gimp', - 'gnome-icon-theme', - 'gnumeric', - 'gnuplot', - 'golang', - 'google-chrome-stable', - 'google-chrome-unstable', - 'gstreamer1.0-libav', - 'gstreamer1.0-opencv', - 'gstreamer1.0-plugins-bad', - 'gstreamer1.0-plugins-ugly', - 'gstreamer1.0-tools', - 'gstreamer1.0-vaapi', - 'heif-gdk-pixbuf', - 'heif-thumbnailer', - 'humanity-icon-theme', - 'i3lock', - 'imagemagick', - 'imwheel', - 'jq', - 'k4dirstat', - 'libheif-examples', - 'libreoffice-draw', - 'libreoffice-impress', - 'libreoffice-writer', - 'libfuse2', # for obsidian (appimage) - 'libxcb-xkb1', # needed for kitty - 'lxterminal', - 'meld', - 'mpv', - 'nmap', - 'nodm', - 'okular', - 'pavucontrol', - 'pamixer', - 'pipewire-audio', - 'python3-dulwich', - 'python3-evemu', - 'python3-opencv', - 'python3-pycurl', - 'python3-rdflib', - 'python3-venv', - 'qjackctl', - 'qv4l2', - 'rar', - 'rclone', - 'recordmydesktop', - 'simple-scan', - 'simplescreenrecorder', - 'solvespace', - 'sqlitebrowser', - 'sshfs', - 'steam-launcher', - 'swi-prolog', - 'syncthing-gtk', # this may pull old ubu syncthing version, which sync.py replaces - 'system-config-printer', - 'systemd-resolved', - 'trayer', - 'ttf-bitstream-vera', - 'visidata', - 'vlc', - 'wamerican', - 'wireshark', - 'wmctrl', - 'x11-apps', - 'x11vnc', - 'xclip', - 'xfonts-base', - 'xfonts-encodings', - 'xfonts-utils', - 'xpad', - 'xsane', - 'xterm', - 'xtightvncviewer', - 'xvfb', - 'libssl-dev', # for pypi 'packages' - 'libcurl4-openssl-dev', # for pypi 'packages' - 'kicad', - 'openscad', - 'dunst', - 'gmic', - 'git-cola', - 'optipng', - 'pngcrush', - 'pngquant', - 'cdparanoia', -] - -xorg = [ - 'kbd', - 'nvidia-modprobe', - 'nvidia-prime', - 'nvidia-settings', - 'screen-resolution-extra', - 'xserver-xorg', -] - - -def k8s_node_with_nvidia_gpu(hostName): - version = { - 'dash': '550', - 'dot': '550', # just not updated yet - 'slash': '550', - 'ditto': '550-server', - # 'bang': '390-server', # no longer in ubuntu - 'squib': '470', # held back for old gfx card - }[hostName] - return [ - 'nvidia-container-runtime', - f'nvidia-headless-{version}', - f'nvidia-utils-{version}', - f'libnvidia-decode-{version}', - f'libnvidia-encode-{version}', - f'nvidia-driver-{version}', - ] + ([] if 'server' in version else [ - f'xserver-xorg-video-nvidia-{version}', - ])
--- a/packages.py Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,153 +0,0 @@ -from io import StringIO - -from pyinfra import host -from pyinfra.operations import apt, files, server, systemd - -import package_lists - - -def kitty(): - apt.packages(packages=['kitty'], present=False, force=True) - vers = '0.36.2' # see https://github.com/kovidgoyal/kitty/releases - home = '/home/drewp' - local = f"{home}/.local/kitty" - dl = f'/tmp/kitty-{vers}-x86_64.txz' - files.download(src=f"https://github.com/kovidgoyal/kitty/releases/download/v{vers}/kitty-{vers}-x86_64.txz", dest=dl) - files.directory(path=local) - server.shell(commands=[ - f"mkdir -p {local}", # https://github.com/Fizzadar/pyinfra/issues/777 - f"aunpack --extract-to={local} {dl}", - ]) - files.link(target="{local}/bin/kitty", path="{home}/bin/kitty") - files.link(target="{local}/bin/kitten", path="{home}/bin/kitten") - - -def nodejs(): - apt.packages(packages=['libnode72'], present=False, force=True) - apt.packages(packages=['nodejs'], latest=True) - server.shell(commands=[ - "rm -f /usr/local/bin/pnp{m,x}", - "corepack enable", - # https://github.com/pnpm/pnpm/releases - # but also https://pnpm.io/installation#compatibility - "corepack prepare 'pnpm@9.8' --activate", - ]) - - -def podman(): - # frigate build wants to mount a single file from the host, which needs podman 4.5.1 - # https://github.com/containers/podman/issues/12123#issuecomment-1620439593 - server.shell(commands='apt --fix-broken install') - apt.deb(src="http://ftp.osuosl.org/pub/ubuntu/pool/main/g/gpgme1.0/libgpgme11t64_1.18.0-4.1ubuntu4_amd64.deb") - server.shell(commands='apt --fix-broken install') - apt.deb(src="http://ftp.osuosl.org/pub/ubuntu/pool/universe/c/conmon/conmon_2.1.10+ds1-1build2_amd64.deb") - apt.deb(src="http://ftp.osuosl.org/pub/ubuntu/pool/universe/libp/libpod/podman_4.9.3+ds1-1build2_amd64.deb") - apt.packages(packages=['libsubid4', 'buildah', 'podman-docker'], latest=True) - - -def pdm(): - # https://github.com/pdm-project/pdm/blob/main/CHANGELOG.md - server.shell(commands=["pip install --break-system-packages 'pdm==2.21.0'"]) - - -def proper_locate(): - apt.packages(packages='mlocate', present=False) - if 'pi' not in host.groups and host.name not in ['prime', 'pipe']: - apt.packages(packages='plocate') - - -def proper_man(): - if 'small' in host.groups or 'pi' in host.groups: - apt.packages(packages=['mandb'], present=False) - - -def no_unwanted_services(): - systemd.service(service='nginx', enabled=False, running=False) - - -apt.packages(packages=package_lists.setup, latest=True) - - -def roblox(): - server.shell(commands='flatpak install -y org.freedesktop.Platform/x86_64/23.08') - server.shell(commands='flatpak install -y flathub org.vinegarhq.Vinegar') # (roblox runner) - files.put( - src=StringIO( - #"#!/bin/sh\nexec flatpak run org.vinegarhq.Vinegar player run 'roblox-player:1'\n" - "#!/bin/sh\n exec /usr/bin/flatpak run --branch=stable --arch=x86_64 --command=vinegar org.vinegarhq.Vinegar player run -app\n" - ), - dest='/usr/local/bin/roblox.real', - mode='755') - - for desktopFile in [ - '/var/lib/flatpak/exports/share/applications/org.vinegarhq.Vinegar.app.desktop', - '/var/lib/flatpak/app/org.vinegarhq.Vinegar/current/active/export/share/applications/org.vinegarhq.Vinegar.player.desktop', - ]: - files.line(path=desktopFile, line="^Exec", replace='Exec=/usr/local/bin/roblox') - files.link(target='/usr/local/bin/run_while_allowed', path='/usr/local/bin/roblox', force=True) - - -def kube_node(): - - # avoid having to this workaround: - # https://longhorn.io/kb/troubleshooting-volume-with-multipath/ - apt.packages(packages=['multipath-tools'], force=True, present=False) - - apt.packages(packages=[ - # https://longhorn.io/docs/1.6.1/deploy/install/#installation-requirements - 'open-iscsi', - 'nfs-common', - 'cryptsetup', - ]) - - -proper_locate() -proper_man() -nodejs() - -apt.packages(packages=package_lists.general, latest=True) -apt.packages(packages=package_lists.debug, latest=True) - -if host.name == "pipe": - apt.packages(packages=package_lists.for_pipe, latest=True) - -if host.name != 'pipe': - apt.packages(packages=['reptyr']) - -if host.name == "prime": - apt.packages(packages=package_lists.for_prime, latest=True) - -if host.name == 'plus': - apt.packages(packages=package_lists.laptop, latest=True) - -if host.data.get('gpu'): - apt.packages(packages=package_lists.k8s_node_with_nvidia_gpu(host.name)) - -if host.data.get('k8s_admin'): - podman() - -is_kube_node = host.name in ['dash', 'slash', 'ditto', 'ws-printer', 'li-drums'] -if is_kube_node: - kube_node() - -if host.name == 'ditto': - apt.packages(packages=package_lists.for_ditto, latest=True) - -if 'pi' not in host.groups: - kitty() - apt.packages(packages=package_lists.non_pi, latest=True) - -if 'pi' in host.groups: - apt.packages(packages=package_lists.pi_setup) - -desktop_env = host.name in ['dash', 'slash', 'plus', 'dot', 'squib', 'pillow', 'tofu'] -if desktop_env: - apt.packages(packages=package_lists.xorg + package_lists.desktop, latest=True) - # broken, per https://vinegarhq.org/ - # roblox() -if desktop_env or host.name in ['bang', 'ditto']: - pdm() - -no_unwanted_services() - -# todo: ./mrv2-v1.0.8-Linux-amd64.deb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/packages/package_lists.py Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,312 @@ +# nodejs+friends are handled outside this file + +setup = [ + 'atool', + 'build-essential', + 'curl', + 'iproute2', # needed for wireguard + 'iptables', + 'mosquitto-clients', + 'mtail', + 'rsync', + 'udns-utils', + 'vim-tiny', + 'wireguard-tools', +] + +pi_setup = [ + 'apt-utils', + 'dirmngr', + 'gnupg2', + 'pigpiod', +] +# something in here tries to get libflac8 & libpulse0 on pipe, which it doesn't have +general = [ + 'apt-listchanges', + 'aptitude', + 'atool', + 'bsd-mailx', + 'fdisk', + 'flatpak', + 'hdparm', + 'isc-dhcp-client', + 'jq', + 'keychain', + 'kitty-terminfo', + 'less', + 'libgraphviz-dev', + 'links', + 'lua5.3', + 'mercurial', + 'moreutils', + 'netcat-openbsd', + 'ntpdate', + 'rename', + 'sshfs', + 'vim-nox', + 'wakeonlan', + 'wget', + 'wireguard', + 'xosview', + 'zsh', +] + +non_pi = [ + 'emacs', + 'lpr', + 'nfs-client', + 'python3-dulwich', # desired, but it may depend on an old python3 + 'python3-atomicwrites', + 'python3-invoke', + 'python3-pip', + 'python3-venv', + 'python3-virtualenv', + 'rclone', +] + +debug = [ + 'debian-goodies', + 'dmidecode', + 'dstat', + 'ethtool', + 'gdb', + 'hdparm', + 'htop', + 'ifstat', + 'iotop', + 'iproute2', + 'lshw', + 'lsof', + 'mtr-tiny', + 'ncdu', + 'net-tools', + 'nmap', + 'oping', + 'screen', + 'smartmontools', + 'speedtest-cli', + 'strace', + 'sysstat', + 'tcpdump', + 'wakeonlan', +] + +for_ditto = [ + 'dnsmasq', + 'nfs-common', + 'openntpd', + 'zfs-auto-snapshot', + 'zfs-zed', + 'zfsutils-linux', + 'tgt', + #'libedgetpu1-std', # for coral? not working on bang +] + +for_pipe = [ + 'dnsmasq', + 'python3-iptables', + 'open-iscsi', +] + +for_prime = [ + 'opendkim', + 'opendkim-tools', +] + +laptop = [ + 'brightnessctl', + 'i3', + 'network-manager', + 'xserver-xorg-input-synaptics', + 'tlp', +] + +audio_plugins = [ + 'amb-plugins', + 'ambdec', + 'autotalent', + 'blepvco', + 'blop', + 'bs2b-ladspa', + 'caps', + 'cmt', + 'csladspa', + 'dpf-plugins-ladspa', + 'fil-plugins', + 'guitarix-ladspa', + 'invada-studio-plugins-ladspa', + 'ladspa-sdk', + 'lsp-plugins-ladspa', + 'mcp-plugins', + 'omins', + 'rev-plugins', + 'ste-plugins', + 'swh-plugins', + 'tap-plugins', + 'vco-plugins', + 'wah-plugins', +] + +desktop = [ + 'adwaita-icon-theme-full', + 'alsa-utils', + 'apache2-utils', + 'arandr', + 'ardour', + 'audacity', + 'brasero', + 'breeze', + 'brightnessctl', + 'checkinstall', + 'cmake', + 'code', + 'cups', + 'dclock', + 'dolphin', + 'eog', + 'evtest', + 'eye', + 'fatrace', + 'firefox', + 'flameshot', + 'fontmatrix', + 'fonts-dejavu-core', + 'fonts-dejavu-extra', + 'fonts-dejavu', + 'fonts-droid-fallback', + 'fonts-emojione', + 'fonts-font-awesome', + 'fonts-freefont-ttf', + 'fonts-lato', + 'fonts-liberation2', + 'fonts-noto', + 'fonts-opensymbol', + 'fonts-quicksand', + 'fonts-texgyre', + 'fonts-ubuntu-console', + 'fonts-ubuntu', + 'fonts-urw-base35', + 'fvwm3', + 'gdb', + 'gedit', + 'gimp-data-extras', + 'gimp-gmic', + 'gimp-plugin-registry', + 'gimp-texturize', + 'gimp', + 'gnome-icon-theme', + 'gnumeric', + 'gnuplot', + 'golang', + 'google-chrome-stable', + 'google-chrome-unstable', + 'gstreamer1.0-libav', + 'gstreamer1.0-opencv', + 'gstreamer1.0-plugins-bad', + 'gstreamer1.0-plugins-ugly', + 'gstreamer1.0-tools', + 'gstreamer1.0-vaapi', + 'heif-gdk-pixbuf', + 'heif-thumbnailer', + 'humanity-icon-theme', + 'i3lock', + 'imagemagick', + 'imwheel', + 'jq', + 'k4dirstat', + 'libheif-examples', + 'libreoffice-draw', + 'libreoffice-impress', + 'libreoffice-writer', + 'libfuse2', # for obsidian (appimage) + 'libxcb-xkb1', # needed for kitty + 'lxterminal', + 'meld', + 'mpv', + 'nmap', + 'nodm', + 'okular', + 'pavucontrol', + 'pamixer', + 'pipewire-audio', + 'python3-dulwich', + 'python3-evemu', + 'python3-opencv', + 'python3-pycurl', + 'python3-rdflib', + 'python3-venv', + 'qjackctl', + 'qv4l2', + 'rar', + 'rclone', + 'recordmydesktop', + 'simple-scan', + 'simplescreenrecorder', + 'solvespace', + 'sqlitebrowser', + 'sshfs', + 'steam-launcher', + 'swi-prolog', + 'syncthing-gtk', # this may pull old ubu syncthing version, which sync.py replaces + 'system-config-printer', + 'systemd-resolved', + 'trayer', + 'ttf-bitstream-vera', + 'visidata', + 'vlc', + 'wamerican', + 'wireshark', + 'wmctrl', + 'x11-apps', + 'x11vnc', + 'xclip', + 'xfonts-base', + 'xfonts-encodings', + 'xfonts-utils', + 'xpad', + 'xsane', + 'xterm', + 'xtightvncviewer', + 'xvfb', + 'libssl-dev', # for pypi 'packages' + 'libcurl4-openssl-dev', # for pypi 'packages' + 'kicad', + 'openscad', + 'dunst', + 'gmic', + 'git-cola', + 'optipng', + 'pngcrush', + 'pngquant', + 'cdparanoia', +] + +xorg = [ + 'kbd', + 'nvidia-modprobe', + 'nvidia-prime', + 'nvidia-settings', + 'screen-resolution-extra', + 'xserver-xorg', +] + + +def k8s_node_with_nvidia_gpu(hostName): + version = { + 'dash': '550', + 'dot': '550', # just not updated yet + 'slash': '550', + 'ditto': '550-server', + # 'bang': '390-server', # no longer in ubuntu + 'squib': '470', # held back for old gfx card + }[hostName] + return [ + 'nvidia-container-runtime', + f'nvidia-headless-{version}', + f'nvidia-utils-{version}', + f'libnvidia-decode-{version}', + f'libnvidia-encode-{version}', + f'nvidia-driver-{version}', + ] + ([] if 'server' in version else [ + f'xserver-xorg-video-nvidia-{version}', + ])
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/packages/packages.py Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,158 @@ +from io import StringIO + +from pyinfra.context import host +from pyinfra.operations import apt, files, server, systemd + +import packages.package_lists as package_lists + + +def kitty(): + apt.packages(packages=['kitty'], present=False, force=True) + vers = '0.36.2' # see https://github.com/kovidgoyal/kitty/releases + home = '/home/drewp' + local = f"{home}/.local/kitty" + dl = f'/tmp/kitty-{vers}-x86_64.txz' + files.download(src=f"https://github.com/kovidgoyal/kitty/releases/download/v{vers}/kitty-{vers}-x86_64.txz", dest=dl) + files.directory(path=local) + server.shell(commands=[ + f"mkdir -p {local}", # https://github.com/Fizzadar/pyinfra/issues/777 + f"aunpack --extract-to={local} {dl}", + ]) + files.link(target="{local}/bin/kitty", path="{home}/bin/kitty") + files.link(target="{local}/bin/kitten", path="{home}/bin/kitten") + + +def nodejs(): + if 'pi' in host.groups or host.name == 'pipe' or host.name == 'prime': + return + apt.packages(packages=['libnode72'], present=False, force=True) + apt.packages(packages=['nodejs'], latest=True) + server.shell(commands=[ + "rm -f /usr/local/bin/pnp{m,x}", + "corepack enable", + # https://github.com/pnpm/pnpm/releases + # but also https://pnpm.io/installation#compatibility + "corepack prepare 'pnpm@9.8' --activate", + ]) + + +def podman(): + # frigate build wants to mount a single file from the host, which needs podman 4.5.1 + # https://github.com/containers/podman/issues/12123#issuecomment-1620439593 + server.shell(commands='apt --fix-broken install') + apt.deb(src="http://ftp.osuosl.org/pub/ubuntu/pool/main/g/gpgme1.0/libgpgme11t64_1.18.0-4.1ubuntu4_amd64.deb") + server.shell(commands='apt --fix-broken install') + apt.deb(src="http://ftp.osuosl.org/pub/ubuntu/pool/universe/c/conmon/conmon_2.1.10+ds1-1build2_amd64.deb") + apt.deb(src="http://ftp.osuosl.org/pub/ubuntu/pool/universe/libp/libpod/podman_4.9.3+ds1-1build2_amd64.deb") + apt.packages(packages=['libsubid4', 'buildah', 'podman-docker'], latest=True) + + +def pdm(): + # https://github.com/pdm-project/pdm/blob/main/CHANGELOG.md + server.shell(commands=["pip install --break-system-packages 'pdm==2.21.0'"]) + + +def proper_locate(): + apt.packages(packages='mlocate', present=False) + if 'pi' not in host.groups and host.name not in ['prime', 'pipe']: + apt.packages(packages='plocate') + + +def proper_man(): + if 'small' in host.groups or 'pi' in host.groups: + apt.packages(packages=['mandb'], present=False) + + +def no_unwanted_services(): + systemd.service(service='nginx', enabled=False, running=False) + + +apt.packages(packages=package_lists.setup, latest=True) + + +def roblox(): + server.shell(commands='flatpak install -y org.freedesktop.Platform/x86_64/23.08') + server.shell(commands='flatpak install -y flathub org.vinegarhq.Vinegar') # (roblox runner) + files.put( + src=StringIO( + #"#!/bin/sh\nexec flatpak run org.vinegarhq.Vinegar player run 'roblox-player:1'\n" + "#!/bin/sh\n exec /usr/bin/flatpak run --branch=stable --arch=x86_64 --command=vinegar org.vinegarhq.Vinegar player run -app\n" + ), + dest='/usr/local/bin/roblox.real', + mode='755') + + for desktopFile in [ + '/var/lib/flatpak/exports/share/applications/org.vinegarhq.Vinegar.app.desktop', + '/var/lib/flatpak/app/org.vinegarhq.Vinegar/current/active/export/share/applications/org.vinegarhq.Vinegar.player.desktop', + ]: + files.line(path=desktopFile, line="^Exec", replace='Exec=/usr/local/bin/roblox') + files.link(target='/usr/local/bin/run_while_allowed', path='/usr/local/bin/roblox', force=True) + + +def kube_node(): + + # avoid having to this workaround: + # https://longhorn.io/kb/troubleshooting-volume-with-multipath/ + apt.packages(packages=['multipath-tools'], force=True, present=False) + + apt.packages(packages=[ + # https://longhorn.io/docs/1.6.1/deploy/install/#installation-requirements + 'open-iscsi', + 'nfs-common', + 'cryptsetup', + ]) + + +def install_packages(): + apt.packages(packages=package_lists.general, latest=True) + apt.packages(packages=package_lists.debug, latest=True) + + if host.name == "pipe": + apt.packages(packages=package_lists.for_pipe, latest=True) + + if host.name != 'pipe': + apt.packages(packages=['reptyr']) + + if host.name == "prime": + apt.packages(packages=package_lists.for_prime, latest=True) + + if host.name == 'plus': + apt.packages(packages=package_lists.laptop, latest=True) + + if host.data.get('gpu'): + apt.packages(packages=package_lists.k8s_node_with_nvidia_gpu(host.name)) + + if host.data.get('k8s_admin'): + podman() + + is_kube_node = host.name in ['dash', 'slash', 'ditto', 'ws-printer', 'li-drums'] + if is_kube_node: + kube_node() + + if host.name == 'ditto': + apt.packages(packages=package_lists.for_ditto, latest=True) + + if 'pi' not in host.groups: + kitty() + apt.packages(packages=package_lists.non_pi, latest=True) + + if 'pi' in host.groups: + apt.packages(packages=package_lists.pi_setup) + + desktop_env = host.name in ['dash', 'slash', 'plus', 'dot', 'squib', 'pillow', 'tofu'] + if desktop_env: + apt.packages(packages=package_lists.xorg + package_lists.desktop, latest=True) + # broken, per https://vinegarhq.org/ + # roblox() + if desktop_env or host.name in ['bang', 'ditto']: + pdm() + + +operations = [ + proper_locate, + proper_man, + nodejs, + install_packages, + no_unwanted_services, +] +# todo: ./mrv2-v1.0.8-Linux-amd64.deb
--- a/pdm.lock Mon Jan 20 14:10:19 2025 -0800 +++ b/pdm.lock Mon Jan 20 21:55:08 2025 -0800 @@ -5,57 +5,57 @@ groups = ["default"] strategy = ["inherit_metadata"] lock_version = "4.5.0" -content_hash = "sha256:9781fcf43396e51303cb5dbdd0f03e03c15e7a8d9a715453d6d86573238cb9df" +content_hash = "sha256:2f3513e59e107ea4c3b5e84ef47ba0525373e5783d6e35047a2c694312cbc1c5" [[metadata.targets]] requires_python = ">=3.11" [[package]] name = "bcrypt" -version = "4.2.0" +version = "4.2.1" requires_python = ">=3.7" summary = "Modern password hashing for your software and your servers" groups = ["default"] files = [ - {file = "bcrypt-4.2.0-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:096a15d26ed6ce37a14c1ac1e48119660f21b24cba457f160a4b830f3fe6b5cb"}, - {file = "bcrypt-4.2.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c02d944ca89d9b1922ceb8a46460dd17df1ba37ab66feac4870f6862a1533c00"}, - {file = "bcrypt-4.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d84cf6d877918620b687b8fd1bf7781d11e8a0998f576c7aa939776b512b98d"}, - {file = "bcrypt-4.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:1bb429fedbe0249465cdd85a58e8376f31bb315e484f16e68ca4c786dcc04291"}, - {file = "bcrypt-4.2.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:655ea221910bcac76ea08aaa76df427ef8625f92e55a8ee44fbf7753dbabb328"}, - {file = "bcrypt-4.2.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:1ee38e858bf5d0287c39b7a1fc59eec64bbf880c7d504d3a06a96c16e14058e7"}, - {file = "bcrypt-4.2.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:0da52759f7f30e83f1e30a888d9163a81353ef224d82dc58eb5bb52efcabc399"}, - {file = "bcrypt-4.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3698393a1b1f1fd5714524193849d0c6d524d33523acca37cd28f02899285060"}, - {file = "bcrypt-4.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:762a2c5fb35f89606a9fde5e51392dad0cd1ab7ae64149a8b935fe8d79dd5ed7"}, - {file = "bcrypt-4.2.0-cp37-abi3-win32.whl", hash = "sha256:5a1e8aa9b28ae28020a3ac4b053117fb51c57a010b9f969603ed885f23841458"}, - {file = "bcrypt-4.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:8f6ede91359e5df88d1f5c1ef47428a4420136f3ce97763e31b86dd8280fbdf5"}, - {file = "bcrypt-4.2.0-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:c52aac18ea1f4a4f65963ea4f9530c306b56ccd0c6f8c8da0c06976e34a6e841"}, - {file = "bcrypt-4.2.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3bbbfb2734f0e4f37c5136130405332640a1e46e6b23e000eeff2ba8d005da68"}, - {file = "bcrypt-4.2.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3413bd60460f76097ee2e0a493ccebe4a7601918219c02f503984f0a7ee0aebe"}, - {file = "bcrypt-4.2.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:8d7bb9c42801035e61c109c345a28ed7e84426ae4865511eb82e913df18f58c2"}, - {file = "bcrypt-4.2.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3d3a6d28cb2305b43feac298774b997e372e56c7c7afd90a12b3dc49b189151c"}, - {file = "bcrypt-4.2.0-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:9c1c4ad86351339c5f320ca372dfba6cb6beb25e8efc659bedd918d921956bae"}, - {file = "bcrypt-4.2.0-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:27fe0f57bb5573104b5a6de5e4153c60814c711b29364c10a75a54bb6d7ff48d"}, - {file = "bcrypt-4.2.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:8ac68872c82f1add6a20bd489870c71b00ebacd2e9134a8aa3f98a0052ab4b0e"}, - {file = "bcrypt-4.2.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:cb2a8ec2bc07d3553ccebf0746bbf3d19426d1c6d1adbd4fa48925f66af7b9e8"}, - {file = "bcrypt-4.2.0-cp39-abi3-win32.whl", hash = "sha256:77800b7147c9dc905db1cba26abe31e504d8247ac73580b4aa179f98e6608f34"}, - {file = "bcrypt-4.2.0-cp39-abi3-win_amd64.whl", hash = "sha256:61ed14326ee023917ecd093ee6ef422a72f3aec6f07e21ea5f10622b735538a9"}, - {file = "bcrypt-4.2.0.tar.gz", hash = "sha256:cf69eaf5185fd58f268f805b505ce31f9b9fc2d64b376642164e9244540c1221"}, + {file = "bcrypt-4.2.1-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:1340411a0894b7d3ef562fb233e4b6ed58add185228650942bdc885362f32c17"}, + {file = "bcrypt-4.2.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1ee315739bc8387aa36ff127afc99120ee452924e0df517a8f3e4c0187a0f5f"}, + {file = "bcrypt-4.2.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dbd0747208912b1e4ce730c6725cb56c07ac734b3629b60d4398f082ea718ad"}, + {file = "bcrypt-4.2.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:aaa2e285be097050dba798d537b6efd9b698aa88eef52ec98d23dcd6d7cf6fea"}, + {file = "bcrypt-4.2.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:76d3e352b32f4eeb34703370e370997065d28a561e4a18afe4fef07249cb4396"}, + {file = "bcrypt-4.2.1-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:b7703ede632dc945ed1172d6f24e9f30f27b1b1a067f32f68bf169c5f08d0425"}, + {file = "bcrypt-4.2.1-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:89df2aea2c43be1e1fa066df5f86c8ce822ab70a30e4c210968669565c0f4685"}, + {file = "bcrypt-4.2.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:04e56e3fe8308a88b77e0afd20bec516f74aecf391cdd6e374f15cbed32783d6"}, + {file = "bcrypt-4.2.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:cfdf3d7530c790432046c40cda41dfee8c83e29482e6a604f8930b9930e94139"}, + {file = "bcrypt-4.2.1-cp37-abi3-win32.whl", hash = "sha256:adadd36274510a01f33e6dc08f5824b97c9580583bd4487c564fc4617b328005"}, + {file = "bcrypt-4.2.1-cp37-abi3-win_amd64.whl", hash = "sha256:8c458cd103e6c5d1d85cf600e546a639f234964d0228909d8f8dbeebff82d526"}, + {file = "bcrypt-4.2.1-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:8ad2f4528cbf0febe80e5a3a57d7a74e6635e41af1ea5675282a33d769fba413"}, + {file = "bcrypt-4.2.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:909faa1027900f2252a9ca5dfebd25fc0ef1417943824783d1c8418dd7d6df4a"}, + {file = "bcrypt-4.2.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cde78d385d5e93ece5479a0a87f73cd6fa26b171c786a884f955e165032b262c"}, + {file = "bcrypt-4.2.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:533e7f3bcf2f07caee7ad98124fab7499cb3333ba2274f7a36cf1daee7409d99"}, + {file = "bcrypt-4.2.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:687cf30e6681eeda39548a93ce9bfbb300e48b4d445a43db4298d2474d2a1e54"}, + {file = "bcrypt-4.2.1-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:041fa0155c9004eb98a232d54da05c0b41d4b8e66b6fc3cb71b4b3f6144ba837"}, + {file = "bcrypt-4.2.1-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f85b1ffa09240c89aa2e1ae9f3b1c687104f7b2b9d2098da4e923f1b7082d331"}, + {file = "bcrypt-4.2.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c6f5fa3775966cca251848d4d5393ab016b3afed251163c1436fefdec3b02c84"}, + {file = "bcrypt-4.2.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:807261df60a8b1ccd13e6599c779014a362ae4e795f5c59747f60208daddd96d"}, + {file = "bcrypt-4.2.1-cp39-abi3-win32.whl", hash = "sha256:b588af02b89d9fad33e5f98f7838bf590d6d692df7153647724a7f20c186f6bf"}, + {file = "bcrypt-4.2.1-cp39-abi3-win_amd64.whl", hash = "sha256:e84e0e6f8e40a242b11bce56c313edc2be121cec3e0ec2d76fce01f6af33c07c"}, + {file = "bcrypt-4.2.1.tar.gz", hash = "sha256:6765386e3ab87f569b276988742039baab087b2cdb01e809d74e74503c2faafe"}, ] [[package]] name = "certifi" -version = "2024.7.4" +version = "2024.12.14" requires_python = ">=3.6" summary = "Python package for providing Mozilla's CA Bundle." groups = ["default"] files = [ - {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, - {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, + {file = "certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56"}, + {file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"}, ] [[package]] name = "cffi" -version = "1.17.0" +version = "1.17.1" requires_python = ">=3.8" summary = "Foreign Function Interface for Python calling C code." groups = ["default"] @@ -63,87 +63,96 @@ "pycparser", ] files = [ - {file = "cffi-1.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5d97162c196ce54af6700949ddf9409e9833ef1003b4741c2b39ef46f1d9720"}, - {file = "cffi-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ba5c243f4004c750836f81606a9fcb7841f8874ad8f3bf204ff5e56332b72b9"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bb9333f58fc3a2296fb1d54576138d4cf5d496a2cc118422bd77835e6ae0b9cb"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:435a22d00ec7d7ea533db494da8581b05977f9c37338c80bc86314bec2619424"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1df34588123fcc88c872f5acb6f74ae59e9d182a2707097f9e28275ec26a12d"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df8bb0010fdd0a743b7542589223a2816bdde4d94bb5ad67884348fa2c1c67e8"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8b5b9712783415695663bd463990e2f00c6750562e6ad1d28e072a611c5f2a6"}, - {file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ffef8fd58a36fb5f1196919638f73dd3ae0db1a878982b27a9a5a176ede4ba91"}, - {file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e67d26532bfd8b7f7c05d5a766d6f437b362c1bf203a3a5ce3593a645e870b8"}, - {file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:45f7cd36186db767d803b1473b3c659d57a23b5fa491ad83c6d40f2af58e4dbb"}, - {file = "cffi-1.17.0-cp311-cp311-win32.whl", hash = "sha256:a9015f5b8af1bb6837a3fcb0cdf3b874fe3385ff6274e8b7925d81ccaec3c5c9"}, - {file = "cffi-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:b50aaac7d05c2c26dfd50c3321199f019ba76bb650e346a6ef3616306eed67b0"}, - {file = "cffi-1.17.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aec510255ce690d240f7cb23d7114f6b351c733a74c279a84def763660a2c3bc"}, - {file = "cffi-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2770bb0d5e3cc0e31e7318db06efcbcdb7b31bcb1a70086d3177692a02256f59"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db9a30ec064129d605d0f1aedc93e00894b9334ec74ba9c6bdd08147434b33eb"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a47eef975d2b8b721775a0fa286f50eab535b9d56c70a6e62842134cf7841195"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f3e0992f23bbb0be00a921eae5363329253c3b86287db27092461c887b791e5e"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6107e445faf057c118d5050560695e46d272e5301feffda3c41849641222a828"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb862356ee9391dc5a0b3cbc00f416b48c1b9a52d252d898e5b7696a5f9fe150"}, - {file = "cffi-1.17.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c1c13185b90bbd3f8b5963cd8ce7ad4ff441924c31e23c975cb150e27c2bf67a"}, - {file = "cffi-1.17.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:17c6d6d3260c7f2d94f657e6872591fe8733872a86ed1345bda872cfc8c74885"}, - {file = "cffi-1.17.0-cp312-cp312-win32.whl", hash = "sha256:c3b8bd3133cd50f6b637bb4322822c94c5ce4bf0d724ed5ae70afce62187c492"}, - {file = "cffi-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:dca802c8db0720ce1c49cce1149ff7b06e91ba15fa84b1d59144fef1a1bc7ac2"}, - {file = "cffi-1.17.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6ce01337d23884b21c03869d2f68c5523d43174d4fc405490eb0091057943118"}, - {file = "cffi-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cab2eba3830bf4f6d91e2d6718e0e1c14a2f5ad1af68a89d24ace0c6b17cced7"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14b9cbc8f7ac98a739558eb86fabc283d4d564dafed50216e7f7ee62d0d25377"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b00e7bcd71caa0282cbe3c90966f738e2db91e64092a877c3ff7f19a1628fdcb"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:41f4915e09218744d8bae14759f983e466ab69b178de38066f7579892ff2a555"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4760a68cab57bfaa628938e9c2971137e05ce48e762a9cb53b76c9b569f1204"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:011aff3524d578a9412c8b3cfaa50f2c0bd78e03eb7af7aa5e0df59b158efb2f"}, - {file = "cffi-1.17.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:a003ac9edc22d99ae1286b0875c460351f4e101f8c9d9d2576e78d7e048f64e0"}, - {file = "cffi-1.17.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ef9528915df81b8f4c7612b19b8628214c65c9b7f74db2e34a646a0a2a0da2d4"}, - {file = "cffi-1.17.0-cp313-cp313-win32.whl", hash = "sha256:70d2aa9fb00cf52034feac4b913181a6e10356019b18ef89bc7c12a283bf5f5a"}, - {file = "cffi-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:b7b6ea9e36d32582cda3465f54c4b454f62f23cb083ebc7a94e2ca6ef011c3a7"}, - {file = "cffi-1.17.0.tar.gz", hash = "sha256:f3157624b7558b914cb039fd1af735e5e8049a87c817cc215109ad1c8779df76"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, + {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, + {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, + {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, + {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, + {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, + {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, + {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, ] [[package]] name = "charset-normalizer" -version = "3.3.2" -requires_python = ">=3.7.0" +version = "3.4.1" +requires_python = ">=3.7" summary = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." groups = ["default"] files = [ - {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, - {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971"}, + {file = "charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85"}, + {file = "charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3"}, ] [[package]] name = "click" -version = "8.1.7" +version = "8.1.8" requires_python = ">=3.7" summary = "Composable command line interface toolkit" groups = ["default"] @@ -152,8 +161,8 @@ "importlib-metadata; python_version < \"3.8\"", ] files = [ - {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, - {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, + {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, + {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, ] [[package]] @@ -169,45 +178,36 @@ ] [[package]] -name = "configparser" -version = "7.1.0" -requires_python = ">=3.8" -summary = "Updated configparser from stdlib for earlier Pythons." -groups = ["default"] -files = [ - {file = "configparser-7.1.0-py3-none-any.whl", hash = "sha256:98e374573c4e10e92399651e3ba1c47a438526d633c44ee96143dec26dad4299"}, - {file = "configparser-7.1.0.tar.gz", hash = "sha256:eb82646c892dbdf773dae19c633044d163c3129971ae09b49410a303b8e0a5f7"}, -] - -[[package]] name = "cryptography" -version = "43.0.0" -requires_python = ">=3.7" +version = "44.0.0" +requires_python = "!=3.9.0,!=3.9.1,>=3.7" summary = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." groups = ["default"] dependencies = [ "cffi>=1.12; platform_python_implementation != \"PyPy\"", ] files = [ - {file = "cryptography-43.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:64c3f16e2a4fc51c0d06af28441881f98c5d91009b8caaff40cf3548089e9c74"}, - {file = "cryptography-43.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3dcdedae5c7710b9f97ac6bba7e1052b95c7083c9d0e9df96e02a1932e777895"}, - {file = "cryptography-43.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d9a1eca329405219b605fac09ecfc09ac09e595d6def650a437523fcd08dd22"}, - {file = "cryptography-43.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ea9e57f8ea880eeea38ab5abf9fbe39f923544d7884228ec67d666abd60f5a47"}, - {file = "cryptography-43.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9a8d6802e0825767476f62aafed40532bd435e8a5f7d23bd8b4f5fd04cc80ecf"}, - {file = "cryptography-43.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cc70b4b581f28d0a254d006f26949245e3657d40d8857066c2ae22a61222ef55"}, - {file = "cryptography-43.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4a997df8c1c2aae1e1e5ac49c2e4f610ad037fc5a3aadc7b64e39dea42249431"}, - {file = "cryptography-43.0.0-cp37-abi3-win32.whl", hash = "sha256:6e2b11c55d260d03a8cf29ac9b5e0608d35f08077d8c087be96287f43af3ccdc"}, - {file = "cryptography-43.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:31e44a986ceccec3d0498e16f3d27b2ee5fdf69ce2ab89b52eaad1d2f33d8778"}, - {file = "cryptography-43.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:7b3f5fe74a5ca32d4d0f302ffe6680fcc5c28f8ef0dc0ae8f40c0f3a1b4fca66"}, - {file = "cryptography-43.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac1955ce000cb29ab40def14fd1bbfa7af2017cca696ee696925615cafd0dce5"}, - {file = "cryptography-43.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:299d3da8e00b7e2b54bb02ef58d73cd5f55fb31f33ebbf33bd00d9aa6807df7e"}, - {file = "cryptography-43.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ee0c405832ade84d4de74b9029bedb7b31200600fa524d218fc29bfa371e97f5"}, - {file = "cryptography-43.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cb013933d4c127349b3948aa8aaf2f12c0353ad0eccd715ca789c8a0f671646f"}, - {file = "cryptography-43.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fdcb265de28585de5b859ae13e3846a8e805268a823a12a4da2597f1f5afc9f0"}, - {file = "cryptography-43.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2905ccf93a8a2a416f3ec01b1a7911c3fe4073ef35640e7ee5296754e30b762b"}, - {file = "cryptography-43.0.0-cp39-abi3-win32.whl", hash = "sha256:47ca71115e545954e6c1d207dd13461ab81f4eccfcb1345eac874828b5e3eaaf"}, - {file = "cryptography-43.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:0663585d02f76929792470451a5ba64424acc3cd5227b03921dab0e2f27b1709"}, - {file = "cryptography-43.0.0.tar.gz", hash = "sha256:b88075ada2d51aa9f18283532c9f60e72170041bba88d7f37e49cbb10275299e"}, + {file = "cryptography-44.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123"}, + {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092"}, + {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831c3c4d0774e488fdc83a1923b49b9957d33287de923d58ebd3cec47a0ae43f"}, + {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb"}, + {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b"}, + {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543"}, + {file = "cryptography-44.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e"}, + {file = "cryptography-44.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e"}, + {file = "cryptography-44.0.0-cp37-abi3-win32.whl", hash = "sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053"}, + {file = "cryptography-44.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:abc998e0c0eee3c8a1904221d3f67dcfa76422b23620173e28c11d3e626c21bd"}, + {file = "cryptography-44.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:660cb7312a08bc38be15b696462fa7cc7cd85c3ed9c576e81f4dc4d8b2b31591"}, + {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1923cb251c04be85eec9fda837661c67c1049063305d6be5721643c22dd4e2b7"}, + {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:404fdc66ee5f83a1388be54300ae978b2efd538018de18556dde92575e05defc"}, + {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289"}, + {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7"}, + {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c"}, + {file = "cryptography-44.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64"}, + {file = "cryptography-44.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285"}, + {file = "cryptography-44.0.0-cp39-abi3-win32.whl", hash = "sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417"}, + {file = "cryptography-44.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:708ee5f1bafe76d041b53a4f95eb28cdeb8d18da17e597d46d7833ee59b97ede"}, + {file = "cryptography-44.0.0.tar.gz", hash = "sha256:cd4e834f340b4293430701e772ec543b0fbe6c2dea510a5286fe0acabe153a02"}, ] [[package]] @@ -223,82 +223,114 @@ [[package]] name = "gevent" -version = "24.2.1" -requires_python = ">=3.8" +version = "24.11.1" +requires_python = ">=3.9" summary = "Coroutine-based network library" groups = ["default"] dependencies = [ - "cffi>=1.12.2; platform_python_implementation == \"CPython\" and sys_platform == \"win32\"", - "greenlet>=2.0.0; platform_python_implementation == \"CPython\" and python_version < \"3.11\"", - "greenlet>=3.0rc3; platform_python_implementation == \"CPython\" and python_version >= \"3.11\"", + "cffi>=1.17.1; platform_python_implementation == \"CPython\" and sys_platform == \"win32\"", + "greenlet>=3.1.1; platform_python_implementation == \"CPython\"", "zope-event", "zope-interface", ] files = [ - {file = "gevent-24.2.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:03aa5879acd6b7076f6a2a307410fb1e0d288b84b03cdfd8c74db8b4bc882fc5"}, - {file = "gevent-24.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8bb35ce57a63c9a6896c71a285818a3922d8ca05d150fd1fe49a7f57287b836"}, - {file = "gevent-24.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d7f87c2c02e03d99b95cfa6f7a776409083a9e4d468912e18c7680437b29222c"}, - {file = "gevent-24.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:968581d1717bbcf170758580f5f97a2925854943c45a19be4d47299507db2eb7"}, - {file = "gevent-24.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7899a38d0ae7e817e99adb217f586d0a4620e315e4de577444ebeeed2c5729be"}, - {file = "gevent-24.2.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:f5e8e8d60e18d5f7fd49983f0c4696deeddaf6e608fbab33397671e2fcc6cc91"}, - {file = "gevent-24.2.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fbfdce91239fe306772faab57597186710d5699213f4df099d1612da7320d682"}, - {file = "gevent-24.2.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cdf66977a976d6a3cfb006afdf825d1482f84f7b81179db33941f2fc9673bb1d"}, - {file = "gevent-24.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:1dffb395e500613e0452b9503153f8f7ba587c67dd4a85fc7cd7aa7430cb02cc"}, - {file = "gevent-24.2.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:6c47ae7d1174617b3509f5d884935e788f325eb8f1a7efc95d295c68d83cce40"}, - {file = "gevent-24.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7cac622e11b4253ac4536a654fe221249065d9a69feb6cdcd4d9af3503602e0"}, - {file = "gevent-24.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bf5b9c72b884c6f0c4ed26ef204ee1f768b9437330422492c319470954bc4cc7"}, - {file = "gevent-24.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f5de3c676e57177b38857f6e3cdfbe8f38d1cd754b63200c0615eaa31f514b4f"}, - {file = "gevent-24.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4faf846ed132fd7ebfbbf4fde588a62d21faa0faa06e6f468b7faa6f436b661"}, - {file = "gevent-24.2.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:368a277bd9278ddb0fde308e6a43f544222d76ed0c4166e0d9f6b036586819d9"}, - {file = "gevent-24.2.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f8a04cf0c5b7139bc6368b461257d4a757ea2fe89b3773e494d235b7dd51119f"}, - {file = "gevent-24.2.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9d8d0642c63d453179058abc4143e30718b19a85cbf58c2744c9a63f06a1d388"}, - {file = "gevent-24.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:94138682e68ec197db42ad7442d3cf9b328069c3ad8e4e5022e6b5cd3e7ffae5"}, - {file = "gevent-24.2.1.tar.gz", hash = "sha256:432fc76f680acf7cf188c2ee0f5d3ab73b63c1f03114c7cd8a34cebbe5aa2056"}, + {file = "gevent-24.11.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:351d1c0e4ef2b618ace74c91b9b28b3eaa0dd45141878a964e03c7873af09f62"}, + {file = "gevent-24.11.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5efe72e99b7243e222ba0c2c2ce9618d7d36644c166d63373af239da1036bab"}, + {file = "gevent-24.11.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d3b249e4e1f40c598ab8393fc01ae6a3b4d51fc1adae56d9ba5b315f6b2d758"}, + {file = "gevent-24.11.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81d918e952954675f93fb39001da02113ec4d5f4921bf5a0cc29719af6824e5d"}, + {file = "gevent-24.11.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9c935b83d40c748b6421625465b7308d87c7b3717275acd587eef2bd1c39546"}, + {file = "gevent-24.11.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff96c5739834c9a594db0e12bf59cb3fa0e5102fc7b893972118a3166733d61c"}, + {file = "gevent-24.11.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d6c0a065e31ef04658f799215dddae8752d636de2bed61365c358f9c91e7af61"}, + {file = "gevent-24.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:97e2f3999a5c0656f42065d02939d64fffaf55861f7d62b0107a08f52c984897"}, + {file = "gevent-24.11.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:a3d75fa387b69c751a3d7c5c3ce7092a171555126e136c1d21ecd8b50c7a6e46"}, + {file = "gevent-24.11.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:beede1d1cff0c6fafae3ab58a0c470d7526196ef4cd6cc18e7769f207f2ea4eb"}, + {file = "gevent-24.11.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:85329d556aaedced90a993226d7d1186a539c843100d393f2349b28c55131c85"}, + {file = "gevent-24.11.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:816b3883fa6842c1cf9d2786722014a0fd31b6312cca1f749890b9803000bad6"}, + {file = "gevent-24.11.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b24d800328c39456534e3bc3e1684a28747729082684634789c2f5a8febe7671"}, + {file = "gevent-24.11.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a5f1701ce0f7832f333dd2faf624484cbac99e60656bfbb72504decd42970f0f"}, + {file = "gevent-24.11.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:d740206e69dfdfdcd34510c20adcb9777ce2cc18973b3441ab9767cd8948ca8a"}, + {file = "gevent-24.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:68bee86b6e1c041a187347ef84cf03a792f0b6c7238378bf6ba4118af11feaae"}, + {file = "gevent-24.11.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:d618e118fdb7af1d6c1a96597a5cd6ac84a9f3732b5be8515c6a66e098d498b6"}, + {file = "gevent-24.11.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2142704c2adce9cd92f6600f371afb2860a446bfd0be5bd86cca5b3e12130766"}, + {file = "gevent-24.11.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92e0d7759de2450a501effd99374256b26359e801b2d8bf3eedd3751973e87f5"}, + {file = "gevent-24.11.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca845138965c8c56d1550499d6b923eb1a2331acfa9e13b817ad8305dde83d11"}, + {file = "gevent-24.11.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:356b73d52a227d3313f8f828025b665deada57a43d02b1cf54e5d39028dbcf8d"}, + {file = "gevent-24.11.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:58851f23c4bdb70390f10fc020c973ffcf409eb1664086792c8b1e20f25eef43"}, + {file = "gevent-24.11.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:1ea50009ecb7f1327347c37e9eb6561bdbc7de290769ee1404107b9a9cba7cf1"}, + {file = "gevent-24.11.1-cp313-cp313-win_amd64.whl", hash = "sha256:ec68e270543ecd532c4c1d70fca020f90aa5486ad49c4f3b8b2e64a66f5c9274"}, + {file = "gevent-24.11.1.tar.gz", hash = "sha256:8bd1419114e9e4a3ed33a5bad766afff9a3cf765cb440a582a1b3a9bc80c1aca"}, ] [[package]] name = "greenlet" -version = "3.0.3" +version = "3.1.1" requires_python = ">=3.7" summary = "Lightweight in-process concurrent programming" groups = ["default"] -marker = "platform_python_implementation == \"CPython\" and python_version >= \"3.11\"" +marker = "platform_python_implementation == \"CPython\"" files = [ - {file = "greenlet-3.0.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22"}, - {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3"}, - {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d"}, - {file = "greenlet-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728"}, - {file = "greenlet-3.0.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf"}, - {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305"}, - {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6"}, - {file = "greenlet-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2"}, - {file = "greenlet-3.0.3.tar.gz", hash = "sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491"}, + {file = "greenlet-3.1.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:e4d333e558953648ca09d64f13e6d8f0523fa705f51cae3f03b5983489958c70"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fc016b73c94e98e29af67ab7b9a879c307c6731a2c9da0db5a7d9b7edd1159"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5e975ca70269d66d17dd995dafc06f1b06e8cb1ec1e9ed54c1d1e4a7c4cf26e"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b2813dc3de8c1ee3f924e4d4227999285fd335d1bcc0d2be6dc3f1f6a318ec1"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e347b3bfcf985a05e8c0b7d462ba6f15b1ee1c909e2dcad795e49e91b152c383"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e8f8c9cb53cdac7ba9793c276acd90168f416b9ce36799b9b885790f8ad6c0a"}, + {file = "greenlet-3.1.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:62ee94988d6b4722ce0028644418d93a52429e977d742ca2ccbe1c4f4a792511"}, + {file = "greenlet-3.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1776fd7f989fc6b8d8c8cb8da1f6b82c5814957264d1f6cf818d475ec2bf6395"}, + {file = "greenlet-3.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:48ca08c771c268a768087b408658e216133aecd835c0ded47ce955381105ba39"}, + {file = "greenlet-3.1.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:4afe7ea89de619adc868e087b4d2359282058479d7cfb94970adf4b55284574d"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f406b22b7c9a9b4f8aa9d2ab13d6ae0ac3e85c9a809bd590ad53fed2bf70dc79"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c3a701fe5a9695b238503ce5bbe8218e03c3bcccf7e204e455e7462d770268aa"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2846930c65b47d70b9d178e89c7e1a69c95c1f68ea5aa0a58646b7a96df12441"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99cfaa2110534e2cf3ba31a7abcac9d328d1d9f1b95beede58294a60348fba36"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1443279c19fca463fc33e65ef2a935a5b09bb90f978beab37729e1c3c6c25fe9"}, + {file = "greenlet-3.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b7cede291382a78f7bb5f04a529cb18e068dd29e0fb27376074b6d0317bf4dd0"}, + {file = "greenlet-3.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:23f20bb60ae298d7d8656c6ec6db134bca379ecefadb0b19ce6f19d1f232a942"}, + {file = "greenlet-3.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:7124e16b4c55d417577c2077be379514321916d5790fa287c9ed6f23bd2ffd01"}, + {file = "greenlet-3.1.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:05175c27cb459dcfc05d026c4232f9de8913ed006d42713cb8a5137bd49375f1"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:935e943ec47c4afab8965954bf49bfa639c05d4ccf9ef6e924188f762145c0ff"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667a9706c970cb552ede35aee17339a18e8f2a87a51fba2ed39ceeeb1004798a"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8a678974d1f3aa55f6cc34dc480169d58f2e6d8958895d68845fa4ab566509e"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efc0f674aa41b92da8c49e0346318c6075d734994c3c4e4430b1c3f853e498e4"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0153404a4bb921f0ff1abeb5ce8a5131da56b953eda6e14b88dc6bbc04d2049e"}, + {file = "greenlet-3.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:275f72decf9932639c1c6dd1013a1bc266438eb32710016a1c742df5da6e60a1"}, + {file = "greenlet-3.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c4aab7f6381f38a4b42f269057aee279ab0fc7bf2e929e3d4abfae97b682a12c"}, + {file = "greenlet-3.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:b42703b1cf69f2aa1df7d1030b9d77d3e584a70755674d60e710f0af570f3761"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1695e76146579f8c06c1509c7ce4dfe0706f49c6831a817ac04eebb2fd02011"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7876452af029456b3f3549b696bb36a06db7c90747740c5302f74a9e9fa14b13"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ead44c85f8ab905852d3de8d86f6f8baf77109f9da589cb4fa142bd3b57b475"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8320f64b777d00dd7ccdade271eaf0cad6636343293a25074cc5566160e4de7b"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6510bf84a6b643dabba74d3049ead221257603a253d0a9873f55f6a59a65f822"}, + {file = "greenlet-3.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:04b013dc07c96f83134b1e99888e7a79979f1a247e2a9f59697fa14b5862ed01"}, + {file = "greenlet-3.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:411f015496fec93c1c8cd4e5238da364e1da7a124bcb293f085bf2860c32c6f6"}, + {file = "greenlet-3.1.1.tar.gz", hash = "sha256:4ce3ac6cdb6adf7946475d7ef31777c26d94bccc377e070a7986bd2d5c515467"}, ] [[package]] name = "idna" -version = "3.8" +version = "3.10" requires_python = ">=3.6" summary = "Internationalized Domain Names in Applications (IDNA)" groups = ["default"] files = [ - {file = "idna-3.8-py3-none-any.whl", hash = "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac"}, - {file = "idna-3.8.tar.gz", hash = "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603"}, + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, +] + +[[package]] +name = "invoke" +version = "2.2.0" +requires_python = ">=3.6" +summary = "Pythonic task execution" +groups = ["default"] +files = [ + {file = "invoke-2.2.0-py3-none-any.whl", hash = "sha256:6ea924cc53d4f78e3d98bc436b08069a03077e6f85ad1ddaa8a116d7dad15820"}, + {file = "invoke-2.2.0.tar.gz", hash = "sha256:ee6cbb101af1a859c7fe84f2a264c059020b0cb7fe3535f9424300ab568f6bd5"}, ] [[package]] name = "jinja2" -version = "3.1.4" +version = "3.1.5" requires_python = ">=3.7" summary = "A very fast and expressive template engine." groups = ["default"] @@ -306,65 +338,85 @@ "MarkupSafe>=2.0", ] files = [ - {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, - {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, + {file = "jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb"}, + {file = "jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb"}, ] [[package]] name = "markupsafe" -version = "2.1.5" -requires_python = ">=3.7" +version = "3.0.2" +requires_python = ">=3.9" summary = "Safely add untrusted strings to HTML/XML markup." groups = ["default"] files = [ - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, - {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, + {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, ] [[package]] name = "more-itertools" -version = "10.4.0" -requires_python = ">=3.8" +version = "10.6.0" +requires_python = ">=3.9" summary = "More routines for operating on iterables, beyond itertools" groups = ["default"] files = [ - {file = "more-itertools-10.4.0.tar.gz", hash = "sha256:fe0e63c4ab068eac62410ab05cccca2dc71ec44ba8ef29916a0090df061cf923"}, - {file = "more_itertools-10.4.0-py3-none-any.whl", hash = "sha256:0f7d9f83a0a8dcfa8a2694a770590d98a67ea943e3d9f5298309a484758c4e27"}, + {file = "more-itertools-10.6.0.tar.gz", hash = "sha256:2cd7fad1009c31cc9fb6a035108509e6547547a7a738374f10bd49a09eb3ee3b"}, + {file = "more_itertools-10.6.0-py3-none-any.whl", hash = "sha256:6eb054cb4b6db1473f6e15fcc676a08e4732548acd47c708f0e179c2c7c01e89"}, ] [[package]] name = "packaging" -version = "24.1" +version = "24.2" requires_python = ">=3.8" summary = "Core utilities for Python packages" groups = ["default"] files = [ - {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, - {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] [[package]] name = "paramiko" -version = "3.4.1" +version = "3.5.0" requires_python = ">=3.6" summary = "SSH2 protocol library" groups = ["default"] @@ -374,25 +426,25 @@ "pynacl>=1.5", ] files = [ - {file = "paramiko-3.4.1-py3-none-any.whl", hash = "sha256:8e49fd2f82f84acf7ffd57c64311aa2b30e575370dc23bdb375b10262f7eac32"}, - {file = "paramiko-3.4.1.tar.gz", hash = "sha256:8b15302870af7f6652f2e038975c1d2973f06046cb5d7d65355668b3ecbece0c"}, + {file = "paramiko-3.5.0-py3-none-any.whl", hash = "sha256:1fedf06b085359051cd7d0d270cebe19e755a8a921cc2ddbfa647fb0cd7d68f9"}, + {file = "paramiko-3.5.0.tar.gz", hash = "sha256:ad11e540da4f55cedda52931f1a3f812a8238a7af7f62a60de538cd80bb28124"}, ] [[package]] name = "psutil" -version = "6.0.0" +version = "6.1.1" requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" summary = "Cross-platform lib for process and system monitoring in Python." groups = ["default"] files = [ - {file = "psutil-6.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c588a7e9b1173b6e866756dde596fd4cad94f9399daf99ad8c3258b3cb2b47a0"}, - {file = "psutil-6.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ed2440ada7ef7d0d608f20ad89a04ec47d2d3ab7190896cd62ca5fc4fe08bf0"}, - {file = "psutil-6.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fd9a97c8e94059b0ef54a7d4baf13b405011176c3b6ff257c247cae0d560ecd"}, - {file = "psutil-6.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e8d0054fc88153ca0544f5c4d554d42e33df2e009c4ff42284ac9ebdef4132"}, - {file = "psutil-6.0.0-cp37-abi3-win32.whl", hash = "sha256:a495580d6bae27291324fe60cea0b5a7c23fa36a7cd35035a16d93bdcf076b9d"}, - {file = "psutil-6.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:33ea5e1c975250a720b3a6609c490db40dae5d83a4eb315170c4fe0d8b1f34b3"}, - {file = "psutil-6.0.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:ffe7fc9b6b36beadc8c322f84e1caff51e8703b88eee1da46d1e3a6ae11b4fd0"}, - {file = "psutil-6.0.0.tar.gz", hash = "sha256:8faae4f310b6d969fa26ca0545338b21f73c6b15db7c4a8d934a5482faa818f2"}, + {file = "psutil-6.1.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:fc0ed7fe2231a444fc219b9c42d0376e0a9a1a72f16c5cfa0f68d19f1a0663e8"}, + {file = "psutil-6.1.1-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0bdd4eab935276290ad3cb718e9809412895ca6b5b334f5a9111ee6d9aff9377"}, + {file = "psutil-6.1.1-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6e06c20c05fe95a3d7302d74e7097756d4ba1247975ad6905441ae1b5b66003"}, + {file = "psutil-6.1.1-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97f7cb9921fbec4904f522d972f0c0e1f4fabbdd4e0287813b21215074a0f160"}, + {file = "psutil-6.1.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33431e84fee02bc84ea36d9e2c4a6d395d479c9dd9bba2376c1f6ee8f3a4e0b3"}, + {file = "psutil-6.1.1-cp37-abi3-win32.whl", hash = "sha256:eaa912e0b11848c4d9279a93d7e2783df352b082f40111e078388701fd479e53"}, + {file = "psutil-6.1.1-cp37-abi3-win_amd64.whl", hash = "sha256:f35cfccb065fff93529d2afb4a2e89e363fe63ca1e4a5da22b603a85833c2649"}, + {file = "psutil-6.1.1.tar.gz", hash = "sha256:cf8496728c18f2d0b45198f06895be52f36611711746b7f30c464b422b50e2f5"}, ] [[package]] @@ -408,13 +460,12 @@ [[package]] name = "pyinfra" -version = "3.1" +version = "3.2" requires_python = ">=3.8" summary = "pyinfra automates/provisions/manages/deploys infrastructure." groups = ["default"] dependencies = [ "click>2", - "configparser", "distro<2,>=1.6", "gevent>=1.5", "graphlib-backport; python_version < \"3.9\"", @@ -429,8 +480,8 @@ "typing-extensions; python_version < \"3.11\"", ] files = [ - {file = "pyinfra-3.1-py2.py3-none-any.whl", hash = "sha256:d3f52d61c9d9bea23175af250299ef60c2d6ebad86f771e3b546dcd96e0dd060"}, - {file = "pyinfra-3.1.tar.gz", hash = "sha256:96fca7c54201ffe00e452b165662423f27cd2a3ae6c9f0272fb04c61c078dc06"}, + {file = "pyinfra-3.2-py2.py3-none-any.whl", hash = "sha256:ca8e6f4b51031b3b56b4ab6e7ce4cb749530ec92d6ba22f1f2657e2d20231416"}, + {file = "pyinfra-3.2.tar.gz", hash = "sha256:ea65f2048860dae6a7d86470d4a7ca67c9e2e82d671e781b849f1e5e163ad6db"}, ] [[package]] @@ -456,8 +507,19 @@ ] [[package]] +name = "pyparsing" +version = "3.2.1" +requires_python = ">=3.9" +summary = "pyparsing module - Classes and methods to define and execute parsing grammars" +groups = ["default"] +files = [ + {file = "pyparsing-3.2.1-py3-none-any.whl", hash = "sha256:506ff4f4386c4cec0590ec19e6302d3aedb992fdc02c761e90416f158dacf8e1"}, + {file = "pyparsing-3.2.1.tar.gz", hash = "sha256:61980854fd66de3a90028d679a954d5f2623e83144b5afe5ee86f43d762e5f0a"}, +] + +[[package]] name = "pyspnego" -version = "0.11.1" +version = "0.11.2" requires_python = ">=3.8" summary = "Windows Negotiate Authentication Client and Server" groups = ["default"] @@ -466,8 +528,8 @@ "sspilib>=0.1.0; sys_platform == \"win32\"", ] files = [ - {file = "pyspnego-0.11.1-py3-none-any.whl", hash = "sha256:129a4294f2c4d681d5875240ef87accc6f1d921e8983737fb0b59642b397951e"}, - {file = "pyspnego-0.11.1.tar.gz", hash = "sha256:e92ed8b0a62765b9d6abbb86a48cf871228ddb97678598dc01c9c39a626823f6"}, + {file = "pyspnego-0.11.2-py3-none-any.whl", hash = "sha256:74abc1fb51e59360eb5c5c9086e5962174f1072c7a50cf6da0bda9a4bcfdfbd4"}, + {file = "pyspnego-0.11.2.tar.gz", hash = "sha256:994388d308fb06e4498365ce78d222bf4f3570b6df4ec95738431f61510c971b"}, ] [[package]] @@ -501,6 +563,21 @@ ] [[package]] +name = "rdflib" +version = "7.1.3" +requires_python = "<4.0.0,>=3.8.1" +summary = "RDFLib is a Python library for working with RDF, a simple yet powerful language for representing information." +groups = ["default"] +dependencies = [ + "isodate<1.0.0,>=0.7.2; python_version < \"3.11\"", + "pyparsing<4,>=2.1.0", +] +files = [ + {file = "rdflib-7.1.3-py3-none-any.whl", hash = "sha256:5402310a9f0f3c07d453d73fd0ad6ba35616286fe95d3670db2b725f3f539673"}, + {file = "rdflib-7.1.3.tar.gz", hash = "sha256:f3dcb4c106a8cd9e060d92f43d593d09ebc3d07adc244f4c7315856a12e383ee"}, +] + +[[package]] name = "requests" version = "2.32.3" requires_python = ">=3.8" @@ -535,53 +612,59 @@ [[package]] name = "setuptools" -version = "73.0.1" -requires_python = ">=3.8" +version = "75.8.0" +requires_python = ">=3.9" summary = "Easily download, build, install, upgrade, and uninstall Python packages" groups = ["default"] files = [ - {file = "setuptools-73.0.1-py3-none-any.whl", hash = "sha256:b208925fcb9f7af924ed2dc04708ea89791e24bde0d3020b27df0e116088b34e"}, - {file = "setuptools-73.0.1.tar.gz", hash = "sha256:d59a3e788ab7e012ab2c4baed1b376da6366883ee20d7a5fc426816e3d7b1193"}, + {file = "setuptools-75.8.0-py3-none-any.whl", hash = "sha256:e3982f444617239225d675215d51f6ba05f845d4eec313da4418fdbb56fb27e3"}, + {file = "setuptools-75.8.0.tar.gz", hash = "sha256:c5afc8f407c626b8313a86e10311dd3f661c6cd9c09d4bf8c15c0e11f9f2b0e6"}, ] [[package]] name = "six" -version = "1.16.0" -requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +version = "1.17.0" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" summary = "Python 2 and 3 compatibility utilities" groups = ["default"] files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, ] [[package]] name = "sspilib" -version = "0.1.0" +version = "0.2.0" requires_python = ">=3.8" summary = "SSPI API bindings for Python" groups = ["default"] marker = "sys_platform == \"win32\"" files = [ - {file = "sspilib-0.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:09d7f72ad5e4bbf9a8f1acf0d5f0c3f9fbe500f44c4a45ac24a99ece84f5654f"}, - {file = "sspilib-0.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e5705e11aaa030a61d2b0a2ce09d2b8a1962dd950e55adc7a3c87dd463c6878"}, - {file = "sspilib-0.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dced8213d311c56f5f38044716ebff5412cc156f19678659e8ffa9bb6a642bd7"}, - {file = "sspilib-0.1.0-cp311-cp311-win32.whl", hash = "sha256:d30d38d52dbd857732224e86ae3627d003cc510451083c69fa481fc7de88a7b6"}, - {file = "sspilib-0.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:61c9067168cce962f7fead42c28804c3a39a164b9a7b660200b8cfe31e3af071"}, - {file = "sspilib-0.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:b526b8e5a236553f5137b951b89a2f108f56138ad05f31fd0a51b10f80b6c3cc"}, - {file = "sspilib-0.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3ff356d40cd34c900f94f1591eaabd458284042af611ebc1dbf609002066dba5"}, - {file = "sspilib-0.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2b0fee3a52d0acef090f6c9b49953a8400fdc1c10aca7334319414a3038aa493"}, - {file = "sspilib-0.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab52d190dad1d578ec40d1fb417a8571954f4e32f35442a14cb709f57d3acbc9"}, - {file = "sspilib-0.1.0-cp312-cp312-win32.whl", hash = "sha256:b3cf819094383ec883e9a63c11b81d622618c815c18a6c9d761d9a14d9f028d1"}, - {file = "sspilib-0.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:b83825a2c43ff84ddff72d09b098057efaabf3841d3c42888078e154cf8e9595"}, - {file = "sspilib-0.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:9aa6ab4c3fc1057251cf1f3f199daf90b99599cdfafc9eade8fdf0c01526dec8"}, - {file = "sspilib-0.1.0.tar.gz", hash = "sha256:58b5291553cf6220549c0f855e0e6973f4977375d8236ce47bb581efb3e9b1cf"}, + {file = "sspilib-0.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e0943204c8ba732966fdc5b69e33cf61d8dc6b24e6ed875f32055d9d7e2f76cd"}, + {file = "sspilib-0.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d1cdfc5ec2f151f26e21aa50ccc7f9848c969d6f78264ae4f38347609f6722df"}, + {file = "sspilib-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a6c33495a3de1552120c4a99219ebdd70e3849717867b8cae3a6a2f98fef405"}, + {file = "sspilib-0.2.0-cp311-cp311-win32.whl", hash = "sha256:400d5922c2c2261009921157c4b43d868e84640ad86e4dc84c95b07e5cc38ac6"}, + {file = "sspilib-0.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3e7d19c16ba9189ef8687b591503db06cfb9c5eb32ab1ca3bb9ebc1a8a5f35c"}, + {file = "sspilib-0.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:f65c52ead8ce95eb78a79306fe4269ee572ef3e4dcc108d250d5933da2455ecc"}, + {file = "sspilib-0.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:abac93a90335590b49ef1fc162b538576249c7f58aec0c7bcfb4b860513979b4"}, + {file = "sspilib-0.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1208720d8e431af674c5645cec365224d035f241444d5faa15dc74023ece1277"}, + {file = "sspilib-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e48dceb871ecf9cf83abdd0e6db5326e885e574f1897f6ae87d736ff558f4bfa"}, + {file = "sspilib-0.2.0-cp312-cp312-win32.whl", hash = "sha256:bdf9a4f424add02951e1f01f47441d2e69a9910471e99c2c88660bd8e184d7f8"}, + {file = "sspilib-0.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:40a97ca83e503a175d1dc9461836994e47e8b9bcf56cab81a2c22e27f1993079"}, + {file = "sspilib-0.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:8ffc09819a37005c66a580ff44f544775f9745d5ed1ceeb37df4e5ff128adf36"}, + {file = "sspilib-0.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:40ff410b64198cf1d704718754fc5fe7b9609e0c49bf85c970f64c6fc2786db4"}, + {file = "sspilib-0.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:02d8e0b6033de8ccf509ba44fdcda7e196cdedc0f8cf19eb22c5e4117187c82f"}, + {file = "sspilib-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad7943fe14f8f6d72623ab6401991aa39a2b597bdb25e531741b37932402480f"}, + {file = "sspilib-0.2.0-cp313-cp313-win32.whl", hash = "sha256:b9044d6020aa88d512e7557694fe734a243801f9a6874e1c214451eebe493d92"}, + {file = "sspilib-0.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:c39a698491f43618efca8776a40fb7201d08c415c507f899f0df5ada15abefaa"}, + {file = "sspilib-0.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:863b7b214517b09367511c0ef931370f0386ed2c7c5613092bf9b106114c4a0e"}, + {file = "sspilib-0.2.0.tar.gz", hash = "sha256:4d6cd4290ca82f40705efeb5e9107f7abcd5e647cb201a3d04371305938615b8"}, ] [[package]] name = "typeguard" -version = "4.3.0" -requires_python = ">=3.8" +version = "4.4.1" +requires_python = ">=3.9" summary = "Run-time type checker for Python" groups = ["default"] dependencies = [ @@ -589,8 +672,8 @@ "typing-extensions>=4.10.0", ] files = [ - {file = "typeguard-4.3.0-py3-none-any.whl", hash = "sha256:4d24c5b39a117f8a895b9da7a9b3114f04eb63bade45a4492de49b175b6f7dfa"}, - {file = "typeguard-4.3.0.tar.gz", hash = "sha256:92ee6a0aec9135181eae6067ebd617fd9de8d75d714fb548728a4933b1dea651"}, + {file = "typeguard-4.4.1-py3-none-any.whl", hash = "sha256:9324ec07a27ec67fc54a9c063020ca4c0ae6abad5e9f0f9804ca59aee68c6e21"}, + {file = "typeguard-4.4.1.tar.gz", hash = "sha256:0d22a89d00b453b47c49875f42b6601b961757541a2e1e0ef517b6e24213c21b"}, ] [[package]] @@ -606,24 +689,24 @@ [[package]] name = "urllib3" -version = "2.2.2" -requires_python = ">=3.8" +version = "2.3.0" +requires_python = ">=3.9" summary = "HTTP library with thread-safe connection pooling, file post, and more." groups = ["default"] files = [ - {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, - {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, + {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, + {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, ] [[package]] name = "xmltodict" -version = "0.13.0" -requires_python = ">=3.4" +version = "0.14.2" +requires_python = ">=3.6" summary = "Makes working with XML feel like you are working with JSON" groups = ["default"] files = [ - {file = "xmltodict-0.13.0-py2.py3-none-any.whl", hash = "sha256:aa89e8fd76320154a40d19a0df04a4695fb9dc5ba977cbb68ab3e4eb225e7852"}, - {file = "xmltodict-0.13.0.tar.gz", hash = "sha256:341595a488e3e01a85a9d8911d8912fd922ede5fecc4dce437eb4b6c8d037e56"}, + {file = "xmltodict-0.14.2-py2.py3-none-any.whl", hash = "sha256:20cc7d723ed729276e808f26fb6b3599f786cbc37e06c65e192ba77c40f20aac"}, + {file = "xmltodict-0.14.2.tar.gz", hash = "sha256:201e7c28bb210e374999d1dde6382923ab0ed1a8a5faeece48ab525b7810a553"}, ] [[package]] @@ -642,7 +725,7 @@ [[package]] name = "zope-interface" -version = "7.0.1" +version = "7.2" requires_python = ">=3.8" summary = "Interfaces for Python" groups = ["default"] @@ -650,20 +733,23 @@ "setuptools", ] files = [ - {file = "zope.interface-7.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:03bd5c0db82237bbc47833a8b25f1cc090646e212f86b601903d79d7e6b37031"}, - {file = "zope.interface-7.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3f52050c6a10d4a039ec6f2c58e5b3ade5cc570d16cf9d102711e6b8413c90e6"}, - {file = "zope.interface-7.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af0b33f04677b57843d529b9257a475d2865403300b48c67654c40abac2f9f24"}, - {file = "zope.interface-7.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:696c2a381fc7876b3056711717dba5eddd07c2c9e5ccd50da54029a1293b6e43"}, - {file = "zope.interface-7.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f89a420cf5a6f2aa7849dd59e1ff0e477f562d97cf8d6a1ee03461e1eec39887"}, - {file = "zope.interface-7.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:b59deb0ddc7b431e41d720c00f99d68b52cb9bd1d5605a085dc18f502fe9c47f"}, - {file = "zope.interface-7.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:52f5253cca1b35eaeefa51abd366b87f48f8714097c99b131ba61f3fdbbb58e7"}, - {file = "zope.interface-7.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:88d108d004e0df25224de77ce349a7e73494ea2cb194031f7c9687e68a88ec9b"}, - {file = "zope.interface-7.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c203d82069ba31e1f3bc7ba530b2461ec86366cd4bfc9b95ec6ce58b1b559c34"}, - {file = "zope.interface-7.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f3495462bc0438b76536a0e10d765b168ae636092082531b88340dc40dcd118"}, - {file = "zope.interface-7.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:192b7a792e3145ed880ff6b1a206fdb783697cfdb4915083bfca7065ec845e60"}, - {file = "zope.interface-7.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:400d06c9ec8dbcc96f56e79376297e7be07a315605c9a2208720da263d44d76f"}, - {file = "zope.interface-7.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c1dff87b30fd150c61367d0e2cdc49bb55f8b9fd2a303560bbc24b951573ae1"}, - {file = "zope.interface-7.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f749ca804648d00eda62fe1098f229b082dfca930d8bad8386e572a6eafa7525"}, - {file = "zope.interface-7.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ec212037becf6d2f705b7ed4538d56980b1e7bba237df0d8995cbbed29961dc"}, - {file = "zope.interface-7.0.1.tar.gz", hash = "sha256:f0f5fda7cbf890371a59ab1d06512da4f2c89a6ea194e595808123c863c38eff"}, + {file = "zope.interface-7.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1909f52a00c8c3dcab6c4fad5d13de2285a4b3c7be063b239b8dc15ddfb73bd2"}, + {file = "zope.interface-7.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:80ecf2451596f19fd607bb09953f426588fc1e79e93f5968ecf3367550396b22"}, + {file = "zope.interface-7.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:033b3923b63474800b04cba480b70f6e6243a62208071fc148354f3f89cc01b7"}, + {file = "zope.interface-7.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a102424e28c6b47c67923a1f337ede4a4c2bba3965b01cf707978a801fc7442c"}, + {file = "zope.interface-7.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25e6a61dcb184453bb00eafa733169ab6d903e46f5c2ace4ad275386f9ab327a"}, + {file = "zope.interface-7.2-cp311-cp311-win_amd64.whl", hash = "sha256:3f6771d1647b1fc543d37640b45c06b34832a943c80d1db214a37c31161a93f1"}, + {file = "zope.interface-7.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:086ee2f51eaef1e4a52bd7d3111a0404081dadae87f84c0ad4ce2649d4f708b7"}, + {file = "zope.interface-7.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:21328fcc9d5b80768bf051faa35ab98fb979080c18e6f84ab3f27ce703bce465"}, + {file = "zope.interface-7.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6dd02ec01f4468da0f234da9d9c8545c5412fef80bc590cc51d8dd084138a89"}, + {file = "zope.interface-7.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e7da17f53e25d1a3bde5da4601e026adc9e8071f9f6f936d0fe3fe84ace6d54"}, + {file = "zope.interface-7.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cab15ff4832580aa440dc9790b8a6128abd0b88b7ee4dd56abacbc52f212209d"}, + {file = "zope.interface-7.2-cp312-cp312-win_amd64.whl", hash = "sha256:29caad142a2355ce7cfea48725aa8bcf0067e2b5cc63fcf5cd9f97ad12d6afb5"}, + {file = "zope.interface-7.2-cp313-cp313-macosx_10_9_x86_64.whl", hash = "sha256:3e0350b51e88658d5ad126c6a57502b19d5f559f6cb0a628e3dc90442b53dd98"}, + {file = "zope.interface-7.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:15398c000c094b8855d7d74f4fdc9e73aa02d4d0d5c775acdef98cdb1119768d"}, + {file = "zope.interface-7.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:802176a9f99bd8cc276dcd3b8512808716492f6f557c11196d42e26c01a69a4c"}, + {file = "zope.interface-7.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb23f58a446a7f09db85eda09521a498e109f137b85fb278edb2e34841055398"}, + {file = "zope.interface-7.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a71a5b541078d0ebe373a81a3b7e71432c61d12e660f1d67896ca62d9628045b"}, + {file = "zope.interface-7.2-cp313-cp313-win_amd64.whl", hash = "sha256:4893395d5dd2ba655c38ceb13014fd65667740f09fa5bb01caa1e6284e48c0cd"}, + {file = "zope.interface-7.2.tar.gz", hash = "sha256:8b49f1a3d1ee4cdaf5b32d2e738362c7f5e40ac8b46dd7d1a65e82a4872728fe"}, ]
--- a/pyproject.toml Mon Jan 20 14:10:19 2025 -0800 +++ b/pyproject.toml Mon Jan 20 21:55:08 2025 -0800 @@ -6,9 +6,11 @@ {name = "", email = ""}, ] dependencies = [ - "pyinfra>=3.1", + "pyinfra>=3.2", "more-itertools>=10.2.0", "psutil>=5.9.8", + "rdflib>=7.1.3", + "invoke>=2.2.0", ] requires-python = ">=3.11" license = {text = "MIT"} @@ -17,4 +19,3 @@ requires = ["pdm-pep517>=1.0.0"] build-backend = "pdm.pep517.api" -[tool.pdm]
--- a/ssh.py Mon Jan 20 14:10:19 2025 -0800 +++ b/ssh.py Mon Jan 20 21:55:08 2025 -0800 @@ -1,17 +1,3 @@ -from pyinfra import host +from pyinfra.context import host from pyinfra.facts.server import LinuxDistribution from pyinfra.operations import files, systemd - - -systemd.service( - service='ssh', - running=True, - enabled=True, -) - -files.line(path='/etc/ssh/ssh_config', line="HashKnownHosts", replace="HashKnownHosts no") - -if 'pi' not in host.groups: - files.line(path='/etc/ssh/sshd_config', line="^UseDNS\b", replace="UseDNS no") - # MAYBE plus needs this fix: adding ListenAddress 0.0.0.0 to /etc/ssh/sshd_config - systemd.service(service='sshd', reloaded=True)
--- a/sync.py Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -from pathlib import Path - -from pyinfra import host -from pyinfra.facts.server import Command -from pyinfra.operations import apt, files, server, systemd - - -def host_running_version(user: str, v: str): - # if this command fails, we go in to error state and run nothing else #bugreport - out = host.get_fact(Command, f"runuser -u {user} syncthing serve --version || exit 0") - if out is None: - return False - _, sv, *_ = out.split() - return sv == v - - -def install_syncthing(user, version, os='linux', arch='amd64'): - tmpdir = Path('/tmp/syncthing_install') - dl_name = f'syncthing-{os}-{arch}-{version}' - url = f'https://github.com/syncthing/syncthing/releases/download/{version}/{dl_name}.tar.gz' - files.directory(path=tmpdir) - files.download(src=url, dest=str(tmpdir / f'{dl_name}.tgz')) # bugreport - server.shell(commands=[f'cd {tmpdir}; aunpack {dl_name}.tgz']) - - systemd.service(service=f'syncthing@{user}', running=False) - - user_svc_template = '/lib/systemd/system/syncthing@.service' - server.shell(commands=[ - f'cp -a {tmpdir}/{dl_name}/{s} {d}' for s, d in [ - ('syncthing', '/usr/bin'), - ('etc/linux-systemd/system/syncthing@.service', user_svc_template), - ] - ]) - files.link(path=f'/etc/systemd/system/multi-user.target.wants/syncthing@{user}.service', target=user_svc_template) - systemd.service(service=f'syncthing@{user}', enabled=True, restarted=True, daemon_reload=True) - - -# also see /my/serv/filesync/syncthing/deploy.yaml for the container one -version = 'v1.27.10' - -# primary instance is in k8s (/my/serv/filesync/syncthing); the rest are run with systemd. -# Configs are in ~/.config/syncthing/ on each box -if host.data.get('syncthing'): - apt.packages(packages=['syncthing'], present=False) - user = 'ari' if host.name == 'dot' else 'drewp' - - if not host_running_version(user, version): - install_syncthing(user, version) - -# something above has broken devnull #bugreport -server.shell(commands=['chmod a+w /dev/null']) - -# also consider https://github.com/Martchus/syncthingtray tray status viewer on dtops
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sync/sync.py Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,57 @@ +from pathlib import Path + +from pyinfra.context import host +from pyinfra.facts.server import Command +from pyinfra.operations import apt, files, server, systemd + + +def host_running_version(user: str, v: str): + # if this command fails, we go in to error state and run nothing else #bugreport + out = host.get_fact(Command, f"runuser -u {user} syncthing serve --version || exit 0") + if out is None: + return False + _, sv, *_ = out.split() + return sv == v + + +def install_syncthing(user, version, os='linux', arch='amd64'): + tmpdir = Path('/tmp/syncthing_install') + dl_name = f'syncthing-{os}-{arch}-{version}' + url = f'https://github.com/syncthing/syncthing/releases/download/{version}/{dl_name}.tar.gz' + files.directory(path=tmpdir) + files.download(src=url, dest=str(tmpdir / f'{dl_name}.tgz')) # bugreport + server.shell(commands=[f'cd {tmpdir}; aunpack {dl_name}.tgz']) + + systemd.service(service=f'syncthing@{user}', running=False) + + user_svc_template = '/lib/systemd/system/syncthing@.service' + server.shell(commands=[ + f'cp -a {tmpdir}/{dl_name}/{s} {d}' for s, d in [ + ('syncthing', '/usr/bin'), + ('etc/linux-systemd/system/syncthing@.service', user_svc_template), + ] + ]) + files.link(path=f'/etc/systemd/system/multi-user.target.wants/syncthing@{user}.service', target=user_svc_template) + systemd.service(service=f'syncthing@{user}', enabled=True, restarted=True, daemon_reload=True) + +def syncthing(): + # also see /my/serv/filesync/syncthing/deploy.yaml for the container one + version = 'v1.27.10' + + # primary instance is in k8s (/my/serv/filesync/syncthing); the rest are run with systemd. + # Configs are in ~/.config/syncthing/ on each box + if host.data.get('syncthing'): + apt.packages(packages=['syncthing'], present=False) + user = 'ari' if host.name == 'dot' else 'drewp' + + if not host_running_version(user, version): + install_syncthing(user, version) + + # something above has broken devnull #bugreport + server.shell(commands=['chmod a+w /dev/null']) + + # also consider https://github.com/Martchus/syncthingtray tray status viewer on dtops + +operations = [ + syncthing, +] \ No newline at end of file
--- a/system.py Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,131 +0,0 @@ -import os -from io import StringIO -from typing import cast - -import pyinfra -from pyinfra import host -from pyinfra.operations import apt, files, server, systemd - -TZ = 'America/Los_Angeles' - - -def timezone(): - files.link(path='/etc/localtime', target=f'/usr/share/zoneinfo/{TZ}') - files.replace(path='/etc/timezone', text='.*', replace=TZ) - - -def fstab(): - fstab_file = f'files/fstab/{host.name}' - if os.path.exists(fstab_file): - files.put(src=fstab_file, dest='/etc/fstab') - - -def pi_tmpfs(): - for line in [ - 'tmpfs /var/log tmpfs defaults,noatime,mode=0755 0 0', - 'tmpfs /tmp tmpfs defaults,noatime 0 0', - ]: - files.line(path="/etc/fstab", line=line, replace=line) - - # stop SD card corruption (along with some mounts in fstab) - apt.packages(packages=['dphys-swapfile'], present=False) - - -def no_sleep(): - server.shell(commands=['systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target']) - - -def nfs_server(): - # remove when we're on longhorn - apt.packages(packages=['nfs-kernel-server']) - files.template(src='templates/bang_exports.j2', dest='/etc/exports') - - -def smaller_journals(): - files.line(name='shorter systemctl log window, for disk space', - path='/etc/systemd/journald.conf', - line='MaxFileSec', - replace="MaxFileSec=7day") - - -def web_forward(): - for port in [80, 443]: - svc = f'web_forward_{port}' - files.template(src="templates/webforward.service.j2", - dest=f"/etc/systemd/system/{svc}.service", - serv_host='bang', - port=port, - name='web', - fam='tcp') - systemd.service(service=svc, enabled=True, restarted=True) - - -def minecraft_forward(): - port = 25765 - for fam in ['tcp', 'udp']: - svc = f'mc_smp_{fam}_forward_{port}' - files.template(src="templates/webforward.service.j2", - dest=f"/etc/systemd/system/{svc}.service", - serv_host='ditto', - port=port, - name='mc_smp', - fam=fam) - systemd.service(service=svc, enabled=True, restarted=True) - - -def pigpiod(): - files.put(src="files/pigpiod.service", dest="/etc/systemd/system/pigpiod.service") - systemd.service(service='pigpiod', daemon_reload=True, enabled=True) - - -def rpi_iscsi_volumes(): - iscsi_dir = '/d2/rpi-iscsi' - for pi_hostname in cast(list, pyinfra.inventory.get_group(name='pi')): - out = f'{iscsi_dir}/{pi_hostname}.disk' - files.directory(path=iscsi_dir) - server.shell(commands=f'dd if=/dev/zero of={out} count=0 bs=1 seek=10G conv=excl || true') - files.put(dest=f"/etc/tgt/conf.d/{pi_hostname}.conf", - src=StringIO(f""" -<target iqn.2024-03.com.bigasterisk:{pi_hostname}.target> - backing-store {out} - initiator-name iqn.2024-03.com.bigasterisk:{pi_hostname}.initiator -</target> - """)) - # restarting is disruptive to connected pis, and they might need to be - # visited: - #systemd.service(service='tgt.service', running=True, restarted=True) - - -server.hostname(hostname=host.name) -timezone() -fstab() - -if host.name == 'ditto': - rpi_iscsi_volumes() - -if 'pi' not in host.groups: - files.line(path='/etc/update-manager/release-upgrades', line="^Prompt=", replace="Prompt=normal") - -if 'pi' in host.groups: - pi_tmpfs() - -if host.name in ['bang', 'pipe', 'ditto']: - no_sleep() - -if host.name in ['bang', 'ditto']: - nfs_server() - -if host.name in ['prime', 'ditto', 'pipe']: - smaller_journals() - -if host.name == 'prime': - web_forward() - minecraft_forward() - -if 'pi' in host.groups: - pigpiod() - -# for space, consider: -# k3s crictl rmi --prune -# snap list --all | while read snapname ver rev trk pub notes; do if [[ $notes = *disabled* ]]; then snap remove "$snapname" --revision="$rev"; fi; done -# podman system reset
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/system/files/ditto_exports Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,7 @@ +# written by pyinfra + +# zfs takes care of its own + +# photoprism on ditto +# /d4/photoprism 10.5.0.7(rw,no_root_squash) +# /d4/frigate 10.5.0.7(rw,no_root_squash)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/system/files/pigpiod.service Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,11 @@ +# written by pyinfra + +[Unit] +Description=Daemon required to control GPIO pins via pigpio + +[Service] +Type=simple +ExecStart=/usr/bin/pigpiod -g -p 8888 + +[Install] +WantedBy=multi-user.target
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/system/fstabs/bang Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,8 @@ +# written by pyinfra + +# <file system> <mount point> <type> <options> <dump> <pass> +/dev/disk/by-uuid/8c7a2d08-60d1-486a-8136-d9f43d83a064 / ext4 relatime 0 0 +/dev/disk/by-uuid/d9a1e1e4-9eba-4988-8b01-c5f6732a2972 /d3 ext4 noatime 0 0 +/dev/disk/by-partuuid/77687eec-15bf-9345-b420-bb83659e6a6b /d4 ext4 noatime 0 0 + +ditto5:/my /my nfs rw,noatime 0 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/system/fstabs/dash Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,11 @@ +# written by pyinfra + +# <file system> <mount point> <type> <options> <dump> <pass> +/dev/disk/by-uuid/d8d23ff1-7c37-4a7d-9fc4-55fc61f912a0 / ext4 defaults 0 1 +/dev/disk/by-uuid/CB55-821E /boot/efi vfat defaults 0 1 + +UUID=73bcd201-5f77-4f68-9fba-47835c3c1692 /d2 ext4 defaults 0 0 +UUID=6cae1c30-3c91-4aa7-9e9f-fcbd7ff706fe /d3 ext4 defaults 0 0 +UUID=3b6780e0-ec86-43be-8d09-e462dbad762e /d4 ext4 defaults 0 0 + +ditto5:/my /my nfs rw,noatime 0 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/system/fstabs/ditto Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,14 @@ +# written by pyinfra + + +# +# Use 'blkid' to print the universally unique identifier for a +# device; this may be used with UUID= as a more robust way to name devices +# that works even if disks are added and removed. See fstab(5). +# +# <file system> <mount point> <type> <options> <dump> <pass> +/dev/disk/by-uuid/6e64ce62-34db-4084-9385-d001e99ad38b / ext4 defaults 0 1 +/dev/disk/by-uuid/3F95-42F4 /boot/efi vfat defaults 0 1 +/dev/disk/by-uuid/74795c77-ed20-417d-988a-abc09c3dfc27 /d2 ext4 defaults 0 1 + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/system/fstabs/dot Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,10 @@ +# written by pyinfra + +# <file system> <mount point> <type> <options> <dump> <pass> + + + +/dev/disk/by-uuid/a9403f0b-aa16-4096-ab0d-2e2069d3f18a / ext4 defaults 0 1 + +/dev/mapper/ubuntu--vg-ubuntu--lv /d2 ext4 defaults 0 1 +/dev/disk/by-uuid/5a6ce8db-cde0-4c26-b6a4-08faef2e01a2 /d3 ext4 defaults 0 1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/system/fstabs/slash Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,7 @@ +# written by pyinfra + +# <file system> <mount point> <type> <options> <dump> <pass> +UUID=df079890-9431-4e17-940c-d9ed8ce4e149 / ext4 errors=remount-ro 0 1 +UUID=1CFA-995B /boot/efi vfat umask=0077 0 1 + +ditto5:/my /my nfs rw,noatime 0 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/system/fstabs/tofu Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,4 @@ +# written by pyinfra + +# <file system> <mount point> <type> <options> <dump> <pass> +/dev/nvme0n1p6 / ext4 rw,relatime 0 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/system/system.py Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,155 @@ +import os +from io import StringIO +from typing import cast + +import pyinfra +from pyinfra.context import host +from pyinfra.operations import apt, files, server, systemd + +TZ = 'America/Los_Angeles' + + +def sshServer(): + systemd.service( + service='ssh', + running=True, + enabled=True, + ) + + files.line(path='/etc/ssh/ssh_config', line="HashKnownHosts", replace="HashKnownHosts no") + + if 'pi' not in host.groups: + files.line(path='/etc/ssh/sshd_config', line="^UseDNS\b", replace="UseDNS no") + # MAYBE plus needs this fix: adding ListenAddress 0.0.0.0 to /etc/ssh/sshd_config + systemd.service(service='sshd', reloaded=True) + + +def timezone(): + files.link(path='/etc/localtime', target=f'/usr/share/zoneinfo/{TZ}') + files.replace(path='/etc/timezone', text='.*', replace=TZ) + + +def fstab(): + fstab_file = f'system/fstabs/{host.name}' + if os.path.exists(fstab_file): + files.put(src=fstab_file, dest='/etc/fstab') + + +def pi_tmpfs(): + if 'pi' not in host.groups: + return + + for line in [ + 'tmpfs /var/log tmpfs defaults,noatime,mode=0755 0 0', + 'tmpfs /tmp tmpfs defaults,noatime 0 0', + ]: + files.line(path="/etc/fstab", line=line, replace=line) + + # stop SD card corruption (along with some mounts in fstab) + apt.packages(packages=['dphys-swapfile'], present=False) + + +def no_sleep(): + if host.name not in ['bang', 'pipe', 'ditto']: + return + + server.shell(commands=['systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target']) + + +def nfs_server(): + if host.name != 'ditto': + return + + # remove when we're on longhorn + apt.packages(packages=['nfs-kernel-server']) + files.put(src='system/files/ditto_exports', dest='/etc/exports') + + +def smaller_journals(): + if host.name not in ['prime', 'ditto', 'pipe']: + return + files.line(name='shorter systemctl log window, for disk space', + path='/etc/systemd/journald.conf', + line='MaxFileSec', + replace="MaxFileSec=7day") + + +def web_forward(): + if host.name != 'prime': + return + for port in [80, 443]: + svc = f'web_forward_{port}' + files.template(src="system/templates/webforward.service.j2", + dest=f"/etc/systemd/system/{svc}.service", + serv_host='bang', + port=port, + name='web', + fam='tcp') + systemd.service(service=svc, enabled=True, restarted=True) + + +def minecraft_forward(): + if host.name != 'prime': + return + port = 25765 + for fam in ['tcp', 'udp']: + svc = f'mc_smp_{fam}_forward_{port}' + files.template(src="system/templates/webforward.service.j2", + dest=f"/etc/systemd/system/{svc}.service", + serv_host='ditto', + port=port, + name='mc_smp', + fam=fam) + systemd.service(service=svc, enabled=True, restarted=True) + + +def pigpiod(): + if 'pi' not in host.groups: + return + files.put(src="system/files/pigpiod.service", dest="/etc/systemd/system/pigpiod.service") + systemd.service(service='pigpiod', daemon_reload=True, enabled=True) + + +def rpi_iscsi_volumes(): + if host.name != 'ditto': + return + + iscsi_dir = '/d2/rpi-iscsi' + for pi_hostname in cast(list, pyinfra.inventory.get_group(name='pi')): + out = f'{iscsi_dir}/{pi_hostname}.disk' + files.directory(path=iscsi_dir) + server.shell(commands=f'dd if=/dev/zero of={out} count=0 bs=1 seek=10G conv=excl || true') + files.put(dest=f"/etc/tgt/conf.d/{pi_hostname}.conf", + src=StringIO(f""" +<target iqn.2024-03.com.bigasterisk:{pi_hostname}.target> + backing-store {out} + initiator-name iqn.2024-03.com.bigasterisk:{pi_hostname}.initiator +</target> + """)) + # restarting is disruptive to connected pis, and they might need to be + # visited: + #systemd.service(service='tgt.service', running=True, restarted=True) + + +def hostname(): + server.hostname(hostname=host.name) + + + +operations = [ + hostname, + timezone, + fstab, + rpi_iscsi_volumes, + pi_tmpfs, + no_sleep, + nfs_server, + smaller_journals, + web_forward, + minecraft_forward, + pigpiod, +] +# for space, consider: +# k3s crictl rmi --prune +# snap list --all | while read snapname ver rev trk pub notes; do if [[ $notes = *disabled* ]]; then snap remove "$snapname" --revision="$rev"; fi; done +# podman system reset
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/system/templates/webforward.service.j2 Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,16 @@ +# written by pyinfra + +[Unit] +Description={{ fam }} forward for port {{ port }} +Requires=network.target +Wants=nss-lookup.target +Before=nss-lookup.target +After=network.target + +[Service] +Type=simple + +ExecStart=/usr/bin/socat {{ 'tcp' if fam=='tcp' else 'udp4' }}-listen:{{ port }},fork,reuseaddr {{ 'tcp' if fam=='tcp' else 'udp' }}:{{serv_host}}:{{ port }} + +[Install] +WantedBy=multi-user.target
--- a/tasks.py Mon Jan 20 14:10:19 2025 -0800 +++ b/tasks.py Mon Jan 20 21:55:08 2025 -0800 @@ -1,4 +1,4 @@ -from invoke import task +from invoke.tasks import task cmd = ''' HOME=/root @@ -13,41 +13,6 @@ @task -def users(ctx): - _run(ctx, 'users.py') - - -@task -def ssh(ctx): - _run(ctx, 'ssh.py') - - -@task -def system(ctx): - _run(ctx, 'system.py') - - -@task -def apt(ctx): - _run(ctx, 'apt/apt.py') - - -@task -def packages(ctx): - _run(ctx, 'packages.py') - - -@task -def net(ctx): - _run(ctx, 'net.py') - - -@task -def dns(ctx): - _run(ctx, 'dns.py') - - -@task def dns_check(ctx): _run(ctx, 'dns_check.py -v') @@ -58,31 +23,6 @@ @task -def wireguard(ctx): - _run(ctx, 'wireguard.py') - - -@task -def kube(ctx): - _run(ctx, 'kube.py') - - -@task -def sync(ctx): - _run(ctx, 'sync.py') - - -@task -def mail(ctx): - _run(ctx, 'mail.py') - - -@task -def home(ctx): - _run(ctx, 'home.py') - - -@task def multikube(ctx): # danger- wipes previous k3s from multikube_config import server_node, nodes ctx.run(cmd + 'inventory.py multikube_wipe.py', pty=True) @@ -98,21 +38,28 @@ @task def all(ctx): - configs = [ - 'users.py', - 'ssh.py', - 'system.py', - 'apt/apt.py', - 'packages.py', - 'net.py', - 'dns.py', - 'wireguard.py', - 'kube.py', - 'sync.py', - 'mail.py', - 'home.py', - ] - ctx.run(' '.join([cmd, '--no-wait', '-y', 'inventory.py'] + configs), pty=True) + for opGroup in [ + 'users', + 'system', + 'apt', + 'packages', + 'net', + 'dns', + 'wireguard', + 'kube', + 'sync', + 'mail', + 'home', + ]: + ctx.run( + ' '.join([ + cmd, #'--no-wait', + '-y', + 'inventory.py', + 'all_operations.py' + ]), + pty=True, + env={'GROUP': opGroup}) ctx.run('touch /my/proj/infra/ran_all.timestamp')
--- a/templates/bang_exports.j2 Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -# written by pyinfra - -# zfs takes care of its own - -# photoprism on ditto -/d4/photoprism 10.5.0.7(rw,no_root_squash) -/d4/frigate 10.5.0.7(rw,no_root_squash)
--- a/templates/dnsmasq/dnsmasq.conf.j2 Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -user=nobody -keep-in-foreground -log-facility=- - -listen-address={{ listen_address }} -{% if net == "10.2" %} -# dnsmasq will not automatically listen on the loopback interface. To achieve -# this, its IP address, 127.0.0.1, must be explicitly given as a -# --listen-address option. -listen-address=127.0.0.1 -{% endif %} -bind-interfaces - -domain-needed -no-resolv -no-hosts -addn-hosts=/opt/dnsmasq/{{ net }}/hosts -local-ttl=30 -mx-host=bigasterisk.com -cache-size=10000 -neg-ttl=60 -dns-forward-max=1000 -domain=bigasterisk.com - -# log-queries -# log-debug - -{% if dhcp_enabled %} -log-dhcp - -dhcp-sequential-ip -dhcp-broadcast -dhcp-authoritative -dhcp-option=option:domain-name,bigasterisk.com -dhcp-script=/opt/dnsmasq_exporter/on_dhcp_change.sh -dhcp-hostsfile=/opt/dnsmasq/{{ net }}/dhcp_hosts -dhcp-leasefile=/opt/dnsmasq/{{ net }}/leases -dhcp-range={{ house_iface }},10.2.0.0,static,infinite -dhcp-range=tag:!known,{{ house_iface }},{{ dhcp_range }},2h -dhcp-option={{ house_iface }},option:dns-server,{{ dns_server }} -dhcp-option={{ house_iface }},option:router,{{ router }} -# hosts are tagged in ./dhcp_hosts.j2 -dhcp-option=tag:filtereddns,option:dns-server,10.2.0.4 - -enable-tftp -tftp-root=/opt/dnsmasq/tftp -pxe-service=0,"Raspberry Pi Boot" - dhcp-mac=set:net-booting-rpi,b8:27:eb:*:*:* - dhcp-reply-delay=tag:net-booting-rpi,2 -{% endif %} - -local=/bigasterisk.com/ -# i didn't say --all-servers, but it was behaving like that -server=208.201.224.11 -#server=208.201.224.33 -#server=8.8.4.4 -#server=8.8.8.8 - -{% if net == "10.5" %} -# net==10.5 is not used for dhcp at all -# use ./hosts, then try the server that knows the dhcp leases -server={{ router }} -{% endif %} - -{% if net == '10.2-filtered' %} -# written by net_routes/dns_blocker.py -addn-hosts=/opt/dnsmasq/10.2-filtered/dynamic-blocking -# but! users of this dns server can't even look up names -# like 'ditto' since those come from dhcp on the 10.2.0.3 -# (nonfiltered) dnsmasq instance -{% endif %}
--- a/templates/dnsmasq/dnsmasq.service.j2 Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -# written by pyinfra - -[Unit] -Description=dnsmasq for {{ net }} network - -# this dnsmasq needs to bind to addr 10.2.0.3 -Requires=network-online.target -Requires=sys-subsystem-net-devices-eth1.device - -Wants=nss-lookup.target -Before=nss-lookup.target -After=network.target - -# startup order has to be like this: -# dnsmasq_10.2 -# wg-quick@wg0.service -# dnsmasq_10.5 -{% if net == '10.2' %} -Before=wg-quick@wg0.service -After=house_net.service -{% endif %} -{% if net == '10.5' %} -Requires=wg-quick@wg0.service -{% endif %} - -[Service] -Type=simple - -# 10.5 will not work until wg0 interface is actually up, so just let it retry -# but i think this next line was not the right way to retry. -#SuccessExitStatus=2 -Restart=always -RestartSec=5 - -# Test the config file and refuse starting if it is not valid. -ExecStartPre=/usr/sbin/dnsmasq --conf-file=/opt/dnsmasq/{{ net }}/dnsmasq.conf --test - -ExecStart=/usr/sbin/dnsmasq --conf-file=/opt/dnsmasq/{{ net }}/dnsmasq.conf - -{% if net == '10.2' %} -# The systemd-*-resolvconf functions configure (and deconfigure) -# resolvconf to work with the dnsmasq DNS server. They're called like -# this to get correct error handling (ie don't start-resolvconf if the -# dnsmasq daemon fails to start. -ExecStartPost=/etc/init.d/dnsmasq systemd-start-resolvconf -ExecStop=/etc/init.d/dnsmasq systemd-stop-resolvconf -{% endif %} - -ExecReload=/bin/kill -HUP $MAINPID - -[Install] -WantedBy=multi-user.target
--- a/templates/dnsmasq/hosts.j2 Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -# written by pyinfra - -162.243.138.136 prime-ext.bigasterisk.com public.bigasterisk.com - -# This is the dns trick-- hosts at home should use the local address -# for 'bigasterisk.com' etc instead of taking a trip to prime. -10.2.0.1 bang bang.bigasterisk.com -10.2.0.133 bigasterisk.com cam-int.bigasterisk.com cam-ext.bigasterisk.com imap.bigasterisk.com repo.bigasterisk.com drewp.quickwitretort.com photo.bigasterisk.com projects.bigasterisk.com quickwitretort.com whatsplayingnext.com whopickedthis.com vpn-home.bigasterisk.com file.bigasterisk.com antigen-superset.bigasterisk.com authenticate.bigasterisk.com authenticate2.bigasterisk.com authenticate3.bigasterisk.com megasecond.club hass.bigasterisk.com bitwarden.bigasterisk.com livegrep.bigasterisk.com dev.bigasterisk.com apprise.bigasterisk.com sco-bot-prefect.bigasterisk.com paperless.bigasterisk.com linkwarden.bigasterisk.com jellyfin.bigasterisk.com viseron.bigasterisk.com chat.bigasterisk.com - -# deleteme -162.243.138.136 light9.bigasterisk.com - -# VIPs on ditto -10.2.0.11 mqtt1 mqtt1.bigasterisk.com -10.2.0.12 mqtt2 mqtt2.bigasterisk.com -# might be used for syncthing -10.2.0.13 mqtt3 mqtt3.bigasterisk.com -10.2.0.14 mqtt4 mqtt4.bigasterisk.com - -10.2.0.15 victorialogs.bigasterisk.com - -# sync with /my/proj/infra/inventory.py -# and with templates/wireguard/wg0.conf.j2 -# Hosts with fixed wg0 addresses: -10.5.0.1 bang5.bigasterisk.com local.bigasterisk.com reg -10.5.0.2 prime5.bigasterisk.com prime.bigasterisk.com -10.5.0.5 dash5.bigasterisk.com -10.5.0.6 slash5.bigasterisk.com -10.5.0.7 ditto5.bigasterisk.com -10.5.0.14 ga-iot5.bigasterisk.com -10.5.0.17 frontbed5.bigasterisk.com -10.5.0.30 dot5.bigasterisk.com -10.5.0.31 ws-printer5.bigasterisk.com -10.5.0.32 gn-music5.bigasterisk.com -10.5.0.33 li-drums5.bigasterisk.com -10.5.0.110 plus5.bigasterisk.com -10.5.0.111 pillow.bigasterisk.com pillow5.bigasterisk.com -10.5.0.112 drew-note5.bigasterisk.com -10.5.0.113 tofu.bigasterisk.com tofu5.bigasterisk.com - -{% if net == '10.2' %} -# Hosts with fixed addrs who don't introduce via dhcp: -# 162.243.138.136 prime.bigasterisk.com -10.2.0.3 pipe pipe.bigasterisk.com -# from netdevices.n3 -10.2.0.133 ditto ditto.bigasterisk.com -{% endif %} - -{% if net == '10.5' %} -# Names that should be routed on wg0 when the DNS lookup is on wg0: -10.5.0.1 bang.bigasterisk.com -10.5.0.5 dash.bigasterisk.com -10.5.0.6 slash.bigasterisk.com -10.5.0.7 ditto.bigasterisk.com -10.5.0.14 ga-iot.bigasterisk.com -10.5.0.17 frontbed.bigasterisk.com -10.5.0.30 dot.bigasterisk.com -10.5.0.110 plus.bigasterisk.com -10.5.0.112 drew-note.bigasterisk.com -{% endif %}
--- a/templates/file-count/file-count.service.j2 Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -# written by pyinfra - -[Unit] -After=wg-quick@wg0.service - -[Service] -Type=exec -KillMode=process -# port 2500 is used in victoriametrics/config/scrape_main.yaml -ExecStart=runuser -u drewp /usr/bin/python3 /opt/file_count.py 10.5.0.2 2500 /home/drewp/Maildir/new maildir_count -Restart=always -RestartSec=5s - -[Install] -WantedBy=multi-user.target
--- a/templates/file-count/file_count.py Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -import http.server -import socketserver -import os -import sys - -interface, port, dir, metric_name = sys.argv[1:] - - -class Web(http.server.SimpleHTTPRequestHandler): - - def do_GET(self): - files_count = len(os.listdir(dir)) - self.send_response(200) - self.send_header('Content-type', 'text/plain') - self.end_headers() - self.wfile.write(f'{metric_name} {files_count}'.encode()) - - -with socketserver.TCPServer((interface, int(port)), Web) as httpd: - httpd.serve_forever()
--- a/templates/hosts.j2 Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -# written by pyinfra - -127.0.0.1 localhost -127.0.1.1 {{ host.name }} - -# The following lines are desirable for IPv6 capable hosts -::1 ip6-localhost ip6-loopback -fe00::0 ip6-localnet -ff00::0 ip6-mcastprefix -ff02::1 ip6-allnodes -ff02::2 ip6-allrouters - - -{% if 'laptop' in host.groups or 'hosted' in host.groups %} -10.5.0.1 bang bang.bigasterisk.com bang5 bang5.bigasterisk.com -10.5.0.7 ditto ditto.bigasterisk.com ditto5 ditto5.bigasterisk.com -10.5.0.5 dash -{% endif %} - -{% if host.name == 'prime' %} -# for wireguard setup: -127.0.0.1 public.bigasterisk.com -{% endif %}
--- a/templates/kube/config-agent.yaml.j2 Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -node-ip: {{ wg_ip }} -token: {{ token }} -server: https://{{ server_ip }}:6443
--- a/templates/kube/config-server.yaml.j2 Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -write-kubeconfig-mode: '640' -node-ip: {{ wg_ip }} -disable: - - traefik
--- a/templates/kube/coredns.yaml Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,228 +0,0 @@ -unused? needs server ip fixes - - -apiVersion: v1 -kind: ServiceAccount -metadata: - name: coredns - namespace: kube-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - kubernetes.io/bootstrapping: rbac-defaults - name: system:coredns -rules: -- apiGroups: - - "" - resources: - - endpoints - - services - - pods - - namespaces - verbs: - - list - - watch -- apiGroups: - - discovery.k8s.io - resources: - - endpointslices - verbs: - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - annotations: - rbac.authorization.kubernetes.io/autoupdate: "true" - labels: - kubernetes.io/bootstrapping: rbac-defaults - name: system:coredns -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:coredns -subjects: -- kind: ServiceAccount - name: coredns - namespace: kube-system ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: coredns - namespace: kube-system -data: - Corefile: | - # update 2022-11-26T23:47 - .:53 { - errors - health - ready - kubernetes cluster.local in-addr.arpa ip6.arpa { - pods insecure - fallthrough in-addr.arpa ip6.arpa - } - hosts /etc/coredns/NodeHosts { - ttl 60 - reload 15s - fallthrough - } - prometheus :9153 - forward . dns://10.2.0.3 - cache 30 - loop - reload - loadbalance - log - } ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: coredns - namespace: kube-system - labels: - k8s-app: kube-dns - kubernetes.io/name: "CoreDNS" -spec: - #replicas: 1 - strategy: - type: RollingUpdate - rollingUpdate: - maxUnavailable: 1 - selector: - matchLabels: - k8s-app: kube-dns - template: - metadata: - labels: - k8s-app: kube-dns - spec: - priorityClassName: "system-cluster-critical" - serviceAccountName: coredns - tolerations: - - key: "CriticalAddonsOnly" - operator: "Exists" - - key: "node-role.kubernetes.io/control-plane" - operator: "Exists" - effect: "NoSchedule" - - key: "node-role.kubernetes.io/master" - operator: "Exists" - effect: "NoSchedule" - nodeSelector: - kubernetes.io/os: linux - affinity: # because dns is broken so often, and it might be a circular config that can't start unless this is on bang - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: "kubernetes.io/hostname" - operator: In - values: ["bang"] - topologySpreadConstraints: - - maxSkew: 1 - topologyKey: kubernetes.io/hostname - whenUnsatisfiable: DoNotSchedule - labelSelector: - matchLabels: - k8s-app: kube-dns - containers: - - name: coredns - image: rancher/mirrored-coredns-coredns:1.9.1 - imagePullPolicy: IfNotPresent - resources: - limits: - memory: 170Mi - requests: - cpu: 100m - memory: 70Mi - args: [ "-conf", "/etc/coredns/Corefile" ] - volumeMounts: - - name: config-volume - mountPath: /etc/coredns - readOnly: true - - name: custom-config-volume - mountPath: /etc/coredns/custom - readOnly: true - ports: - - containerPort: 53 - name: dns - protocol: UDP - - containerPort: 53 - name: dns-tcp - protocol: TCP - - containerPort: 9153 - name: metrics - protocol: TCP - securityContext: - allowPrivilegeEscalation: false - capabilities: - add: - - NET_BIND_SERVICE - drop: - - all - readOnlyRootFilesystem: true - livenessProbe: - httpGet: - path: /health - port: 8080 - scheme: HTTP - initialDelaySeconds: 60 - periodSeconds: 10 - timeoutSeconds: 1 - successThreshold: 1 - failureThreshold: 3 - readinessProbe: - httpGet: - path: /ready - port: 8181 - scheme: HTTP - initialDelaySeconds: 0 - periodSeconds: 2 - timeoutSeconds: 1 - successThreshold: 1 - failureThreshold: 3 - dnsPolicy: Default - volumes: - - name: config-volume - configMap: - name: coredns - items: - - key: Corefile - path: Corefile - - key: NodeHosts - path: NodeHosts - - name: custom-config-volume - configMap: - name: coredns-custom - optional: true ---- -apiVersion: v1 -kind: Service -metadata: - name: kube-dns - namespace: kube-system - annotations: - prometheus.io/port: "9153" - prometheus.io/scrape: "true" - labels: - k8s-app: kube-dns - kubernetes.io/cluster-service: "true" - kubernetes.io/name: "CoreDNS" -spec: - selector: - k8s-app: kube-dns - clusterIP: '10.5.0.1' - ports: - - name: dns - port: 53 - protocol: UDP - - name: dns-tcp - port: 53 - protocol: TCP - - name: metrics - port: 9153 - protocol: TCP
--- a/templates/kube/k3s.service.j2 Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -# written by pyinfra - -[Unit] -Description=Lightweight Kubernetes -Documentation=https://k3s.io -After=network-online.target - -[Service] -Type=notify -ExecStartPre=-/sbin/modprobe br_netfilter -ExecStartPre=-/sbin/modprobe overlay -ExecStart=/usr/local/bin/k3s {{ role }} --config /etc/k3s_config.yaml --kubelet-arg=config=/etc/rancher/k3s/kubelet.config -KillMode=process -Delegate=yes -# Having non-zero Limit*s causes performance problems due to accounting overhead -# in the kernel. We recommend using cgroups to do container-local accounting. -LimitNOFILE=1048576 -LimitNPROC=infinity -LimitCORE=infinity -TasksMax=infinity -TimeoutStartSec=0 -Restart=always -RestartSec=5s - -[Install] -WantedBy=multi-user.target
--- a/templates/kube/podman_registries.conf.j2 Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -[[registry]] -location = "{{reg}}" -insecure = true
--- a/templates/kube/registries.yaml.j2 Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -# written by pyinfra - - -# docs: https://rancher.com/docs/k3s/latest/en/installation/private-registry/ - - -mirrors: - "{{reg}}": - endpoint: - - "http://{{reg}}"
--- a/templates/mail/main.cf.j2 Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,104 +0,0 @@ -# written by pyinfra - -compatibility_level = 3 - -smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu) - -readme_directory = /usr/share/doc/postfix -html_directory = /usr/share/doc/postfix/html - -inet_interfaces = all - -# TLS parameters -smtpd_tls_cert_file=/etc/ssl/certs/self1-ca.crt -smtpd_tls_key_file=/etc/ssl/certs/self1-ca.key -smtpd_use_tls=yes -smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache -smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache -smtpd_tls_loglevel = 0 -smtpd_tls_security_level = may -smtpd_tls_received_header = yes -smtpd_relay_before_recipient_restrictions = yes -smtp_address_preference = ipv4 - -# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for -# information on enabling SSL in the smtp client. - -relayhost = {{ 'prime.bigasterisk.com' if host.name != 'prime' else '' }} - -alias_maps = hash:/etc/postfix/aliases -alias_database = hash:/etc/postfix/aliases - -{% if host.name == 'prime' %} -myhostname = bigasterisk.com -mydestination = /etc/postfix/mydestination -{% else %} -myhostname = {{ host.name }}.bigasterisk.com -# must relay, even if you think you're the destination name is correct -mydestination = -{% endif %} - -relay_domains = $mydestination -mynetworks_style = subnet -mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 10.1.0.0/16 10.3.0.0/16 10.5.0.0/24 192.168.0.3/32 [fc7b:54e8:69a9:e165:86c8:9d42:6cc5:b2a1]/128 [fcc8:29d:5660:ec63:754f:37af:de4a:a9df]/128 - -# allow realuser+fakepart@bigasterisk.com -recipient_delimiter = + - -{% if host.name == 'prime' %} -# mail can only deliver on prime -mailbox_size_limit = 0 -home_mailbox = Maildir/ -biff = no -message_size_limit = 50000000 -#mailbox_command = procmail -a "$EXTENSION" -{% endif %} - - -# http://www.spamcop.net/fom-serve/cache/349.html -# upgraded, per http://www.wrightthisway.com/Articles/000062.html - -smtpd_recipient_restrictions = - permit_mynetworks, - permit_sasl_authenticated, -# check_client_access /etc/passwd somehow? - reject_invalid_hostname, - reject_non_fqdn_sender, - reject_non_fqdn_recipient, - reject_unknown_sender_domain, - reject_unknown_recipient_domain, - reject_unauth_pipelining, - permit_tls_clientcerts, - reject_unauth_destination, - check_sender_access hash:/etc/postfix/sender_access, - reject_rbl_client bl.spamcop.net, - permit - -smtpd_tls_ask_ccert = yes - -# no dovecot -smtpd_sasl_type = cyrus -cyrus_sasl_config_path = /etc/postfix/sasl/ - -# yes dovecot -#smtpd_sasl_type = dovecot -#smtpd_sasl_path = private/auth - -smtpd_sasl_auth_enable = yes -smtpd_sasl_security_options = noanonymous -smtpd_sasl_tls_security_options = $smtpd_sasl_security_options -smtpd_tls_auth_only = yes - -queue_directory = /var/spool/postfix - -# Postfix is the final destination for the specified list -{% if host.name == 'prime' %} -virtual_alias_domains = adkinslawgroup.com iveseenyoubefore.com fantasyfamegame.com maxradi.us whopickedthis.com quickwitretort.com drewp.quickwitretort.com kelsi.quickwitretort.com photo.bigasterisk.com whatsplayingnext.com williamperttula.com - -# Optional lookup tables that alias specific mail addresses or domains to other local or remote addresses -virtual_alias_maps = hash:/etc/postfix/virtual -{% endif %} - -smtpd_milters = inet:127.0.0.1:8891 -non_smtpd_milters = $smtpd_milters -milter_default_action = accept
--- a/templates/mail/mydestination.j2 Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -localhost -localhost.bigasterisk.com -10.2.0.1 -a.mx.bigasterisk.com -bang.bigasterisk.com -bigast.com -bigasterisk.com -dash.bigasterisk.com -mail.bigasterisk.com -www.bigasterisk.com -chitty.bigasterisk.com -cuisine.bigasterisk.com -dot.bigasterisk.com -drewp.quickwitretort.com -kelsi.quickwitretort.com -maxradi.us -williamperttula.com -ditto.bigasterisk.com -chat.bigasterisk.com -
--- a/templates/mail/opendkim-KeyTable.j2 Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -default._domainkey.bigasterisk.com bigasterisk.com:default:/etc/opendkim/keys/bigasterisk.com/default.private -default._domainkey.chat.bigasterisk.com chat.bigasterisk.com:default:/etc/opendkim/keys/chat.bigasterisk.com/default.private
--- a/templates/mail/opendkim-SigningTable.j2 Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -*@bigasterisk.com default._domainkey.bigasterisk.com -*@chat.bigasterisk.com default._domainkey.chat.bigasterisk.com
--- a/templates/mail/opendkim-TrustedHosts.j2 Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -127.0.0.1 -::1 -*.bigasterisk.com -10.5.0.0/16
--- a/templates/mail/opendkim.conf.j2 Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,772 +0,0 @@ -## -## opendkim.conf -- configuration file for OpenDKIM filter -## -## Copyright (c) 2010-2015, 2018, The Trusted Domain Project. -## All rights reserved. -## - -## -## For settings that refer to a "dataset", see the opendkim(8) man page. -## - -## DEPRECATED CONFIGURATION OPTIONS -## -## The following configuration options are no longer valid. They should be -## removed from your existing configuration file to prevent potential issues. -## Failure to do so may result in opendkim being unable to start. -## -## Removed in 2.10.0: -## AddAllSignatureResults -## ADSPAction -## ADSPNoSuchDomain -## BogusPolicy -## DisableADSP -## LDAPSoftStart -## LocalADSP -## NoDiscardableMailTo -## On-PolicyError -## SendADSPReports -## UnprotectedPolicy - -## CONFIGURATION OPTIONS - -## AllowSHA1Only { yes | no } -## default "no" -## -## By default, the filter will refuse to start if support for SHA256 is -## not available since this violates the strong recommendations of -## RFC6376 Section 3.3, which says: -## -## "Verifiers MUST implement both rsa-sha1 and rsa-sha256. Signers MUST -## implement and SHOULD sign using rsa-sha256." -## -## This forces that violation to be explicitly selected by the administrator. - -# AllowSHA1Only no - -## AlwaysAddARHeader { yes | no } -## default "no" -## -## Add an "Authentication-Results:" header even to unsigned messages -## from domains with no "signs all" policy. The reported DKIM result -## will be "none" in such cases. Normally unsigned mail from non-strict -## domains does not cause the results header to be added. - -# AlwaysAddARHeader no - -## AuthservID string -## default (local host name) -## -## Defines the "authserv-id" token to be used when generating -## Authentication-Results headers after message verification. - -# AuthservID example.com - -## AuthservIDWithJobID -## default "no" -## -## Appends a "/" followed by the MTA's job ID to the "authserv-id" token -## when generating Authentication-Results headers after message verification. - -# AuthservIDWithJobId no - -## AutoRestart { yes | no } -## default "no" -## -## Indicate whether or not the filter should arrange to restart automatically -## if it crashes. - -# AutoRestart No - -## AutoRestartCount n -## default 0 -## -## Sets the maximum automatic restart count. After this number of -## automatic restarts, the filter will give up and terminate. A value of 0 -## implies no limit. - -# AutoRestartCount 0 - -## AutoRestartRate n/t[u] -## default (none) -## -## Sets the maximum automatic restart rate. See the opendkim.conf(5) -## man page for the format of this parameter. - -# AutoRestartRate n/tu - -## Background { yes | no } -## default "yes" -## -## Indicate whether or not the filter should run in the background. - -# Background Yes - -## BaseDirectory path -## default (none) -## -## Causes the filter to change to the named directory before beginning -## operation. Thus, cores will be dumped here and configuration files -## are read relative to this location. - -# BaseDirectory /var/run/opendkim - -## BodyLengthDB dataset -## default (none) -## -## A data set that is checked against envelope recipients to see if a -## body length tag should be included in the generated signature. -## This has security implications; see opendkim.conf(5) for details. - -# BodyLengthDB dataset - -## Canonicalization hdrcanon[/bodycanon] -## default "simple/simple" -## -## Select canonicalizations to use when signing. If the "bodycanon" is -## omitted, "simple" is used. Valid values for each are "simple" and -## "relaxed". - -# Canonicalization simple/simple - -## ClockDrift n -## default 300 -## -## Specify the tolerance range for expired signatures or signatures -## which appear to have timestamps in the future, allowing for clock -## drift. - -# ClockDrift 300 - -## Diagnostics { yes | no } -## default "no" -## -## Specifies whether or not signatures with header diagnostic tags should -## be generated. - -# Diagnostics No - -## DNSTimeout n -## default 10 -## -## Specify the time in seconds to wait for replies from the nameserver when -## requesting keys or signing policies. - -# DNSTimeout 10 - -## Domain dataset -## default (none) -## -## Specify for which domain(s) signing should be done. No default; must -## be specified for signing. - -Domain bigasterisk.com,chat.bigasterisk.com - -## DomainKeysCompat { yes | no } -## default "no" -## -## When enabled, backward compatibility with DomainKeys (RFC4870) key -## records is enabled. Otherwise, such key records are considered to be -## syntactically invalid. - -# DomainKeysCompat no - -## DontSignMailTo dataset -## default (none) -## -## Gives a list of recipient addresses or address patterns whose mail should -## not be signed. - -# DontSignMailTo addr1,addr2,... - -## EnableCoredumps { yes | no } -## default "no" -## -## On systems which have support for such, requests that the kernel dump -## core even though the process may change user ID during its execution. - -# EnableCoredumps no - -## ExemptDomains dataset -## default (none) -## -## A data set of domain names that are checked against the message sender's -## domain. If a match is found, the message is ignored by the filter. - -# ExemptDomains domain1,domain2,... - -## ExternalIgnoreList filename -## -## Names a file from which a list of externally-trusted hosts is read. -## These are hosts which are allowed to send mail through you for signing. -## Automatically contains 127.0.0.1. See man page for file format. - -ExternalIgnoreList refile:/etc/opendkim/TrustedHosts - -## FixCRLF { yes | no } -## -## Requests that the library convert "naked" CR and LF characters to -## CRLFs during canonicalization. The default is "no". - -# FixCRLF no - -## IgnoreMalformedMail { yes | no } -## default "no" -## -## Silently passes malformed messages without alteration. This includes -## messages that fail the RequiredHeaders check, if enabled. The default is -## to pass those messages but add an Authentication-Results field indicating -## that they were malformed. - -# IgnoreMalformedMail no - -## InternalHosts dataset -## default "127.0.0.1" -## -## Names a file from which a list of internal hosts is read. These are -## hosts from which mail should be signed rather than verified. -## Automatically contains 127.0.0.1. - -InternalHosts refile:/etc/opendkim/TrustedHosts - -## KeepTemporaryFiles { yes | no } -## default "no" -## -## If set, causes temporary files generated during message signing or -## verifying to be left behind for debugging use. Not for normal operation; -## can fill your disks quite fast on busy systems. - -# KeepTemporaryFiles no - -## KeyFile filename -## default (none) -## -## Specifies the path to the private key to use when signing. Ignored if -## SigningTable and KeyTable are used. No default; must be specified for -## signing if SigningTable/KeyTable are not in use. - -KeyFile /etc/opendkim/keys/default.private - -## KeyTable dataset -## default (none) -## -## Defines a table that will be queried to convert key names to -## sets of data of the form (signing domain, signing selector, private key). -## The private key can either contain a PEM-formatted private key, -## a base64-encoded DER format private key, or a path to a file containing -## one of those. - -KeyTable /etc/opendkim/KeyTable - -## LogWhy { yes | no } -## default "no" -## -## If logging is enabled (see Syslog below), issues very detailed logging -## about the logic behind the filter's decision to either sign a message -## or verify it. The logic behind the decision is non-trivial and can be -## confusing to administrators not familiar with its operation. A -## description of how the decision is made can be found in the OPERATIONS -## section of the opendkim(8) man page. This causes a large increase -## in the amount of log data generated for each message, so it should be -## limited to debugging use and not enabled for general operation. - -LogWhy yes - -## MacroList macro[=value][,...] -## -## Gives a set of MTA-provided macros which should be checked to see -## if the sender has been determined to be a local user and therefore -## whether or not signing should be done. See opendkim.conf(5) for -## more information. - -# MacroList foo=bar,baz=blivit - -## MaximumHeaders n -## -## Disallow messages whose header blocks are bigger than "n" bytes. -## Intended to detect and block a denial-of-service attack. The default -## is 65536. A value of 0 disables this test. - -# MaximumHeaders n - -## MaximumSignaturesToVerify n -## (default 3) -## -## Verify no more than "n" signatures on an arriving message. -## A value of 0 means "no limit". - -# MaximumSignaturesToVerify n - -## MaximumSignedBytes n -## -## Don't sign more than "n" bytes of the message. The default is to -## sign the entire message. Setting this implies "BodyLengths". - -# MaximumSignedBytes n - -## MilterDebug n -## -## Request a debug level of "n" from the milter library. The default is 0. - -# MilterDebug 0 - -## Minimum n[% | +] -## default 0 -## -## Sets a minimum signing volume; one of the following formats: -## n at least n bytes (or the whole message, whichever is less) -## must be signed -## n% at least n% of the message must be signed -## n+ if a length limit was presented in the signature, no more than -## n bytes may have been added - -# Minimum n - -## MinimumKeyBits n -## default 1024 -## -## Causes the library not to accept signatures matching keys made of fewer -## than the specified number of bits, even if they would otherwise pass -## DKIM signing. - -# MinimumKeyBits 1024 - -## Mode [sv] -## default sv -## -## Indicates which mode(s) of operation should be provided. "s" means -## "sign", "v" means "verify". - -Mode sv - -## MTA dataset -## default (none) -## -## Specifies a list of MTAs whos mail should always be signed rather than -## verified. The "mtaname" is extracted from the DaemonPortOptions line -## in effect. - -# MTA name - -## MultipleSignatures { yes | no } -## default no -## -## Allows multiple signatures to be added. If set to "true" and a SigningTable -## is in use, all SigningTable entries that match the candidate message will -## cause a signature to be added. Otherwise, only the first matching -## SigningTable entry will be added, or only the key defined by Domain, -## Selector and KeyFile will be added. - -# MultipleSignatures no - -## MustBeSigned dataset -## default (none) -## -## Defines a list of headers which, if present on a message, must be -## signed for the signature to be considered acceptable. - -# MustBeSigned header1,header2,... - -## Nameservers addr1[,addr2[,...]] -## default (none) -## -## Provides a comma-separated list of IP addresses that are to be used when -## doing DNS queries to retrieve DKIM keys, VBR records, etc. -## These override any local defaults built in to the resolver in use, which -## may be defined in /etc/resolv.conf or hard-coded into the software. - -# Nameservers addr1,addr2,... - -## NoHeaderB { yes | no } -## default "no" -## -## Suppresses addition of "header.b" tags on Authentication-Results -## header fields. - -# NoHeaderB no - -## OmitHeaders dataset -## default (none) -## -## Specifies a list of headers that should always be omitted when signing. -## Header names should be separated by commas. - -# OmitHeaders header1,header2,... - -## On-... -## -## Specifies what to do when certain error conditions are encountered. -## -## See opendkim.conf(5) for more information. - -# On-Default -# On-BadSignature -# On-DNSError -# On-InternalError -# On-NoSignature -# On-Security -# On-SignatureError - -## OversignHeaders dataset -## default (none) -## -## Specifies a set of header fields that should be included in all signature -## header lists (the "h=" tag) once more than the number of times they were -## actually present in the signed message. See opendkim.conf(5) for more -## information. - -# OverSignHeaders header1,header2,... - -## PeerList dataset -## default (none) -## -## Contains a list of IP addresses, CIDR blocks, hostnames or domain names -## whose mail should be neither signed nor verified by this filter. See man -## page for file format. - -# PeerList filename - -## PidFile filename -## default (none) -## -## Name of the file where the filter should write its pid before beginning -## normal operations. - -# PidFile filename - -## POPDBFile dataset -## default (none) -## -## Names a database which should be checked for "POP before SMTP" records -## as a form of authentication of users who may be sending mail through -## the MTA for signing. Requires special compilation of the filter. -## See opendkim.conf(5) for more information. - -# POPDBFile filename - -## Quarantine { yes | no } -## default "no" -## -## Indicates whether or not the filter should arrange to quarantine mail -## which fails verification. Intended for diagnostic use only. - -# Quarantine No - -## QueryCache { yes | no } -## default "no" -## -## Instructs the DKIM library to maintain its own local cache of keys and -## policies retrieved from DNS, rather than relying on the nameserver for -## caching service. Useful if the nameserver being used by the filter is -## not local. The filter must be compiled with the QUERY_CACHE flag to enable -## this feature, since it adds a library dependency. - -# QueryCache No - -## RedirectFailuresTo address -## default (none) -## -## Redirects signed messages to the specified address if none of the -## signatures present failed to verify. - -# RedirectFailuresTo postmaster@example.com - -## RemoveARAll { yes | no } -## default "no" -## -## Remove all Authentication-Results: headers on all arriving mail. - -# RemoveARAll No - -## RemoveARFrom dataset -## default (none) -## -## Remove all Authentication-Results: headers on all arriving mail that -## claim to have been added by hosts listed in this parameter. The list -## should be comma-separated. Entire domains may be specified by preceding -## the dopmain name by a single dot (".") character. - -# RemoveARFrom host1,host2,.domain1,.domain2,... - -## RemoveOldSignatures { yes | no } -## default "no" -## -## Remove old signatures on messages, if any, when generating a signature. - -# RemoveOldSignatures No - -## ReportAddress addr -## default (executing user)@(hostname) -## -## Specifies the sending address to be used on From: headers of outgoing -## failure reports. By default, the e-mail address of the user executing -## the filter is used. - -# ReportAddress "DKIM Error Postmaster" <postmaster@example.com> - -## ReportBccAddress addr -## default (none) -## -## Specifies additional recipient address(es) to receive outgoing failure -## reports. - -# ReportBccAddress postmaster@example.com, john@example.com - -## RequiredHeaders { yes | no } -## default no -## -## Rejects messages which don't conform to RFC5322 header count requirements. - -# RequiredHeaders No - -## RequireSafeKeys { yes | no } -## default yes -## -## Refuses to use key files that appear to have unsafe permissions. - -# RequireSafeKeys Yes -RequireSafeKeys false - -## ResignAll { yes | no } -## default no -## -## Where ResignMailTo triggers a re-signing action, this flag indicates -## whether or not all mail should be signed (if set) versus only verified -## mail being signed (if not set). - -# ResignAll No - -## ResignMailTo dataset -## default (none) -## -## Checks each message recipient against the specified dataset for a -## matching record. The full address is checked in each case, then the -## hostname, then each domain preceded by ".". If there is a match, the -## value returned is presumed to be the name of a key in the KeyTable -## (if defined) to be used to re-sign the message in addition to -## verifying it. If there is a match without a KeyTable, the default key -## is applied. - -# ResignMailTo dataset - -## ResolverConfiguration string -## -## Passes arbitrary configuration data to the resolver. For the stock UNIX -## resolver, this is ignored; for Unbound, it names a resolv.conf(5)-style -## file that should be read for configuration information. - -# ResolverConfiguration string - -## ResolverTracing { yes | no } -## -## Requests enabling of resolver trace features, if available. The effect -## of setting this flag depends on how trace features, if any, are implemented -## in the resolver in use. Currently only effective when used with the -## OpenDKIM asynchronous resolver. - -# ResolverTracing no - -## Selector name -## -## The name of the selector to use when signing. No default; must be -## specified for signing. - -Selector default - -## SenderHeaders dataset -## default (none) -## -## Overrides the default list of headers that will be used to determine -## the sending domain when deciding whether to sign the message and with -## with which key(s). See opendkim.conf(5) for details. - -# SenderHeaders From - -## SendReports { yes | no } -## default "no" -## -## Specifies whether or not the filter should generate report mail back -## to senders when verification fails and an address for such a purpose -## is provided. See opendkim.conf(5) for details. - -# SendReports No - -## SignatureAlgorithm signalg -## default "rsa-sha256" -## -## Signature algorithm to use when generating signatures. Must be one of -## "rsa-sha1", "rsa-sha256", or "ed25519-sha256". - -# SignatureAlgorithm rsa-sha256 - -## SignatureTTL seconds -## default "0" -## -## Specifies the lifetime in seconds of signatures generated by the -## filter. A value of 0 means no expiration time is included in the -## signature. - -# SignatureTTL 0 - -## SignHeaders dataset -## default (none) -## -## Specifies the list of headers which should be included when generating -## signatures. The string should be a comma-separated list of header names. -## See the opendkim.conf(5) man page for more information. - -# SignHeaders header1,header2,... - -## SigningTable dataset -## default (none) -## -## Defines a dataset that will be queried for the message sender's address -## to determine which private key(s) (if any) should be used to sign the -## message. The sender is determined from the value of the sender -## header fields as described with SenderHeaders above. The key for this -## lookup should be an address or address pattern that matches senders; -## see the opendkim.conf(5) man page for more information. The value -## of the lookup should return the name of a key found in the KeyTable -## that should be used to sign the message. If MultipleSignatures -## is set, all possible lookup keys will be attempted which may result -## in multiple signatures being applied. - -SigningTable refile:/etc/opendkim/SigningTable - -## SingleAuthResult { yes | no} -## default "no" -## -## When DomainKeys verification is enabled, multiple Authentication-Results -## will be added, one for DK and one for DKIM. With this enabled, only -## a DKIM result will be reported unless DKIM failed but DK passed, in which -## case only a DK result will be reported. - -# SingleAuthResult no - -## SMTPURI uri -## -## Specifies a URI (e.g., "smtp://localhost") to which mail should be sent -## via SMTP when notifications are generated. - -# Socket smtp://localhost - -## Socket socketspec -## -## Names the socket where this filter should listen for milter connections -## from the MTA. Required. Should be in one of these forms: -## -## inet:port@address to listen on a specific interface -## inet:port to listen on all interfaces -## local:/path/to/socket to listen on a UNIX domain socket - -Socket inet:8891@localhost - -## SoftwareHeader { yes | no } -## default "no" -## -## Add a DKIM-Filter header field to messages passing through this filter -## to identify messages it has processed. - -# SoftwareHeader no - -## StrictHeaders { yes | no } -## default "no" -## -## Requests that the DKIM library refuse to process a message whose -## header fields do not conform to the standards, in particular Section 3.6 -## of RFC5322. - -# StrictHeaders no - -## StrictTestMode { yes | no } -## default "no" -## -## Selects strict CRLF mode during testing (see the "-t" command line -## flag in the opendkim(8) man page). Messages for which all header -## fields and body lines are not CRLF-terminated are considered malformed -## and will produce an error. - -# StrictTestMode no - -## SubDomains { yes | no } -## default "no" -## -## Sign for subdomains as well? - -# SubDomains No - -## Syslog { yes | no } -## default "yes" -## -## Log informational and error activity to syslog? - -Syslog Yes - -## SyslogFacility facility -## default "mail" -## -## Valid values are : -## auth cron daemon kern lpr mail news security syslog user uucp -## local0 local1 local2 local3 local4 local5 local6 local7 -## -## syslog facility to be used - -# SyslogFacility mail - -## SyslogName ident -## default "opendkim" (or the name of the executable) -## -## Identifier to be prepended to all generated log entries. - -# SyslogName opendkim - -## SyslogSuccess { yes | no } -## default "no" -## -## Log success activity to syslog? - -# SyslogSuccess No - -## TemporaryDirectory path -## default /tmp -## -## Specifies which directory will be used for creating temporary files -## during message processing. - -# TemporaryDirectory /tmp - -## TestPublicKeys filename -## default (none) -## -## Names a file from which public keys should be read. Intended for use -## only during automated testing. - -# TestPublicKeys /tmp/testkeys - -## TrustAnchorFile filename -## default (none) -## -## Specifies a file from which trust anchor data should be read when doing -## DNS queries and applying the DNSSEC protocol. See the Unbound documentation -## at http://unbound.net for the expected format of this file. - -# TrustAnchorFile /var/named/trustanchor - -## UMask mask -## default (none) -## -## Change the process umask for file creation to the specified value. -## The system has its own default which will be used (usually 022). -## See the umask(2) man page for more information. - -# UMask 022 - -# UnboundConfigFile /var/named/unbound.conf - -## Userid userid -## default (none) -## -## Change to user "userid" before starting normal operation? May include -## a group ID as well, separated from the userid by a colon. - -UserID opendkim
--- a/templates/mail/opendkim.service.j2 Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -[Unit] -Description=OpenDKIM Milter -Documentation=man:opendkim(8) man:opendkim.conf(5) man:opendkim-lua(3) man:opendkim-genkey(8) man:opendkim-genzone(8) man:opendkim-testkey(8) http://www.opendkim.org/docs.html -After=network-online.target nss-lookup.target -Wants=network-online.target - -[Service] -Type=forking -#PIDFile=/run/opendkim/opendkim.pid -ExecStart=/usr/sbin/opendkim -vv -#ExecReload=/bin/kill -USR1 $MAINPID -Restart=on-failure - -[Install] -WantedBy=multi-user.target \ No newline at end of file
--- a/templates/resolved.conf.j2 Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -# written by pyinfra - -# See resolved.conf(5) for details - -{% if host.name == 'prime' %} -[Resolve] -# This list is tried randomly, not in order, so we could have -# some trouble with internal names -DNS=10.5.0.1 8.8.8.8 8.8.4.4 -Domains=bigasterisk.com - -{% else %} -[Resolve] -# worst case- you might get a better one over DHCP, which would get listed AFTER this one so it needs to be the only one. -#DNS=10.2.0.4 -#FallbackDNS= -Domains=bigasterisk.com -#LLMNR=no -#MulticastDNS=no -#DNSSEC=no -#DNSOverTLS=no -#Cache=yes -#DNSStubListener=yes -#ReadEtcHosts=yes -{% endif %} \ No newline at end of file
--- a/templates/webforward.service.j2 Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -# written by pyinfra - -[Unit] -Description={{ fam }} forward for port {{ port }} -Requires=network.target -Wants=nss-lookup.target -Before=nss-lookup.target -After=network.target - -[Service] -Type=simple - -ExecStart=/usr/bin/socat {{ 'tcp' if fam=='tcp' else 'udp4' }}-listen:{{ port }},fork,reuseaddr {{ 'tcp' if fam=='tcp' else 'udp' }}:{{serv_host}}:{{ port }} - -[Install] -WantedBy=multi-user.target
--- a/templates/wireguard/bogasterisk.conf.j2 Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -# written by pyinfra - -[Interface] -# {{ host.name }} -Address = 10.7.0.2/16 -PrivateKey = {{priv_key}} -ListenPort = 2113 - -{{ peer_block('monk', '10.7.0.42/32') }} -{{ peer_block('firebert (phone)', '10.7.0.88/32') }} -{{ peer_block('bird', '10.7.0.46/32') }} -{{ peer_block('pixel7', '10.7.0.77/32') }}
--- a/templates/wireguard/wg.service.j2 Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ -# written by pyinfra - -[Unit] -Description=WireGuard via wg-quick(8) for {{wireguard_interface}} -After=network-online.target nss-lookup.target -Wants=network-online.target nss-lookup.target -PartOf=wg-quick.target -Documentation=man:wg-quick(8) -Documentation=man:wg(8) -Documentation=https://www.wireguard.com/ -Documentation=https://www.wireguard.com/quickstart/ -Documentation=https://git.zx2c4.com/wireguard-tools/about/src/man/wg-quick.8 -Documentation=https://git.zx2c4.com/wireguard-tools/about/src/man/wg.8 - -[Service] -Type=oneshot -RemainAfterExit=yes -ExecStart=/usr/bin/wg-quick up {{wireguard_interface}} -ExecStop=/usr/bin/wg-quick down {{wireguard_interface}} -ExecReload=/bin/bash -c 'exec /usr/bin/wg syncconf {{wireguard_interface}} <(exec /usr/bin/wg-quick strip {{wireguard_interface}})' -Environment=WG_ENDPOINT_RESOLUTION_RETRIES=infinity - -[Install] -WantedBy=multi-user.target \ No newline at end of file
--- a/templates/wireguard/wg0.conf.j2 Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -# written by pyinfra - -[Interface] -# {{ host.name }} -Address = {{wireguard_ip}}/24 -PrivateKey = {{priv_key}} -ListenPort = 1195 - -# suggested by https://i.reddit.com/r/WireGuard/comments/jcwleo/ubuntu_2004_lts_server_as_wireguard_client/ -#FwMark = 0x4000 - -{% if host.name == 'ditto' %} - {{ peer_block('bang', '10.5.0.1/32') }} - {{ peer_block('dash', '10.5.0.5/32') }} - {{ peer_block('dot', '10.5.0.30/32') }} - {{ peer_block('pipe', '10.5.0.3/32') }} - {{ peer_block('prime', '10.5.0.0/24', 'public.bigasterisk.com:1195', 50) }} - {{ peer_block('slash', '10.5.0.6/32') }} - {{ peer_block('ws-printer', '10.5.0.31/32') }} - {{ peer_block('gn-music', '10.5.0.32/32') }} - {{ peer_block('li-drums', '10.5.0.33/32') }} - {{ peer_block('ga-iot', '10.5.0.14/32') }} -{% elif host.name == 'prime' %} -# this list is wg_roamer & ditto & phone: - {{ peer_block('ditto', '10.5.0.0/24') }} - {{ peer_block('drew-note10', '10.5.0.112/32') }} - {{ peer_block('plus', '10.5.0.110/32', 'public.bigasterisk.com:1195') }} - {{ peer_block('pillow', '10.5.0.111/32', 'public.bigasterisk.com:1195') }} - {{ peer_block('tofu', '10.5.0.113/32', 'public.bigasterisk.com:1195') }} -{% elif host.data.get('wg_roamer') %} - {{ peer_block('prime', '10.5.0.0/24', 'public.bigasterisk.com:1195', 50) }} -{% else %} -# note that hosts on filtered dns cannot currently look up the name 'ditto' - {{ peer_block('ditto', '10.5.0.0/24', '10.2.0.133:1195', 50) }} -{% endif %}
--- a/users.py Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -from pyinfra import host -from pyinfra.operations import server -from pyinfra.facts.server import LinuxDistribution - - -# raspbian took 1000 for 'pi' group, but drewp is rarely used on pi -# setups so hopefully it won't matter much that drew group has a -# different id. -drewp_uid, drewp_gid = host.data.drewp_uid, host.data.drewp_gid -drewp_groups = [ - 'lp', 'adm', 'dialout', 'cdrom', 'sudo', 'audio', 'video', 'plugdev', - 'games', 'users', 'netdev', 'i2c', 'input', 'spi', 'gpio', 'fuse', - 'render', 'mongodb', 'lpadmin' -] - -for group in [ - 'fuse', - 'spi', - 'gpio', - 'i2c', - 'input', - 'netdev', - 'render', - 'lpadmin', -]: - server.group(group=group, system=True) - -svcIds = 1050 -for svc in [ - # only append to this list: - "photoprism", - "mongodb", -]: - server.group(group=svc, gid=svcIds) - server.user(user=svc, uid=svcIds, group=svc) - svcIds += 1 - -# the following gets scrambled on new rpi. Run "useradd -u 1501 drewp" as workaround. -server.group(group='drewp', gid=drewp_gid) -# this won't change existing drewp uid; I've been doing that myself. -server.user(user='drewp', uid=drewp_uid, group='drewp', groups=drewp_groups) - -if 'pi' not in host.groups: - server.group(group='adm', gid=4) - server.group(group='cdrom', gid=24) - server.group(group='dialout', gid=20) - server.group(group='dip', gid=30) - server.group(group='lp', gid=7) - # prime has something on 109 - server.group(group='lpadmin', gid=200) - server.group(group='plugdev', gid=46) - - - server.user(user='drewp', - uid=drewp_uid, - group='drewp', - groups=drewp_groups) - - for name, uid, gid in [ - ('ari', 3019, 3019), - ('talia', 1003, 1003), - ]: - server.group(group=name, gid=gid) - server.user(user=name, - uid=uid, - group=name, - groups=['audio', 'dialout', 'docker', 'lp', 'lpadmin', 'sudo', 'video']) - - server.user(user='dmcc', uid=1013) - - server.group(group='elastic', gid=3018) - server.user(user='elastic', uid=3018, group='elastic') - - server.group(group='kelsi', gid=1008) - server.user(user='kelsi', uid=1008, group='elastic') - - server.group(group='drewnote', gid=1009) - server.user(user='drewnote', uid=1009) - - server.group(group='prometheus', gid=1010) - server.user(user='prometheus', uid=1010)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/users/users.py Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,83 @@ +from pyinfra.context import host +from pyinfra.operations import server + + +def setupUsers(): + # raspbian took 1000 for 'pi' group, but drewp is rarely used on pi + # setups so hopefully it won't matter much that drew group has a + # different id. + drewp_uid, drewp_gid = host.data.drewp_uid, host.data.drewp_gid + drewp_groups = [ + 'lp', 'adm', 'dialout', 'cdrom', 'sudo', 'audio', 'video', 'plugdev', 'games', 'users', 'netdev', 'i2c', 'input', 'spi', + 'gpio', 'fuse', 'render', 'mongodb', 'lpadmin' + ] + + svcIds = 1050 + for svc in [ + # only append to this list: + "photoprism", + "mongodb", + ]: + server.group(group=svc, gid=svcIds) + server.user(user=svc, uid=svcIds, group=svc) + svcIds += 1 + + # the following gets scrambled on new rpi. Run "useradd -u 1501 drewp" as workaround. + server.group(group='drewp', gid=drewp_gid) + # this won't change existing drewp uid; I've been doing that myself. + server.user(user='drewp', uid=drewp_uid, group='drewp', groups=drewp_groups) + + if 'pi' not in host.groups: + + server.user(user='drewp', uid=drewp_uid, group='drewp', groups=drewp_groups) + + for name, uid, gid in [ + ('ari', 3019, 3019), + ('talia', 1003, 1003), + ]: + server.group(group=name, gid=gid) + server.user(user=name, uid=uid, group=name, groups=['audio', 'dialout', 'docker', 'lp', 'lpadmin', 'sudo', 'video']) + + server.user(user='dmcc', uid=1013) + + server.group(group='elastic', gid=3018) + server.user(user='elastic', uid=3018, group='elastic') + + server.group(group='kelsi', gid=1008) + server.user(user='kelsi', uid=1008, group='elastic') + + server.group(group='drewnote', gid=1009) + server.user(user='drewnote', uid=1009) + + server.group(group='prometheus', gid=1010) + server.user(user='prometheus', uid=1010) + + +def systemGroups(): + for group in [ + 'fuse', + 'spi', + 'gpio', + 'i2c', + 'input', + 'netdev', + 'render', + 'lpadmin', + ]: + server.group(group=group, system=True) + + if 'pi' not in host.groups: + server.group(group='adm', gid=4) + server.group(group='cdrom', gid=24) + server.group(group='dialout', gid=20) + server.group(group='dip', gid=30) + server.group(group='lp', gid=7) + # prime has something on 109 + server.group(group='lpadmin', gid=200) + server.group(group='plugdev', gid=46) + + +operations = [ + systemGroups, + setupUsers, +]
--- a/wireguard.py Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -import subprocess - -from pyinfra import host -from pyinfra.facts.files import FindInFile -from pyinfra.operations import files, systemd - -import wireguard_pubkey - -# other options: -# https://www.reddit.com/r/WireGuard/comments/fkr240/shortest_path_between_peers/ -# https://github.com/k4yt3x/wireguard-mesh-configurator -# https://github.com/mawalu/wireguard-private-networking -# - - -def peer_block(hostname, allowed_ips, endpoint=None, keepalive=None): - # allowed_ips should be determined mostly from host.data.wireguard_address - - public_key = wireguard_pubkey.pubkey[hostname] - out = f'''\ - -[Peer] -# {hostname} -PublicKey = {public_key} -AllowedIPs = {allowed_ips} -''' - if endpoint is not None: - out += f'Endpoint = {endpoint}\n' - if keepalive is not None: - out += f'PersistentKeepalive = {keepalive}\n' - return out - - -def get_priv_key(wireguard_interface) -> str: - priv_key_lines = host.get_fact(FindInFile, path=f'/etc/wireguard/{wireguard_interface}.conf', pattern=r'PrivateKey.*') - if not priv_key_lines: - priv_key = subprocess.check_output(['wg', 'genkey']).strip().decode('ascii') - else: - priv_key = priv_key_lines[0].split(' = ')[1] - return priv_key - - -def compute_pub_key(priv_key: str) -> str: - pub_key = subprocess.check_output(['wg', 'pubkey'], input=priv_key.encode('ascii')).strip().decode('ascii') - # todo: if this was new, it should be added to a file of pubkeys that - # peer_block can refer to. meanwhile, edit the template. - return pub_key - - -for wireguard_interface in ['wg0', 'bogasterisk']: - if wireguard_interface == 'bogasterisk' and host.name != 'prime': - continue - - # note- this is specific to the wg0 setup. Other conf files don't use it. - wireguard_ip = host.host_data.get('wireguard_address') - if wireguard_interface == 'wg0' and wireguard_ip is None: - continue - - # new pi may fail with 'Unable to access interface: Protocol not supported'. reboot fixes. - - priv_key = get_priv_key(wireguard_interface) - - # unused since I still hand-maintain wireguard_pubkey.py :( - # pub_key = compute_pub_key(priv_key) - - files.template( - src=f'templates/wireguard/{wireguard_interface}.conf.j2', - dest=f'/etc/wireguard/{wireguard_interface}.conf', - mode='600', - wireguard_ip=wireguard_ip, - priv_key=priv_key, - peer_block=peer_block, - ) - svc = f'wg-quick@{wireguard_interface}.service' - - files.template(src='templates/wireguard/wg.service.j2', - dest=f'/etc/systemd/system/{svc}', - wireguard_interface=wireguard_interface) - systemd.service(service=svc, daemon_reload=True, restarted=True, enabled=True)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wireguard/templates/bogasterisk.conf.j2 Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,12 @@ +# written by pyinfra + +[Interface] +# {{ host.name }} +Address = 10.7.0.2/16 +PrivateKey = {{priv_key}} +ListenPort = 2113 + +{{ peer_block('monk', '10.7.0.42/32') }} +{{ peer_block('firebert (phone)', '10.7.0.88/32') }} +{{ peer_block('bird', '10.7.0.46/32') }} +{{ peer_block('pixel7', '10.7.0.77/32') }}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wireguard/templates/wg.service.j2 Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,24 @@ +# written by pyinfra + +[Unit] +Description=WireGuard via wg-quick(8) for {{wireguard_interface}} +After=network-online.target nss-lookup.target +Wants=network-online.target nss-lookup.target +PartOf=wg-quick.target +Documentation=man:wg-quick(8) +Documentation=man:wg(8) +Documentation=https://www.wireguard.com/ +Documentation=https://www.wireguard.com/quickstart/ +Documentation=https://git.zx2c4.com/wireguard-tools/about/src/man/wg-quick.8 +Documentation=https://git.zx2c4.com/wireguard-tools/about/src/man/wg.8 + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/bin/wg-quick up {{wireguard_interface}} +ExecStop=/usr/bin/wg-quick down {{wireguard_interface}} +ExecReload=/bin/bash -c 'exec /usr/bin/wg syncconf {{wireguard_interface}} <(exec /usr/bin/wg-quick strip {{wireguard_interface}})' +Environment=WG_ENDPOINT_RESOLUTION_RETRIES=infinity + +[Install] +WantedBy=multi-user.target \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wireguard/templates/wg0.conf.j2 Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,35 @@ +# written by pyinfra + +[Interface] +# {{ host.name }} +Address = {{wireguard_ip}}/24 +PrivateKey = {{priv_key}} +ListenPort = 1195 + +# suggested by https://i.reddit.com/r/WireGuard/comments/jcwleo/ubuntu_2004_lts_server_as_wireguard_client/ +#FwMark = 0x4000 + +{% if host.name == 'ditto' %} + {{ peer_block('bang', '10.5.0.1/32') }} + {{ peer_block('dash', '10.5.0.5/32') }} + {{ peer_block('dot', '10.5.0.30/32') }} + {{ peer_block('pipe', '10.5.0.3/32') }} + {{ peer_block('prime', '10.5.0.0/24', 'public.bigasterisk.com:1195', 50) }} + {{ peer_block('slash', '10.5.0.6/32') }} + {{ peer_block('ws-printer', '10.5.0.31/32') }} + {{ peer_block('gn-music', '10.5.0.32/32') }} + {{ peer_block('li-drums', '10.5.0.33/32') }} + {{ peer_block('ga-iot', '10.5.0.14/32') }} +{% elif host.name == 'prime' %} +# this list is wg_roamer & ditto & phone: + {{ peer_block('ditto', '10.5.0.0/24') }} + {{ peer_block('drew-note10', '10.5.0.112/32') }} + {{ peer_block('plus', '10.5.0.110/32', 'public.bigasterisk.com:1195') }} + {{ peer_block('pillow', '10.5.0.111/32', 'public.bigasterisk.com:1195') }} + {{ peer_block('tofu', '10.5.0.113/32', 'public.bigasterisk.com:1195') }} +{% elif host.data.get('wg_roamer') %} + {{ peer_block('prime', '10.5.0.0/24', 'public.bigasterisk.com:1195', 50) }} +{% else %} +# note that hosts on filtered dns cannot currently look up the name 'ditto' + {{ peer_block('ditto', '10.5.0.0/24', '10.2.0.133:1195', 50) }} +{% endif %}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wireguard/wireguard.py Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,85 @@ +import subprocess + +from pyinfra.context import host +from pyinfra.facts.files import FindInFile +from pyinfra.operations import files, systemd + +import wireguard.wireguard_pubkey as wireguard_pubkey + +# other options: +# https://www.reddit.com/r/WireGuard/comments/fkr240/shortest_path_between_peers/ +# https://github.com/k4yt3x/wireguard-mesh-configurator +# https://github.com/mawalu/wireguard-private-networking +# + + +def peer_block(hostname, allowed_ips, endpoint=None, keepalive=None): + # allowed_ips should be determined mostly from host.data.wireguard_address + + public_key = wireguard_pubkey.pubkey[hostname] + out = f'''\ + +[Peer] +# {hostname} +PublicKey = {public_key} +AllowedIPs = {allowed_ips} +''' + if endpoint is not None: + out += f'Endpoint = {endpoint}\n' + if keepalive is not None: + out += f'PersistentKeepalive = {keepalive}\n' + return out + + +def get_priv_key(wireguard_interface) -> str: + priv_key_lines = host.get_fact(FindInFile, path=f'/etc/wireguard/{wireguard_interface}.conf', pattern=r'PrivateKey.*') + if not priv_key_lines: + priv_key = subprocess.check_output(['wg', 'genkey']).strip().decode('ascii') + else: + priv_key = priv_key_lines[0].split(' = ')[1] + return priv_key + + +def compute_pub_key(priv_key: str) -> str: + pub_key = subprocess.check_output(['wg', 'pubkey'], input=priv_key.encode('ascii')).strip().decode('ascii') + # todo: if this was new, it should be added to a file of pubkeys that + # peer_block can refer to. meanwhile, edit the template. + return pub_key + + +def wireguard(): + for wireguard_interface in ['wg0', 'bogasterisk']: + if wireguard_interface == 'bogasterisk' and host.name != 'prime': + continue + + # note- this is specific to the wg0 setup. Other conf files don't use it. + wireguard_ip = host.host_data.get('wireguard_address') + if wireguard_interface == 'wg0' and wireguard_ip is None: + continue + + # new pi may fail with 'Unable to access interface: Protocol not supported'. reboot fixes. + + priv_key = get_priv_key(wireguard_interface) + + # unused since I still hand-maintain wireguard_pubkey.py :( + # pub_key = compute_pub_key(priv_key) + + files.template( + src=f'wireguard/templates/{wireguard_interface}.conf.j2', + dest=f'/etc/wireguard/{wireguard_interface}.conf', + mode='600', + wireguard_ip=wireguard_ip, + priv_key=priv_key, + peer_block=peer_block, + ) + svc = f'wg-quick@{wireguard_interface}.service' + + files.template(src='wireguard/templates/wg.service.j2', + dest=f'/etc/systemd/system/{svc}', + wireguard_interface=wireguard_interface) + systemd.service(service=svc, daemon_reload=True, restarted=True, enabled=True) + + +operations = [ + wireguard, +]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wireguard/wireguard_pubkey.py Mon Jan 20 21:55:08 2025 -0800 @@ -0,0 +1,25 @@ +pubkey = { + 'bang': 'xDkAqfljmeVj7bB6VslxD/vVwlUh/vLXX5Wo7ZCoTQ4=', + 'dash': 'YqcNr+QImfHqhyYH7vUYCodaGmFJkb+XGYD8TL4Ejlk=', + 'ditto': 'IaOJzsn+KK9SuNzn8lJfaD/dgu4Otp094SK0Xz4i4VA=', + 'dot': '0youwd1ZHBQgbd+YUg8WdxhSqiK2rSKxmzDpf+gu4z0=', + 'drew-note10': 'QMgx4cmuUTfJ7RH4Q46b54tSQl4eISOmdEney17fnE8=', + 'frontbed': 'ENhRhEgGaFfwV74MqYBHJgkOFpNAF5kVHVK5/tRVTjU=', + 'ga-iot': 'oqbSKq3CNTApp9g5sEwYZhofLy2jgWjXi00H5sTSgQs=', + 'pipe': 'yI0zt8/+baHjadhiBCX6u8sSkhjoh/Q5cIZkGf1H6S4=', + 'plus': 'hRCwLRUGY3hYNHwsmxSmAPWqAvMr+ZM6IVAte8tLVyU=', + 'prime': 'vR9lfsUSOIMxkY/k2gRJ6E8ZudccfPpVhrbE9zuxalU=', + 'slash': 'dZSvwUPLKPrBWY66o8GNeWCcol6lK5QG80HLtOnCRko=', + 'pillow': 'gi54uHkV3WQWvU7b90oZV9ss69kqyeDerkaRk1dYziU=', + 'ws-printer': 'HGQkw9ayf4g73s8Rvj76nUCIzr5oDqNVx3GuGq6Xvnw=', + 'li-drums': 'CkFzBGjSJLHnR7FeWzandx2F03x5tncaqpCuiNcIoCc=', + 'gn-music': 'XKkjSfdvROkLe0zxp9wal+ObTWqh/o7kJTXL8O9AOSQ=', + 'tofu': 'abh0iwycB8kPY1yiI18dppil7/20/IskaHMRboTg2Qg=', +} + +pubkey.update({ + 'bird': '9CkgqeAiX1GhNM+t9m2nJD5QJHx9iTCFRB5c1x7h704=', + 'firebert (phone)': 'Rr9N6dGbMLzl6wuEJlaq67gNQ5QW2ZcwD4Brn/3XJyA=', + 'monk': 'aroc8MNdTnKg175HYxri+Yr1afuaC0awyr6TfGMpvxI=', + 'pixel7': 'RMY3wgh/xA98aU85qE7qnFk2wStGbXAcMOl28gqu2zo=', +})
--- a/wireguard_pubkey.py Mon Jan 20 14:10:19 2025 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -pubkey = { - 'bang': 'xDkAqfljmeVj7bB6VslxD/vVwlUh/vLXX5Wo7ZCoTQ4=', - 'dash': 'YqcNr+QImfHqhyYH7vUYCodaGmFJkb+XGYD8TL4Ejlk=', - 'ditto': 'IaOJzsn+KK9SuNzn8lJfaD/dgu4Otp094SK0Xz4i4VA=', - 'dot': '0youwd1ZHBQgbd+YUg8WdxhSqiK2rSKxmzDpf+gu4z0=', - 'drew-note10': 'QMgx4cmuUTfJ7RH4Q46b54tSQl4eISOmdEney17fnE8=', - 'frontbed': 'ENhRhEgGaFfwV74MqYBHJgkOFpNAF5kVHVK5/tRVTjU=', - 'ga-iot': 'oqbSKq3CNTApp9g5sEwYZhofLy2jgWjXi00H5sTSgQs=', - 'pipe': 'yI0zt8/+baHjadhiBCX6u8sSkhjoh/Q5cIZkGf1H6S4=', - 'plus': 'hRCwLRUGY3hYNHwsmxSmAPWqAvMr+ZM6IVAte8tLVyU=', - 'prime': 'vR9lfsUSOIMxkY/k2gRJ6E8ZudccfPpVhrbE9zuxalU=', - 'slash': 'dZSvwUPLKPrBWY66o8GNeWCcol6lK5QG80HLtOnCRko=', - 'pillow': 'gi54uHkV3WQWvU7b90oZV9ss69kqyeDerkaRk1dYziU=', - 'ws-printer': 'HGQkw9ayf4g73s8Rvj76nUCIzr5oDqNVx3GuGq6Xvnw=', - 'li-drums': 'CkFzBGjSJLHnR7FeWzandx2F03x5tncaqpCuiNcIoCc=', - 'gn-music': 'XKkjSfdvROkLe0zxp9wal+ObTWqh/o7kJTXL8O9AOSQ=', - 'tofu': 'abh0iwycB8kPY1yiI18dppil7/20/IskaHMRboTg2Qg=', -} - -pubkey.update({ - 'bird': '9CkgqeAiX1GhNM+t9m2nJD5QJHx9iTCFRB5c1x7h704=', - 'firebert (phone)': 'Rr9N6dGbMLzl6wuEJlaq67gNQ5QW2ZcwD4Brn/3XJyA=', - 'monk': 'aroc8MNdTnKg175HYxri+Yr1afuaC0awyr6TfGMpvxI=', - 'pixel7': 'RMY3wgh/xA98aU85qE7qnFk2wStGbXAcMOl28gqu2zo=', -})