Merge branch 'master' into develop

Conflicts:
	Dockerfile
	README.md
This commit is contained in:
Lucas Briese 2019-07-29 21:57:07 +02:00
commit 102a1c21e7
19 changed files with 836 additions and 78 deletions

View File

@ -1,8 +0,0 @@
services:
- docker
script:
- docker build -t "jusito/docker-ttt:develop" .
- docker volume create TTT
- docker run -d -P -e INSTALL_CSS=true -e WORKSHOP_COLLECTION_ID=899062542 --name "TTT" -p 27015:27015/tcp -p 27015:27015/udp -v "TTT:/home/steam/server:rw" \
"jusito/docker-ttt:develop" "testing"

128
README.md
View File

@ -1,53 +1,101 @@
# docker-ttt
Garry's mod, gamemode TTT as docker image: https://hub.docker.com/r/jusito/
# GMOD TTT
GMOD TTT server image, https://hub.docker.com/r/jusito/
## TODO
* sv_password not working
* rcon not working
* scrds doesn't like different internal / external ports (thats why no ports are exposed)
* replacer config in other repo u2d?
* health check -> details
* volume for steam workshop
* volume for other games
* volume for gmod config
* AppArmor Profile
## Getting Started
1. Create 2 workshop collections. One containing Maps and a subcollection. Subcollection containing all non-map elements.
2. Do you want forced auto download? If no go 3., if yes use `-e WORKSHOP_COLLECTION_ID=*SubCollectionID*`.
3. Let Gmod server know which collection should be used. `[...]jusito/docker-ttt:beta +host_workshop_collection *MainCollectionID* [...]`
4. Do you want CSS or other game content installed and mounted(CSS recommended)? If no go 5., if yes `-e INSTALL_CSS=true` or see environment variables.
5. Choose your ports. Default is 27015. `docker run [...] -p 27015:27015/tcp jusito/docker-ttt:beta -port 27015 [...]`
1. Create public workshop collection without maps, dummy ID:=123456. Use `jusito/docker-ttt [...] +host_workshop_collection 123456`. Create a collection with maps ID:=7891011 and add/link it to 123456. If you want the clients to automatically load the collection from the workshop when connecting without subscribing, use `-e WORKSHOP_COLLECTION_ID=123456`. The users loading all non-maps at startup and the map if needed, but you don't need to point them to the collection in the workshop.
2. Do this elements need CSS, HL2, HLDM, TF2? Use `-e INSTALL_CSS=true` or `-e INSTALL_HL2=true` aso.
3. Which ports? 27015/udp is default for game traffic x/tcp for rcon, for 27016 you would use `-p 27016:27016/udp [...] jusito/docker-ttt [...] -port 27016`.
4. Set environment variables like servername `-e SERVER_NAME="My Server"`, password `-e SERVER_PASSWORD="securepw"` and timezone for cron `-e TZ="Europe/Berlin"`, default short downtime at Sunday 10 o'clock.
5. Add options for server like startmap `+map ttt_rooftops_2016_v1` and max players `-maxplayers 10`
### run example
### run example without rcon
```
docker run -dit -p 27015:27015/tcp -p 27015:27015/udp -e WORKSHOP_COLLECTION_ID=123456 -e INSTALL_CSS=true "jusito/docker-ttt:beta" -port 27015 +host_workshop_collection 123456 +map ttt_rooftops_2016_v1 -maxplayers 16
docker run -d \
-e INSTALL_CSS=true \
-p 27015:27015/udp \
-e SERVER_NAME="My Server" \
-e SERVER_PASSWORD="securepw" \
-e TZ="Europe/Berlin" \
jusito/docker-ttt:gmod_ttt_debian \
-port 27015 \
+map ttt_rooftops_2016_v1 \
-maxplayers 10
```
* _-it_ needed for seeing all output if attached
* _27015/tcp_(optional) - rcon port, you will need this too: -usercon +rcon_password "yourPW"
* _27015/udp_ - udp port for game traffic
* _-port 27015_ - only needed if you want to use non-default port, docker -p 27016:27015 will _not_ work.
* _-e WORKSHOP_COLLECTION_ID_(optional) - add every element to forced
* _-e INSTALL_CSS_(optional) - download CSS and mount it
* _+host_workshop_collection_ - Garry's Mod will load this collection
* _+map_(optional) - default map to start
* _-maxplayers_(optional) - max count of players
### whats missing, why tag beta:
1. cron service needs to be started otherwise the server will get only updates on restart
2. force cleanup of downloaded elements => removed workshop elements are otherwise used
3. I failed to create a proper volume, mount /home/steam/serverfiles.
### run example with rcon
```
docker run -d \
-e WORKSHOP_COLLECTION_ID=123456 \
-e INSTALL_CSS=true \
-p 27015:27015/udp -p 27015:27015/tcp \
-e SERVER_NAME="My Server" \
-e SERVER_PASSWORD="securepw" \
-e TZ="Europe/Berlin" \
jusito/docker-ttt:gmod_ttt_debian \
-port 27015 \
+map ttt_rooftops_2016_v1 \
-maxplayers 10 \
-usercon +rcon_password "yourPW"
```
## Tags
* lgsm\_debian - Linux Game Server Manager in Debian
* gmod\_debian - Garrys Mod with Debian and LGSM
* gmod\_ttt\_debian
## Environment Variables
### Server Properties
### additional config
### Internal Used (don't change please)
## GMOD Parameters
## LGSM Usage
docker exec -it CONTAINER ./home/steam/gmodserver console
## File Locations
### Volumes
### Other
## environment variables
| Variable | Default | Description | Example |
|----------|---------|-------------|---------|
|WORKSHOP_COLLECTION_ID|""(empty)|Every element on this list is set to forced download. The users don't need to subscribe to your collection. Don't add maps here, they are already forced by default.|1358835428|
|||||
|SERVER_NAME|""(empty)|overwrite server.cfg value|"[TTT] dockerized"|
|SERVER_PASSWORD|""(empty)|overwrite server.cfg value|"SecurePW"|
|SERVER_VOICE_ENABLE|1|overwrite server.cfg value|0 (disabling ingame voice)|
|||||
|INSTALL_CSS|false|Install & Mount CSS. Most of the time you will set this to true.|true|
|INSTALL_HL2|false|Install & Mount HL2.|true|
|INSTALL_HLDM|false|Install & Mount HLDM.|true|
|INSTALL_TF2|false|Install & Mount TF2.|true|
If set every workshop item at the collection is added as forced, that means its automatically downloaded on connecting. Don't add collections with maps here just like weapons aso.
WORKSHOP_COLLECTION_ID=
This variables are used to write the value to the server.cfg:
SERVER_NAME=""
SERVER_PASSWORD=""
SERVER_VOICE_ENABLE="1"
If set to "true" the game is installed and mounted, most of the time you want to add the css content.
INSTALL_CSS=false
INSTALL_HL2=false
INSTALL_HLDM=false
INSTALL_TF2=false
## server config
* [TTT config variables](http://ttt.badking.net/config-and-commands/convars)
* [Server.cfg variables](https://wiki.garrysmod.de/server.cfg)
http://ttt.badking.net/config-and-commands/convars
https://wiki.garrysmod.de/server.cfg
Path in container is:
docker cp "your server.cfg path" CONTAINER:/home/steam/serverfiles/garrysmod/cfg/server.cfg
## Additional
* Attach to console after start, `docker exec -it _CONTAINER_ /home/steam/gmodserver console`
* Copy your server.cfg in, `docker cp "your server.cfg path" CONTAINER:/home/steam/serverfiles/garrysmod/cfg/server.cfg`
- Debian Buster, one dependency is missing: https://packages.debian.org/search?keywords=lib32tinfo5
- Alpine, steamcmd doesn't like musl
### Debian Buster
Currently one dependency is missing: https://packages.debian.org/search?keywords=lib32tinfo5

9
TTT/Dockerfile Normal file
View File

@ -0,0 +1,9 @@
FROM jusito/docker-ttt:gmod_debian
ENV SERVER_GAMEMODE="terrortown"
COPY "server.cfg.default" "/home/server.cfg.default"
USER "$USER_ID:$GROUP_ID"
VOLUME "$SERVER_PATH"

69
apparmor/JusitoGmod Normal file
View File

@ -0,0 +1,69 @@
// +build linux
package apparmor // import "github.com/docker/docker/profiles/apparmor"
// baseTemplate defines the default apparmor profile for containers.
const baseTemplate = `
{{range $value := .Imports}}
{{$value}}
{{end}}
profile {{.Name}} flags=(attach_disconnected,mediate_deleted) {
{{range $value := .InnerImports}}
{{$value}}
{{end}}
network,
capability,
file,
umount,
{{if ge .Version 208096}}
{{/* Allow 'docker kill' to actually send signals to container processes. */}}
signal (receive) peer={{.DaemonProfile}},
{{/* Allow container processes to send signals amongst themselves. */}}
signal (send,receive) peer={{.Name}},
{{end}}
deny @{PROC}/* w, # deny write for all files directly in /proc (not in a subdir)
# deny write to files not in /proc/<number>/** or /proc/sys/**
deny @{PROC}/{[^1-9],[^1-9][^0-9],[^1-9s][^0-9y][^0-9s],[^1-9][^0-9][^0-9][^0-9]*}/** w,
deny @{PROC}/sys/[^k]** w, # deny /proc/sys except /proc/sys/k* (effectively /proc/sys/kernel)
deny @{PROC}/sys/kernel/{?,??,[^s][^h][^m]**} w, # deny everything except shm* in /proc/sys/kernel/
deny @{PROC}/sysrq-trigger rwklx,
deny @{PROC}/kcore rwklx,
deny mount,
deny /sys/[^f]*/** wklx,
deny /sys/f[^s]*/** wklx,
deny /sys/fs/[^c]*/** wklx,
deny /sys/fs/c[^g]*/** wklx,
deny /sys/fs/cg[^r]*/** wklx,
deny /sys/firmware/** rwklx,
deny /sys/kernel/security/** rwklx,
deny /bin/*/** w,
deny /boot/*/** w,
deny /dev/*/** w,
deny /etc/*/** w,
deny /home/* w,
deny /lib/*/** w,
deny /lib64/*/** w,
deny /media/*/** w,
deny /mnt/*/** w,
deny /opt/*/** w,
deny /proc/*/** w,
deny /root/*/** w,
deny /run/*/** w,
deny /sbin/*/** w,
deny /srv/*/** w,
deny /sys/*/** w,
deny /tmp/*/** w,
deny /usr/*/** w,
deny /var/*/** w,
{{if ge .Version 208095}}
# suppress ptrace denials when using 'docker ps' or using 'ps' inside a container
ptrace (trace,read,tracedby,readby) peer={{.Name}},
{{end}}
}

View File

@ -0,0 +1,12 @@
#!/bin/sh
if [ "${DEBUGGING}" = "true" ]; then
set -o xtrace
fi
set -o errexit
set -o pipefail
set -o nounset
wget -qO "apparmor.profile" 'https://raw.githubusercontent.com/moby/moby/master/profiles/apparmor/template.go'

View File

@ -1,28 +0,0 @@
#!/bin/bash
set -e
#using WORKSHOP_COLLECTION_ID
LUA_PATH="${SERVER_PATH}/garrysmod/lua/autorun/server"
LUA_FILE="${LUA_PATH}/workshop_autoload.lua"
#remove old file
if [ -e "$LUA_FILE" ]; then
rm "$LUA_FILE"
else
mkdir -p "$LUA_PATH"
fi
if [ "$WORKSHOP_COLLECTION_ID" = "0" ] || [ "$WORKSHOP_COLLECTION_ID" = "" ]; then
echo "given ID is default, no workshop download"
else
touch "$LUA_FILE"
arr="$(wget -q -O - https://steamcommunity.com/sharedfiles/filedetails/?id=${WORKSHOP_COLLECTION_ID} | tr '\n' ' ' | grep -Po '"workshopItem"[^"]+"https://steamcommunity.com/sharedfiles/filedetails/\?id=(\d+)' | grep -Po '\d\d\d+' )"
str=""
for i in ${arr[@]}
do
str=${str}"resource.AddWorkshop( \"${i}\" )"$'\n'
done
echo "$str" > "$LUA_FILE"
fi

83
gmod/Dockerfile Normal file
View File

@ -0,0 +1,83 @@
FROM jusito/docker-ttt:lgsm_debian
# Const \\ Overwrite Env \\ Configs optional
ENV CSS_PATH="/home/steam/addons/css" \
HL2_PATH="/home/steam/addons/hl2" \
HLDM_PATH="/home/steam/addons/hldm" \
TF2_PATH="/home/steam/addons/tf2" \
\
\
SERVER_EXECUTABLE="gmodserver" \
SERVER_GAME="gmodserver" \
\
\
WORKSHOP_COLLECTION_ID="" \
WORKSHOP_API_KEY="" \
WORKSHOP_AUTOLOAD="true" \
SERVER_NAME="" \
SERVER_PASSWORD="" \
SERVER_VOICE_ENABLE="1" \
SERVER_IP="0.0.0.0" \
SERVER_PORT="27015" \
SERVER_CLIENTPORT="27005" \
SERVER_SOURCETVPORT="27020" \
SERVER_DEFAULT_MAP="gm_construct" \
SERVER_MAX_PLAYERS="16" \
SERVER_TICKRATE="66" \
SERVER_GAMEMODE="sandbox" \
SERVER_LOGIN_TOKEN="" \
SERVER_ADDITIONAL_PARAMETERS="-disableluarefresh" \
LGSM_DISPLAYIP="" \
LGSM_POSTALERT="off" \
LGSM_POSTDAYS="7" \
LGSM_POSTTARGET="https://hastebin.com" \
LGSM_DISCORDALERT="off" \
LGSM_DISCORDWEBHOOK="webhook" \
LGSM_EMAILALERT="off" \
LGSM_EMAIL="email@example.com" \
LGSM_EMAILFROM="" \
LGSM_IFTTTALERT="off" \
LGSM_IFTTTTOKEN="accesstoken" \
LGSM_IFTTTEVENT="linuxgsm_alert" \
LGSM_MAILGUNALERT="off" \
LGSM_MAILGUNTOKEN="accesstoken" \
LGSM_MAILGUNDOMAIN="example.com" \
LGSM_MAILGUNEMAILFROM="alert@example.com" \
LGSM_MAILGUNEMAIL="email@myemail.com" \
LGSM_PUSHBULLETALERT="off" \
LGSM_PUSHBULLETTOKEN="accesstoken" \
LGSM_CHANNELTAG="" \
LGSM_PUSHOVERALERT="off" \
LGSM_PUSHOVERTOKEN="accesstoken" \
LGSM_TELEGRAMALERT="off" \
LGSM_TELEGRAMTOKEN="accesstoken" \
LGSM_TELEGRAMCHATID="" \
LGSM_CURLCUSTOMSTRING="" \
LGSM_UPDATEONSTART="off" \
LGSM_MAXBACKUPS="4" \
LGSM_MAXBACKUPDAYS="30" \
LGSM_STOPONBACKUP="on" \
LGSM_CONSOLELOGGING="on" \
LGSM_LOGDAYS="7" \
LGSM_QUERYDELAY="5" \
LGSM_BRANCH="" \
LGSM_STEAMMASTER="true" \
\
INSTALL_CSS=false \
INSTALL_HL2=false \
INSTALL_HLDM=false \
INSTALL_TF2=false \
\
USE_MY_REPLACER_CONFIG=false
COPY ["prepareServer.sh", "initConfig.sh", "forceWorkshopDownload.sh", "installAndMountAddons.sh", "common.cfg", "/home/"]
RUN chown "$DOCKER_USER:$DOCKER_USER" /home/prepareServer.sh && \
chown "$DOCKER_USER:$DOCKER_USER" /home/initConfig.sh && \
chown "$DOCKER_USER:$DOCKER_USER" /home/forceWorkshopDownload.sh && \
chown "$DOCKER_USER:$DOCKER_USER" /home/installAndMountAddons.sh && \
chmod a=rx /home/prepareServer.sh && \
chmod a=rx /home/initConfig.sh && \
chmod a=rx /home/forceWorkshopDownload.sh && \
chmod a=rx /home/installAndMountAddons.sh

162
gmod/common.cfg Normal file
View File

@ -0,0 +1,162 @@
#!/bin/sh
if [ "${DEBUGGING}" = "true" ]; then
set -o xtrace
fi
#set -o errexit
#set -o pipefail
#travistest: unbound variable
#set -o nounset
## Server Start Settings | https://docs.linuxgsm.com/configuration/start-parameters
ip="$SERVER_IP"
port="$SERVER_PORT"
clientport="$SERVER_CLIENTPORT"
sourcetvport="$SERVER_SOURCETVPORT"
defaultmap="gm_construct"
maxplayers="$SERVER_MAX_PLAYERS"
tickrate="$SERVER_TICKRATE"
gamemode="$SERVER_GAMEMODE"
## Workshop Parameters | https://wiki.garrysmod.com/page/Workshop_for_Dedicated_Servers
# To get an API key visit - https://steamcommunity.com/dev/apikey
wsapikey="$WORKSHOP_API_KEY"
wscollectionid="$WORKSHOP_COLLECTION_ID"
## Custom Start Parameters
# Default -disableluarefresh, disables lua autorefresh reducing server lag. Auto refresh only useful for developers.
customparms="$SERVER_ADDITIONAL_PARAMETERS"
## Optional: Game Server Login Token
# GSLT can be used for running a public server.
# More info: https://linuxgsm.com/gslt
gslt="$SERVER_LOGIN_TOKEN"
## Server Start Command | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters
fn_parms(){
#shellcheck disable=SC2034,SC2154
parms="-game garrysmod -strictportbind -ip ${ip} -port ${port} -tickrate ${tickrate} +host_workshop_collection ${wscollectionid} -authkey ${wsapikey} +clientport ${clientport} +tv_port ${sourcetvport} +gamemode ${gamemode} +map ${defaultmap} +sv_setsteamaccount ${gslt} +servercfgfile ${servercfg} -maxplayers ${maxplayers} ${customparms}"
}
#### LinuxGSM Settings ####
## Notification Alerts
# (on|off)
# Display IP | https://docs.linuxgsm.com/alerts#display-ip
#shellcheck disable=SC2034
displayip="$LGSM_DISPLAYIP"
# More info | https://docs.linuxgsm.com/alerts#more-info
#shellcheck disable=SC2034
postalert="$LGSM_POSTALERT"
#shellcheck disable=SC2034
postdays="$LGSM_POSTDAYS"
#shellcheck disable=SC2034
posttarget="$LGSM_POSTTARGET"
# Discord Alerts | https://docs.linuxgsm.com/alerts/discord
#shellcheck disable=SC2034
discordalert="$LGSM_DISCORDALERT"
#shellcheck disable=SC2034
discordwebhook="$LGSM_DISCORDWEBHOOK"
# Email Alerts | https://docs.linuxgsm.com/alerts/email
#shellcheck disable=SC2034
emailalert="$LGSM_EMAILALERT"
#shellcheck disable=SC2034
email="$LGSM_EMAIL"
#shellcheck disable=SC2034
emailfrom="$LGSM_EMAILFROM"
# IFTTT Alerts | https://docs.linuxgsm.com/alerts/ifttt
#shellcheck disable=SC2034
iftttalert="$LGSM_IFTTTALERT"
#shellcheck disable=SC2034
ifttttoken="$LGSM_IFTTTTOKEN"
#shellcheck disable=SC2034
iftttevent="$LGSM_IFTTTEVENT"
# Mailgun Email Alerts | https://docs.linuxgsm.com/alerts/mailgun
#shellcheck disable=SC2034
mailgunalert="$LGSM_MAILGUNALERT"
#shellcheck disable=SC2034
mailguntoken="$LGSM_MAILGUNTOKEN"
#shellcheck disable=SC2034
mailgundomain="$LGSM_MAILGUNDOMAIN"
#shellcheck disable=SC2034
mailgunemailfrom="$LGSM_MAILGUNEMAILFROM"
#shellcheck disable=SC2034
mailgunemail="$LGSM_MAILGUNEMAIL"
# Pushbullet Alerts | https://docs.linuxgsm.com/alerts/pushbullet
#shellcheck disable=SC2034
pushbulletalert="$LGSM_PUSHBULLETALERT"
#shellcheck disable=SC2034
pushbullettoken="$LGSM_PUSHBULLETTOKEN"
#shellcheck disable=SC2034
channeltag="$LGSM_CHANNELTAG"
# Pushover Alerts | https://docs.linuxgsm.com/alerts/pushover
#shellcheck disable=SC2034
pushoveralert="$LGSM_PUSHOVERALERT"
#shellcheck disable=SC2034
pushovertoken="$LGSM_PUSHOVERTOKEN"
# Telegram Alerts | https://docs.linuxgsm.com/alerts/telegram
# You can add a custom cURL string eg proxy (useful in Russia) or else in "curlcustomstring".
# like a "--socks5 ipaddr:port" for socks5 proxy see more in "curl --help", if you not need
# any custom string in curl - simple ignore this parameter.
#shellcheck disable=SC2034
telegramalert="$LGSM_TELEGRAMALERT"
#shellcheck disable=SC2034
telegramtoken="$LGSM_TELEGRAMTOKEN"
#shellcheck disable=SC2034
telegramchatid="$LGSM_TELEGRAMCHATID"
#shellcheck disable=SC2034
curlcustomstring="$LGSM_CURLCUSTOMSTRING"
## Updating | https://docs.linuxgsm.com/commands/update
#shellcheck disable=SC2034
updateonstart="$LGSM_UPDATEONSTART"
## Backup | https://docs.linuxgsm.com/commands/backup
#shellcheck disable=SC2034
maxbackups="$LGSM_MAXBACKUPS"
#shellcheck disable=SC2034
maxbackupdays="$LGSM_MAXBACKUPDAYS"
#shellcheck disable=SC2034
stoponbackup="$LGSM_STOPONBACKUP"
## Logging | https://docs.linuxgsm.com/features/logging
#shellcheck disable=SC2034
consolelogging="$LGSM_CONSOLELOGGING"
#shellcheck disable=SC2034
logdays="$LGSM_LOGDAYS"
## Monitor | https://docs.linuxgsm.com/commands/monitor
# Query delay time
#shellcheck disable=SC2034
querydelay="$LGSM_QUERYDELAY"
#### LinuxGSM Advanced Settings ####
# ANSI Colors
#shellcheck disable=SC2034
ansi="on"
# Message Display Time
#shellcheck disable=SC2034
sleeptime="0.5"
## SteamCMD Settings
# Server appid
#shellcheck disable=SC2034
appid="4020"
# SteamCMD Branch | https://docs.linuxgsm.com/steamcmd/branch
#shellcheck disable=SC2034
branch="$LGSM_BRANCH"
# Master Server | https://docs.linuxgsm.com/steamcmd/steam-master-server
#shellcheck disable=SC2034
steammaster="$LGSM_STEAMMASTER"

View File

@ -0,0 +1,36 @@
#!/bin/bash
if [ "${DEBUGGING}" = "true" ]; then
set -o xtrace
fi
set -o errexit
set -o nounset
set -o pipefail
#using WORKSHOP_COLLECTION_ID
LUA_PATH="${SERVER_PATH}/garrysmod/lua/autorun/server"
LUA_FILE="${LUA_PATH}/workshop_autoload.lua"
#remove old file
if [ -e "$LUA_FILE" ]; then
rm "$LUA_FILE"
else
mkdir -p "$LUA_PATH"
fi
if [ "$WORKSHOP_COLLECTION_ID" = "0" ] || [ "$WORKSHOP_COLLECTION_ID" = "" ] || [ "$WORKSHOP_AUTOLOAD" != "true" ]; then
echo "No auto workshop download"
else
touch "$LUA_FILE"
arr=$(wget -q -O - https://steamcommunity.com/sharedfiles/filedetails/?id="${WORKSHOP_COLLECTION_ID}" | tr '\n' ' ' | grep -Po '"workshopItem"[^"]+"https://steamcommunity.com/sharedfiles/filedetails/\?id=(\d+)' | grep -Po '\d\d\d+' )
str=""
# resplitting needed here, otherwise one string with complete ids
# shellcheck disable=SC2068
for i in ${arr[@]}
do
str=${str}"resource.AddWorkshop( \"${i}\" )"$'\n'
done
echo "$str" > "$LUA_FILE"
fi

60
gmod/initConfig.sh Normal file
View File

@ -0,0 +1,60 @@
#!/bin/bash
if [ "${DEBUGGING}" = "true" ]; then
set -o xtrace
fi
set -o errexit
set -o nounset
set -o pipefail
function configReplace() {
source="$1"
target="$source \"$2\""
count=$(grep -Poc "($source).+" "${SERVER_PATH}/garrysmod/cfg/server.cfg")
echo "Request for replacing $source to $target, source is found $count times"
if [ "$count" == "1" ]; then
source=$(grep -Po "($source).+" "${SERVER_PATH}/garrysmod/cfg/server.cfg" | sed 's/\\/\\\\/g' | sed 's/\//\\\//g')
target=$(echo "$target" | sed 's/\\/\\\\/g' | sed 's/\//\\\//g')
sed -i "s/$source/$target/g" "${SERVER_PATH}/garrysmod/cfg/server.cfg"
elif [ "$count" == "0" ]; then
echo "" >> "${SERVER_PATH}/garrysmod/cfg/server.cfg"
echo "$target" >> "${SERVER_PATH}/garrysmod/cfg/server.cfg"
else
echo "can't set $1 because there are multiple in"
fi
}
#create default server.config
# not empty: grep -q '[^[:space:]]' < 'server.cfg' && echo "not empty"
if [ ! -e "${SERVER_PATH}/garrysmod/cfg/server.cfg" ] || [ "0" = "$(grep -oc '[^[:space:]]' "${SERVER_PATH}/garrysmod/cfg/server.cfg")" ]; then
mkdir -p "${SERVER_PATH}/garrysmod/cfg" || true
cp -f "/home/server.cfg.default" "${SERVER_PATH}/garrysmod/cfg/server.cfg"
chown "$USER_ID:$GROUP_ID" "${SERVER_PATH}/garrysmod/cfg/server.cfg"
chmod u+rw "${SERVER_PATH}/garrysmod/cfg/server.cfg"
fi
#set hostname & password, working if only one entry is in
if [ -n "${SERVER_NAME}" ]; then
configReplace "hostname" "$SERVER_NAME"
fi
if [ -n "${SERVER_PASSWORD}" ]; then
configReplace "sv_password" "$SERVER_PASSWORD"
fi
if [ -n "${SERVER_VOICE_ENABLE}" ]; then
configReplace "sv_voiceenable" "$SERVER_VOICE_ENABLE"
fi
#this is a simple option for myself, but you can use it too
if [ "$USE_MY_REPLACER_CONFIG" = "true" ] && [ ! -e "${SERVER_PATH}/garrysmod/data/jusito_ttt_entity_replace" ]; then
mkdir -p "${SERVER_PATH}/garrysmod/data/jusito_ttt_entity_replace"
wget -O "${SERVER_PATH}/garrysmod/data/jusito_ttt_entity_replace/config.txt" "https://raw.githubusercontent.com/jusito/ttt_entity_replace/master/config.txt.example_fas2"
fi

View File

@ -1,6 +1,12 @@
#!/bin/bash
set -e
if [ "${DEBUGGING}" = "true" ]; then
set -o xtrace
fi
set -o errexit
set -o nounset
set -o pipefail
cd "$STEAM_CMD"
mount='"mountcfg"'$'\n{\n'
if [ "$INSTALL_CSS" = "true" ]; then

36
gmod/prepareServer.sh Normal file
View File

@ -0,0 +1,36 @@
#!/bin/sh
if [ "${DEBUGGING}" = "true" ]; then
set -o xtrace
fi
set -o errexit
set -o nounset
#./prepareServer.sh: 9: set: Illegal option -o pipefail
#set -o pipefail
mkdir -p "/home/steam/lgsm/config-lgsm/gmodserver/"
cp -f "/home/common.cfg" "/home/steam/lgsm/config-lgsm/gmodserver/common.cfg"
cd "/home"
echo "check configurations"
./initConfig.sh
echo "force workshop download"
./forceWorkshopDownload.sh
echo "install & mount gamefiles"
./installAndMountAddons.sh
cd "$STEAM_PATH"
#docker args -> lgsm args
temp=""
temp=$(printf "%s " "$@") || true
export parms="-game garrysmod $SERVER_GAMEMODE $temp"
if [ -e "${STEAM_PATH}/lgsm/config-lgsm/gmodserver/gmodserver.cfg" ]; then
rm -f "${STEAM_PATH}/lgsm/config-lgsm/gmodserver/gmodserver.cfg"
fi
mkdir -p "${STEAM_PATH}/lgsm/config-lgsm/gmodserver/"
touch "${STEAM_PATH}/lgsm/config-lgsm/gmodserver/gmodserver.cfg"
echo "fn_parms(){" > "${STEAM_PATH}/lgsm/config-lgsm/gmodserver/gmodserver.cfg"
echo "parms="'"'"$parms"'"' >> "${STEAM_PATH}/lgsm/config-lgsm/gmodserver/gmodserver.cfg"
echo "}" >> "${STEAM_PATH}/lgsm/config-lgsm/gmodserver/gmodserver.cfg"
echo "starting with $parms"

67
lgsm/Dockerfile Normal file
View File

@ -0,0 +1,67 @@
FROM debian:stretch-slim
# Const \\ Overwrite Env \\ Configs possible \\ Configs needed
ENV STEAM_PATH="/home/steam" \
SERVER_PATH="/home/steam/serverfiles" \
STEAM_CMD="/home/steam/steamcmd" \
GROUP_ID=10000 \
USER_ID=10000 \
DOCKER_USER=steam \
SUPERCRONIC_URL=https://github.com/aptible/supercronic/releases/download/v0.1.9/supercronic-linux-amd64 \
SUPERCRONIC=supercronic-linux-amd64 \
SUPERCRONIC_SHA1SUM=5ddf8ea26b56d4a7ff6faecdd8966610d5cb9d85 \
\
\
DEBIAN_FRONTEND=noninteractive \
LANG=C.UTF-8 \
TERM=xterm \
\
\
DEBUGGING=false \
CRON_MONITOR="*/5 * * * *" \
CRON_UPDATE="*/30 * * * *" \
CRON_FORCE_UPDATE="0 10 * * 0" \
CRON_LOG_ROTATE="0 0 * * 0" \
\
\
SERVER_EXECUTABLE="" \
SERVER_GAME="" \
TZ="Europe/Berlin"
#https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
ENTRYPOINT ["./home/entrypoint.sh"]
#WORKDIR "$STEAM_PATH"
COPY ["entrypoint.sh", "initCron.sh", "/home/"]
# procps needed for ps command
# iproute2 needed because of "-slim"
RUN dpkg --add-architecture i386 && \
apt-get update -y && \
apt-get install -y mailutils postfix curl wget file bzip2 gzip unzip bsdmainutils python util-linux ca-certificates \
binutils bc jq tmux lib32gcc1 libstdc++6 libstdc++6:i386 lib32tinfo5 \
procps iproute2 && \
\
groupadd -g $GROUP_ID $DOCKER_USER && \
useradd -d "$STEAM_PATH" -g $GROUP_ID -u $USER_ID -m $DOCKER_USER && \
chown "$DOCKER_USER:$DOCKER_USER" /home/entrypoint.sh && \
chown "$DOCKER_USER:$DOCKER_USER" /home/initCron.sh && \
mkdir -p "$SERVER_PATH" && \
chown -R "$DOCKER_USER:$DOCKER_USER" "$STEAM_PATH" && \
chmod a=rx /home/entrypoint.sh && \
chmod a=rx /home/initCron.sh && \
\
ulimit -n 2048 && \
\
wget -O "$STEAM_PATH/linuxgsm.sh" "https://linuxgsm.sh" && \
chown "$DOCKER_USER:$DOCKER_USER" "$STEAM_PATH/linuxgsm.sh" && \
chmod +x "$STEAM_PATH/linuxgsm.sh" && \
\
\
wget -O "${SUPERCRONIC}" "$SUPERCRONIC_URL" && \
echo "${SUPERCRONIC_SHA1SUM} ${SUPERCRONIC}" | sha1sum -c - && \
chmod +x "$SUPERCRONIC" && \
mv "$SUPERCRONIC" "/usr/local/bin/${SUPERCRONIC}" && \
ln -s "/usr/local/bin/${SUPERCRONIC}" /usr/local/bin/supercronic

70
lgsm/entrypoint.sh Normal file
View File

@ -0,0 +1,70 @@
#!/bin/bash
if [ "${DEBUGGING}" = "true" ]; then
set -o xtrace
fi
set -o errexit
set -o nounset
set -o pipefail
echo "starting entrypoint.sh"
set -e
# --- Install / Update ---
cd "$STEAM_PATH"
if [ -n "$SERVER_EXECUTABLE" ] && [ -e "${STEAM_PATH}/$SERVER_EXECUTABLE" ]; then
./"$SERVER_EXECUTABLE" update-lgsm
./"$SERVER_EXECUTABLE" update
else
bash linuxgsm.sh "$SERVER_GAME"
./"$SERVER_EXECUTABLE" auto-install
fi
if [ -e "/home/prepareServer.sh" ]; then
cd /home
./prepareServer.sh "$@"
cd "$STEAM_PATH"
fi
# --- Start Server ---
#start server
IS_RUNNING="true"
function stopServer() {
echo "stopping server..."
cd "${STEAM_PATH}"
pid=$(pidof "$SERVER_EXECUTABLE")
kill -2 "$pid" || true
echo "server stopped!"
echo "stopping entrypoint..."
IS_RUNNING="false"
echo "done!"
}
./"$SERVER_EXECUTABLE" start &
trap stopServer SIGTERM
#start cron
bash "/home/initCron.sh"
# --- Wait for Shutdown ---
echo "Server is running, waiting for SIGTERM"
while [ "$IS_RUNNING" = "true" ]
do
sleep 1s
done
echo "entrypoint stopped"
exit 0

34
lgsm/initCron.sh Normal file
View File

@ -0,0 +1,34 @@
#!/bin/sh
if [ "${DEBUGGING}" = "true" ]; then
set -o xtrace
fi
set -o errexit
set -o pipefail
set -o nounset
LOG_PATH="$STEAM_PATH/logs"
CRON="$LOG_PATH/lgsm.cron"
CRON_LOG="$LOG_PATH/cron.log"
#set up cronjob
mkdir "$LOG_PATH" || true
rm -f "$CRON" || true
touch "$CRON"
# false positive
# shellcheck disable=SC2129
echo "$CRON_MONITOR $STEAM_PATH/gmodserver monitor > '$LOG_PATH/monitor.log' 2>&1" >> "$CRON"
# shellcheck disable=SC2129
echo "$CRON_UPDATE $STEAM_PATH/gmodserver update > '$LOG_PATH/update.log' 2>&1" >> "$CRON"
# shellcheck disable=SC2129
echo "$CRON_FORCE_UPDATE $STEAM_PATH/gmodserver force-update >'$LOG_PATH/force-update.log' 2>&1" >> "$CRON"
# shellcheck disable=SC2129
echo "$CRON_LOG_ROTATE mv -f '$CRON_LOG' '${CRON_LOG}.old'" >> "$CRON"
echo "" >> "$CRON"
if [ -e "$CRON_LOG" ]; then
mv -f "$CRON_LOG" "${CRON_LOG}.old"
fi
supercronic "$CRON" 2> "$LOG_PATH/cron.log" &

35
test/testCaseQuick.sh Normal file
View File

@ -0,0 +1,35 @@
#!/bin/bash
if [ "${DEBUGGING}" = "true" ]; then
set -o xtrace
else
DEBUGGING="false"
fi
set -o errexit
set -o nounset
set -o pipefail
#bash test/testStyle.sh
echo "[testBuild][INFO]build"
docker rmi "jusito/docker-ttt:lgsm_debian" || true
docker build -t "jusito/docker-ttt:lgsm_debian" "./lgsm/"
docker rmi "jusito/docker-ttt:gmod_debian" || true
docker build -t "jusito/docker-ttt:gmod_debian" "./gmod/"
docker rmi "jusito/docker-ttt:gmod_ttt_debian" || true
docker build -t "jusito/docker-ttt:gmod_ttt_debian" "./TTT/"
echo "[testRun][INFO]running"
if ! docker run -ti --name "JusitoTesting" --rm -e TEST_MODE=true -e DEBUGGING="$DEBUGGING" -e SERVER_PASSWORD="testpw" -e SERVER_MAX_PLAYERS="10" "jusito/docker-ttt:gmod_ttt_debian"; then
echo "[testRun][ERROR]run test failed for docker-ttt:ubuntu"
exit 1
fi
docker stop "JusitoTesting" || true
docker rm "JusitoTesting" || true
#docker run -ti --name "JusitoTesting" -p 27015:27015/udp -p 27015:27015/tcp --rm -e TEST_MODE=true -e DEBUGGING="$DEBUGGING" -e SERVER_PASSWORD="testpw" -e SERVER_MAX_PLAYERS="10" "jusito/docker-ttt:gmod_ttt_debian"

13
test/testHealth.sh Normal file
View File

@ -0,0 +1,13 @@
#!/bin/bash
if [ "${DEBUGGING:?}" = "true" ]; then
set -o xtrace
fi
set -o errexit
set -o nounset
set -o pipefail
docker exec -it CONTAINER ./home/steam/gmodserver details
Status: OFFLINE -> fail Health

54
test/testStyle.sh Normal file
View File

@ -0,0 +1,54 @@
#!/bin/sh
if [ "${DEBUGGING}" = "true" ]; then
set -o xtrace
fi
set -o errexit
set -o nounset
set -o pipefail
# test sha3sums
#if ! printf '%s %s' "$(grep -Eo "grep -Eq '\^[^\\]+" Dockerfile | sed 's/...........//')" "checkHealth.sh" | sha3sum -c ; then
# echo "[testStyle][ERROR]Sha3sum of checkHealth.sh in Dockerfile invalid"
# exit 2
#fi
directory="$PWD"
echo "[testStyle][INFO]workdir $directory"
check() {
file="$1"
exclude=""
if [ -n "$2" ]; then
exclude="--exclude=$2"
fi
echo "[testStyle][INFO]processing $file with extra arg: $exclude"
# shellcheck disable=SC2086
if shellcheck $exclude "$file"; then
return 0
else
echo "[testStyle][ERROR]style is bad"
return 1
fi
}
find "${directory}" -maxdepth 1 -type f -iname '*.sh' |
while read -r filename
do
if ! check "$filename" ''; then
exit 1
fi
done
# shellcheck disable=SC2181
if [ "$?" = "0" ]; then
echo "[testStyle][INFO]all elements passed style check"
exit 0
else
echo "[testStyle][ERROR]style in at least one element looks bad"
exit 1
fi