From 3469d98a43718a4db311b35297a2eea50d4baac9 Mon Sep 17 00:00:00 2001 From: CroneKorkN Date: Sun, 24 Aug 2025 13:33:05 +0200 Subject: [PATCH] the next l4d2 server iteration, this time more simple and kinda working --- bundles/left4dead2/README.md | 59 +----- bundles/left4dead2/files/setup | 96 +++++++++ bundles/left4dead2/files/start | 28 +++ bundles/left4dead2/items.py | 137 +++---------- bundles/left4dead2/metadata.py | 128 +++++------- bundles/left4dead2_old/README.md | 58 ++++++ .../files/server.cfg | 0 bundles/left4dead2_old/items.py | 122 ++++++++++++ bundles/left4dead2_old/metadata.py | 127 ++++++++++++ bundles/left4dead2_old2/README.md | 97 ++++++++++ bundles/left4dead2_old2/files/server.cfg | 0 bundles/left4dead2_old2/items.py | 183 ++++++++++++++++++ bundles/left4dead2_old2/metadata.py | 107 ++++++++++ .../{steam => left4dead2_steam_old}/items.py | 0 .../metadata.py | 0 bundles/steam/README.md | 55 ------ nodes/htz.mails.py | 22 +++ nodes/ovh.secondary.py | 21 +- 18 files changed, 925 insertions(+), 315 deletions(-) create mode 100644 bundles/left4dead2/files/setup create mode 100644 bundles/left4dead2/files/start create mode 100644 bundles/left4dead2_old/README.md rename bundles/{left4dead2 => left4dead2_old}/files/server.cfg (100%) create mode 100644 bundles/left4dead2_old/items.py create mode 100644 bundles/left4dead2_old/metadata.py create mode 100644 bundles/left4dead2_old2/README.md create mode 100644 bundles/left4dead2_old2/files/server.cfg create mode 100644 bundles/left4dead2_old2/items.py create mode 100644 bundles/left4dead2_old2/metadata.py rename bundles/{steam => left4dead2_steam_old}/items.py (100%) rename bundles/{steam => left4dead2_steam_old}/metadata.py (100%) delete mode 100644 bundles/steam/README.md diff --git a/bundles/left4dead2/README.md b/bundles/left4dead2/README.md index 4295b4b..1e9f846 100644 --- a/bundles/left4dead2/README.md +++ b/bundles/left4dead2/README.md @@ -1,58 +1 @@ -https://developer.valvesoftware.com/wiki/List_of_L4D2_Cvars - -Dead Center c1m1_hotel -Dead Center c1m2_streets -Dead Center c1m3_mall -Dead Center c1m4_atrium -Dark Carnival c2m1_highway -Dark Carnival c2m2_fairgrounds -Dark Carnival c2m3_coaster -Dark Carnival c2m4_barns -Dark Carnival c2m5_concert -Swamp Fever c3m1_plankcountry -Swamp Fever c3m2_swamp -Swamp Fever c3m3_shantytown -Swamp Fever c3m4_plantation -Hard Rain c4m1_milltown_a -Hard Rain c4m2_sugarmill_a -Hard Rain c4m3_sugarmill_b -Hard Rain c4m4_milltown_b -Hard Rain c4m5_milltown_escape -The Parish c5m1_waterfront_sndscape -The Parish c5m1_waterfront -The Parish c5m2_park -The Parish c5m3_cemetery -The Parish c5m4_quarter -The Parish c5m5_bridge -The Passing c6m1_riverbank -The Passing c6m2_bedlam -The Passing c6m3_port -The Sacrifice c7m1_docks -The Sacrifice c7m2_barge -The Sacrifice c7m3_port -No Mercy c8m1_apartment -No Mercy c8m2_subway -No Mercy c8m3_sewers -No Mercy c8m4_interior -No Mercy c8m5_rooftop -Crash Course c9m1_alleys -Crash Course c9m2_lots -Death Toll c10m1_caves -Death Toll c10m2_drainage -Death Toll c10m3_ranchhouse -Death Toll c10m4_mainstreet -Death Toll c10m5_houseboat -Dead Air c11m1_greenhouse -Dead Air c11m2_offices -Dead Air c11m3_garage -Dead Air c11m4_terminal -Dead Air c11m5_runway -Blood Harvest c12m1_hilltop -Blood Harvest c12m2_traintunnel -Blood Harvest c12m3_bridge -Blood Harvest c12m4_barn -Blood Harvest c12m5_cornfield -Cold Stream c13m1_alpinecreek -Cold Stream c13m2_southpinestream -Cold Stream c13m3_memorialbridge -Cold Stream c13m4_cutthroatcreek +https://github.com/SirPlease/L4D2-Competitive-Rework/blob/master/Dedicated%20Server%20Install%20Guide/README.md \ No newline at end of file diff --git a/bundles/left4dead2/files/setup b/bundles/left4dead2/files/setup new file mode 100644 index 0000000..e20633b --- /dev/null +++ b/bundles/left4dead2/files/setup @@ -0,0 +1,96 @@ +#!/bin/bash + +set -xeuo pipefail + +getent passwd steam >/dev/null || useradd -M -d /opt/l4d2 -s /bin/bash steam +mkdir -p /opt/l4d2 /tmp/dumps +chown steam:steam /opt/l4d2 /tmp/dumps +dpkg --add-architecture i386 +apt update +DEBIAN_FRONTEND=noninteractive apt install -y libc6:i386 lib32z1 + +function steam() { + # für systemd, damit es den prozess beenden kann + setpriv --reuid=steam --regid=steam --init-groups "$@" + export HOME=/opt/l4d2/steam +} + +# -- STEAM -- # + +steam mkdir -p /opt/l4d2/steam +test -f /opt/l4d2/steam/steamcmd_linux.tar.gz || \ + steam wget http://media.steampowered.com/installer/steamcmd_linux.tar.gz -P /opt/l4d2/steam +test -f /opt/l4d2/steam/steamcmd.sh || \ + steam tar -xvzf /opt/l4d2/steam/steamcmd_linux.tar.gz -C /opt/l4d2/steam + +# fix for: /opt/l4d2/.steam/sdk32/steamclient.so: cannot open shared object file: No such file or directory +steam mkdir -p /opt/l4d2/steam/.steam # needs to be in steam users home dir +readlink /opt/l4d2/steam/.steam/sdk32 | grep -q ^/opt/l4d2/steam/linux32$ || \ + steam ln -sf /opt/l4d2/steam/linux32 /opt/l4d2/steam/.steam/sdk32 +readlink /opt/l4d2/steam/.steam/sdk64 | grep -q ^/opt/l4d2/steam/linux64$ || \ + steam ln -sf /opt/l4d2/steam/linux64 /opt/l4d2/steam/.steam/sdk64 + +# -- INSTALL -- # + +# erst die windows deps zu installieren scheint ein workaround für x64 zu sein? +steam mkdir -p /opt/l4d2/installation +steam /opt/l4d2/steam/steamcmd.sh \ + +force_install_dir /opt/l4d2/installation \ + +login anonymous \ + +@sSteamCmdForcePlatformType windows \ + +app_update 222860 validate \ + +quit +steam /opt/l4d2/steam/steamcmd.sh \ + +force_install_dir /opt/l4d2/installation \ + +login anonymous \ + +@sSteamCmdForcePlatformType linux \ + +app_update 222860 validate \ + +quit + +# -- OVERLAYS -- # + +steam mkdir -p /opt/l4d2/overlays + +# workshop downloader +test -f /opt/l4d2/steam-workshop-download || \ + steam wget -4 https://git.sublimity.de/cronekorkn/steam-workshop-downloader/raw/branch/master/steam-workshop-download -P /opt/l4d2 +steam chmod +x /opt/l4d2/steam-workshop-download + +# -- OVERLAY PVE -- # + +steam mkdir -p /opt/l4d2/overlays/pve + +# server config +steam mkdir -p /opt/l4d2/overlays/pve/left4dead2/cfg +steam cat <<'EOF' > /opt/l4d2/overlays/pve/left4dead2/cfg/server.cfg +motd_enabled 0 + +sv_steamgroup "38347879" +#sv_steamgroup_exclusive 0 + +sv_minrate 60000 +sv_maxrate 0 +net_splitpacket_maxrate 60000 + +#sv_cheats 1 +#sb_all_bot_game 1 +EOF + +# admin system +steam mkdir -p /opt/l4d2/overlays/pve/left4dead2/addons +test -f /opt/l4d2/overlays/pve/left4dead2/addons/2524204971.vpk || \ + steam /opt/l4d2/steam-workshop-download 2524204971 --out /opt/l4d2/overlays/pve/left4dead2/addons +steam mkdir -p "/opt/l4d2/overlays/pve/left4dead2/ems/admin system" +steam echo "STEAM_1:0:12376499" > "/opt/l4d2/overlays/pve/left4dead2/ems/admin system/admins.txt" + +# ions vocalizer +test -f /opt/l4d2/overlays/pve/left4dead2/addons/698857882.vpk || \ + steam /opt/l4d2/steam-workshop-download 698857882 --out /opt/l4d2/overlays/pve/left4dead2/addons + +test -f /opt/l4d2/overlays/pve/left4dead2/addons/1575673903.vpk || \ + steam /opt/l4d2/steam-workshop-download 1575673903 --out /opt/l4d2/overlays/pve/left4dead2/addons + +# -- SERVERS -- # + +#steam rm -rf /opt/l4d2/servers +steam mkdir -p /opt/l4d2/servers \ No newline at end of file diff --git a/bundles/left4dead2/files/start b/bundles/left4dead2/files/start new file mode 100644 index 0000000..4d64020 --- /dev/null +++ b/bundles/left4dead2/files/start @@ -0,0 +1,28 @@ +#!/bin/bash + +set -xeuo pipefail + +name=$1 +overlay=$2 +port=$3 + +function steam() { + # für systemd, damit es den prozess beenden kann + setpriv --reuid=steam --regid=steam --init-groups "$@" + export HOME=/opt/l4d2/steam +} + +mountpoint -q "/opt/l4d2/servers/$name/merged" && umount "/opt/l4d2/servers/$name/merged" +steam rm -rf "/opt/l4d2/servers/$name" + +steam mkdir -p \ + "/opt/l4d2/servers/$name" \ + "/opt/l4d2/servers/$name/work" \ + "/opt/l4d2/servers/$name/upper" \ + "/opt/l4d2/servers/$name/merged" + +mount -t overlay overlay \ + -o "lowerdir=/opt/l4d2/overlays/$overlay:/opt/l4d2/installation,upperdir=/opt/l4d2/servers/$name/upper,workdir=/opt/l4d2/servers/$name/work" \ + "/opt/l4d2/servers/$name/merged" + +steam "/opt/l4d2/servers/$name/merged/srcds_run" -norestart -pidfile "/opt/l4d2/servers/$name/pid" -game left4dead2 -ip 0.0.0.0 -port "$port" +hostname "Crone_$name" +map c1m1_hotel \ No newline at end of file diff --git a/bundles/left4dead2/items.py b/bundles/left4dead2/items.py index 59c8429..fecec4d 100644 --- a/bundles/left4dead2/items.py +++ b/bundles/left4dead2/items.py @@ -1,122 +1,31 @@ -assert node.has_bundle('steam') and node.has_bundle('steam-workshop-download') - -directories = { - '/opt/steam/left4dead2-servers': { - 'owner': 'steam', - 'group': 'steam', - 'mode': '0755', - 'purge': True, +files = { + '/opt/l4d2/setup': { + 'mode': '755', }, - # Current zfs doesnt support zfs upperdir. The support was added in October 2022. Move upperdir - unused anyway - - # to another dir. Also move workdir alongside it, as it has to be on same fs. - '/opt/steam-zfs-overlay-workarounds': { - 'owner': 'steam', - 'group': 'steam', - 'mode': '0755', - 'purge': True, + '/opt/l4d2/start': { + 'mode': '755', }, } -# /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', - } -} - -# -# SERVERS -# - -for name, config in node.metadata.get('left4dead2/servers').items(): - - #overlay - directories[f'/opt/steam/left4dead2-servers/{name}'] = { - 'owner': 'steam', - 'group': 'steam', - } - directories[f'/opt/steam-zfs-overlay-workarounds/{name}/upper'] = { - 'owner': 'steam', - 'group': 'steam', - } - directories[f'/opt/steam-zfs-overlay-workarounds/{name}/workdir'] = { - 'owner': 'steam', - 'group': 'steam', - } - - # conf - files[f'/opt/steam/left4dead2-servers/{name}/left4dead2/cfg/server.cfg'] = { - 'content_type': 'mako', - 'source': 'server.cfg', - 'context': { - 'name': name, - 'steamgroups': node.metadata.get('left4dead2/steamgroups'), - 'rcon_password': config['rcon_password'], +svc_systemd = { + 'left4dead2-initialize.service': { + 'enabled': True, + 'running': None, + 'needs': { + 'file:/usr/local/lib/systemd/system/left4dead2-initialize.service', }, - 'owner': 'steam', - 'group': 'steam', - 'triggers': [ - f'svc_systemd:left4dead2-{name}.service:restart', - ], - } + }, +} - # service - svc_systemd[f'left4dead2-{name}.service'] = { - 'needs': [ - f'file:/opt/steam/left4dead2-servers/{name}/left4dead2/cfg/server.cfg', - f'file:/usr/local/lib/systemd/system/left4dead2-{name}.service', - ], - } - - # - # ADDONS - # - - # base - files[f'/opt/steam/left4dead2-servers/{name}/left4dead2/addons/readme.txt'] = { - 'content_type': 'any', - 'owner': 'steam', - 'group': 'steam', - } - directories[f'/opt/steam/left4dead2-servers/{name}/left4dead2/addons'] = { - 'owner': 'steam', - 'group': 'steam', - 'purge': True, - 'triggers': [ - f'svc_systemd:left4dead2-{name}.service:restart', - ], - } - for id in [ - *config.get('workshop', []), - *node.metadata.get('left4dead2/workshop'), - ]: - files[f'/opt/steam/left4dead2-servers/{name}/left4dead2/addons/{id}.vpk'] = { - 'content_type': 'any', - 'owner': 'steam', - 'group': 'steam', - 'triggers': [ - f'svc_systemd:left4dead2-{name}.service:restart', - ], +for server_name in node.metadata.get('left4dead2').keys(): + svc_systemd[f'left4dead2-{server_name}.service'] = { + 'enabled': True, + 'running': True, + 'tags': { + 'left4dead2-servers', + }, + 'needs': { + 'svc_systemd:left4dead2-initialize.service', + f'file:/usr/local/lib/systemd/system/left4dead2-{server_name}.service', } - - # admin system - - directories[f'/opt/steam/left4dead2-servers/{name}/left4dead2/ems/admin system'] = { - 'owner': 'steam', - 'group': 'steam', - 'mode': '0755', - 'triggers': [ - f'svc_systemd:left4dead2-{name}.service:restart', - ], - } - files[f'/opt/steam/left4dead2-servers/{name}/left4dead2/ems/admin system/admins.txt'] = { - 'owner': 'steam', - 'group': 'steam', - 'mode': '0755', - 'content': '\n'.join(sorted(node.metadata.get('left4dead2/admins'))), - 'triggers': [ - f'svc_systemd:left4dead2-{name}.service:restart', - ], } diff --git a/bundles/left4dead2/metadata.py b/bundles/left4dead2/metadata.py index 3ab593f..02c73c3 100644 --- a/bundles/left4dead2/metadata.py +++ b/bundles/left4dead2/metadata.py @@ -1,102 +1,68 @@ -assert node.has_bundle('steam') +from re import match -from shlex import quote defaults = { - 'steam': { - 'games': { - 'left4dead2': 222860, + 'apt': { + 'packages': { + 'libc6_i386': {}, # installs libc6:i386 + 'lib32z1': {}, + 'unzip': {}, }, }, - 'left4dead2': { - 'servers': {}, - 'admins': set(), - 'workshop': set(), + 'left4dead2': {}, + 'nftables': { + 'input': { + 'udp dport { 27005, 27020 } accept', + }, + }, + 'systemd': { + 'units': { + 'left4dead2-initialize.service': { + 'Unit': { + 'Description': 'initialize left4dead2', + 'After': 'network-online.target', + }, + 'Service': { + 'Type': 'oneshot', + 'RemainAfterExit': 'yes', + 'ExecStart': '/opt/l4d2/setup', + 'StandardOutput': 'journal', + 'StandardError': 'journal', + }, + 'Install': { + 'WantedBy': {'multi-user.target'}, + }, + }, + }, }, } @metadata_reactor.provides( - 'left4dead2/servers', -) -def rconn_password(metadata): - # only works from localhost! - return { - 'left4dead2': { - 'servers': { - server: { - 'rcon_password': repo.vault.password_for(f'{node.name} left4dead2 {server} rcon', length=24), - } - for server in metadata.get('left4dead2/servers') - }, - }, - } - - -@metadata_reactor.provides( - 'steam-workshop-download', 'systemd/units', ) def server_units(metadata): units = {} - workshop = {} - for name, config in metadata.get('left4dead2/servers').items(): - # mount overlay - mountpoint = f'/opt/steam/left4dead2-servers/{name}' - mount_unit_name = mountpoint[1:].replace('-', '\\x2d').replace('/', '-') + '.mount' - units[mount_unit_name] = { - 'Unit': { - 'Description': f"Mount left4dead2 server {name} overlay", - 'Conflicts': {'umount.target'}, - 'Before': {'umount.target'}, - }, - 'Mount': { - 'What': 'overlay', - 'Where': mountpoint, - 'Type': 'overlay', - 'Options': ','.join([ - 'auto', - 'lowerdir=/opt/steam/left4dead2', - f'upperdir=/opt/steam-zfs-overlay-workarounds/{name}/upper', - f'workdir=/opt/steam-zfs-overlay-workarounds/{name}/workdir', - ]), - }, - 'Install': { - 'RequiredBy': { - f'left4dead2-{name}.service', - }, - }, - } + for name, config in metadata.get('left4dead2').items(): + assert match(r'^[A-z0-9-_-]+$', name) + assert config["overlay"] in {'pve'} + assert 27000 <= config["port"] <= 27100 - # individual workshop - workshop_ids = config.get('workshop', set()) | metadata.get('left4dead2/workshop', set()) - if workshop_ids: - workshop[f'left4dead2-{name}'] = { - 'ids': workshop_ids, - 'path': f'/opt/steam/left4dead2-servers/{name}/left4dead2/addons', - 'user': 'steam', - 'requires': { - mount_unit_name, - }, - 'required_by': { - f'left4dead2-{name}.service', - }, - } - - # left4dead2 server unit units[f'left4dead2-{name}.service'] = { 'Unit': { 'Description': f'left4dead2 server {name}', - 'After': {'steam-update.service'}, - 'Requires': {'steam-update.service'}, + 'After': {'left4dead2-initialize.service'}, + 'Requires': {'left4dead2-initialize.service'}, }, 'Service': { - 'User': 'steam', - 'Group': 'steam', - 'WorkingDirectory': f'/opt/steam/left4dead2-servers/{name}', - 'ExecStart': f'/opt/steam/left4dead2-servers/{name}/srcds_run -port {config["port"]} +exec server.cfg', + 'Type': 'simple', + 'ExecStart': f'/opt/l4d2/start {name} {config["overlay"]} {config["port"]}', 'Restart': 'on-failure', + 'Nice': -10, + 'CPUWeight': 200, + 'IOSchedulingClass': 'best-effort', + 'IOSchedulingPriority': 0, }, 'Install': { 'WantedBy': {'multi-user.target'}, @@ -104,7 +70,6 @@ def server_units(metadata): } return { - 'steam-workshop-download': workshop, 'systemd': { 'units': units, }, @@ -114,14 +79,13 @@ def server_units(metadata): @metadata_reactor.provides( 'nftables/input', ) -def firewall(metadata): - ports = set(str(server['port']) for server in metadata.get('left4dead2/servers').values()) +def nftables(metadata): + ports = sorted(str(config["port"]) for config in metadata.get('left4dead2', {}).values()) return { 'nftables': { 'input': { - f"tcp dport {{ {', '.join(sorted(ports))} }} accept", - f"udp dport {{ {', '.join(sorted(ports))} }} accept", + f'ip protocol {{ tcp, udp }} th dport {{ {", ".join(ports)} }} accept' }, }, } diff --git a/bundles/left4dead2_old/README.md b/bundles/left4dead2_old/README.md new file mode 100644 index 0000000..4295b4b --- /dev/null +++ b/bundles/left4dead2_old/README.md @@ -0,0 +1,58 @@ +https://developer.valvesoftware.com/wiki/List_of_L4D2_Cvars + +Dead Center c1m1_hotel +Dead Center c1m2_streets +Dead Center c1m3_mall +Dead Center c1m4_atrium +Dark Carnival c2m1_highway +Dark Carnival c2m2_fairgrounds +Dark Carnival c2m3_coaster +Dark Carnival c2m4_barns +Dark Carnival c2m5_concert +Swamp Fever c3m1_plankcountry +Swamp Fever c3m2_swamp +Swamp Fever c3m3_shantytown +Swamp Fever c3m4_plantation +Hard Rain c4m1_milltown_a +Hard Rain c4m2_sugarmill_a +Hard Rain c4m3_sugarmill_b +Hard Rain c4m4_milltown_b +Hard Rain c4m5_milltown_escape +The Parish c5m1_waterfront_sndscape +The Parish c5m1_waterfront +The Parish c5m2_park +The Parish c5m3_cemetery +The Parish c5m4_quarter +The Parish c5m5_bridge +The Passing c6m1_riverbank +The Passing c6m2_bedlam +The Passing c6m3_port +The Sacrifice c7m1_docks +The Sacrifice c7m2_barge +The Sacrifice c7m3_port +No Mercy c8m1_apartment +No Mercy c8m2_subway +No Mercy c8m3_sewers +No Mercy c8m4_interior +No Mercy c8m5_rooftop +Crash Course c9m1_alleys +Crash Course c9m2_lots +Death Toll c10m1_caves +Death Toll c10m2_drainage +Death Toll c10m3_ranchhouse +Death Toll c10m4_mainstreet +Death Toll c10m5_houseboat +Dead Air c11m1_greenhouse +Dead Air c11m2_offices +Dead Air c11m3_garage +Dead Air c11m4_terminal +Dead Air c11m5_runway +Blood Harvest c12m1_hilltop +Blood Harvest c12m2_traintunnel +Blood Harvest c12m3_bridge +Blood Harvest c12m4_barn +Blood Harvest c12m5_cornfield +Cold Stream c13m1_alpinecreek +Cold Stream c13m2_southpinestream +Cold Stream c13m3_memorialbridge +Cold Stream c13m4_cutthroatcreek diff --git a/bundles/left4dead2/files/server.cfg b/bundles/left4dead2_old/files/server.cfg similarity index 100% rename from bundles/left4dead2/files/server.cfg rename to bundles/left4dead2_old/files/server.cfg diff --git a/bundles/left4dead2_old/items.py b/bundles/left4dead2_old/items.py new file mode 100644 index 0000000..59c8429 --- /dev/null +++ b/bundles/left4dead2_old/items.py @@ -0,0 +1,122 @@ +assert node.has_bundle('steam') and node.has_bundle('steam-workshop-download') + +directories = { + '/opt/steam/left4dead2-servers': { + 'owner': 'steam', + 'group': 'steam', + 'mode': '0755', + 'purge': True, + }, + # Current zfs doesnt support zfs upperdir. The support was added in October 2022. Move upperdir - unused anyway - + # to another dir. Also move workdir alongside it, as it has to be on same fs. + '/opt/steam-zfs-overlay-workarounds': { + 'owner': 'steam', + 'group': 'steam', + 'mode': '0755', + 'purge': True, + }, +} + +# /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', + } +} + +# +# SERVERS +# + +for name, config in node.metadata.get('left4dead2/servers').items(): + + #overlay + directories[f'/opt/steam/left4dead2-servers/{name}'] = { + 'owner': 'steam', + 'group': 'steam', + } + directories[f'/opt/steam-zfs-overlay-workarounds/{name}/upper'] = { + 'owner': 'steam', + 'group': 'steam', + } + directories[f'/opt/steam-zfs-overlay-workarounds/{name}/workdir'] = { + 'owner': 'steam', + 'group': 'steam', + } + + # conf + files[f'/opt/steam/left4dead2-servers/{name}/left4dead2/cfg/server.cfg'] = { + 'content_type': 'mako', + 'source': 'server.cfg', + 'context': { + 'name': name, + 'steamgroups': node.metadata.get('left4dead2/steamgroups'), + 'rcon_password': config['rcon_password'], + }, + 'owner': 'steam', + 'group': 'steam', + 'triggers': [ + f'svc_systemd:left4dead2-{name}.service:restart', + ], + } + + # service + svc_systemd[f'left4dead2-{name}.service'] = { + 'needs': [ + f'file:/opt/steam/left4dead2-servers/{name}/left4dead2/cfg/server.cfg', + f'file:/usr/local/lib/systemd/system/left4dead2-{name}.service', + ], + } + + # + # ADDONS + # + + # base + files[f'/opt/steam/left4dead2-servers/{name}/left4dead2/addons/readme.txt'] = { + 'content_type': 'any', + 'owner': 'steam', + 'group': 'steam', + } + directories[f'/opt/steam/left4dead2-servers/{name}/left4dead2/addons'] = { + 'owner': 'steam', + 'group': 'steam', + 'purge': True, + 'triggers': [ + f'svc_systemd:left4dead2-{name}.service:restart', + ], + } + for id in [ + *config.get('workshop', []), + *node.metadata.get('left4dead2/workshop'), + ]: + files[f'/opt/steam/left4dead2-servers/{name}/left4dead2/addons/{id}.vpk'] = { + 'content_type': 'any', + 'owner': 'steam', + 'group': 'steam', + 'triggers': [ + f'svc_systemd:left4dead2-{name}.service:restart', + ], + } + + # admin system + + directories[f'/opt/steam/left4dead2-servers/{name}/left4dead2/ems/admin system'] = { + 'owner': 'steam', + 'group': 'steam', + 'mode': '0755', + 'triggers': [ + f'svc_systemd:left4dead2-{name}.service:restart', + ], + } + files[f'/opt/steam/left4dead2-servers/{name}/left4dead2/ems/admin system/admins.txt'] = { + 'owner': 'steam', + 'group': 'steam', + 'mode': '0755', + 'content': '\n'.join(sorted(node.metadata.get('left4dead2/admins'))), + 'triggers': [ + f'svc_systemd:left4dead2-{name}.service:restart', + ], + } diff --git a/bundles/left4dead2_old/metadata.py b/bundles/left4dead2_old/metadata.py new file mode 100644 index 0000000..3ab593f --- /dev/null +++ b/bundles/left4dead2_old/metadata.py @@ -0,0 +1,127 @@ +assert node.has_bundle('steam') + +from shlex import quote + +defaults = { + 'steam': { + 'games': { + 'left4dead2': 222860, + }, + }, + 'left4dead2': { + 'servers': {}, + 'admins': set(), + 'workshop': set(), + }, +} + + +@metadata_reactor.provides( + 'left4dead2/servers', +) +def rconn_password(metadata): + # only works from localhost! + return { + 'left4dead2': { + 'servers': { + server: { + 'rcon_password': repo.vault.password_for(f'{node.name} left4dead2 {server} rcon', length=24), + } + for server in metadata.get('left4dead2/servers') + }, + }, + } + + +@metadata_reactor.provides( + 'steam-workshop-download', + 'systemd/units', +) +def server_units(metadata): + units = {} + workshop = {} + + for name, config in metadata.get('left4dead2/servers').items(): + # mount overlay + mountpoint = f'/opt/steam/left4dead2-servers/{name}' + mount_unit_name = mountpoint[1:].replace('-', '\\x2d').replace('/', '-') + '.mount' + units[mount_unit_name] = { + 'Unit': { + 'Description': f"Mount left4dead2 server {name} overlay", + 'Conflicts': {'umount.target'}, + 'Before': {'umount.target'}, + }, + 'Mount': { + 'What': 'overlay', + 'Where': mountpoint, + 'Type': 'overlay', + 'Options': ','.join([ + 'auto', + 'lowerdir=/opt/steam/left4dead2', + f'upperdir=/opt/steam-zfs-overlay-workarounds/{name}/upper', + f'workdir=/opt/steam-zfs-overlay-workarounds/{name}/workdir', + ]), + }, + 'Install': { + 'RequiredBy': { + f'left4dead2-{name}.service', + }, + }, + } + + # individual workshop + workshop_ids = config.get('workshop', set()) | metadata.get('left4dead2/workshop', set()) + if workshop_ids: + workshop[f'left4dead2-{name}'] = { + 'ids': workshop_ids, + 'path': f'/opt/steam/left4dead2-servers/{name}/left4dead2/addons', + 'user': 'steam', + 'requires': { + mount_unit_name, + }, + 'required_by': { + f'left4dead2-{name}.service', + }, + } + + # left4dead2 server unit + units[f'left4dead2-{name}.service'] = { + 'Unit': { + 'Description': f'left4dead2 server {name}', + 'After': {'steam-update.service'}, + 'Requires': {'steam-update.service'}, + }, + 'Service': { + 'User': 'steam', + 'Group': 'steam', + 'WorkingDirectory': f'/opt/steam/left4dead2-servers/{name}', + 'ExecStart': f'/opt/steam/left4dead2-servers/{name}/srcds_run -port {config["port"]} +exec server.cfg', + 'Restart': 'on-failure', + }, + 'Install': { + 'WantedBy': {'multi-user.target'}, + }, + } + + return { + 'steam-workshop-download': workshop, + 'systemd': { + '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(sorted(ports))} }} accept", + f"udp dport {{ {', '.join(sorted(ports))} }} accept", + }, + }, + } diff --git a/bundles/left4dead2_old2/README.md b/bundles/left4dead2_old2/README.md new file mode 100644 index 0000000..13f91dc --- /dev/null +++ b/bundles/left4dead2_old2/README.md @@ -0,0 +1,97 @@ +# https://github.com/SirPlease/L4D2-Competitive-Rework/blob/master/Dedicated%20Server%20Install%20Guide/README.md + +getent passwd steam >/dev/null || useradd -M -d /opt/l4d2 -s /bin/bash steam +mkdir -p /opt/l4d2 /tmp/dumps +chown steam:steam /opt/l4d2 /tmp/dumps +dpkg --add-architecture i386 +apt update +DEBIAN_FRONTEND=noninteractive apt install -y libc6:i386 lib32z1 + +function steam() { sudo -Hiu steam $* } + +# -- STEAM -- # + +steam mkdir -p /opt/l4d2/steam +test -f /opt/l4d2/steam/steamcmd_linux.tar.gz || \ + steam wget http://media.steampowered.com/installer/steamcmd_linux.tar.gz -P /opt/l4d2/steam +test -f /opt/l4d2/steam/steamcmd.sh || \ + steam tar -xvzf /opt/l4d2/steam/steamcmd_linux.tar.gz -C /opt/l4d2/steam + +# fix: /opt/l4d2/.steam/sdk32/steamclient.so: cannot open shared object file: No such file or directory +steam mkdir -p /opt/l4d2/steam/.steam +test -f /opt/l4d2/steam/.steam/sdk32/steamclient.so || \ + steam ln -s /opt/l4d2/steam/linux32 /opt/l4d2/steam/.steam/sdk32 + +# -- INSTALL -- # + +# erst die windows deps zu installieren scheint ein workaround für x64 zu sein? +steam mkdir -p /opt/l4d2/installation +steam /opt/l4d2/steam/steamcmd.sh \ + +force_install_dir /opt/l4d2/installation \ + +login anonymous \ + +@sSteamCmdForcePlatformType windows \ + +app_update 222860 validate \ + +quit +steam /opt/l4d2/steam/steamcmd.sh \ + +force_install_dir /opt/l4d2/installation \ + +login anonymous \ + +@sSteamCmdForcePlatformType linux \ + +app_update 222860 validate \ + +quit + +# -- OVERLAYS -- # + +steam mkdir -p /opt/l4d2/overlays + +# workshop downloader +steam wget -4 https://git.sublimity.de/cronekorkn/steam-workshop-downloader/raw/branch/master/steam-workshop-download -P /opt/l4d2 +steam chmod +x /opt/l4d2/steam-workshop-download + +# -- OVERLAY PVE -- # + +steam mkdir -p /opt/l4d2/overlays/pve + +# admin system +steam mkdir -p /opt/l4d2/overlays/pve/left4dead2/addons +steam /opt/l4d2/steam-workshop-download 2524204971 --out /opt/l4d2/overlays/pve/left4dead2/addons +steam mkdir -p "/opt/l4d2/overlays/pve/left4dead2/ems/admin system" +echo "STEAM_1:0:12376499" | steam tee "/opt/l4d2/overlays/pve/left4dead2/ems/admin system/admins.txt" + +# ions vocalizer +steam /opt/l4d2/steam-workshop-download 698857882 --out /opt/l4d2/overlays/pve/left4dead2/addons + +# -- OVERLAY ZONEMOD -- # + +true + +# -- SERVERS -- # + +steam mkdir -p /opt/l4d2/servers + +# -- SERVER PVE1 -- # + +steam mkdir -p \ + /opt/l4d2/servers/pve1 \ + /opt/l4d2/servers/pve1/work \ + /opt/l4d2/servers/pve1/upper \ + /opt/l4d2/servers/pve1/merged + +mount -t overlay overlay \ + -o lowerdir=/opt/l4d2/overlays/pve:/opt/l4d2/installation,upperdir=/opt/l4d2/servers/pve1/upper,workdir=/opt/l4d2/servers/pve1/work \ + /opt/l4d2/servers/pve1/merged + +# run server +steam cat <<'EOF' > /opt/l4d2/servers/pve1/merged/left4dead2/cfg/server.cfg +hostname "CKNs Server" +motd_enabled 0 + +sv_steamgroup "38347879" +#sv_steamgroup_exclusive 0 + +sv_minrate 60000 +sv_maxrate 0 +net_splitpacket_maxrate 60000 + +sv_hibernate_when_empty 0 +EOF +steam /opt/l4d2/servers/pve1/merged/srcds_run -game left4dead2 -ip 0.0.0.0 -port 27015 +map c1m1_hotel diff --git a/bundles/left4dead2_old2/files/server.cfg b/bundles/left4dead2_old2/files/server.cfg new file mode 100644 index 0000000..e69de29 diff --git a/bundles/left4dead2_old2/items.py b/bundles/left4dead2_old2/items.py new file mode 100644 index 0000000..42e2a3e --- /dev/null +++ b/bundles/left4dead2_old2/items.py @@ -0,0 +1,183 @@ +from shlex import quote + + +def steam_run(cmd): + return f'su - steam -c {quote(cmd)}' + + +users = { + 'steam': { + 'home': '/opt/steam', + }, +} + +directories = { + '/opt/steam': { + 'owner': 'steam', + 'group': 'steam', + }, + '/opt/steam/.steam': { + 'owner': 'steam', + 'group': 'steam', + }, + '/opt/left4dead2': { + 'owner': 'steam', + 'group': 'steam', + }, + '/opt/left4dead2/left4dead2/ems/admin system': { + 'owner': 'steam', + 'group': 'steam', + }, + '/opt/left4dead2/left4dead2/addons': { + 'owner': 'steam', + 'group': 'steam', + }, + '/tmp/dumps': { + 'owner': 'steam', + 'group': 'steam', + 'mode': '1770', + }, +} + +symlinks = { + '/opt/steam/.steam/sdk32': { + 'target': '/opt/steam/linux32', + 'owner': 'steam', + 'group': 'steam', + }, +} + +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', + }, + '/opt/left4dead2/left4dead2/ems/admin system/admins.txt': { + 'unless': 'test -f /opt/left4dead2/left4dead2/ems/admin system/admins.txt', + 'content': 'STEAM_1:0:12376499', + 'owner': 'steam', + 'group': 'steam', + }, +} + +actions = { + 'dpkg_add_architecture': { + 'command': 'dpkg --add-architecture i386', + 'unless': 'dpkg --print-foreign-architectures | grep -q i386', + 'triggers': [ + 'action:apt_update', + ], + 'needed_by': [ + 'pkg_apt:libc6_i386', + ], + }, + 'download_steam': { + 'command': steam_run('wget http://media.steampowered.com/installer/steamcmd_linux.tar.gz -P /opt/steam'), + 'unless': steam_run('test -f /opt/steam/steamcmd_linux.tar.gz'), + 'needs': { + 'pkg_apt:libc6_i386', + 'directory:/opt/steam', + } + }, + 'extract_steamcmd': { + 'command': steam_run('tar -xvzf /opt/steam/steamcmd_linux.tar.gz -C /opt/steam'), + 'unless': steam_run('test -f /opt/steam/steamcmd.sh'), + 'needs': { + 'action:download_steam', + } + }, +} + +for addon_id in [2524204971]: + actions[f'download-left4dead2-addon-{addon_id}'] = { + 'command': steam_run(f'/opt/steam-workshop-download {addon_id} --out /opt/left4dead2/left4dead2/addons'), + 'unless': steam_run(f'test -f /opt/left4dead2/left4dead2/addons/{addon_id}.vpk'), + 'needs': { + 'directory:/opt/left4dead2/left4dead2/addons', + }, + 'needed_by': { + 'tag:left4dead2-servers', + }, + } + +svc_systemd = { + 'left4dead2-install.service': { + 'enabled': True, + 'running': False, + 'needs': { + 'file:/usr/local/lib/systemd/system/left4dead2-install.service', + }, + }, +} + +for server_name, server_config in node.metadata.get('left4dead2/servers', {}).items(): + svc_systemd[f'left4dead2-{server_name}.service'] = { + 'enabled': True, + 'running': True, + 'tags': { + 'left4dead2-servers', + }, + 'needs': { + 'svc_systemd:left4dead2-install.service', + f'file:/usr/local/lib/systemd/system/left4dead2-{server_name}.service', + } + } + + + +# # https://github.com/SirPlease/L4D2-Competitive-Rework/blob/master/Dedicated%20Server%20Install%20Guide/README.md + +# mkdir /opt/steam /tmp/dumps +# useradd -M -d /opt/steam -s /bin/bash steam +# chown steam:steam /opt/steam /tmp/dumps +# dpkg --add-architecture i386 +# apt update +# apt install libc6:i386 lib32z1 +# sudo su - steam -s /bin/bash + +# #-------- + +# wget http://media.steampowered.com/installer/steamcmd_linux.tar.gz +# tar -xvzf steamcmd_linux.tar.gz + +# # fix: /opt/steam/.steam/sdk32/steamclient.so: cannot open shared object file: No such file or directory +# mkdir /opt/steam/.steam && ln -s /opt/steam/linux32 /opt/steam/.steam/sdk32 + +# # erst die windows deps zu installieren scheint ein workaround für x64 zu sein? +# ./steamcmd.sh \ +# +force_install_dir /opt/steam/left4dead2 \ +# +login anonymous \ +# +@sSteamCmdForcePlatformType windows \ +# +app_update 222860 validate \ +# +quit +# ./steamcmd.sh \ +# +force_install_dir /opt/steam/left4dead2 \ +# +login anonymous \ +# +@sSteamCmdForcePlatformType linux \ +# +app_update 222860 validate \ +# +quit + +# # download admin system +# wget -4 https://git.sublimity.de/cronekorkn/steam-workshop-downloader/raw/branch/master/steam-workshop-download +# chmod +x steam-workshop-download +# ./steam-workshop-download 2524204971 --out /opt/steam/left4dead2/left4dead2/addons +# mkdir -p "/opt/steam/left4dead2/left4dead2/ems/admin system" +# echo "STEAM_1:0:12376499" > "/opt/steam/left4dead2/left4dead2/ems/admin system/admins.txt" + +# /opt/steam/left4dead2/srcds_run -game left4dead2 -ip 0.0.0.0 -port 27015 +map c1m1_hotel + + +# cat <<'EOF' > /opt/steam/left4dead2/left4dead2/cfg/server.cfg +# hostname "CKNs Server" +# motd_enabled 0 + +# sv_steamgroup "38347879" +# #sv_steamgroup_exclusive 0 + +# sv_minrate 60000 +# sv_maxrate 0 +# net_splitpacket_maxrate 60000 + +# sv_hibernate_when_empty 0 +# EOF diff --git a/bundles/left4dead2_old2/metadata.py b/bundles/left4dead2_old2/metadata.py new file mode 100644 index 0000000..95c9c27 --- /dev/null +++ b/bundles/left4dead2_old2/metadata.py @@ -0,0 +1,107 @@ +from re import match + +defaults = { + 'apt': { + 'packages': { + 'libc6_i386': {}, # installs libc6:i386 + 'lib32z1': {}, + 'unzip': {}, + }, + }, + 'left4dead2': { + 'servers': {}, + }, + 'nftables': { + 'input': { + 'udp dport { 27005, 27020 } accept', + }, + }, +} + + +@metadata_reactor.provides( + 'nftables/input', +) +def nftables(metadata): + ports = sorted(str(config["port"]) for config in metadata.get('left4dead2/servers', {}).values()) + + return { + 'nftables': { + 'input': { + f'ip protocol {{ tcp, udp }} th dport {{ {", ".join(ports)} }} accept' + }, + }, + } + + +@metadata_reactor.provides( + 'systemd/units', +) +def initial_unit(metadata): + install_command = ( + '/opt/steam/steamcmd.sh ' + '+force_install_dir /opt/left4dead2 ' + '+login anonymous ' + '+@sSteamCmdForcePlatformType {platform} ' + '+app_update 222860 validate ' + '+quit ' + ) + + return { + 'systemd': { + 'units': { + 'left4dead2-install.service': { + 'Unit': { + 'Description': 'install or update left4dead2', + 'After': 'network-online.target', + }, + 'Service': { + 'Type': 'oneshot', + 'RemainAfterExit': 'yes', + 'User': 'steam', + 'Group': 'steam', + 'WorkingDirectory': '/opt/steam', + 'ExecStartPre': install_command.format(platform='windows'), + 'ExecStart': install_command.format(platform='linux'), + }, + 'Install': { + 'WantedBy': {'multi-user.target'}, + }, + }, + }, + }, + } + + +@metadata_reactor.provides( + 'systemd/units', +) +def server_units(metadata): + units = {} + + for name, config in metadata.get('left4dead2/servers').items(): + assert match(r'^[A-z0-9-_-]+$', name) + + units[f'left4dead2-{name}.service'] = { + 'Unit': { + 'Description': f'left4dead2 server {name}', + 'After': {'left4dead2-install.service'}, + 'Requires': {'left4dead2-install.service'}, + }, + 'Service': { + 'User': 'steam', + 'Group': 'steam', + 'WorkingDirectory': '/opt/left4dead2', + 'ExecStart': f'/opt/left4dead2/srcds_run -port {config["port"]} +exec server_{name}.cfg', + 'Restart': 'on-failure', + }, + 'Install': { + 'WantedBy': {'multi-user.target'}, + }, + } + + return { + 'systemd': { + 'units': units, + }, + } diff --git a/bundles/steam/items.py b/bundles/left4dead2_steam_old/items.py similarity index 100% rename from bundles/steam/items.py rename to bundles/left4dead2_steam_old/items.py diff --git a/bundles/steam/metadata.py b/bundles/left4dead2_steam_old/metadata.py similarity index 100% rename from bundles/steam/metadata.py rename to bundles/left4dead2_steam_old/metadata.py diff --git a/bundles/steam/README.md b/bundles/steam/README.md deleted file mode 100644 index b08fa74..0000000 --- a/bundles/steam/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# https://github.com/SirPlease/L4D2-Competitive-Rework/blob/master/Dedicated%20Server%20Install%20Guide/README.md - -mkdir /opt/steam /tmp/dumps -useradd -M -d /opt/steam -s /bin/bash steam -chown steam:steam /opt/steam /tmp/dumps -dpkg --add-architecture i386 -apt update -apt install libc6:i386 lib32z1 -sudo su - steam -s /bin/bash - -#-------- - -wget http://media.steampowered.com/installer/steamcmd_linux.tar.gz -tar -xvzf steamcmd_linux.tar.gz - -# fix: /opt/steam/.steam/sdk32/steamclient.so: cannot open shared object file: No such file or directory -mkdir /opt/steam/.steam && ln -s /opt/steam/linux32 /opt/steam/.steam/sdk32 - -# erst die windows deps zu installieren scheint ein workaround für x64 zu sein? -./steamcmd.sh \ - +force_install_dir /opt/steam/left4dead2 \ - +login anonymous \ - +@sSteamCmdForcePlatformType windows \ - +app_update 222860 validate \ - +quit -./steamcmd.sh \ - +force_install_dir /opt/steam/left4dead2 \ - +login anonymous \ - +@sSteamCmdForcePlatformType linux \ - +app_update 222860 validate \ - +quit - -# download admin system -wget -4 https://git.sublimity.de/cronekorkn/steam-workshop-downloader/raw/branch/master/steam-workshop-download -chmod +x steam-workshop-download -./steam-workshop-download 2524204971 --out /opt/steam/left4dead2/left4dead2/addons -mkdir -p "/opt/steam/left4dead2/left4dead2/ems/admin system" -echo "STEAM_1:0:12376499" > "/opt/steam/left4dead2/left4dead2/ems/admin system/admins.txt" - -/opt/steam/left4dead2/srcds_run -game left4dead2 -ip 0.0.0.0 -port 27015 +map c1m1_hotel - - -cat <<'EOF' > /opt/steam/left4dead2/left4dead2/cfg/server.cfg -hostname "CKNs Server" -motd_enabled 0 - -sv_steamgroup "38347879" -#sv_steamgroup_exclusive 0 - -sv_minrate 60000 -sv_maxrate 0 -net_splitpacket_maxrate 60000 - -sv_hibernate_when_empty 0 -EOF \ No newline at end of file diff --git a/nodes/htz.mails.py b/nodes/htz.mails.py index cbbda44..e2e4447 100644 --- a/nodes/htz.mails.py +++ b/nodes/htz.mails.py @@ -171,6 +171,28 @@ 'version': '1.6.11', 'installer': False, }, + 'sysctl': { + 'net': { + 'ipv4': { + 'ip_forward': 1, + 'conf': { + 'default': { + 'forwarding': 1, + }, + }, + }, + 'ipv6': { + 'conf': { + 'all': { + 'forwarding': 1, + }, + 'default': { + 'forwarding': 1, + }, + }, + }, + }, + }, 'vm': { 'cores': 2, 'ram': 4096, diff --git a/nodes/ovh.secondary.py b/nodes/ovh.secondary.py index 3979259..f262978 100644 --- a/nodes/ovh.secondary.py +++ b/nodes/ovh.secondary.py @@ -7,6 +7,7 @@ ], 'bundles': [ 'wireguard', + 'left4dead2', ], 'metadata': { 'id': 'd5080b1a-b310-48be-bd5a-02cfcecf0c90', @@ -25,6 +26,20 @@ }, }, }, + 'left4dead2': { + 'server1': { + 'overlay': 'pve', + 'port': 27015, + }, + 'server2': { + 'overlay': 'pve', + 'port': 27016, + }, + 'server3': { + 'overlay': 'pve', + 'port': 27017, + }, + }, 'bind': { 'master_node': 'htz.mails', 'hostname': 'secondary.resolver.name', @@ -46,11 +61,5 @@ }, }, }, - 'nftables': { - 'input': { - 'tcp dport 27015 accept', - 'udp dport { 27005, 27015, 27020 } accept', - }, - }, }, }