From df253d53e1bba6bbdcb5dee32f3b210f34c6b8cd Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Sun, 21 Jul 2019 23:04:00 +0200 Subject: [PATCH 01/13] + split docker images successful --- Dockerfile | 6 +- README.md | 7 ++- TTT/Dockerfile | 9 +++ TTT/server.cfg.default | 101 ++++++++++++++++++++++++++++++++++ cronTest/Dockerfile | 56 +++++++++++++++++++ cronTest/entrypoint.sh | 17 ++++++ cronTest/initCron.sh | 16 ++++++ entrypoint.sh | 8 ++- experimental.sh | 14 ++--- forceWorkshopDownload.sh | 4 +- gmod/Dockerfile | 40 ++++++++++++++ gmod/forceWorkshopDownload.sh | 34 ++++++++++++ gmod/initConfig.sh | 60 ++++++++++++++++++++ gmod/installAndMountAddons.sh | 54 ++++++++++++++++++ gmod/prepareServer.sh | 33 +++++++++++ lgsm/Dockerfile | 64 +++++++++++++++++++++ lgsm/entrypoint.sh | 81 +++++++++++++++++++++++++++ lgsm/initCron.sh | 34 ++++++++++++ test/testBuild.sh | 12 ++++ test/testCaseQuick.sh | 22 ++++++++ test/testCaseQuick2.sh | 33 +++++++++++ test/testHealth.sh | 13 +++++ test/testRun.sh | 20 +++++++ test/testStyle.sh | 54 ++++++++++++++++++ 24 files changed, 775 insertions(+), 17 deletions(-) create mode 100644 TTT/Dockerfile create mode 100644 TTT/server.cfg.default create mode 100644 cronTest/Dockerfile create mode 100644 cronTest/entrypoint.sh create mode 100644 cronTest/initCron.sh create mode 100644 gmod/Dockerfile create mode 100644 gmod/forceWorkshopDownload.sh create mode 100644 gmod/initConfig.sh create mode 100644 gmod/installAndMountAddons.sh create mode 100644 gmod/prepareServer.sh create mode 100644 lgsm/Dockerfile create mode 100644 lgsm/entrypoint.sh create mode 100644 lgsm/initCron.sh create mode 100644 test/testBuild.sh create mode 100644 test/testCaseQuick.sh create mode 100644 test/testCaseQuick2.sh create mode 100644 test/testHealth.sh create mode 100644 test/testRun.sh create mode 100644 test/testStyle.sh diff --git a/Dockerfile b/Dockerfile index 5a461bd..3ccc9ef 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM debian:stretch EXPOSE 27015/udp 27015/tcp @@ -32,6 +32,7 @@ ENTRYPOINT ["./home/entrypoint.sh"] COPY ["entrypoint.sh", "experimental.sh", "forceWorkshopDownload.sh", "installAndMountAddons.sh", "/home/"] # removed dep. lib32gcc1 libtcmalloc-minimal4:i386 gdb +#sudo dpkg --add-architecture i386; 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 \ @@ -49,7 +50,8 @@ RUN dpkg --add-architecture i386 && \ chmod a=rx /home/installAndMountAddons.sh && \ \ ulimit -n 2048 && \ - locale-gen en_US.UTF-8 && \ + sed -i 's/# en_US.UTF-8/en_US.UTF-8/' /etc/locale.gen && \ + locale-gen && \ \ wget -O "$STEAM_PATH/linuxgsm.sh" "https://linuxgsm.sh" && \ chown "$DOCKER_USER:$DOCKER_USER" "$STEAM_PATH/linuxgsm.sh" && \ diff --git a/README.md b/README.md index 05b163b..8d5b0d9 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# docker-ttt +# GMOD TTT GMOD TTT server image, https://hub.docker.com/r/jusito/ ## TODO @@ -38,3 +38,8 @@ 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 + +### Debian Buster +Currently one dependency is missing: https://packages.debian.org/search?keywords=lib32tinfo5 diff --git a/TTT/Dockerfile b/TTT/Dockerfile new file mode 100644 index 0000000..ba294aa --- /dev/null +++ b/TTT/Dockerfile @@ -0,0 +1,9 @@ +FROM jusito/docker-ttt:gmod_debian + +ENV SERVER_GAMEMODE="+gamemode terrortown" + +COPY "server.cfg.default" "/home/server.cfg.default" + +USER "$USER_ID:$GROUP_ID" + +VOLUME "$SERVER_PATH" \ No newline at end of file diff --git a/TTT/server.cfg.default b/TTT/server.cfg.default new file mode 100644 index 0000000..d868572 --- /dev/null +++ b/TTT/server.cfg.default @@ -0,0 +1,101 @@ +hostname "" +sv_password "" +sv_voiceenable 0 + +sv_contact "unknown" + + +// rcon passsword +sv_rcon_banpenalty 5 +sv_rcon_maxfailures 3 + +//DNA +ttt_killer_dna_range 300 +ttt_killer_dna_basetime 100 + + +//Prep +ttt_firstpreptime 60 +ttt_preptime_seconds 30 +ttt_posttime_seconds 3 + + +//Round length +ttt_haste 0 +// ttt_haste_starting_minutes 5 +// ttt_haste_minutes_per_death 0.5 + +ttt_roundtime_minutes 10 + + + +//Map Switching +ttt_round_limit 10 +ttt_time_limit_minutes 75 + +//ttt_always_use_mapcycle 0 + + +//Player Counts +ttt_minimum_players 2 +ttt_traitor_pct 0.4 +ttt_traitor_max 32 +ttt_detective_pct 0.1 +ttt_detective_max 32 +ttt_detective_min_players 6 +ttt_detective_karma_min 600 + + +//Karma +ttt_karma 1 +ttt_karma_strict 1 +ttt_karma_starting 1000 +ttt_karma_max 1000 +ttt_karma_ratio 0.001 +ttt_karma_kill_penalty 50 +ttt_karma_round_increment 5 +ttt_karma_clean_bonus 30 +ttt_karma_traitordmg_ratio 0.0003 +ttt_karma_traitorkill_bonus 100 +ttt_karma_low_autokick 1 +ttt_karma_low_amount 300 +ttt_karma_low_ban 0 +ttt_karma_low_ban_minutes 60 +ttt_karma_persist 1 +ttt_karma_clean_half 0.25 + +//Other +ttt_postround_dm 0 +ttt_no_nade_throw_during_prep 0 +ttt_weapon_carrying 1 +ttt_weapon_carrying_range 50 +ttt_teleport_telefrags 1 +ttt_ragdoll_pinning 1 +ttt_ragdoll_pinning_innocents 1 +ttt_use_weapon_spawn_scripts 1 +ttt_spawn_wave_interval 2 +ttt_allow_discomb_jump 1 +ttt_debug_preventwin 0 + +// server logging +log on +sv_logbans 1 +sv_logecho 1 +sv_logfile 0 +sv_log_onefile 0 + +// operation +sv_lan 0 +sv_region 3 //Europa + +// traitor +ttt_credits_detectivekill 2 +ttt_credits_award_repeat 0.5 + +// fastdl +sv_allowdownload 1 +sv_allowupload 0 +// sv_downloadurl "your url" + +exec banned_user.cfg +exec banned_ip.cfg \ No newline at end of file diff --git a/cronTest/Dockerfile b/cronTest/Dockerfile new file mode 100644 index 0000000..a7894be --- /dev/null +++ b/cronTest/Dockerfile @@ -0,0 +1,56 @@ +FROM debian:stretch + +# 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 \ + \ + \ + DEBUGGING=false \ + CRON_MONITOR="*/5 * * * *" \ + CRON_UPDATE="*/30 * * * *" \ + CRON_FORCE_UPDATE="0 10 * * 0" \ + \ + \ + SERVER_EXECUTABLE="" \ + SERVER_GAME="" \ + TZ="US/Eastern" +#https://en.wikipedia.org/wiki/List_of_tz_database_time_zones + +ENTRYPOINT ["./home/entrypoint.sh"] + +COPY ["entrypoint.sh", "initCron.sh", "/home/"] + +RUN dpkg --add-architecture i386 && \ + apt-get update -y && \ + apt-get install -y locales sudo curl && \ + \ + 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 && \ + sudo -u "$DOCKER_USER" 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 && \ + sed -i 's/# en_US.UTF-8/en_US.UTF-8/' /etc/locale.gen && \ + locale-gen && \ + \ + \ + curl -fsSLO "$SUPERCRONIC_URL" && \ + echo "${SUPERCRONIC_SHA1SUM} ${SUPERCRONIC}" | sha1sum -c - && \ + chmod a+rx "$SUPERCRONIC" && \ + mv "$SUPERCRONIC" "/usr/local/bin/${SUPERCRONIC}" && \ + ln -s "/usr/local/bin/${SUPERCRONIC}" /usr/local/bin/supercronic + diff --git a/cronTest/entrypoint.sh b/cronTest/entrypoint.sh new file mode 100644 index 0000000..2824d96 --- /dev/null +++ b/cronTest/entrypoint.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +if [ "${DEBUGGING}" = "true" ]; then + set -o xtrace +fi + +set -o errexit +set -o pipefail + +echo "starting entrypoint.sh" +set -e + + +#start cron +bash "/home/initCron.sh" + +exec /bin/bash \ No newline at end of file diff --git a/cronTest/initCron.sh b/cronTest/initCron.sh new file mode 100644 index 0000000..9dc601d --- /dev/null +++ b/cronTest/initCron.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +if [ "${DEBUGGING}" = "true" ]; then + set -o xtrace +fi + +set -o errexit +set -o pipefail +set -o nounset + +#set up cronjob +rm -f "$STEAM_PATH/lgsm-cronjobs" || true +touch "$STEAM_PATH/lgsm-cronjobs" +# false positive +echo "*/1 * * * * date >> date.log" >> "$STEAM_PATH/lgsm-cronjobs" # out on release +echo "" >> "$STEAM_PATH/lgsm-cronjobs" diff --git a/entrypoint.sh b/entrypoint.sh index bed1618..54d04d0 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -25,7 +25,9 @@ echo "install & mount gamefiles" cd "$STEAM_PATH" #docker args -> lgsm args -export parms="-game garrysmod +gamemode terrortown "$(printf "%s " "$@") +temp="" +temp=$(printf "%s " "$@") || true +export parms="-game garrysmod +gamemode terrortown $temp" if [ -e "${STEAM_PATH}/lgsm/config-lgsm/gmodserver/gmodserver.cfg" ]; then rm -f "${STEAM_PATH}/lgsm/config-lgsm/gmodserver/gmodserver.cfg" fi @@ -49,8 +51,8 @@ IS_RUNNING="true" function stopServer() { echo "stopping server..." cd "${STEAM_PATH}" - pkill -2 srcds_linux - pkill -2 srcds_run + kill -2 "$(pidof srcds_linux)" || true + kill -2 "$(pidof srcds_run)" || true echo "server stopped!" echo "stopping entrypoint..." IS_RUNNING="false" diff --git a/experimental.sh b/experimental.sh index 96ad791..e4f0fd4 100644 --- a/experimental.sh +++ b/experimental.sh @@ -5,6 +5,8 @@ set -e function configReplace() { source="$1" target="$source \"$2\"" + #grep -c would be nicer + # shellcheck disable=SC2126 count=$(grep -Po "($source).+" "${SERVER_PATH}/garrysmod/cfg/server.cfg" | wc -l) echo "Request for replacing $source to $target, source is found $count times" @@ -23,6 +25,8 @@ function configReplace() { #create default server.config # not empty: grep -q '[^[:space:]]' < 'server.cfg' && echo "not empty" +#grep -c would be nicer +# shellcheck disable=SC2126 if [ ! -e "${SERVER_PATH}/garrysmod/cfg/server.cfg" ] || [ "0" = "$(grep -o '[^[:space:]]' "${SERVER_PATH}/garrysmod/cfg/server.cfg" | wc -l)" ]; then mkdir -p "${SERVER_PATH}/garrysmod/cfg" wget -O "${SERVER_PATH}/garrysmod/cfg/server.cfg" "https://raw.githubusercontent.com/jusito/docker-ttt/master/server.cfg" @@ -41,15 +45,7 @@ if [ -n "${SERVER_VOICE_ENABLE}" ]; then configReplace "sv_voiceenable" "$SERVER_VOICE_ENABLE" fi -#set up cronjob -crontab -r | true -rm -f "$STEAM_PATH/lgsm-cronjobs" | true -touch "$STEAM_PATH/lgsm-cronjobs" -echo "*/5 * * * * su - '$DOCKER_USER' -c '$STEAM_PATH/gmodserver monitor' > /dev/null 2>&1" >> "$STEAM_PATH/lgsm-cronjobs" -echo "*/30 * * * * su - '$DOCKER_USER' -c '$STEAM_PATH/gmodserver update' > /dev/null 2>&1" >> "$STEAM_PATH/lgsm-cronjobs" -echo "0 10 * * 0 su - '$DOCKER_USER' -c '$STEAM_PATH/gmodserver force-update' > /dev/null 2>&1" >> "$STEAM_PATH/lgsm-cronjobs" -echo "" >> "$STEAM_PATH/lgsm-cronjobs" -crontab "$STEAM_PATH/lgsm-cronjobs" + #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 diff --git a/forceWorkshopDownload.sh b/forceWorkshopDownload.sh index 6e2c130..b64668a 100644 --- a/forceWorkshopDownload.sh +++ b/forceWorkshopDownload.sh @@ -17,9 +17,9 @@ if [ "$WORKSHOP_COLLECTION_ID" = "0" ] || [ "$WORKSHOP_COLLECTION_ID" = "" ]; th 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+' )" + 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[@]} + for i in "${arr[@]}" do str=${str}"resource.AddWorkshop( \"${i}\" )"$'\n' done diff --git a/gmod/Dockerfile b/gmod/Dockerfile new file mode 100644 index 0000000..0dc514a --- /dev/null +++ b/gmod/Dockerfile @@ -0,0 +1,40 @@ +FROM jusito/docker-ttt:lgsm_debian + +EXPOSE 27015/udp 27015/tcp + +# Const \\ Overwrite Env \\ Configs optional \\ Configs needed +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= \ + SERVER_NAME="" \ + SERVER_PASSWORD="" \ + SERVER_VOICE_ENABLE="1" \ + \ + INSTALL_CSS=false \ + INSTALL_HL2=false \ + INSTALL_HLDM=false \ + INSTALL_TF2=false \ + \ + USE_MY_REPLACER_CONFIG=false \ + \ + \ + SERVER_GAMEMODE="" + +COPY ["prepareServer.sh", "initConfig.sh", "forceWorkshopDownload.sh", "installAndMountAddons.sh", "/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 diff --git a/gmod/forceWorkshopDownload.sh b/gmod/forceWorkshopDownload.sh new file mode 100644 index 0000000..0648b76 --- /dev/null +++ b/gmod/forceWorkshopDownload.sh @@ -0,0 +1,34 @@ +#!/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" = "" ]; 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 + diff --git a/gmod/initConfig.sh b/gmod/initConfig.sh new file mode 100644 index 0000000..0b9a103 --- /dev/null +++ b/gmod/initConfig.sh @@ -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 + diff --git a/gmod/installAndMountAddons.sh b/gmod/installAndMountAddons.sh new file mode 100644 index 0000000..d62e460 --- /dev/null +++ b/gmod/installAndMountAddons.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +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 + echo "installing & mounting css" + ./steamcmd.sh +login anonymous +force_install_dir "$CSS_PATH" +app_update 232330 validate +quit + mount=${mount}' "cstrike" "'"${CSS_PATH}/cstrike"$'"\n' + if [ "$INSTALL_HL2" != "true" ]; then + mount=${mount}' "hl2" "'"${CSS_PATH}/hl2"$'"\n' + fi +fi +if [ "$INSTALL_HL2" = "true" ]; then + echo "installing & mounting hl2" + ./steamcmd.sh +login anonymous +force_install_dir "$HL2_PATH" +app_update 232370 validate +quit + mount=${mount}' "hl2" "'"${HL2_PATH}/hl2"$'"\n' + mount=${mount}' "hl2mp" "'"${HL2_PATH}/hl2mp"$'"\n' +fi +if [ "$INSTALL_TF2" = "true" ]; then + echo "installing & mounting tf2" + ./steamcmd.sh +login anonymous +force_install_dir "$TF2_PATH" +app_update 232250 validate +quit + mount=${mount}' "tf2" "'"${TF2_PATH}/tf"$'"\n' + if [ "$INSTALL_CSS" != "true" ] && [ "$INSTALL_HL2" != "true" ]; then + mount=${mount}' "hl2" "'"${TF2_PATH}/hl2"$'"\n' + fi +fi +if [ "$INSTALL_HLDM" = "true" ]; then + echo "installing & mounting hldm" + ./steamcmd.sh +login anonymous +force_install_dir "$HLDM_PATH" +app_update 255470 validate +quit + mount=${mount}' "hl1" "'"${HLDM_PATH}/hl1"$'"\n' + mount=${mount}' "hldm" "'"${HLDM_PATH}/hldm"$'"\n' + if [ "$INSTALL_CSS" != "true" ] && [ "$INSTALL_HL2" != "true" ] && [ "$INSTALL_TF2" != "true" ]; then + mount=${mount}' "hl2" "'"${HLDM_PATH}/hl2"$'"\n' + fi +fi +mount=${mount}$'}\n' + + +if [ ! -e "${SERVER_PATH}/garrysmod/cfg" ]; then + mkdir -p "${SERVER_PATH}/garrysmod/cfg" +fi +if [ -e "${SERVER_PATH}/garrysmod/cfg/mount.cfg" ]; then + rm "${SERVER_PATH}/garrysmod/cfg/mount.cfg" +fi +touch "${SERVER_PATH}/garrysmod/cfg/mount.cfg" +echo "$mount" > "${SERVER_PATH}/garrysmod/cfg/mount.cfg" + diff --git a/gmod/prepareServer.sh b/gmod/prepareServer.sh new file mode 100644 index 0000000..bdd5218 --- /dev/null +++ b/gmod/prepareServer.sh @@ -0,0 +1,33 @@ +#!/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 + +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" \ No newline at end of file diff --git a/lgsm/Dockerfile b/lgsm/Dockerfile new file mode 100644 index 0000000..b433dcb --- /dev/null +++ b/lgsm/Dockerfile @@ -0,0 +1,64 @@ +FROM debian:stretch + +# 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 \ + \ + \ + 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"] + +COPY ["entrypoint.sh", "initCron.sh", "/home/"] + +# procps needed for ps command +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 \ + locales procps && \ + \ + 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 && \ + sed -i 's/# en_US.UTF-8/en_US.UTF-8/' /etc/locale.gen && \ + locale-gen && \ + \ + 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 + diff --git a/lgsm/entrypoint.sh b/lgsm/entrypoint.sh new file mode 100644 index 0000000..2f954c6 --- /dev/null +++ b/lgsm/entrypoint.sh @@ -0,0 +1,81 @@ +#!/bin/bash + +if [ "${DEBUGGING}" = "true" ]; then + set -o xtrace +fi + +set -o errexit +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 + + + + + + +# --- Apply LGSM Workarounds --- +#force fetch of command_console.sh +if [ ! -e "${STEAM_PATH}/lgsm/functions/command_console.sh" ]; then + wget -O "${STEAM_PATH}/lgsm/functions/command_console.sh" "https://raw.githubusercontent.com/GameServerManagers/LinuxGSM/master/lgsm/functions/command_console.sh" + chmod +x "${STEAM_PATH}/lgsm/functions/command_console.sh" +fi +#skip confirmation +sed -i 's/! fn_prompt_yn "Continue?" Y/[ "1" != "1" ]/' "${STEAM_PATH}/lgsm/functions/command_console.sh" + + + + + +# --- 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" +} +./"$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 \ No newline at end of file diff --git a/lgsm/initCron.sh b/lgsm/initCron.sh new file mode 100644 index 0000000..218cd10 --- /dev/null +++ b/lgsm/initCron.sh @@ -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" & \ No newline at end of file diff --git a/test/testBuild.sh b/test/testBuild.sh new file mode 100644 index 0000000..b644427 --- /dev/null +++ b/test/testBuild.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +if [ "${DEBUGGING:?}" = "true" ]; then + set -o xtrace +fi + +set -o errexit +set -o nounset +set -o pipefail + +docker rmi "jusito/docker-ttt:ubuntu" || true +docker build -t "jusito/docker-ttt:ubuntu" "." \ No newline at end of file diff --git a/test/testCaseQuick.sh b/test/testCaseQuick.sh new file mode 100644 index 0000000..4a2d515 --- /dev/null +++ b/test/testCaseQuick.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +if [ "${DEBUGGING}" = "true" ]; then + set -o xtrace +fi + +set -o errexit +set -o nounset +set -o pipefail + +#bash test/testStyle.sh + +echo "[testBuild][INFO]build docker-ttt:ubuntu" +docker rmi "jusito/docker-ttt:ubuntu" || true +docker build -t "jusito/docker-ttt:ubuntu" "." +echo "[testRun][INFO]running docker-ttt:ubuntu" +if ! docker run -ti --name "JusitoTesting" --rm -e TEST_MODE=true -e DEBUGGING="${DEBUGGING}" "jusito/docker-ttt:ubuntu"; then + echo "[testRun][ERROR]run test failed for docker-ttt:ubuntu" + exit 1 +fi +docker stop "JusitoTesting" || true +docker rm "JusitoTesting" || true \ No newline at end of file diff --git a/test/testCaseQuick2.sh b/test/testCaseQuick2.sh new file mode 100644 index 0000000..d60c024 --- /dev/null +++ b/test/testCaseQuick2.sh @@ -0,0 +1,33 @@ +#!/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" "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 \ No newline at end of file diff --git a/test/testHealth.sh b/test/testHealth.sh new file mode 100644 index 0000000..a09c63f --- /dev/null +++ b/test/testHealth.sh @@ -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 \ No newline at end of file diff --git a/test/testRun.sh b/test/testRun.sh new file mode 100644 index 0000000..8959e2a --- /dev/null +++ b/test/testRun.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +if [ "${DEBUGGING:?}" = "true" ]; then + set -o xtrace +fi + +set -o errexit +set -o nounset +set -o pipefail + +docker stop "JusitoTesting" || true +docker rm "JusitoTesting" || true + +echo "[testRun][INFO]running docker-ttt:ubuntu" +if ! docker run -ti --name "JusitoTesting" --rm -e TEST_MODE=true -e DEBUGGING="${DEBUGGING}" "jusito/docker-ttt:ubuntu"; then + echo "[testRun][ERROR]run test failed for docker-ttt:ubuntu" + exit 1 +fi +docker stop "JusitoTesting" || true +docker rm "JusitoTesting" || true \ No newline at end of file diff --git a/test/testStyle.sh b/test/testStyle.sh new file mode 100644 index 0000000..8d26c9f --- /dev/null +++ b/test/testStyle.sh @@ -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 \ No newline at end of file From e45478f9f401a88f6694936e51b677f8221a59cd Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Sun, 21 Jul 2019 23:04:39 +0200 Subject: [PATCH 02/13] - removed old files / testing files --- Dockerfile | 62 ------------------------ entrypoint.sh | 68 -------------------------- experimental.sh | 55 --------------------- forceWorkshopDownload.sh | 28 ----------- installAndMountAddons.sh | 48 ------------------- server.cfg | 101 --------------------------------------- 6 files changed, 362 deletions(-) delete mode 100644 Dockerfile delete mode 100644 entrypoint.sh delete mode 100644 experimental.sh delete mode 100644 forceWorkshopDownload.sh delete mode 100644 installAndMountAddons.sh delete mode 100644 server.cfg diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 3ccc9ef..0000000 --- a/Dockerfile +++ /dev/null @@ -1,62 +0,0 @@ -FROM debian:stretch - -EXPOSE 27015/udp 27015/tcp - -ENV STEAM_PATH="/home/steam" \ - SERVER_PATH="/home/steam/serverfiles" \ - STEAM_CMD="/home/steam/steamcmd" \ - GROUP_ID=10000 \ - USER_ID=10000 \ - DOCKER_USER=steam \ - \ - WORKSHOP_COLLECTION_ID= \ - SERVER_NAME="" \ - SERVER_PASSWORD="" \ - SERVER_VOICE_ENABLE="1" \ - \ - INSTALL_CSS=false \ - INSTALL_HL2=false \ - INSTALL_HLDM=false \ - INSTALL_TF2=false \ - \ - CSS_PATH="/home/steam/addons/css" \ - HL2_PATH="/home/steam/addons/hl2" \ - HLDM_PATH="/home/steam/addons/hldm" \ - TF2_PATH="/home/steam/addons/tf2" \ - \ - USE_MY_REPLACER_CONFIG=false \ - DEBIAN_FRONTEND=noninteractive - -ENTRYPOINT ["./home/entrypoint.sh"] - -COPY ["entrypoint.sh", "experimental.sh", "forceWorkshopDownload.sh", "installAndMountAddons.sh", "/home/"] - -# removed dep. lib32gcc1 libtcmalloc-minimal4:i386 gdb -#sudo dpkg --add-architecture i386; -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 \ - locales sudo cron && \ - \ - 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 && \ - sudo -u "$DOCKER_USER" mkdir -p "$SERVER_PATH" && \ - chown -R "$DOCKER_USER:$DOCKER_USER" "$STEAM_PATH" && \ - chmod a=rx /home/entrypoint.sh && \ - chmod a=rx /home/experimental.sh && \ - chmod a=rx /home/forceWorkshopDownload.sh && \ - chmod a=rx /home/installAndMountAddons.sh && \ - \ - ulimit -n 2048 && \ - sed -i 's/# en_US.UTF-8/en_US.UTF-8/' /etc/locale.gen && \ - locale-gen && \ - \ - wget -O "$STEAM_PATH/linuxgsm.sh" "https://linuxgsm.sh" && \ - chown "$DOCKER_USER:$DOCKER_USER" "$STEAM_PATH/linuxgsm.sh" && \ - chmod +x "$STEAM_PATH/linuxgsm.sh" - -USER "$USER_ID:$GROUP_ID" - -VOLUME "$SERVER_PATH" diff --git a/entrypoint.sh b/entrypoint.sh deleted file mode 100644 index 54d04d0..0000000 --- a/entrypoint.sh +++ /dev/null @@ -1,68 +0,0 @@ -#!/bin/bash - -sleep 2s -echo "starting entrypoint.sh" -set -e - -cd "$STEAM_PATH" -#suggested -disableluarefresh -tickrate 66 +host_workshop_collection -port 27015 - -if [ -e "${STEAM_PATH}/gmodserver" ]; then - ./gmodserver update-lgsm - ./gmodserver update -else - bash linuxgsm.sh gmodserver - ./gmodserver auto-install -fi - -cd "/home" -echo "check various options" -./experimental.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 +gamemode terrortown $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" - -#force fetch of command_console.sh -if [ ! -e "${STEAM_PATH}/lgsm/functions/command_console.sh" ]; then - wget -O "${STEAM_PATH}/lgsm/functions/command_console.sh" "https://raw.githubusercontent.com/GameServerManagers/LinuxGSM/master/lgsm/functions/command_console.sh" - chmod +x "${STEAM_PATH}/lgsm/functions/command_console.sh" -fi -#skip confirmation -sed -i 's/! fn_prompt_yn "Continue?" Y/[ "1" != "1" ]/' "${STEAM_PATH}/lgsm/functions/command_console.sh" - -#start server -IS_RUNNING="true" -function stopServer() { - echo "stopping server..." - cd "${STEAM_PATH}" - kill -2 "$(pidof srcds_linux)" || true - kill -2 "$(pidof srcds_run)" || true - echo "server stopped!" - echo "stopping entrypoint..." - IS_RUNNING="false" -} -./gmodserver start -trap stopServer SIGTERM -echo "Server is running, waiting for SIGTERM" -while [ "$IS_RUNNING" = "true" ] -do - sleep 1s -done -echo "entrypoint stopped" -exit 0 \ No newline at end of file diff --git a/experimental.sh b/experimental.sh deleted file mode 100644 index e4f0fd4..0000000 --- a/experimental.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/bash - -set -e - -function configReplace() { - source="$1" - target="$source \"$2\"" - #grep -c would be nicer - # shellcheck disable=SC2126 - count=$(grep -Po "($source).+" "${SERVER_PATH}/garrysmod/cfg/server.cfg" | wc -l) - - 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" -#grep -c would be nicer -# shellcheck disable=SC2126 -if [ ! -e "${SERVER_PATH}/garrysmod/cfg/server.cfg" ] || [ "0" = "$(grep -o '[^[:space:]]' "${SERVER_PATH}/garrysmod/cfg/server.cfg" | wc -l)" ]; then - mkdir -p "${SERVER_PATH}/garrysmod/cfg" - wget -O "${SERVER_PATH}/garrysmod/cfg/server.cfg" "https://raw.githubusercontent.com/jusito/docker-ttt/master/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 - diff --git a/forceWorkshopDownload.sh b/forceWorkshopDownload.sh deleted file mode 100644 index b64668a..0000000 --- a/forceWorkshopDownload.sh +++ /dev/null @@ -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 - diff --git a/installAndMountAddons.sh b/installAndMountAddons.sh deleted file mode 100644 index 121308a..0000000 --- a/installAndMountAddons.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash - -set -e -cd "$STEAM_CMD" -mount='"mountcfg"'$'\n{\n' -if [ "$INSTALL_CSS" = "true" ]; then - echo "installing & mounting css" - ./steamcmd.sh +login anonymous +force_install_dir "$CSS_PATH" +app_update 232330 validate +quit - mount=${mount}' "cstrike" "'"${CSS_PATH}/cstrike"$'"\n' - if [ "$INSTALL_HL2" != "true" ]; then - mount=${mount}' "hl2" "'"${CSS_PATH}/hl2"$'"\n' - fi -fi -if [ "$INSTALL_HL2" = "true" ]; then - echo "installing & mounting hl2" - ./steamcmd.sh +login anonymous +force_install_dir "$HL2_PATH" +app_update 232370 validate +quit - mount=${mount}' "hl2" "'"${HL2_PATH}/hl2"$'"\n' - mount=${mount}' "hl2mp" "'"${HL2_PATH}/hl2mp"$'"\n' -fi -if [ "$INSTALL_TF2" = "true" ]; then - echo "installing & mounting tf2" - ./steamcmd.sh +login anonymous +force_install_dir "$TF2_PATH" +app_update 232250 validate +quit - mount=${mount}' "tf2" "'"${TF2_PATH}/tf"$'"\n' - if [ "$INSTALL_CSS" != "true" ] && [ "$INSTALL_HL2" != "true" ]; then - mount=${mount}' "hl2" "'"${TF2_PATH}/hl2"$'"\n' - fi -fi -if [ "$INSTALL_HLDM" = "true" ]; then - echo "installing & mounting hldm" - ./steamcmd.sh +login anonymous +force_install_dir "$HLDM_PATH" +app_update 255470 validate +quit - mount=${mount}' "hl1" "'"${HLDM_PATH}/hl1"$'"\n' - mount=${mount}' "hldm" "'"${HLDM_PATH}/hldm"$'"\n' - if [ "$INSTALL_CSS" != "true" ] && [ "$INSTALL_HL2" != "true" ] && [ "$INSTALL_TF2" != "true" ]; then - mount=${mount}' "hl2" "'"${HLDM_PATH}/hl2"$'"\n' - fi -fi -mount=${mount}$'}\n' - - -if [ ! -e "${SERVER_PATH}/garrysmod/cfg" ]; then - mkdir -p "${SERVER_PATH}/garrysmod/cfg" -fi -if [ -e "${SERVER_PATH}/garrysmod/cfg/mount.cfg" ]; then - rm "${SERVER_PATH}/garrysmod/cfg/mount.cfg" -fi -touch "${SERVER_PATH}/garrysmod/cfg/mount.cfg" -echo "$mount" > "${SERVER_PATH}/garrysmod/cfg/mount.cfg" - diff --git a/server.cfg b/server.cfg deleted file mode 100644 index d868572..0000000 --- a/server.cfg +++ /dev/null @@ -1,101 +0,0 @@ -hostname "" -sv_password "" -sv_voiceenable 0 - -sv_contact "unknown" - - -// rcon passsword -sv_rcon_banpenalty 5 -sv_rcon_maxfailures 3 - -//DNA -ttt_killer_dna_range 300 -ttt_killer_dna_basetime 100 - - -//Prep -ttt_firstpreptime 60 -ttt_preptime_seconds 30 -ttt_posttime_seconds 3 - - -//Round length -ttt_haste 0 -// ttt_haste_starting_minutes 5 -// ttt_haste_minutes_per_death 0.5 - -ttt_roundtime_minutes 10 - - - -//Map Switching -ttt_round_limit 10 -ttt_time_limit_minutes 75 - -//ttt_always_use_mapcycle 0 - - -//Player Counts -ttt_minimum_players 2 -ttt_traitor_pct 0.4 -ttt_traitor_max 32 -ttt_detective_pct 0.1 -ttt_detective_max 32 -ttt_detective_min_players 6 -ttt_detective_karma_min 600 - - -//Karma -ttt_karma 1 -ttt_karma_strict 1 -ttt_karma_starting 1000 -ttt_karma_max 1000 -ttt_karma_ratio 0.001 -ttt_karma_kill_penalty 50 -ttt_karma_round_increment 5 -ttt_karma_clean_bonus 30 -ttt_karma_traitordmg_ratio 0.0003 -ttt_karma_traitorkill_bonus 100 -ttt_karma_low_autokick 1 -ttt_karma_low_amount 300 -ttt_karma_low_ban 0 -ttt_karma_low_ban_minutes 60 -ttt_karma_persist 1 -ttt_karma_clean_half 0.25 - -//Other -ttt_postround_dm 0 -ttt_no_nade_throw_during_prep 0 -ttt_weapon_carrying 1 -ttt_weapon_carrying_range 50 -ttt_teleport_telefrags 1 -ttt_ragdoll_pinning 1 -ttt_ragdoll_pinning_innocents 1 -ttt_use_weapon_spawn_scripts 1 -ttt_spawn_wave_interval 2 -ttt_allow_discomb_jump 1 -ttt_debug_preventwin 0 - -// server logging -log on -sv_logbans 1 -sv_logecho 1 -sv_logfile 0 -sv_log_onefile 0 - -// operation -sv_lan 0 -sv_region 3 //Europa - -// traitor -ttt_credits_detectivekill 2 -ttt_credits_award_repeat 0.5 - -// fastdl -sv_allowdownload 1 -sv_allowupload 0 -// sv_downloadurl "your url" - -exec banned_user.cfg -exec banned_ip.cfg \ No newline at end of file From bd5fdd60415c5aa7977e641535ca2d1983abefdf Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Sun, 21 Jul 2019 23:04:51 +0200 Subject: [PATCH 03/13] - removed testing files --- cronTest/Dockerfile | 56 ------------------------------------------ cronTest/entrypoint.sh | 17 ------------- cronTest/initCron.sh | 16 ------------ 3 files changed, 89 deletions(-) delete mode 100644 cronTest/Dockerfile delete mode 100644 cronTest/entrypoint.sh delete mode 100644 cronTest/initCron.sh diff --git a/cronTest/Dockerfile b/cronTest/Dockerfile deleted file mode 100644 index a7894be..0000000 --- a/cronTest/Dockerfile +++ /dev/null @@ -1,56 +0,0 @@ -FROM debian:stretch - -# 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 \ - \ - \ - DEBUGGING=false \ - CRON_MONITOR="*/5 * * * *" \ - CRON_UPDATE="*/30 * * * *" \ - CRON_FORCE_UPDATE="0 10 * * 0" \ - \ - \ - SERVER_EXECUTABLE="" \ - SERVER_GAME="" \ - TZ="US/Eastern" -#https://en.wikipedia.org/wiki/List_of_tz_database_time_zones - -ENTRYPOINT ["./home/entrypoint.sh"] - -COPY ["entrypoint.sh", "initCron.sh", "/home/"] - -RUN dpkg --add-architecture i386 && \ - apt-get update -y && \ - apt-get install -y locales sudo curl && \ - \ - 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 && \ - sudo -u "$DOCKER_USER" 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 && \ - sed -i 's/# en_US.UTF-8/en_US.UTF-8/' /etc/locale.gen && \ - locale-gen && \ - \ - \ - curl -fsSLO "$SUPERCRONIC_URL" && \ - echo "${SUPERCRONIC_SHA1SUM} ${SUPERCRONIC}" | sha1sum -c - && \ - chmod a+rx "$SUPERCRONIC" && \ - mv "$SUPERCRONIC" "/usr/local/bin/${SUPERCRONIC}" && \ - ln -s "/usr/local/bin/${SUPERCRONIC}" /usr/local/bin/supercronic - diff --git a/cronTest/entrypoint.sh b/cronTest/entrypoint.sh deleted file mode 100644 index 2824d96..0000000 --- a/cronTest/entrypoint.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -if [ "${DEBUGGING}" = "true" ]; then - set -o xtrace -fi - -set -o errexit -set -o pipefail - -echo "starting entrypoint.sh" -set -e - - -#start cron -bash "/home/initCron.sh" - -exec /bin/bash \ No newline at end of file diff --git a/cronTest/initCron.sh b/cronTest/initCron.sh deleted file mode 100644 index 9dc601d..0000000 --- a/cronTest/initCron.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -if [ "${DEBUGGING}" = "true" ]; then - set -o xtrace -fi - -set -o errexit -set -o pipefail -set -o nounset - -#set up cronjob -rm -f "$STEAM_PATH/lgsm-cronjobs" || true -touch "$STEAM_PATH/lgsm-cronjobs" -# false positive -echo "*/1 * * * * date >> date.log" >> "$STEAM_PATH/lgsm-cronjobs" # out on release -echo "" >> "$STEAM_PATH/lgsm-cronjobs" From dca294b01ee726d7ad4d96b617b278d29650ecaa Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Sun, 21 Jul 2019 23:20:03 +0200 Subject: [PATCH 04/13] - cleanup tests --- test/testBuild.sh | 12 ------------ test/testCaseQuick.sh | 21 ++++++++++++++++----- test/testCaseQuick2.sh | 33 --------------------------------- test/testRun.sh | 20 -------------------- 4 files changed, 16 insertions(+), 70 deletions(-) delete mode 100644 test/testBuild.sh delete mode 100644 test/testCaseQuick2.sh delete mode 100644 test/testRun.sh diff --git a/test/testBuild.sh b/test/testBuild.sh deleted file mode 100644 index b644427..0000000 --- a/test/testBuild.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -if [ "${DEBUGGING:?}" = "true" ]; then - set -o xtrace -fi - -set -o errexit -set -o nounset -set -o pipefail - -docker rmi "jusito/docker-ttt:ubuntu" || true -docker build -t "jusito/docker-ttt:ubuntu" "." \ No newline at end of file diff --git a/test/testCaseQuick.sh b/test/testCaseQuick.sh index 4a2d515..d60c024 100644 --- a/test/testCaseQuick.sh +++ b/test/testCaseQuick.sh @@ -2,6 +2,8 @@ if [ "${DEBUGGING}" = "true" ]; then set -o xtrace +else + DEBUGGING="false" fi set -o errexit @@ -10,11 +12,20 @@ set -o pipefail #bash test/testStyle.sh -echo "[testBuild][INFO]build docker-ttt:ubuntu" -docker rmi "jusito/docker-ttt:ubuntu" || true -docker build -t "jusito/docker-ttt:ubuntu" "." -echo "[testRun][INFO]running docker-ttt:ubuntu" -if ! docker run -ti --name "JusitoTesting" --rm -e TEST_MODE=true -e DEBUGGING="${DEBUGGING}" "jusito/docker-ttt:ubuntu"; then +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" "jusito/docker-ttt:gmod_ttt_debian"; then echo "[testRun][ERROR]run test failed for docker-ttt:ubuntu" exit 1 fi diff --git a/test/testCaseQuick2.sh b/test/testCaseQuick2.sh deleted file mode 100644 index d60c024..0000000 --- a/test/testCaseQuick2.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/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" "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 \ No newline at end of file diff --git a/test/testRun.sh b/test/testRun.sh deleted file mode 100644 index 8959e2a..0000000 --- a/test/testRun.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -if [ "${DEBUGGING:?}" = "true" ]; then - set -o xtrace -fi - -set -o errexit -set -o nounset -set -o pipefail - -docker stop "JusitoTesting" || true -docker rm "JusitoTesting" || true - -echo "[testRun][INFO]running docker-ttt:ubuntu" -if ! docker run -ti --name "JusitoTesting" --rm -e TEST_MODE=true -e DEBUGGING="${DEBUGGING}" "jusito/docker-ttt:ubuntu"; then - echo "[testRun][ERROR]run test failed for docker-ttt:ubuntu" - exit 1 -fi -docker stop "JusitoTesting" || true -docker rm "JusitoTesting" || true \ No newline at end of file From 8672c0f382af4fcb5bb206e84f5a60b5d4b5a666 Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Tue, 23 Jul 2019 12:30:30 +0200 Subject: [PATCH 05/13] - removed not needed files --- .travis.yml | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 5b5050d..0000000 --- a/.travis.yml +++ /dev/null @@ -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" \ No newline at end of file From 1bc86b7422d7f88ef9b11f1d198926a1a6382866 Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Tue, 23 Jul 2019 12:31:15 +0200 Subject: [PATCH 06/13] + minimize image size -locales stretch to stretch-slim --- lgsm/Dockerfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lgsm/Dockerfile b/lgsm/Dockerfile index b433dcb..5b980f1 100644 --- a/lgsm/Dockerfile +++ b/lgsm/Dockerfile @@ -1,4 +1,4 @@ -FROM debian:stretch +FROM debian:stretch-slim # Const \\ Overwrite Env \\ Configs possible \\ Configs needed ENV STEAM_PATH="/home/steam" \ @@ -13,6 +13,8 @@ ENV STEAM_PATH="/home/steam" \ \ \ DEBIAN_FRONTEND=noninteractive \ + LANG=C.UTF-8 \ + TERM=xterm \ \ \ DEBUGGING=false \ @@ -36,7 +38,7 @@ 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 \ - locales procps && \ + procps iproute2 && \ \ groupadd -g $GROUP_ID $DOCKER_USER && \ useradd -d "$STEAM_PATH" -g $GROUP_ID -u $USER_ID -m $DOCKER_USER && \ @@ -48,8 +50,6 @@ RUN dpkg --add-architecture i386 && \ chmod a=rx /home/initCron.sh && \ \ ulimit -n 2048 && \ - sed -i 's/# en_US.UTF-8/en_US.UTF-8/' /etc/locale.gen && \ - locale-gen && \ \ wget -O "$STEAM_PATH/linuxgsm.sh" "https://linuxgsm.sh" && \ chown "$DOCKER_USER:$DOCKER_USER" "$STEAM_PATH/linuxgsm.sh" && \ From c349bdc2598e31b5803537dedd97595eb224a746 Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Mon, 29 Jul 2019 21:51:34 +0200 Subject: [PATCH 07/13] + use lgsm for config (looks working) --- gmod/common.cfg | 162 ++++++++++++++++++++++++++++++++++++++++++ gmod/prepareServer.sh | 3 + 2 files changed, 165 insertions(+) create mode 100644 gmod/common.cfg diff --git a/gmod/common.cfg b/gmod/common.cfg new file mode 100644 index 0000000..dcf08f5 --- /dev/null +++ b/gmod/common.cfg @@ -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" \ No newline at end of file diff --git a/gmod/prepareServer.sh b/gmod/prepareServer.sh index bdd5218..8ecba73 100644 --- a/gmod/prepareServer.sh +++ b/gmod/prepareServer.sh @@ -9,6 +9,9 @@ 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 From 1f85a9a406946fea549a54244ede2a865afde386 Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Mon, 29 Jul 2019 21:51:58 +0200 Subject: [PATCH 08/13] + added info --- lgsm/Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lgsm/Dockerfile b/lgsm/Dockerfile index 5b980f1..6456419 100644 --- a/lgsm/Dockerfile +++ b/lgsm/Dockerfile @@ -30,10 +30,13 @@ ENV STEAM_PATH="/home/steam" \ #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 \ From 789195d2d90c2b935b9be68e1862dbc277f3cc86 Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Mon, 29 Jul 2019 21:52:25 +0200 Subject: [PATCH 09/13] + added lgsm config variables --- TTT/Dockerfile | 2 +- gmod/Dockerfile | 61 +++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/TTT/Dockerfile b/TTT/Dockerfile index ba294aa..a120c8a 100644 --- a/TTT/Dockerfile +++ b/TTT/Dockerfile @@ -1,6 +1,6 @@ FROM jusito/docker-ttt:gmod_debian -ENV SERVER_GAMEMODE="+gamemode terrortown" +ENV SERVER_GAMEMODE="terrortown" COPY "server.cfg.default" "/home/server.cfg.default" diff --git a/gmod/Dockerfile b/gmod/Dockerfile index 0dc514a..08b477a 100644 --- a/gmod/Dockerfile +++ b/gmod/Dockerfile @@ -1,8 +1,6 @@ FROM jusito/docker-ttt:lgsm_debian -EXPOSE 27015/udp 27015/tcp - -# Const \\ Overwrite Env \\ Configs optional \\ Configs needed +# Const \\ Overwrite Env \\ Configs optional ENV CSS_PATH="/home/steam/addons/css" \ HL2_PATH="/home/steam/addons/hl2" \ HLDM_PATH="/home/steam/addons/hldm" \ @@ -13,22 +11,67 @@ ENV CSS_PATH="/home/steam/addons/css" \ SERVER_GAME="gmodserver" \ \ \ - WORKSHOP_COLLECTION_ID= \ + 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 \ - \ - \ - SERVER_GAMEMODE="" + USE_MY_REPLACER_CONFIG=false + -COPY ["prepareServer.sh", "initConfig.sh", "forceWorkshopDownload.sh", "installAndMountAddons.sh", "/home/"] +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 && \ From 6c65b855a596e0fd6c4b0a779cc2e18316e6d97b Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Mon, 29 Jul 2019 21:53:26 +0200 Subject: [PATCH 10/13] - removed testing vars + -o nounset --- lgsm/entrypoint.sh | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/lgsm/entrypoint.sh b/lgsm/entrypoint.sh index 2f954c6..4888c51 100644 --- a/lgsm/entrypoint.sh +++ b/lgsm/entrypoint.sh @@ -5,6 +5,7 @@ if [ "${DEBUGGING}" = "true" ]; then fi set -o errexit +set -o nounset set -o pipefail echo "starting entrypoint.sh" @@ -27,7 +28,7 @@ fi if [ -e "/home/prepareServer.sh" ]; then cd /home - ./prepareServer.sh + ./prepareServer.sh "$@" cd "$STEAM_PATH" fi @@ -36,19 +37,6 @@ fi -# --- Apply LGSM Workarounds --- -#force fetch of command_console.sh -if [ ! -e "${STEAM_PATH}/lgsm/functions/command_console.sh" ]; then - wget -O "${STEAM_PATH}/lgsm/functions/command_console.sh" "https://raw.githubusercontent.com/GameServerManagers/LinuxGSM/master/lgsm/functions/command_console.sh" - chmod +x "${STEAM_PATH}/lgsm/functions/command_console.sh" -fi -#skip confirmation -sed -i 's/! fn_prompt_yn "Continue?" Y/[ "1" != "1" ]/' "${STEAM_PATH}/lgsm/functions/command_console.sh" - - - - - # --- Start Server --- #start server IS_RUNNING="true" @@ -60,8 +48,9 @@ function stopServer() { echo "server stopped!" echo "stopping entrypoint..." IS_RUNNING="false" + echo "done!" } -./"$SERVER_EXECUTABLE" start +./"$SERVER_EXECUTABLE" start & trap stopServer SIGTERM #start cron From 45b4d0235b6cb176dfc27871234c9c9a4555677b Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Mon, 29 Jul 2019 21:53:55 +0200 Subject: [PATCH 11/13] = fix, shellcheck false positive --- gmod/forceWorkshopDownload.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/gmod/forceWorkshopDownload.sh b/gmod/forceWorkshopDownload.sh index 0648b76..edb132f 100644 --- a/gmod/forceWorkshopDownload.sh +++ b/gmod/forceWorkshopDownload.sh @@ -19,13 +19,15 @@ else mkdir -p "$LUA_PATH" fi -if [ "$WORKSHOP_COLLECTION_ID" = "0" ] || [ "$WORKSHOP_COLLECTION_ID" = "" ]; then - echo "given ID is default, no workshop download" +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="" - for i in "${arr[@]}" + # resplitting needed here, otherwise one string with complete ids + # shellcheck disable=SC2068 + for i in ${arr[@]} do str=${str}"resource.AddWorkshop( \"${i}\" )"$'\n' done From 931305705e87ddbd4d44582585fa49f94ab5eb49 Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Mon, 29 Jul 2019 21:54:31 +0200 Subject: [PATCH 12/13] + test try to change details with lgsm --- test/testCaseQuick.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/testCaseQuick.sh b/test/testCaseQuick.sh index d60c024..85876d5 100644 --- a/test/testCaseQuick.sh +++ b/test/testCaseQuick.sh @@ -25,9 +25,11 @@ 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" "jusito/docker-ttt:gmod_ttt_debian"; then +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 \ No newline at end of file +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" \ No newline at end of file From 6012948575a1b6b95f58046591a249939bd1fcc6 Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Mon, 29 Jul 2019 21:55:01 +0200 Subject: [PATCH 13/13] ~ temp commit, working on readme & apparmor --- README.md | 78 +++++++++++++++++++++++++---- apparmor/JusitoGmod | 69 +++++++++++++++++++++++++ apparmor/generateAppArmorProfile.sh | 12 +++++ 3 files changed, 148 insertions(+), 11 deletions(-) create mode 100644 apparmor/JusitoGmod create mode 100644 apparmor/generateAppArmorProfile.sh diff --git a/README.md b/README.md index 8d5b0d9..8013440 100644 --- a/README.md +++ b/README.md @@ -2,20 +2,75 @@ GMOD TTT server image, https://hub.docker.com/r/jusito/ ## TODO -- use readme template -- force cleanup of downloaded elements => removed workshop elements are otherwise used +* 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 -## run example -``` -docker run -d -p 27015:27015/tcp -p 27015:27015/udp -e WORKSHOP_COLLECTION_ID=123456 -e INSTALL_CSS=true "jusito/docker-ttt" +host_workshop_collection 123456 +map ttt_rooftops_2016_v1 -maxplayers -``` --d exit if entrypoint exits -tcp port for rcon, if you want to use it start with -usercon +rcon_password "yourPW" -udp port for game traffic +## Getting Started +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` -## access console +### run example without rcon +``` +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 +``` + +### 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 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= @@ -40,6 +95,7 @@ docker cp "your server.cfg path" CONTAINER:/home/steam/serverfiles/garrysmod/cfg ## Additional - +- 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 diff --git a/apparmor/JusitoGmod b/apparmor/JusitoGmod new file mode 100644 index 0000000..a6335b1 --- /dev/null +++ b/apparmor/JusitoGmod @@ -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//** 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}} +} \ No newline at end of file diff --git a/apparmor/generateAppArmorProfile.sh b/apparmor/generateAppArmorProfile.sh new file mode 100644 index 0000000..822b801 --- /dev/null +++ b/apparmor/generateAppArmorProfile.sh @@ -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' +