From 6b0e92447a26a911a1988f94c775b763afd41c1b Mon Sep 17 00:00:00 2001 From: cronekorkn Date: Thu, 6 Oct 2022 14:42:52 +0200 Subject: [PATCH] left4dead --- bundles/left4dead2/items.py | 119 +++++++------------- bundles/left4dead2/metadata.py | 74 ++++++------ bundles/steam-workshop-download/items.py | 7 ++ bundles/steam-workshop-download/metadata.py | 39 +++++++ bundles/steam/items.py | 18 +-- bundles/steam/metadata.py | 12 +- bundles/systemd/items.py | 4 +- bundles/systemd/metadata.py | 3 - groups/applications/left4dead2.py | 7 ++ nodes/netcup.mails.py | 21 ++++ 10 files changed, 164 insertions(+), 140 deletions(-) create mode 100644 bundles/steam-workshop-download/items.py create mode 100644 bundles/steam-workshop-download/metadata.py create mode 100644 groups/applications/left4dead2.py diff --git a/bundles/left4dead2/items.py b/bundles/left4dead2/items.py index bf7208e..bbcc535 100644 --- a/bundles/left4dead2/items.py +++ b/bundles/left4dead2/items.py @@ -1,106 +1,71 @@ +assert node.has_bundle('steam') and node.has_bundle('steam-workshop-download') + directories = { - '/opt/left4dead2': { + '/opt/steam/left4dead2/left4dead2/ems/admin system': { 'owner': 'steam', + 'group': 'steam', + 'mode': '0744', }, - '/opt/left4dead2/ems/admin system': { + '/opt/steam/left4dead2/left4dead2/cfg/server': { 'owner': 'steam', + 'group': 'steam', + 'purge': True, }, - '/opt/left4dead2/left4dead2/cfg': { - 'owner': 'steam', - }, - '/opt/left4dead2/left4dead2/addons': { + '/opt/steam/left4dead2/left4dead2/addons': { 'owner': 'steam', + 'group': 'steam', 'purge': True, }, } files = { - '/opt/left4dead2/ems/admin system/admins.txt': { + '/opt/steam/left4dead2/left4dead2/ems/admin system/admins.txt': { 'owner': 'steam', - 'content': '\n'.join(node.metadata.get('left4dead2/admins')), + 'content': '\n'.join(sorted(node.metadata.get('left4dead2/admins'))), } } -svc_systemd = { - 'left4dead2-workshop': { - 'running': False, - 'needs': [ - 'svc_systemd:steam-update', - ], - }, -} - -for id in node.metadata.get('left4dead2/workshop'): - directories[f'/opt/left4dead2/left4dead2/addons/{id}'] = { - 'owner': 'steam', - 'triggers': [ - 'svc_systemd:left4dead2-workshop:restart', - ], - } - -server_units = set() for name, config in node.metadata.get('left4dead2/servers').items(): - config.pop('port') - config = { - 'hostname': name, - 'sv_steamgroup': ','.join( - str(gid) for gid in node.metadata.get('left4dead2/steamgroups') - ), - 'z_difficulty': 'Impossible', - 'sv_gametypes': 'realism', - 'sv_region': 3, # europe - 'log': 'on', - 'sv_logecho': 1, - 'sv_logfile': 1, - 'sv_log_onefile': 0, - 'sv_logbans': 1, - 'sv_logflush': 0, - 'sv_logsdir': 'logs', # /opt/left4dead2/left4dead2/logs - **config, - } - - files[f'/opt/left4dead2/left4dead2/cfg/server-{name}.cfg'] = { - 'content': '\n'.join( - f'{key} "{value}"' for key, value in sorted(config.items()) - ) + '\n', + files[f'/opt/steam/left4dead2/left4dead2/cfg/server/{name}.cfg'] = { + 'content_type': 'mako', + 'source': 'server.cfg', + 'context': { + 'name': name, + 'steamgroups': node.metadata.get('left4dead2/steamgroups'), + }, 'owner': 'steam', + 'group': 'steam', 'triggers': [ - f'svc_systemd:left4dead2-server-{name}:restart', + f'svc_systemd:left4dead2-{name}.service:restart', ], } - svc_systemd[f'left4dead2-server-{name}'] = { + svc_systemd[f'left4dead2-{name}.service'] = { 'needs': [ - f'file:/usr/local/lib/systemd/system/left4dead2-server-{name}.service', + f'file:/opt/steam/left4dead2/left4dead2/cfg/server/{name}.cfg', + f'file:/usr/local/lib/systemd/system/left4dead2-{name}.service', ], } - server_units.add(f'left4dead2-server-{name}') - + + +files[f'/opt/steam/left4dead2/left4dead2/addons/readme.txt'] = { + 'content_type': 'any', + 'owner': 'steam', + 'group': 'steam', +} + for id in node.metadata.get('left4dead2/workshop'): - directories[f'/opt/left4dead2/addons/{id}'] = { + files[f'/opt/steam/left4dead2/left4dead2/addons/{id}.vpk'] = { + 'content_type': 'any', 'owner': 'steam', - 'triggers': [ - 'svc_systemd:left4dead2-workshop:restart', - ], + 'group': 'steam', } -# TIDYUP - -find_obsolete_units = ( - 'find /usr/local/lib/systemd/system -type f -name "left4dead2-server-*.service" ' + - ' '.join(f"! -name '{name}.service'" for name in server_units) -) -actions['remove_obsolete_left4dead2_units'] = { - 'command': ( - f'for unitfile in $({find_obsolete_units}); ' - f'do ' - f'systemctl stop $(basename "$unitfile"); ' - f'systemctl disable $(basename "$unitfile"); ' - f'rm "$unitfile"; ' - f'systemctl daemon-reload; ' - f'done' - ), - 'unless': ( - find_obsolete_units + " | wc -l | grep -q '^0$'" - ), +# /opt/steam/steam/.steam/sdk32/steamclient.so: cannot open shared object file: No such file or directory +symlinks = { + '/opt/steam/steam/.steam/sdk32': { + 'target': '/opt/steam/steam/linux32', + 'owner': 'steam', + 'group': 'steam', + } } diff --git a/bundles/left4dead2/metadata.py b/bundles/left4dead2/metadata.py index 89ffbf1..da9cba0 100644 --- a/bundles/left4dead2/metadata.py +++ b/bundles/left4dead2/metadata.py @@ -17,43 +17,20 @@ defaults = { @metadata_reactor.provides( - 'systemd/units', + 'steam-workshop-download/left4dead', ) -def workshop(metadata): - command = ( - 'set -x; ' - 'for ID in ' + ' '.join(metadata.get('left4dead2/workshop')) + '; ' - 'do ' - 'if ! ls /opt/left4dead2/left4dead2/addons/$ID/*.vpk; ' - 'then ' - 'cd /opt/left4dead2/left4dead2/addons/$ID; ' - '/opt/steam-workshop-downloader https://steamcommunity.com/sharedfiles/filedetails\?id\=$ID; ' - 'unzip $ID.zip; ' - 'fi; ' - 'done' - ) - +def workshop_download(metadata): + if not metadata.get('left4dead2/workshop'): + return {} + return { - 'systemd': { - 'units': { - 'left4dead2-workshop.service': { - 'Unit': { - 'Description': 'install workshop items', - 'After': 'network.target', - 'Requires': 'steam-update.service', - 'PartOf': 'steam-update.service' - }, - 'Service': { - 'Type': 'oneshot', - 'User': 'steam', - 'ExecStart': f'/bin/bash -c {quote(command)}', - }, - 'Install': { - 'WantedBy': {'multi-user.target'}, - }, - } - } - } + 'steam-workshop-download': { + 'left4dead': { + 'ids': metadata.get('left4dead2/workshop'), + 'path': '/opt/steam/left4dead2/left4dead2/addons', + 'user': 'steam', + }, + }, } @@ -62,19 +39,18 @@ def workshop(metadata): ) def server_units(metadata): units = {} - + for name, config in metadata.get('left4dead2/servers').items(): - units[f'left4dead2-server-{name}.service'] = { + units[f'left4dead2-{name}.service'] = { 'Unit': { 'Description': f'left4dead2 server {name}', - 'After': 'network.target', - 'Requires': 'steam-update.service', + 'After': {'steam.target'}, }, 'Service': { 'User': 'steam', 'Group': 'steam', - 'WorkingDirectory': '/opt/left4dead2', - 'ExecStart': f'/opt/left4dead2/srcds_run -port {config["port"]} -insecure +map {config["map"]} +exec server-{name}.cfg', + 'WorkingDirectory': '/opt/steam/left4dead2', + 'ExecStart': f'/opt/steam/left4dead2/srcds_run -port {config["port"]} +exec server/{name}.cfg', 'Restart': 'on-failure', }, 'Install': { @@ -87,3 +63,19 @@ def server_units(metadata): 'units': units, }, } + + +@metadata_reactor.provides( + 'nftables/input', +) +def firewall(metadata): + ports = set(str(server['port']) for server in metadata.get('left4dead2/servers').values()) + + return { + 'nftables': { + 'input': { + f"tcp dport {{ {', '.join(ports)} }} accept", + f"udp dport {{ {', '.join(ports)} }} accept", + }, + }, + } diff --git a/bundles/steam-workshop-download/items.py b/bundles/steam-workshop-download/items.py new file mode 100644 index 0000000..8a690b6 --- /dev/null +++ b/bundles/steam-workshop-download/items.py @@ -0,0 +1,7 @@ +files = { + '/opt/steam-workshop-download': { + 'content_type': 'download', + 'source': 'https://git.sublimity.de/cronekorkn/steam-workshop-downloader/raw/branch/master/steam-workshop-download', + 'mode': '755', + }, +} diff --git a/bundles/steam-workshop-download/metadata.py b/bundles/steam-workshop-download/metadata.py new file mode 100644 index 0000000..4423bec --- /dev/null +++ b/bundles/steam-workshop-download/metadata.py @@ -0,0 +1,39 @@ +from shlex import quote + + +defaults = { + 'steam-workshop-download': {}, +} + + +@metadata_reactor.provides( + 'systemd/units', +) +def workshop(metadata): + units = {} + + for name, conf in metadata.get('steam-workshop-download').items(): + units[f'steam-workshop-download-{name}.service'] = { + 'Unit': { + 'Description': 'install workshop items', + 'After': { + 'network-online.target', + 'steam-update.target', + }, + 'Before': 'steam.target', + }, + 'Service': { + 'Type': 'oneshot', + 'User': conf['user'], + 'ExecStart': f"/opt/steam-workshop-download {' '.join(quote(str(id)) for id in conf['ids'])} --out {quote(conf['path'])}", + }, + 'Install': { + 'WantedBy': {'multi-user.target'}, + }, + } + + return { + 'systemd': { + 'units': units, + }, + } diff --git a/bundles/steam/items.py b/bundles/steam/items.py index 9a196ee..451d702 100644 --- a/bundles/steam/items.py +++ b/bundles/steam/items.py @@ -22,7 +22,7 @@ for game in node.metadata.get('steam/games'): 'owner': 'steam', 'group': 'steam', 'needed_by': [ - 'svc_systemd:steam-update', + 'svc_systemd:steam-update.service', ], } @@ -33,22 +33,8 @@ files = { 'owner': 'steam', 'group': 'steam', }, - '/opt/steam/steam/workshop-downloader': { - 'content_type': 'download', - 'source': 'https://github.com/SegoCode/swd/releases/download/1.1/swd-linux-amd64', - 'owner': 'steam', - 'group': 'steam', - 'mode': '750', - }, } -# symlinks = { -# # /opt/steam/.steam/sdk32/steamclient.so: cannot open shared object file: No such file or directory -# '/opt/steam/.steam/sdk32': { -# 'target': '/opt/steam/linux32', -# } -# } - actions = { 'extract_steamcmd': { 'command': """su - steam -c 'tar xfvz /opt/steam/steam/steamcmd_linux.tar.gz --directory /opt/steam/steam'""", @@ -59,7 +45,7 @@ actions = { }, } -svc_systemd['steam-update'] = { +svc_systemd['steam-update.service'] = { 'running': False, 'enabled': False, 'needs': { diff --git a/bundles/steam/metadata.py b/bundles/steam/metadata.py index 199d35a..7af9f8e 100644 --- a/bundles/steam/metadata.py +++ b/bundles/steam/metadata.py @@ -10,6 +10,15 @@ defaults = { 'left4dead2': 222860, }, }, + 'systemd': { + 'units': { + 'steam.target': { + 'Unit': { + 'Description': 'steam is ready', + }, + }, + }, + }, 'zfs': { 'datasets': { 'tank/steam': { @@ -31,7 +40,8 @@ def initial_unit(metadata): 'steam-update.service': { 'Unit': { 'Description': 'steam: install and update games', - 'After': 'network.target', + 'After': 'network-online.target', + 'Before': 'steam.target', }, 'Service': { 'Type': 'oneshot', diff --git a/bundles/systemd/items.py b/bundles/systemd/items.py index 51f108d..7927115 100644 --- a/bundles/systemd/items.py +++ b/bundles/systemd/items.py @@ -14,7 +14,7 @@ actions = { 'command': 'systemctl daemon-reload', 'cascade_skip': False, 'triggered': True, - }, + }, } for name, unit in node.metadata.get('systemd/units').items(): @@ -30,7 +30,7 @@ for name, unit in node.metadata.get('systemd/units').items(): 'svc_systemd:systemd-networkd:restart', ], } - elif extension in ['timer', 'service', 'mount', 'swap']: + elif extension in ['timer', 'service', 'mount', 'swap', 'target']: path = f'/usr/local/lib/systemd/system/{name}' dependencies = { 'triggers': [ diff --git a/bundles/systemd/metadata.py b/bundles/systemd/metadata.py index 32c901a..364dc32 100644 --- a/bundles/systemd/metadata.py +++ b/bundles/systemd/metadata.py @@ -25,9 +25,6 @@ def units(metadata): type = name.split('.')[-1] - if type not in ['timer', 'service', 'network', 'netdev', 'mount', 'swap']: - raise Exception(f'unknown type {type}') - if not config.get('Install/WantedBy'): if type == 'service': units[name] = { diff --git a/groups/applications/left4dead2.py b/groups/applications/left4dead2.py new file mode 100644 index 0000000..cb8ece7 --- /dev/null +++ b/groups/applications/left4dead2.py @@ -0,0 +1,7 @@ +{ + 'bundles': [ + 'steam', + 'steam-workshop-download', + 'left4dead2', + ], +} diff --git a/nodes/netcup.mails.py b/nodes/netcup.mails.py index 4e75990..e31d4a0 100644 --- a/nodes/netcup.mails.py +++ b/nodes/netcup.mails.py @@ -7,6 +7,7 @@ 'monitored', 'webserver', 'dnsserver', + 'left4dead2', ], 'bundles': [ 'bind-acme', @@ -68,6 +69,26 @@ 'download-server': { 'hostname': 'dl.sublimity.de', }, + 'left4dead2': { + 'servers': { + 'standard': { + 'port': 27020, + }, + }, + 'admins': { + 'STEAM_1:0:12376499', # CroneKorkN ☮️UKRAINE❤ + 'STEAM_1:1:169960486', # *RED* + 'STEAM_1:1:112940736', # Ðark-AnGeℓ❤ + 'STEAM_1:1:34263261', # Alekc + 'STEAM_1:1:79349632', # VOID + }, + 'workshop': { + 214630948, + 1229957234, + 698857882, + }, + 'steamgroups': {'103582791467869287'}, + }, 'letsencrypt': { 'domains': { 'ckn.li': {},