Add more interactive functionality: Login, update, rcon, etc. All WIPs.

Simplify things by consolidating all the bash stuff into dayzserver and removing files where the content has become managed interactively.
Make sure steamcmd has proper permissions in the container.
More updated documentation.
This commit is contained in:
Daniel Ceregatti 2022-03-26 16:37:39 -07:00
parent d87c5fad0e
commit 164d5b41d6
8 changed files with 249 additions and 122 deletions

View file

@ -33,9 +33,10 @@ ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8 ENV LC_ALL en_US.UTF-8
# Add steamcmd to the image # Add steamcmd to the image.
RUN mkdir -p /steamcmd && \ RUN mkdir -p /steamcmd && \
curl -sqL "https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz" | tar zxf - -C steamcmd cd /steamcmd && \
curl -sqL "https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz" | tar zxf -
# Make our docker scripts easier to run # Make our docker scripts easier to run
ENV PATH /files:/steamcmd:${PATH} ENV PATH /files:/steamcmd:${PATH}
@ -47,6 +48,9 @@ RUN groupadd user && \
# The volume needs to be owned by the user # The volume needs to be owned by the user
RUN cd /home/user; rm -rf *; rm -rf .*; chown user:user /home/user -R RUN cd /home/user; rm -rf *; rm -rf .*; chown user:user /home/user -R
# SteamCMD wants to manage itself, so it has to be owned by the docker user.
RUN chown user:user /steamcmd -R
# Use our non-privileged user # Use our non-privileged user
USER user USER user

View file

@ -14,7 +14,7 @@ moment. Only the [DayZ Experimental client](https://dayz.fandom.com/wiki/Experim
This process will create a docker volume for the unprivileged user's home directory, which stores the DayZ server files. This process will create a docker volume for the unprivileged user's home directory, which stores the DayZ server files.
This volume can get quite large. It will require at least 2G of disk space for the default install. Much more with mods. This volume can get quite large. It will require at least 2G of disk space for the default install. Much more with mods.
## Setup, Build. and Configure ## Configure and Build
Edit `files/serverDZ.cfg` and set the values of any variables there. Edit `files/serverDZ.cfg` and set the values of any variables there.
See the [documentation](https://forums.dayz.com/topic/239635-dayz-server-files-documentation/): See the [documentation](https://forums.dayz.com/topic/239635-dayz-server-files-documentation/):
@ -22,53 +22,75 @@ See the [documentation](https://forums.dayz.com/topic/239635-dayz-server-files-d
``` ```
hostname = "Something other than Server Name"; // Server name hostname = "Something other than Server Name"; // Server name
``` ```
Optionally edit `files/beserver_x64.cfg` and set the RCON password: Optionally edit `files/beserver_x64.cfg` and set the RCON password (leaving the other lines intact):
``` ```
RConPassword h4CKm3 RConPassword h4CKm3
``` ```
If the above step is not performed, a random RCON password will be generated and output on the first run. It can also be If the above step is not performed, a random RCON password will be generated and output to the log on the first run. It
obtained and reset. (See [Management](#manage)) can also be obtained and reset. See [Manage](#manage).
Add your Steam credentials. This step is necessary if you want to add mods. The vanilla server is installable by setting Build the Docker image:
the steamlogin to `anonymous`. Edit `files/steamlogin` and set the steam username.
```
steamlogin=your_real_steam_username_or_anonymous
```
If you choose not to be anonymous, then you must login using your credentials. This is an interactive process that will
prompt for the password and Steam Guard code. This only needs to be done once.
Either way, we must build the container fist:
``` ```
docker-compose build docker-compose build
``` ```
Now login:
### Steam Integration
[SteamDMD](https://developer.valvesoftware.com/wiki/SteamCMD) is used to manage Steam downloads. A vanilla DayZ server
can be installed with the `anonymous` Steam user, but most mods cannot. If the goal is to add mods, a real Steam login
must be used. Login:
``` ```
docker-compose run --rm run manage login docker-compose run --rm main dayzserver login
``` ```
Follow the prompts. Hit enter to accept the default, which is to use the `anonymous` user, otherwise use your real
username and keep following the prompts to add your password and Steam Guard code. With Steam Guard enabled on the Steam
account, entering the password will trigger the sending of an email with the code. This process will wait indefinitely
until the code is entered.
The credentials will be managed by [SteamCMD](https://developer.valvesoftware.com/wiki/SteamCMD) and stored in the
docker volume. All subsequent SteamCMD command will use the cached credentials. so this process does not need to be
repeated unless the session expires or the docker volume is deleted.
Run the command again to manage the login. See [Manage](#manage).
## Run ## Run
Launch the container into the background: Launch the container into the background:
``` ```
docker-compose up -d run docker-compose up -d main
``` ```
Tail the log: Tail the log:
``` ```
docker-compose logs -f run docker-compose logs -f main
``` ```
## Manage ## Manage
### Workshop ### RCON
To add a workshop item, edit `files/workshop.cfg` and add the item's id after the comment. Each id should be on its own Show the current `beserver_x64.cfg` file:
line, after the comment, which should not be removed. Install them:
``` ```
docker-compose run --rm manage docker-compose run --rm main rcon show
```
Reset the RCON password:
```
docker-compose run --rm main rcon reset
```
### Restart
```
docker-compose run --rm main restart
```
### Update the DayZ server files
```
docker-compose run --rm main update
```
### Workshop
WIP
```
docker-compose run --rm main workshop
``` ```
* Makage -mod= command line * Makage -mod= command line
## TODO ## TODO
* Update the server
* Restart the server
* RCON to the server? * RCON to the server?
* List current rocn password * List current rocn password
* Detect changes to config files and propagate them, with prompting. * Detect changes to config files and propagate them, with prompting.

View file

@ -5,7 +5,7 @@ volumes:
services: services:
run: main:
build: . build: .
ports: ports:
- "2302:2302/udp" - "2302:2302/udp"

View file

@ -1,8 +1,10 @@
#!/usr/bin/env bash #!/usr/bin/env bash
appid=1042420 # Make sure we don't start collecting core files
dayz_id=221100 # FIXME Set this in Docker somewhere
ulimit -c 0
# Colors
default="\e[0m" default="\e[0m"
red="\e[31m" red="\e[31m"
green="\e[32m" green="\e[32m"
@ -13,75 +15,154 @@ lightblue="\e[94m"
magenta="\e[35m" magenta="\e[35m"
cyan="\e[36m" cyan="\e[36m"
STEAMCMD=/steamcmd/steamcmd.sh # Base directories
CFG_SRC_FILES="/files"
SERVER_FILES="${HOME}/serverfiles"
SERVER_PROFILE="${HOME}/serverprofile"
# Default config file
DEFAULT_CFG="${CFG_SRC_FILES}/default.cfg"
# Battle Eye files
BE_SERVER_FILE="beserver_x64.cfg"
BE_SERVER_DST="${SERVER_FILES}/battleye/${BE_SERVER_FILE}"
BE_SERVER_SRC="${CFG_SRC_FILES}/${BE_SERVER_FILE}"
# Server configuration file
SERVER_CFG_FILE="serverDZ.cfg"
SERVER_CFG_DST="${SERVER_FILES}/${SERVER_CFG_FILE}"
SERVER_CFG_SRC="${CFG_SRC_FILES}/${SERVER_CFG_FILE}"
# Used to check if dayZ is installed
SERVER_INSTALL_FILE="${SERVER_FILES}/DayZServer"
# Steam files
STEAM_LOGIN_DST="${HOME}/.steamlogin"
STEAMCMD=steamcmd.sh
# Workshop
WORKSHOP_CFG="${HOME}/workshop.cfg"
fn_prompt_yn(){
echo -n "${1} (y|N) " >&2
read -s -n 1 a
a=$(echo ${a} | tr A-Z a-z)
if [[ "${a}" = "y" ]]
then
echo
return 0
else
return 1
fi
}
fn_loadconfig_dayz(){ fn_loadconfig_dayz(){
source /files/default.cfg source ${DEFAULT_CFG}
# Handle adding the server cfg file # Handle the server configuration file
if [ ! -f ${HOME}/serverfiles/serverDZ.cfg ] if [ ! -f ${SERVER_CFG_DST} ]
then then
echo "Creating initial serverDZ.cfg" echo "Creating initial server configuration file"
cp /files/serverDZ.cfg "${HOME}/serverfiles/serverDZ.cfg" cp "${SERVER_CFG_SRC}" "${SERVER_CFG_DST}"
elif diff -q /files/default.cfg "${HOME}/serverfiles/serverDZ.cfg" > /dev/null elif diff -q "${SERVER_CFG_SRC}" "${SERVER_CFG_DST}" > /dev/null
then then
echo "Updating serverDZ.cfg" if fn_prompt_yn "The new server configuration file differs from what's installed. Use it?"
cp /files/serverDZ.cfg "${HOME}/serverfiles/serverDZ.cfg" then
echo "Updating the server configuration file"
cp "${SERVER_CFG_SRC}" "${SERVER_CFG_DST}"
else
echo "NOT updating the server configuration file"
fi
fi fi
} }
# Checks for the destination file are already done before calls to this
fn_do_rcon(){
echo -n "Creating the Battle Eye configuration file "
cp "${BE_SERVER_SRC}" "${BE_SERVER_DST}"
# Set a random RCON password, unless one's set in the environment
if grep -q RCON_PASSWORD "${BE_SERVER_SRC}"
then
RCON_PASSWORD=$(< /dev/urandom tr -dc 'A-Za-z0-9' | head -c10)
echo -e "using random RCON password ${yellow}${RCON_PASSWORD}${default}"
sed -i "${BE_SERVER_DST}" -e "s/RCON_PASSWORD/${RCON_PASSWORD}/"
else
echo "using the RCON_PASSWORD already set in ${BE_SERVER_SRC}."
fi
}
fn_create_beconfig(){ fn_create_beconfig(){
if [ -d "${HOME}/serverfiles/battleye" ] && [ ! -f "${HOME}/serverfiles/battleye/beserver_x64.cfg" ] if [ ! -f "${BE_SERVER_DST}" ]
then then
echo -n "Creating Battle Eye RCON file " echo -n "Creating Battle Eye RCON file "
fn_do_rcon fn_do_rcon
elif diff -q /files/beserver_x64.cfg "${HOME}/serverfiles/battleye/beserver_x64.cfg" > /dev/null elif diff -q "${BE_SERVER_SRC}" "${BE_SERVER_DST}" > /dev/null
then then
echo -n "Updating Battle Eye RCON file " echo -n "Updating Battle Eye RCON file "
fn_do_rcon fn_do_rcon
fi fi
} }
fn_do_rcon(){
cp /files/beserver_x64.cfg "${HOME}/serverfiles/battleye/beserver_x64.cfg"
# Set a random RCON password, unless one's set in the environment
if grep -v RCON_PASSWORD /files/beserver_x64.cfg
then
RCON_PASSWORD=$(< /dev/urandom tr -dc 'A-Za-z0-9' | head -c10)
echo -e "using random RCON password ${yellow}${RCON_PASSWORD}"
sed -i "${HOME}/serverfiles/battleye/beserver_x64.cfg" -e "s/RCON_PASSWORD/${RCON_PASSWORD}/"
else
echo "using the RCON_PASSWORD already set in files/beserver_x64.cfg."
fi
}
fn_start_dayz(){ fn_start_dayz(){
fn_create_beconfig
fn_loadconfig_dayz fn_loadconfig_dayz
fn_workshop_mods fn_workshop_mods
printf "[ ${green}DayZ${default} ] Starting server...\n" printf "[ ${green}DayZ${default} ] Starting server...\n"
cd ${HOME}/serverfiles cd ${SERVER_FILES}
./DayZServer $dayzparameter "$workshop" || ( ./DayZServer $dayzparameter "$workshop" || (
echo echo
echo -e "${yellow}========================================== error.log ==========================================" echo -e "${yellow}========================================== error.log =========================================="
find /home/user -name error.log -exec cat {} \; -exec rm -f {} \; find "${HOME}" -name error.log -exec cat {} \; -exec rm -f {} \;
echo echo
echo -e "${yellow}========================================== script*.log ========================================" echo -e "${yellow}========================================== script*.log ========================================"
find /home/user -name "script*.log" -exec cat {} \; -exec rm -f {} \; find "${HOME}" -name "script*.log" -exec cat {} \; -exec rm -f {} \;
echo echo
echo -e "${yellow}========================================== *.RPT ==============================================" echo -e "${yellow}========================================== *.RPT =============================================="
find /home/user -name "*.RPT" -exec cat {} \; -exec rm -f {} \; find "${HOME}" -name "*.RPT" -exec cat {} \; -exec rm -f {} \;
echo echo
echo -e "${yellow}========================================== End crash log ======================================" echo -e "${yellow}========================================== End crash log ======================================"
) )
} }
fn_steam_login(){
if [ -f "${STEAM_LOGIN_DST}" ]
then
if fn_prompt_yn "The steam login is already set. Reset it?"
then
rm -f "${STEAM_LOGIN_DST}"
else
echo
echo "Not reset. Nothing to do. Exiting..."
exit 0
fi
fi
if [ ! -f "${STEAM_LOGIN_DST}" ]
then
echo "Setting up Steam credentials"
echo -n "Steam Username (anonymous): "
read steamlogin
if [[ "${steamlogin}" = "" ]]
then
echo "Steam login set to 'anonymous'"
steamlogin="anonymous"
fi
${STEAMCMD} +force_install_dir ${SERVER_FILES} +login "${steamlogin}" +quit
fi
}
fn_steamlogin_dayz(){ fn_steamlogin_dayz(){
source /files/steamlogin if [ -f "${STEAM_LOGIN_DST}" ]
then
source "${STEAM_LOGIN_DST}"
else
echo "No cached Steam credentials. Please configure this now: "
fn_steam_login
fi
} }
fn_install_dayz(){ fn_install_dayz(){
if [ ! -f "${HOME}/serverfiles/DayZServer" ]; then if [ ! -f "${SERVER_INSTALL_FILE}" ]; then
mkdir ${HOME}/serverfiles &> /dev/null mkdir -p "${SERVER_FILES}"
mkdir ${HOME}/serverprofile &> /dev/null mkdir -p "${SERVER_PROFILE}"
printf "[ ${yellow}DayZ${default} ] Downloading DayZ Server-Files!\n" printf "[ ${yellow}DayZ${default} ] Downloading DayZ Server-Files!\n"
fn_steamlogin_dayz fn_steamlogin_dayz
fn_runvalidate_dayz fn_runvalidate_dayz
@ -92,13 +173,13 @@ fn_install_dayz(){
fn_runupdate_dayz(){ fn_runupdate_dayz(){
fn_loadconfig_dayz fn_loadconfig_dayz
${STEAMCMD} +force_install_dir ${HOME}/serverfiles +login "${steamlogin}" +app_update "${appid}" +quit ${STEAMCMD} +force_install_dir ${SERVER_FILES} +login "${steamlogin}" +app_update "${appid}" +quit
} }
fn_update_dayz(){ fn_update_dayz(){
fn_steamlogin_dayz fn_steamlogin_dayz
fn_loadconfig_dayz fn_loadconfig_dayz
appmanifestfile=${HOME}/serverfiles/steamapps/appmanifest_"${appid}".acf appmanifestfile=${SERVER_FILES}/steamapps/appmanifest_"${appid}".acf
printf "[ ... ] Checking for update: SteamCMD" printf "[ ... ] Checking for update: SteamCMD"
# gets currentbuild # gets currentbuild
currentbuild=$(grep buildid "${appmanifestfile}" | tr '[:blank:]"' ' ' | tr -s ' ' | cut -d \ -f3) currentbuild=$(grep buildid "${appmanifestfile}" | tr '[:blank:]"' ' ' | tr -s ' ' | cut -d \ -f3)
@ -108,7 +189,8 @@ fn_update_dayz(){
sleep 1 sleep 1
fi fi
# check for new build # check for new build
availablebuild=$(${STEAMCMD} +login "${steamlogin}" +app_info_update 1 +app_info_print "${appid}" +app_info_print "${appid}" +quit | sed -n '/branch/,$p' | grep -m 1 buildid | tr -cd '[:digit:]') availablebuild=$(${STEAMCMD} +login "${steamlogin}" +app_info_update 1 +app_info_print "${appid}" +app_info_print \
"${appid}" +quit | sed -n '/branch/,$p' | grep -m 1 buildid | tr -cd '[:digit:]')
if [ -z "${availablebuild}" ]; then if [ -z "${availablebuild}" ]; then
printf "\r[ ${red}FAIL${default} ] Checking for update: SteamCMD\n" printf "\r[ ${red}FAIL${default} ] Checking for update: SteamCMD\n"
printf "\r[ ${red}FAIL${default} ] Checking for update: SteamCMD: Not returning version info\n" printf "\r[ ${red}FAIL${default} ] Checking for update: SteamCMD: Not returning version info\n"
@ -138,23 +220,23 @@ fn_update_dayz(){
fn_runvalidate_dayz(){ fn_runvalidate_dayz(){
fn_loadconfig_dayz fn_loadconfig_dayz
${STEAMCMD} +force_install_dir ${HOME}/serverfiles +login "${steamlogin}" +app_update "${appid}" validate +quit ${STEAMCMD} +force_install_dir ${SERVER_FILES} +login "${steamlogin}" +app_update "${appid}" validate +quit
} }
fn_workshop_mods(){ fn_workshop_mods(){
fn_steamlogin_dayz fn_steamlogin_dayz
fn_loadconfig_dayz fn_loadconfig_dayz
declare -a workshopID declare -a workshopID
workshopfolder="${HOME}/serverfiles/steamapps/workshop/content/221100" workshopfolder="${SERVER_FILES}/steamapps/workshop/content/${dayz_id}"
workshoplist="" workshoplist=""
if [ ! -f /files/workshop.cfg ] if [ ! -f "${WORKSHOP_CFG}" ]
then then
echo "No workshop mods..." echo "No workshop mods..."
return return
else else
echo "Syncing workshop mods..." echo "Syncing workshop mods..."
fi fi
mapfile -t -s 1 workshopID < /files/workshop.cfg mapfile -t workshopID < "${WORKSHOP_CFG}"
# gather mods # gather mods
for i in "${workshopID[@]}" for i in "${workshopID[@]}"
do do
@ -163,30 +245,90 @@ fn_workshop_mods(){
fi fi
done done
# download mods # download mods
${STEAMCMD} +force_install_dir ${HOME}/serverfiles +login "${steamlogin}" ${workshoplist} +quit ${STEAMCMD} +force_install_dir ${SERVER_FILES} +login "${steamlogin}" ${workshoplist} +quit
# link mods # link mods
for i in "${workshopID[@]}" for i in "${workshopID[@]}"
do do
if [[ $i =~ ^[0-9] ]] && [ $(expr length $i) -gt 7 ] && [ -d "${workshopfolder}/$i" ]; then if [[ $i =~ ^[0-9] ]] && [ $(expr length $i) -gt 7 ] && [ -d "${workshopfolder}/$i" ]; then
modname=$(cut -d '"' -f 2 <<< $(grep name ${workshopfolder}/$i/meta.cpp)) modname=$(cut -d '"' -f 2 <<< $(grep name ${workshopfolder}/$i/meta.cpp))
if [ ! -d "${HOME}/serverfiles/@${modname}" ]; then if [ ! -d "${SERVER_FILES}/@${modname}" ]; then
ln -s ${workshopfolder}/$i "${HOME}/serverfiles/@${modname}" &> /dev/null ln -s ${workshopfolder}/$i "${SERVER_FILES}/@${modname}" &> /dev/null
fi fi
find "${workshopfolder}/$i" -depth -exec rename -f 's/(.*)\/([^\/]*)/$1\/\L$2/' {} \; find "${workshopfolder}/$i" -depth -exec rename -f 's/(.*)\/([^\/]*)/$1\/\L$2/' {} \;
fi fi
done done
if ls ${HOME}/serverfiles/@* 1> /dev/null 2>&1; then if ls ${SERVER_FILES}/@* 1> /dev/null 2>&1; then
printf "\n[ ${green}DayZ${default} ] Copy Key Files from Mods...\n" printf "\n[ ${green}DayZ${default} ] Copy Key Files from Mods...\n"
cp -vu ${HOME}/serverfiles/@*/keys/* "${HOME}/serverfiles/keys/" > /dev/null 2>&1 cp -vu ${SERVER_FILES}/@*/keys/* "${SERVER_FILES}/keys/" > /dev/null 2>&1
fi fi
} }
# Make sure we don't start collecting core files fn_rcon(){
ulimit -c 0 case "${1}" in
show)
if [ ! -f "${BE_SERVER_DST}" ]
then
fn_do_rcon
fi
echo "=================================================================="
cat "${BE_SERVER_DST}"
echo "=================================================================="
;;
reset)
if fn_prompt_yn "Reset RCON password?"
then
rm -f "${BE_SERVER_DST}"
fn_do_rcon
else
echo
echo "Not reset. Nothing to do. Exiting..."
exit 0
fi
;;
esac
}
if [[ ${1} = "start" ]] fn_restart_dayz(){
then echo "Restarting DayZ server..."
fn_install_dayz }
fn_create_beconfig
fn_start_dayz fn_backup(){
fi echo "Creating backup...WIP"
}
case "${1}" in
backup)
fn_backup
;;
install)
fn_install_dayz
;;
login)
fn_steam_login
;;
rcon)
fn_rcon "${2}"
;;
restart)
fn_restart_dayz
;;
start)
fn_start_dayz
;;
stop)
echo "Stopping DayZ server..."
;;
update)
echo "Updating DayZ..."
fn_update_dayz
;;
workshop)
echo "Manage workshopp..."
fn_workshop_mods
;;
**)
echo "Unknown option '${1}'"
echo "Usage: $0 [ backup | login | rcon [ show | reset ] | restart | start | stop | update | workshop ]"
exit 0
;;
esac

View file

@ -1,39 +0,0 @@
#!/usr/bin/env bash
if [[ "${1}" = "login" ]]
then
if [ -f ${HOME}/.steamlogin ]
then
echo -n "The steam login is already set. Reset it? (Y|n): "
read -s -n 1 a
a=$(echo ${a} | tr A-Z a-z)
if [[ "${a}" = "y" ]]
then
rm -f ${HOME}/.steamlogin
else
echo "Not reset. Nothing to do. Exiting..."
exit 0
fi
fi
if [ ! -f ${HOME}/.steamlogin ]
then
echo "Setting up Steam credentials"
cp /files/steamlogin "${HOME}/.steamlogin"
source "${HOME}/.steamlogin"
steamcmd.sh +force_install_dir ${HOME}/serverfiles +login "${steamlogin}" +quit
fi
elif [[ "${1}" = "workshop" ]]
then
echo "Updating workshopp..."
elif [[ "${1}" = "backup" ]]
then
echo "Creating backup..."
elif [[ "${1}" = "rconpassword" ]]
then
echo "The RCON password is: ..."
else
echo "Unknown option '${1}'"
echo "Usage: manage backup | login | workshop | rconpassword"
exit 0
fi

View file

@ -1 +0,0 @@
steamlogin=your_real_steam_username_or_anonymous

View file

@ -1 +0,0 @@
# Add one id per line