34 changed files with 8529 additions and 1178 deletions
@ -0,0 +1,66 @@ |
|||
// |
|||
// server.cfg |
|||
// |
|||
// comments are written with "//" in front of them. |
|||
// dont change any of the line numbers, the script *might* break |
|||
|
|||
// PORTS |
|||
//default 2302, needs to be unique if multiple servers on same box |
|||
//ignore how the line is commented, it is still interprited by the main script |
|||
//serverport=2302 |
|||
//default 2304, needs to be unique if multiple servers on same box (master port) |
|||
steamport=2304; |
|||
//default 2303, needs to be unique if multiple servers on same box (query port) |
|||
steamqueryport=2303; |
|||
|
|||
// GLOBAL SETTINGS |
|||
// The name of the server that shall be displayed in the public server list |
|||
hostname = "arma3server"; |
|||
// Password for joining, eg connecting to the server |
|||
//password = "ServerAccessPassword"; |
|||
// Password to become server admin. When you're in Arma MP and connected to the server, type '#login xyz' |
|||
passwordAdmin = "AdminPassword"; |
|||
logFile = "arma3server.log"; |
|||
verifySignatures = 2; |
|||
//kick if data/mods are not equal |
|||
equalModRequired = 0; |
|||
//was used to define type of secureID |
|||
requiredSecureId = 2; |
|||
|
|||
// WELCOME MESSAGE ("message of the day") |
|||
// It can be several lines, separated by comma |
|||
// Empty messages "" will not be displayed at all but are only for increasing the interval |
|||
motd[]={ |
|||
"Welcome to My Arma 3 Server", |
|||
"TS3 Server: teamspeak.somewhere.com", |
|||
"Web: www.example.com" |
|||
}; |
|||
motdInterval = 30; // Time interval (in seconds) between each message |
|||
|
|||
// JOINING RULES |
|||
maxPlayers = 40; // Maximum amount of players. Civilians and watchers, beholder, bystanders and so on also count as player. |
|||
kickDuplicate = 1; // Each ArmA version has its own ID. If kickDuplicate is set to 1, a player will be kicked |
|||
//requiredBuild = 12345 // Require clients joining to have at least build 12345 of game, preventing obsolete clients to connect |
|||
|
|||
// VOTING |
|||
voteMissionPlayers = 1; // Tells the server how many people must connect so that it displays the mission selection screen. |
|||
voteThreshold = 0.33; // 33% or more players need to vote for something, for example an admin or a new map, to become effective |
|||
//voteMissionPlayers = 0; |
|||
|
|||
// INGAME SETTINGS |
|||
disableVoN = 1; // If set to 1, Voice over Net will not be available |
|||
vonCodecQuality = 0; // supports range 1-30 //8kHz is 0-10 (narrowband), 16kHz is 11-20 (wideband), 32kHz is 21-30 (ultrawideband) |
|||
persistent = 1; // If 1, missions still run on even after the last player disconnected. |
|||
timeStampFormat = "short"; // Set the timestamp format used on each report line in server-side RPT file. Possible values are "none" (default),"short","full". |
|||
BattlEye = 1; // Server to use BattlEye system |
|||
allowedLoadFileExtensions[] = {"hpp","txt"}; // only allow files with those extensions to be loaded via loadFile command (since Arma 3 build 1.19.124216) |
|||
|
|||
// SCRIPTING ISSUES |
|||
onUserConnected = ""; // |
|||
onUserDisconnected = ""; // |
|||
doubleIdDetected = ""; // |
|||
|
|||
// SIGNATURE VERIFICATION |
|||
onUnsignedData = "kick (_this select 0)"; // unsigned data detected |
|||
onHackedData = "kick (_this select 0)"; //"ban (_this select 0)"; // tampering of the signature detected |
|||
onDifferentData = ""; |
@ -0,0 +1,977 @@ |
|||
#!/bin/bash |
|||
# ARMA 3 |
|||
# Server Management Script |
|||
# Author: Daniel Gibbs |
|||
# Contributor: Scarsz |
|||
# Website: http://danielgibbs.co.uk |
|||
# Version: 061014 |
|||
|
|||
#### Variables #### |
|||
|
|||
# Notification Email |
|||
# (on|off) |
|||
emailnotification="off" |
|||
email="[email protected]" |
|||
|
|||
# Steam login |
|||
steamuser="username" |
|||
steampass="password" |
|||
|
|||
# Server IP |
|||
ip="0.0.0.0" |
|||
|
|||
fn_parms(){ |
|||
parms="-netlog -port=${serverport} -ip=${ip} -config=${servercfg}" |
|||
} |
|||
|
|||
#### Advanced Variables #### |
|||
|
|||
# Steam |
|||
appid="233780" |
|||
|
|||
# Server Details |
|||
servicename="arma3-server" |
|||
gamename="ARMA 3" |
|||
engine="realvirtuality" |
|||
|
|||
# Directories |
|||
rootdir="$(cd "$(dirname "${BASH_SOURCE[0]}" )" && pwd )" |
|||
selfname="$0" |
|||
lockselfname=$(echo ".${servicename}.lock") |
|||
filesdir="${rootdir}/serverfiles" |
|||
systemdir="${filesdir}" |
|||
executabledir="${filesdir}" |
|||
executable="./arma3server" |
|||
servercfgdir="${systemdir}" |
|||
servercfg="${servicename}.cfg" |
|||
servercfgfullpath="${servercfgdir}/${servercfg}" |
|||
backupdir="backups" |
|||
|
|||
# Server Details |
|||
servername=$(grep -s hostname "${servercfgfullpath}"|sed -e 's/\<hostname\>//g'| tr -d '=\"; ') |
|||
serverport=$(sed -n -e '10 p' ${servercfgfullpath} 2>/dev/null| sed 's/[\/\; ]//g' | tr -cd [:digit:]) |
|||
queryport=$(sed -n -e '14 p' ${servercfgfullpath} 2>/dev/null| sed 's/[\/\; ]//g' | tr -cd [:digit:]) |
|||
masterport=$(sed -n -e '12 p' ${servercfgfullpath} 2>/dev/null| sed 's/[\/\; ]//g' | tr -cd [:digit:]) |
|||
|
|||
# Logging |
|||
logdays="7" |
|||
gamelogdir="${systemdir}/logs" |
|||
scriptlogdir="${rootdir}/log/script" |
|||
consolelogdir="${rootdir}/log/console" |
|||
|
|||
scriptlog="${scriptlogdir}/${servicename}-script.log" |
|||
consolelog="${consolelogdir}/${servicename}-console.log" |
|||
emaillog="${scriptlogdir}/${servicename}-email.log" |
|||
|
|||
scriptlogdate="${scriptlogdir}/${servicename}-script-$(date '+%d-%m-%Y-%H-%M-%S').log" |
|||
consolelogdate="${consolelogdir}/${servicename}-console-$(date '+%d-%m-%Y-%H-%M-%S').log" |
|||
|
|||
##### Script ##### |
|||
# Do not edit |
|||
# unless you know |
|||
# what you are doing |
|||
|
|||
fn_scriptlog(){ |
|||
echo -e "$(date '+%b %d %H:%M:%S') ${servicename}: ${1}" >> ${scriptlog} |
|||
} |
|||
|
|||
# [ FAIL ] |
|||
fn_printfail(){ |
|||
echo -en "\r\033[K[\e[0;31m FAIL \e[0;39m] $@" |
|||
} |
|||
|
|||
fn_printfailnl(){ |
|||
echo -e "\r\033[K[\e[0;31m FAIL \e[0;39m] $@" |
|||
} |
|||
|
|||
fn_printok(){ |
|||
echo -en "\r\033[K[\e[0;32m OK \e[0;39m] $@" |
|||
} |
|||
|
|||
# [ OK ] |
|||
fn_printoknl(){ |
|||
echo -e "\r\033[K[\e[0;32m OK \e[0;39m] $@" |
|||
} |
|||
|
|||
fn_printinfo(){ |
|||
echo -en "\r\033[K[\e[0;36m INFO \e[0;39m] $@" |
|||
} |
|||
|
|||
fn_printinfonl(){ |
|||
echo -e "\r\033[K[\e[0;36m INFO \e[0;39m] $@" |
|||
} |
|||
|
|||
# [ INFO ] |
|||
fn_printokinfonl(){ |
|||
echo -e "\r\033[K[\e[0;36m INFO \e[0;39m] $@" |
|||
} |
|||
|
|||
fn_printwarn(){ |
|||
echo -en "\r\033[K[\e[1;33m WARN \e[0;39m] $@" |
|||
} |
|||
|
|||
fn_printwarnnl(){ |
|||
echo -e "\r\033[K[\e[1;33m WARN \e[0;39m] $@" |
|||
} |
|||
|
|||
# [ .... ] |
|||
fn_printdots(){ |
|||
echo -en "\r\033[K[ .... ] $@" |
|||
} |
|||
|
|||
fn_rootcheck(){ |
|||
if [ `whoami` = "root" ]; then |
|||
fn_printfailnl "Script will not run as root!" |
|||
exit |
|||
fi |
|||
} |
|||
|
|||
fn_syscheck(){ |
|||
if [ ! -e "${systemdir}" ]; then |
|||
fn_printfailnl "Cannot access ${systemdir}: No such directory" |
|||
exit |
|||
fi |
|||
} |
|||
|
|||
fn_autoip(){ |
|||
# Identifies the server interface IP |
|||
# If multiple interfaces this will need to be set manually |
|||
getip=$(ip -o -4 addr|awk '{print $4 }'|grep -oe '\([0-9]\{1,3\}\.\?\)\{4\}'|grep -v 127.0.0) |
|||
getipwc=$(ip -o -4 addr|awk '{print $4 }'|grep -oe '\([0-9]\{1,3\}\.\?\)\{4\}'|grep -v 127.0.0|wc -l) |
|||
if [ "${ip}" == "0.0.0.0" ]||[ "${ip}" == "" ]; then |
|||
if [ "${getipwc}" -ge "2" ]; then |
|||
fn_printwarn "Multiple active network interfaces.\n\n" |
|||
echo -en "Manually specify the IP you want to use within the ${selfname} script.\n" |
|||
echo -en "Set ip=\"0.0.0.0\" to one of the following:\n" |
|||
echo -en "${getip}\n" |
|||
exit |
|||
else |
|||
ip=${getip} |
|||
fi |
|||
fi |
|||
} |
|||
|
|||
fn_logmanager(){ |
|||
if [ ! -e "${consolelog}" ]; then |
|||
touch "${consolelog}" |
|||
fi |
|||
# log manager will active if finds logs older than ${logdays} |
|||
if [ `find "${scriptlogdir}"/* -mtime +${logdays}|wc -l` -ne "0" ]; then |
|||
fn_printdots "Starting log cleaner" |
|||
sleep 1 |
|||
fn_printok "Starting log cleaner" |
|||
fn_scriptlog "Starting log cleaner" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
fn_printinfo "Removing logs older than ${logdays} days" |
|||
fn_scriptlog "Removing logs older than ${logdays} days" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
if [ "${engine}" == "unreal2" ]; then |
|||
find "${gamelogdir}"/* -mtime +${logdays}|tee >> "${scriptlog}" |
|||
fi |
|||
find "${scriptlogdir}"/* -mtime +${logdays}|tee >> "${scriptlog}" |
|||
find "${consolelogdir}"/* -mtime +${logdays}|tee >> "${scriptlog}" |
|||
if [ "${engine}" == "unreal2" ]; then |
|||
gamecount=$(find "${scriptlogdir}"/* -mtime +${logdays}|wc -l) |
|||
fi |
|||
scriptcount=$(find "${scriptlogdir}"/* -mtime +${logdays}|wc -l) |
|||
consolecount=$(find "${consolelogdir}"/* -mtime +${logdays}|wc -l) |
|||
count=$((${scriptcount} + ${consolecount})) |
|||
if [ "${engine}" == "unreal2" ]; then |
|||
count=$((${scriptcount} + ${consolecount} + ${gamecount})) |
|||
else |
|||
count=$((${scriptcount} + ${consolecount})) |
|||
fi |
|||
if [ "${engine}" == "unreal2" ]; then |
|||
find "${gamelogdir}"/* -mtime +${logdays} -exec rm {} \; |
|||
fi |
|||
find "${scriptlogdir}"/* -mtime +${logdays} -exec rm {} \; |
|||
find "${consolelogdir}"/* -mtime +${logdays} -exec rm {} \; |
|||
fn_printok "Log cleaner removed ${count} log files" |
|||
fn_scriptlog "Log cleaner removed ${count} log files" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
fi |
|||
} |
|||
|
|||
fn_debugserver(){ |
|||
fn_rootcheck |
|||
fn_syscheck |
|||
fn_autoip |
|||
fn_distro |
|||
fn_uptime |
|||
fn_load |
|||
fn_parms |
|||
echo "" |
|||
echo "${gamename} Debug" |
|||
echo "============================" |
|||
echo "" |
|||
echo -e "Distro: ${os}" |
|||
echo -e "Arch: ${arch}" |
|||
echo -e "Kernel: ${kernel}" |
|||
echo -e "Hostname: $HOSTNAME" |
|||
echo "" |
|||
echo "Start parameters:" |
|||
echo ${parms} |
|||
echo "" |
|||
echo -e "Use for identifying server issues only!" |
|||
echo -e "Press CTRL+c to drop out of debug mode" |
|||
echo -e "\e[0;31mWARNING!\e[0;39m If ${servicename} is already running it will be stopped" |
|||
echo "" |
|||
while true; do |
|||
read -p "Continue? [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) break;; |
|||
[Nn]* ) echo Exiting; return 1;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
fn_stopserver |
|||
fn_printdots "Starting debug mode ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_printok "Starting debug mode ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_scriptlog "Started debug mode ${servername}" |
|||
echo -en "\n" |
|||
cd "${executabledir}" |
|||
${executable} ${parms} |
|||
} |
|||
|
|||
fn_console(){ |
|||
fn_rootcheck |
|||
fn_syscheck |
|||
echo "" |
|||
echo "${gamename} Console" |
|||
echo "============================" |
|||
echo "" |
|||
echo "Press \"CTRL+b d\" to exit console" |
|||
echo -e "\e[0;31mWARNING!\e[0;39m Do NOT press CTRL+c to exit" |
|||
echo "" |
|||
while true; do |
|||
read -p "Continue? [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) break;; |
|||
[Nn]* ) echo Exiting; return 1;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
fn_printdots "Starting ${servicename} console" |
|||
sleep 1 |
|||
tmuxwc=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -v failed|grep -E "^${servicename}:"|wc -l) |
|||
if [ ${tmuxwc} -eq 1 ]; then |
|||
fn_printoknl "Starting ${servicename} console" |
|||
fn_scriptlog "Console accessed" |
|||
sleep 1 |
|||
tmux attach-session -t ${servicename} |
|||
else |
|||
fn_printfailnl "Starting ${servicename} console: ${servername} not running" |
|||
sleep 1 |
|||
while true; do |
|||
read -p "Do you want to start the server? [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) fn_startserver; break;; |
|||
[Nn]* ) break;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
fi |
|||
} |
|||
|
|||
fn_backupserver(){ |
|||
fn_rootcheck |
|||
fn_syscheck |
|||
backupname="${servicename}-$(date '+%Y-%m-%d-%H%M%S')" |
|||
echo "" |
|||
echo "${gamename} Backup" |
|||
echo "============================" |
|||
echo "" |
|||
echo "The following backup will be created." |
|||
echo "" |
|||
echo "${backupdir}/${backupname}.tar.gz" |
|||
echo "" |
|||
while true; do |
|||
read -p "Continue? [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) break;; |
|||
[Nn]* ) echo Exiting; return 1;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
tmuxwc=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -v failed|grep -E "^${servicename}:"|wc -l) |
|||
if [ ${tmuxwc} -eq 1 ]; then |
|||
echo -e "\e[0;31mWARNING!\e[0;39m ${servicename} is currently running" |
|||
while true; do |
|||
read -p "Would you like to stop ${servicename} while running the backup? [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) fn_stopserver; break;; |
|||
[Nn]* ) break;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
fi |
|||
fn_printdots "Starting backup ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_printok "Starting backup ${servicename}: ${servername}" |
|||
fn_scriptlog "Backup started" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
cd "${rootdir}" |
|||
mkdir -pv "${backupdir}" > /dev/null 2>&1 |
|||
tar -cvzf "${backupdir}/${backupname}.tar.gz" --exclude "${backupdir}" * |
|||
echo -en "\r\033[K${servicename} Backup complete" |
|||
fn_scriptlog "Backup complete" |
|||
} |
|||
|
|||
fn_distro(){ |
|||
arch=$(uname -m) |
|||
kernel=$(uname -r) |
|||
if [ -f /etc/lsb-release ]; then |
|||
os=$(lsb_release -s -d) |
|||
elif [ -f /etc/debian_version ]; then |
|||
os="Debian $(cat /etc/debian_version)" |
|||
elif [ -f /etc/redhat-release ]; then |
|||
os=$(cat /etc/redhat-release) |
|||
else |
|||
os="$(uname -s) $(uname -r)" |
|||
fi |
|||
} |
|||
|
|||
fn_uptime(){ |
|||
uptime=$(</proc/uptime) |
|||
uptime=${uptime%%.*} |
|||
minutes=$(( uptime/60%60 )) |
|||
hours=$(( uptime/60/60%24 )) |
|||
days=$(( uptime/60/60/24 )) |
|||
} |
|||
|
|||
fn_load(){ |
|||
load=$(uptime|awk -F 'load average' '{ print $2 }') |
|||
} |
|||
|
|||
fn_emailnotification(){ |
|||
fn_distro |
|||
fn_uptime |
|||
fn_load |
|||
{ |
|||
echo -e "========================================\n${servicename} details\n========================================\n" |
|||
echo -e "Service: ${servicename}" |
|||
echo -e "Server: ${servername}" |
|||
echo -e "Game: ${gamename}" |
|||
echo -e "Failure reason: ${failurereason}" |
|||
echo -e "Action Taken: ${actiontaken}\n" |
|||
echo -e "========================================\nServer details\n========================================\n" |
|||
echo -e "Date: $(date)" |
|||
echo -e "Distro: ${os}" |
|||
echo -e "Arch: ${arch}" |
|||
echo -e "Kernel: ${kernel}" |
|||
echo -e "Hostname: $HOSTNAME" |
|||
echo -e "Uptime: ${days}d, ${hours}h, ${minutes}m" |
|||
echo -e "Avg Load${load}\n" |
|||
echo -e "========================================\nLogs\n========================================\n" |
|||
echo -e "Script log\n===================\n" |
|||
}|tee "${scriptlogdir}/${servicename}-email.log" > /dev/null 2>&1 |
|||
tail -25 "${scriptlog}" >> "${emaillog}" |
|||
if [ ! -z "${consolelog}" ]; then |
|||
echo -e "\n\nConsole log\n====================\n" >> "${emaillog}" |
|||
tail -25 "${consolelog}" >> "${emaillog}" |
|||
fi |
|||
if [ ! -z "${gamelogdir}" ]; then |
|||
echo -e "\n\nServer log\n====================\n" >> "${emaillog}" |
|||
tail "${gamelogdir}"/*|grep -v "==>"|sed '/^$/d'|tail -25 >> "${emaillog}" |
|||
fi |
|||
mail -s "${subject}" ${email} < "${emaillog}" |
|||
fn_printinfo "Sent email notification to ${email}" |
|||
fn_scriptlog "Sent email notification to ${email}" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
} |
|||
|
|||
fn_emailtest(){ |
|||
fn_rootcheck |
|||
fn_syscheck |
|||
fn_scriptlog "Emailing test notification" |
|||
if [ "${emailnotification}" = "on" ]; then |
|||
subject="${servicename} Email Test Notification - Testing ${servername}" |
|||
failurereason="Testing ${servicename} email notification" |
|||
actiontaken="Sent test email...hello is this thing on?" |
|||
fn_emailnotification |
|||
else |
|||
fn_printfailnl "Email notification not enabled" |
|||
fn_scriptlog "Email notification not enabled" |
|||
fi |
|||
sleep 1 |
|||
echo -en "\n" |
|||
} |
|||
|
|||
fn_serverquery(){ |
|||
# uses gsquery.py to directly query the server |
|||
# detects if the server locks up |
|||
if [ -f gsquery.py ]; then |
|||
if [ "${engine}" == "unreal" ]||[ "${engine}" == "unreal2" ]; then |
|||
gameport=$(grep Port= ${systemdir}/${ini}|grep -v Master|grep -v LAN|grep -v Proxy|grep -v Listen|sed 's/\Port=//g') |
|||
port=$((${gameport} + 1)) |
|||
elif [ "${engine}" == "spark" ]; then |
|||
port=$((${port} + 1)) |
|||
elif [ "${engine}" == "realvirtuality" ]; then |
|||
port=${queryport} |
|||
fi |
|||
fn_printinfo "Monitoring ${servicename}: Detected gsquery.py" |
|||
fn_scriptlog "Detected gsquery.py" |
|||
sleep 1 |
|||
fn_printdots "Monitoring ${servicename}: Querying port: ${ip}:${port}: QUERYING" |
|||
fn_scriptlog "Querying port: ${ip}:${port}: QUERYING" |
|||
sleep 1 |
|||
serverquery=$(./gsquery.py -a ${ip} -p ${port} -e ${engine} 2>&1) |
|||
exitcode=$? |
|||
if [ "${exitcode}" == "1" ]||[ "${exitcode}" == "2" ]||[ "${exitcode}" == "3" ]||[ "${exitcode}" == "4" ]; then |
|||
fn_printfail "Monitoring ${servicename}: Querying port: ${ip}:${port}: ${serverquery}" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
fn_scriptlog "Querying port: ${ip}:${port}: ${serverquery}" |
|||
if [[ -z "${secondquery}" ]]; then |
|||
fn_printinfo "Monitoring ${servicename}: Waiting 30 seconds to re-query" |
|||
fn_scriptlog "Waiting 30 seconds to re-query" |
|||
sleep 30 |
|||
secondquery=1 |
|||
fn_serverquery |
|||
fi |
|||
if [ "${emailnotification}" = "on" ]; then |
|||
subject="${servicename} Monitor - Starting ${servername}" |
|||
failurereason="Failed to query ${servicename}: ${serverquery}" |
|||
actiontaken="restarted ${servicename}" |
|||
fn_emailnotification |
|||
fi |
|||
fn_restartserver |
|||
exit |
|||
elif [ "${exitcode}" == "0" ]; then |
|||
fn_printok "Monitoring ${servicename}: Querying port: ${ip}:${port}: OK" |
|||
fn_scriptlog "Querying port: ${ip}:${port}: OK" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
exit |
|||
elif [ "${exitcode}" == "126" ]; then |
|||
fn_printfail "Monitoring ${servicename}: Querying port: ${ip}:${port}: ERROR: ./gsquery.py: Permission denied" |
|||
fn_scriptlog "Querying port: ${ip}:${port}: ./gsquery.py: Permission denied" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
echo "Attempting to resolve automatically" |
|||
chmod +x -v gsquery.py |
|||
exitcode=$? |
|||
if [ "${exitcode}" == "0" ]; then |
|||
fn_serverquery |
|||
else |
|||
echo -en "\nUnable to resolve automatically. Please manually fix permissions\n" |
|||
owner=$(ls -al gsquery.py|awk '{ print $3 }') |
|||
echo "As user ${owner} or root run the following command" |
|||
whoami=$(whoami) |
|||
echo -en "\nchown ${whoami}:${whoami} gsquery.py\n\n" |
|||
exit |
|||
fi |
|||
else |
|||
fn_printfail "Monitoring ${servicename}: Querying port: ${ip}:${port}: UNKNOWN ERROR" |
|||
fn_scriptlog "Querying port: ${ip}:${port}: UNKNOWN ERROR" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
./gsquery.py -a ${ip} -p ${port} -e ${engine} |
|||
exit |
|||
fi |
|||
fi |
|||
} |
|||
|
|||
fn_monitorserver(){ |
|||
fn_rootcheck |
|||
fn_syscheck |
|||
fn_autoip |
|||
fn_printdots "Monitoring ${servicename}: ${servername}" |
|||
fn_scriptlog "Monitoring ${servername}" |
|||
sleep 1 |
|||
if [ ! -f ${lockselfname} ]; then |
|||
fn_printinfo "Monitoring ${servicename}: Monitor disabled: No lock file found" |
|||
fn_scriptlog "Monitor disabled: No lock file found" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
echo "To enable monitor run ${selfname} start" |
|||
exit |
|||
fi |
|||
updatecheck=$(ps -ef|grep "${selfname} update"|grep -v grep|wc -l) |
|||
if [ "${updatecheck}" = "0" ]; then |
|||
fn_printdots "Monitoring ${servicename}: Checking session: CHECKING" |
|||
fn_scriptlog "Checking session: CHECKING" |
|||
sleep 1 |
|||
tmuxwc=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -v failed|grep -E "^${servicename}:"|wc -l) |
|||
if [ ${tmuxwc} -eq 1 ]; then |
|||
fn_printok "Monitoring ${servicename}: Checking session: OK" |
|||
fn_scriptlog "Checking session: OK" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
fn_serverquery |
|||
exit |
|||
else |
|||
fn_printfail "Monitoring ${servicename}: Checking session: FAIL" |
|||
fn_scriptlog "Checking session: FAIL" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
if [ "${emailnotification}" = "on" ]; then |
|||
subject="${servicename} Monitor - Starting ${servername}" |
|||
failurereason="${servicename} process not running" |
|||
actiontaken="${servicename} has been restarted" |
|||
fn_emailnotification |
|||
fi |
|||
fn_scriptlog "Monitor is starting ${servername}" |
|||
fn_startserver |
|||
fi |
|||
else |
|||
fn_printinfonl "Monitoring ${servicename}: Detected SteamCMD is checking for updates" |
|||
fn_scriptlog "Detected SteamCMD is checking for updates" |
|||
sleep 1 |
|||
fn_printinfonl "Monitoring ${servicename}: When updates complete ${servicename} will start" |
|||
fn_scriptlog "When updates complete ${servicename} will start" |
|||
sleep 1 |
|||
fi |
|||
} |
|||
|
|||
fn_updateserver(){ |
|||
fn_rootcheck |
|||
fn_syscheck |
|||
fn_printdots "Updating ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_printok "Updating ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_scriptlog "Updating ${servername}" |
|||
cd "${rootdir}" |
|||
cd "steamcmd" |
|||
./steamcmd.sh +login ${steamuser} "${steampass}" +force_install_dir "${filesdir}" +app_update ${appid} +quit|tee -a "${scriptlog}" |
|||
} |
|||
|
|||
fn_validateserver(){ |
|||
fn_rootcheck |
|||
fn_syscheck |
|||
fn_printwarn "Validating may overwrite some customised files." |
|||
sleep 1 |
|||
echo -en "\n" |
|||
echo -en "https://developer.valvesoftware.com/wiki/SteamCMD#Validate" |
|||
sleep 5 |
|||
echo -en "\n" |
|||
fn_printdots "Validating ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_printok "Validating ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_scriptlog "Validating ${servername}" |
|||
cd "${rootdir}" |
|||
cd "steamcmd" |
|||
./steamcmd.sh +login ${steamuser} "${steampass}" +force_install_dir "${filesdir}" +app_update ${appid} validate +quit|tee -a "${scriptlog}" |
|||
} |
|||
|
|||
fn_restartserver(){ |
|||
fn_scriptlog "Restarting ${servername}" |
|||
fn_stopserver |
|||
fn_startserver |
|||
} |
|||
|
|||
fn_stopserver(){ |
|||
fn_rootcheck |
|||
fn_syscheck |
|||
pid=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -E "^${servicename}:"|wc -l) |
|||
fn_printdots "Stopping ${servicename}: ${servername}" |
|||
fn_scriptlog "Stopping ${servername}" |
|||
sleep 1 |
|||
if [ "${pid}" == "0" ]; then |
|||
fn_printfail "Stopping ${servicename}: ${servername} is already stopped" |
|||
fn_scriptlog "${servername} is already stopped" |
|||
else |
|||
tmux kill-session -t ${servicename} |
|||
fn_printok "Stopping ${servicename}: ${servername}" |
|||
fn_scriptlog "Stopped ${servername}" |
|||
fi |
|||
# Remove lock file |
|||
rm -f ${lockselfname} |
|||
sleep 1 |
|||
echo -en "\n" |
|||
} |
|||
|
|||
fn_startserver(){ |
|||
fn_rootcheck |
|||
fn_syscheck |
|||
fn_autoip |
|||
fn_parms |
|||
fn_logmanager |
|||
tmuxwc=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -v failed|grep -E "^${servicename}:"|wc -l) |
|||
if [ ${tmuxwc} -eq 0 ]; then |
|||
fn_scriptlog "Rotating log files" |
|||
if [ "${engine}" == "unreal2" ]; then |
|||
mv "${gamelog}" "${gamelogdate}" |
|||
fi |
|||
mv "${scriptlog}" "${scriptlogdate}" |
|||
mv "${consolelog}" "${consolelogdate}" |
|||
fi |
|||
fn_printdots "Starting ${servicename}: ${servername}" |
|||
fn_scriptlog "Starting ${servername}" |
|||
sleep 1 |
|||
if [ ${tmuxwc} -eq 1 ]; then |
|||
fn_printinfo "Starting ${servicename}: ${servername} is already running" |
|||
fn_scriptlog "${servername} is already running" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
exit |
|||
fi |
|||
# Create lock file |
|||
date > "${rootdir}/${lockselfname}" |
|||
cd "${executabledir}" |
|||
tmux new-session -d -s ${servicename} "${executable} ${parms}" 2> ${scriptlogdir}/.${servicename}-tmux-error.tmp |
|||
tmux pipe-pane -o -t ${servicename} "exec cat >> '${consolelog}'" |
|||
sleep 1 |
|||
tmuxwc=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -E "^${servicename}:"|wc -l) |
|||
if [ ${tmuxwc} -eq 0 ]; then |
|||
fn_printfailnl "Starting ${servicename}: Failed to start ${servername}" |
|||
echo -en " Check log files: ${rootdir}/log" |
|||
fn_scriptlog "failed to start ${servername}" |
|||
if [ -a ${scriptlogdir}/.${servicename}-tmux-error.tmp ]; then |
|||
fn_scriptlog "tmux returned the following error" |
|||
cat ${scriptlogdir}/.${servicename}-tmux-error.tmp >> ${scriptlog} |
|||
rm ${scriptlogdir}/.${servicename}-tmux-error.tmp |
|||
fi |
|||
else |
|||
fn_printok "Starting ${servicename}: ${servername}" |
|||
fn_scriptlog "Started ${servername}" |
|||
fi |
|||
sleep 1 |
|||
echo -en "\n" |
|||
} |
|||
|
|||
fn_arma3details(){ |
|||
fn_autoip |
|||
pid=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -E "^${servicename}:"|wc -l) |
|||
echo "" |
|||
echo "${gamename} Server Details" |
|||
echo "============================" |
|||
echo "Server name: ${servername}" |
|||
echo "Server IP: ${ip}:${serverport}" |
|||
echo "Config file: ${servercfgfullpath}" |
|||
echo "" |
|||
echo "Admin Password: ${adminpass}" |
|||
echo "" |
|||
echo "${servername} Ports" |
|||
echo "============================" |
|||
echo "Ports the server is currently using." |
|||
echo "" |
|||
echo "PROTOCOL DESCRIPTION PORT" |
|||
echo "UDP Game port ${serverport}" |
|||
echo "UDP STEAM query port ${queryport}" |
|||
echo "UDP STEAM master traffic port ${masterport}" |
|||
echo "" |
|||
echo "You can change ports by editing the" |
|||
echo "parameters in ${servercfgfullpath}" |
|||
echo "" |
|||
if [ "${pid}" == "0" ]; then |
|||
echo -e "Status:\e[0;31m OFFLINE\e[0;39m" |
|||
else |
|||
echo -e "Status:\e[0;32m ONLINE\e[0;39m" |
|||
fi |
|||
echo "" |
|||
} |
|||
|
|||
# |
|||
## Installer |
|||
# |
|||
|
|||
fn_glibcfix(){ |
|||
if [ -z $(command -v ldd) ]; then |
|||
echo "" |
|||
echo -e "\r\033[K\e[0;31mFAIL\e[0;39m GLIBC is not detected." |
|||
sleep 1 |
|||
echo "Install GLIBC and retry installation" |
|||
sleep 1 |
|||
echo "" |
|||
while true; do |
|||
read -p "Continue install? [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) break;; |
|||
[Nn]* ) echo Exiting; exit;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
elif [ "$(ldd --version | sed -n '1 p' | tr -cd [:digit:] | tail -c 3)" -lt 215 ]; then |
|||
echo "GLIBC Fix required" |
|||
echo "============================" |
|||
sleep 1 |
|||
echo -e "\e[0;31mWARNING!\e[0;39m ${gamename} requires GLIBC_2.15 or above" |
|||
sleep 1 |
|||
echo "" |
|||
echo "Currently installed: GLIBC_$(ldd --version |grep ldd|awk '{print $NF}')" |
|||
echo "Required: => GLIBC_2.15" |
|||
echo "" |
|||
sleep 1 |
|||
echo "The installer will now detect and download the required files to allow ${gamename} server to run on a distro with GLIBC_2.14 or less." |
|||
echo "note: This will NOT upgrade GLIBC on your system" |
|||
sleep 1 |
|||
echo "" |
|||
echo "Downloading Required files" |
|||
echo "=================================" |
|||
sleep 1 |
|||
if [ "${gamename}" == "Insurgency" ];then |
|||
echo "Detected Insurgency" |
|||
sleep 1 |
|||
echo "Downloading files for Insurgency GLIBC Fix" |
|||
cd "${filesdir}/bin" |
|||
wget -nv -N https://github.com/dgibbs64/linuxgameservers/raw/master/Insurgency/dependencies/libc.so.6 |
|||
wget -nv -N https://github.com/dgibbs64/linuxgameservers/raw/master/Insurgency/dependencies/librt.so.1 |
|||
wget -nv -N https://github.com/dgibbs64/linuxgameservers/raw/master/Insurgency/dependencies/libpthread.so.0 |
|||
sleep 1 |
|||
elif [ "${gamename}" == "Garrys's Mod" ];then |
|||
echo "Detected Garrys's Mod" |
|||
sleep 1 |
|||
echo "Downloading files for Garrys's Mod GLIBC Fix" |
|||
sleep 1 |
|||
cd "${filesdir}/bin" |
|||
wget -nv -N https://github.com/dgibbs64/linuxgameservers/raw/master/GarrysMod/dependencies/libc.so.6 |
|||
wget -nv -N https://github.com/dgibbs64/linuxgameservers/raw/master/GarrysMod/dependencies/libm.so.6 |
|||
wget -nv -N https://github.com/dgibbs64/linuxgameservers/raw/master/GarrysMod/dependencies/libpthread.so.0 |
|||
sleep 1 |
|||
echo "" |
|||
elif [ "${gamename}" == "Natural Selection 2" ];then |
|||
echo "Detected Natural Selection 2" |
|||
sleep 1 |
|||
echo "Downloading files for Natural Selection 2 GLIBC Fix" |
|||
sleep 1 |
|||
cd "${filesdir}" |
|||
wget -nv -N https://github.com/dgibbs64/linuxgameservers/raw/master/NaturalSelection2/dependencies/libm.so.6 |
|||
cp -v "${rootdir}/steamcmd/linux32/libstdc++.so.6" "${filesdir}/libstdc++.so.6" |
|||
sleep 1 |
|||
echo "" |
|||
elif [ "${gamename}" == "No More Room in Hell" ];then |
|||
echo "Detected No More Room in Hell" |
|||
sleep 1 |
|||
echo "Downloading files for No More Room in Hell GLIBC Fix" |
|||
sleep 1 |
|||
cd "${filesdir}/srcds" |
|||
wget -nv -N https://github.com/dgibbs64/linuxgameservers/raw/master/NoMoreRoomInHell/dependencies/libm.so.6 |
|||
cp -v "${rootdir}/steamcmd/linux32/libstdc++.so.6" "${filesdir}/srcds/libstdc++.so.6" |
|||
sleep 1 |
|||
echo "" |
|||
elif [ "${gamename}" == "Blade Symphony" ];then |
|||
echo "Detected Blade Symphony" |
|||
sleep 1 |
|||
echo "Downloading files for Blade Symphony GLIBC Fix" |
|||
sleep 1 |
|||
cp -v "${rootdir}/steamcmd/linux32/libstdc++.so.6" "${filesdir}/libstdc++.so.6" |
|||
sleep 1 |
|||
echo "" |
|||
elif [ "${gamename}" == "Fistful of Frags" ];then |
|||
echo "Detected Fistful of Frags" |
|||
sleep 1 |
|||
echo "Downloading files for Fistful of Frags GLIBC Fix" |
|||
sleep 1 |
|||
cd "${filesdir}" |
|||
wget -nv -N https://github.com/dgibbs64/linuxgameservers/raw/master/FistfulOfFrags/dependencies/libm.so.6 |
|||
sleep 1 |
|||
echo "" |
|||
elif [ "${gamename}" == "ARMA 3" ];then |
|||
echo "Detected ARMA 3" |
|||
sleep 1 |
|||
echo "Downloading files for ARMA 3 GLIBC Fix" |
|||
sleep 1 |
|||
cp -v "${rootdir}/steamcmd/linux32/libstdc++.so.6" "${filesdir}/libstdc++.so.6" |
|||
sleep 1 |
|||
echo "" |
|||
else |
|||
echo "error: Unable to detect game. Fix not applied" |
|||
fi |
|||
echo "GLIBC fix has been applied!" |
|||
sleep 1 |
|||
echo "" |
|||
fi |
|||
} |
|||
|
|||
fn_arma3config(){ |
|||
echo "Downloading CONFIG_Vanilla.cfg" |
|||
echo "=================================" |
|||
sleep 1 |
|||
cd "${systemdir}" |
|||
wget -nv -N https://raw.githubusercontent.com/dgibbs64/linuxgameservers/master/Arma3/CONFIG_Vanilla.cfg |
|||
echo "Creating ${servicename}.cfg config file." |
|||
sleep 1 |
|||
cp -v CONFIG_Vanilla.cfg ${servercfgfullpath} |
|||
sleep 1 |
|||
echo "" |
|||
} |
|||
|
|||
fn_header(){ |
|||
clear |
|||
echo "=================================" |
|||
echo "${gamename}" |
|||
echo "Linux Game Server Manager" |
|||
echo "by Daniel Gibbs" |
|||
echo "contributions by Scarsz" |
|||
echo "http://danielgibbs.co.uk" |
|||
echo "=================================" |
|||
echo "" |
|||
} |
|||
|
|||
fn_steamdl(){ |
|||
echo "Installing SteamCMD" |
|||
echo "=================================" |
|||
cd "${rootdir}" |
|||
mkdir -pv "steamcmd" |
|||
sleep 1 |
|||
cd "steamcmd" |
|||
if [ ! -f steamcmd.sh ]; then |
|||
wget -nv -N http://media.steampowered.com/client/steamcmd_linux.tar.gz |
|||
tar --verbose -zxf steamcmd_linux.tar.gz |
|||
rm -v steamcmd_linux.tar.gz |
|||
chmod +x steamcmd.sh |
|||
sleep 1 |
|||
else |
|||
echo "" |
|||
echo "Steam already installed!" |
|||
fi |
|||
sleep 1 |
|||
echo "" |
|||
} |
|||
|
|||
fn_steaminstall(){ |
|||
echo "Installing ${gamename} Server" |
|||
echo "=================================" |
|||
sleep 1 |
|||
mkdir -pv "${filesdir}" |
|||
cd "${rootdir}/steamcmd" |
|||
STEAMEXE=steamcmd ./steamcmd.sh +login ${steamuser} "${steampass}" +force_install_dir "${filesdir}" +app_update ${appid} validate +quit |
|||
echo "" |
|||
echo "=================================" |
|||
while true; do |
|||
read -p "Was the install successful? [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) break;; |
|||
[Nn]* ) fn_retryinstall;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
echo "" |
|||
} |
|||
|
|||
fn_steamfix(){ |
|||
echo "Applying steamclient.so fix" |
|||
echo "=================================" |
|||
sleep 1 |
|||
mkdir -pv "${HOME}/.steam" |
|||
mkdir -pv "${HOME}/.steam/sdk32" |
|||
cp -v "${rootdir}/steamcmd/linux32/steamclient.so" "${HOME}/.steam/sdk32/steamclient.so" |
|||
sleep 1 |
|||
echo "" |
|||
} |
|||
|
|||
fn_loginstall(){ |
|||
echo "Creating log directorys" |
|||
echo "=================================" |
|||
sleep 1 |
|||
mkdir -pv "${rootdir}/log" |
|||
mkdir -pv "${scriptlogdir}" |
|||
touch "${scriptlog}" |
|||
mkdir -pv "${consolelogdir}" |
|||
touch "${consolelog}" |
|||
if [ ! -h ${rootdir}/log/server ]; then |
|||
ln -sv "${gamelogdir}" "${rootdir}/log/server" |
|||
else |
|||
echo "Symbolic link ${gamelogdir} => ${rootdir}/log/server already exists!" |
|||
fi |
|||
sleep 1 |
|||
echo "" |
|||
} |
|||
|
|||
fn_retryinstall(){ |
|||
while true; do |
|||
read -p "Retry install? [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) fn_install; exit;; |
|||
[Nn]* ) echo Exiting; exit;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
} |
|||
|
|||
fn_install(){ |
|||
fn_rootcheck |
|||
fn_header |
|||
if [ -d "${filesdir}" ]; then |
|||
echo "${gamename} Server is already installed here:" |
|||
pwd |
|||
echo "" |
|||
while true; do |
|||
read -p "Continue [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) fn_header; break;; |
|||
[Nn]* ) echo Exiting; return 1;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
fi |
|||
echo "Install Directory:" |
|||
pwd |
|||
echo "" |
|||
while true; do |
|||
read -p "Continue [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) break;; |
|||
[Nn]* ) echo Exiting; return 1;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
fn_header |
|||
fn_steamdl |
|||
fn_steaminstall |
|||
fn_steamfix |
|||
fn_loginstall |
|||
fn_glibcfix |
|||
fn_arma3config |
|||
sleep 1 |
|||
echo "" |
|||
fn_header |
|||
sleep 1 |
|||
fn_arma3details |
|||
sleep 1 |
|||
echo "=================================" |
|||
echo "Install Complete!" |
|||
echo "" |
|||
echo "To start server type:" |
|||
echo "${selfname} start" |
|||
echo "" |
|||
} |
|||
|
|||
case "$1" in |
|||
start) |
|||
fn_startserver;; |
|||
stop) |
|||
fn_stopserver;; |
|||
restart) |
|||
fn_restartserver;; |
|||
update) |
|||
fn_updateserver;; |
|||
update-restart) |
|||
fn_stopserver |
|||
fn_updateserver |
|||
fn_startserver;; |
|||
validate) |
|||
fn_validateserver;; |
|||
validate-restart) |
|||
fn_stopserver |
|||
fn_validateserver |
|||
fn_startserver;; |
|||
monitor) |
|||
fn_monitorserver;; |
|||
email-test) |
|||
fn_emailtest;; |
|||
details) |
|||
fn_arma3details;; |
|||
backup) |
|||
fn_backupserver;; |
|||
console) |
|||
fn_console;; |
|||
debug) |
|||
fn_debugserver;; |
|||
install) |
|||
fn_install;; |
|||
*) |
|||
echo "Usage: $0 {start|stop|restart|update|update-restart|validate|validate-restart|monitor|email-test|details|backup|console|debug|install}" |
|||
exit 1;; |
|||
esac |
|||
exit |
File diff suppressed because it is too large
Binary file not shown.
File diff suppressed because it is too large
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
@ -0,0 +1,862 @@ |
|||
#!/bin/bash |
|||
# Just Cause 2 |
|||
# Server Management Script |
|||
# Author: Daniel Gibbs |
|||
# Website: http://danielgibbs.co.uk |
|||
# Version: 061014 |
|||
|
|||
#### Variables #### |
|||
|
|||
# Notification Email |
|||
# (on|off) |
|||
emailnotification="off" |
|||
email="[email protected]" |
|||
|
|||
# Steam login |
|||
steamuser="anonymous" |
|||
steampass="" |
|||
|
|||
# Start Variables |
|||
maxplayers="10" |
|||
port="7777" |
|||
ip="0.0.0.0" |
|||
|
|||
fn_parms(){ |
|||
parms="--maxplayers ${maxplayers} --bindip ${ip} --bindport ${port}" |
|||
} |
|||
|
|||
#### Advanced Variables #### |
|||
|
|||
# Steam |
|||
appid="261140" |
|||
|
|||
# Server Details |
|||
servicename="jc2-server" |
|||
gamename="Just Cause 2" |
|||
engine="avalanche" |
|||
|
|||
# Directories |
|||
rootdir="$(cd "$(dirname "${BASH_SOURCE[0]}" )" && pwd )" |
|||
selfname="$0" |
|||
lockselfname=$(echo ".${servicename}.lock") |
|||
filesdir="${rootdir}/serverfiles" |
|||
systemdir="${filesdir}" |
|||
executabledir="${filesdir}" |
|||
executable="./Jcmp-Server" |
|||
servercfgdir="${filesdir}" |
|||
servercfg="config.lua" |
|||
servercfgfullpath="${servercfgdir}/${servercfg}" |
|||
backupdir="backups" |
|||
|
|||
# Server Details |
|||
servername=$(grep -s hostname "${servercfgfullpath}"|sed 's/hostname //g'|sed 's/"//g') |
|||
|
|||
# Logging |
|||
logdays="7" |
|||
gamelogdir="${systemdir}/logs" |
|||
scriptlogdir="${rootdir}/log/script" |
|||
consolelogdir="${rootdir}/log/console" |
|||
|
|||
scriptlog="${scriptlogdir}/${servicename}-script.log" |
|||
consolelog="${consolelogdir}/${servicename}-console.log" |
|||
emaillog="${scriptlogdir}/${servicename}-email.log" |
|||
|
|||
scriptlogdate="${scriptlogdir}/${servicename}-script-$(date '+%d-%m-%Y-%H-%M-%S').log" |
|||
consolelogdate="${consolelogdir}/${servicename}-console-$(date '+%d-%m-%Y-%H-%M-%S').log" |
|||
|
|||
##### Script ##### |
|||
# Do not edit |
|||
# unless you know |
|||
# what you are doing |
|||
|
|||
fn_scriptlog(){ |
|||
echo -e "$(date '+%b %d %H:%M:%S') ${servicename}: ${1}" >> ${scriptlog} |
|||
} |
|||
|
|||
# [ FAIL ] |
|||
fn_printfail(){ |
|||
echo -en "\r\033[K[\e[0;31m FAIL \e[0;39m] $@" |
|||
} |
|||
|
|||
fn_printfailnl(){ |
|||
echo -e "\r\033[K[\e[0;31m FAIL \e[0;39m] $@" |
|||
} |
|||
|
|||
fn_printok(){ |
|||
echo -en "\r\033[K[\e[0;32m OK \e[0;39m] $@" |
|||
} |
|||
|
|||
# [ OK ] |
|||
fn_printoknl(){ |
|||
echo -e "\r\033[K[\e[0;32m OK \e[0;39m] $@" |
|||
} |
|||
|
|||
fn_printinfo(){ |
|||
echo -en "\r\033[K[\e[0;36m INFO \e[0;39m] $@" |
|||
} |
|||
|
|||
fn_printinfonl(){ |
|||
echo -e "\r\033[K[\e[0;36m INFO \e[0;39m] $@" |
|||
} |
|||
|
|||
# [ INFO ] |
|||
fn_printokinfonl(){ |
|||
echo -e "\r\033[K[\e[0;36m INFO \e[0;39m] $@" |
|||
} |
|||
|
|||
fn_printwarn(){ |
|||
echo -en "\r\033[K[\e[1;33m WARN \e[0;39m] $@" |
|||
} |
|||
|
|||
fn_printwarnnl(){ |
|||
echo -e "\r\033[K[\e[1;33m WARN \e[0;39m] $@" |
|||
} |
|||
|
|||
# [ .... ] |
|||
fn_printdots(){ |
|||
echo -en "\r\033[K[ .... ] $@" |
|||
} |
|||
|
|||
fn_rootcheck(){ |
|||
if [ `whoami` = "root" ]; then |
|||
fn_printfailnl "Script will not run as root!" |
|||
exit |
|||
fi |
|||
} |
|||
|
|||
fn_syscheck(){ |
|||
if [ ! -e "${systemdir}" ]; then |
|||
fn_printfailnl "Cannot access ${systemdir}: No such directory" |
|||
exit |
|||
fi |
|||
} |
|||
|
|||
fn_autoip(){ |
|||
# Identifies the server interface IP |
|||
# If multiple interfaces this will need to be set manually |
|||
getip=$(ip -o -4 addr|awk '{print $4 }'|grep -oe '\([0-9]\{1,3\}\.\?\)\{4\}'|grep -v 127.0.0) |
|||
getipwc=$(ip -o -4 addr|awk '{print $4 }'|grep -oe '\([0-9]\{1,3\}\.\?\)\{4\}'|grep -v 127.0.0|wc -l) |
|||
if [ "${ip}" == "0.0.0.0" ]||[ "${ip}" == "" ]; then |
|||
if [ "${getipwc}" -ge "2" ]; then |
|||
fn_printwarn "Multiple active network interfaces.\n\n" |
|||
echo -en "Manually specify the IP you want to use within the ${selfname} script.\n" |
|||
echo -en "Set ip=\"0.0.0.0\" to one of the following:\n" |
|||
echo -en "${getip}\n" |
|||
exit |
|||
else |
|||
ip=${getip} |
|||
fi |
|||
fi |
|||
} |
|||
|
|||
fn_logmanager(){ |
|||
if [ ! -e "${consolelog}" ]; then |
|||
touch "${consolelog}" |
|||
fi |
|||
# log manager will active if finds logs older than ${logdays} |
|||
if [ `find "${scriptlogdir}"/* -mtime +${logdays}|wc -l` -ne "0" ]; then |
|||
fn_printdots "Starting log cleaner" |
|||
sleep 1 |
|||
fn_printok "Starting log cleaner" |
|||
fn_scriptlog "Starting log cleaner" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
fn_printinfo "Removing logs older than ${logdays} days" |
|||
fn_scriptlog "Removing logs older than ${logdays} days" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
if [ "${engine}" == "unreal2" ]; then |
|||
find "${gamelogdir}"/* -mtime +${logdays}|tee >> "${scriptlog}" |
|||
fi |
|||
find "${scriptlogdir}"/* -mtime +${logdays}|tee >> "${scriptlog}" |
|||
find "${consolelogdir}"/* -mtime +${logdays}|tee >> "${scriptlog}" |
|||
if [ "${engine}" == "unreal2" ]; then |
|||
gamecount=$(find "${scriptlogdir}"/* -mtime +${logdays}|wc -l) |
|||
fi |
|||
scriptcount=$(find "${scriptlogdir}"/* -mtime +${logdays}|wc -l) |
|||
consolecount=$(find "${consolelogdir}"/* -mtime +${logdays}|wc -l) |
|||
count=$((${scriptcount} + ${consolecount})) |
|||
if [ "${engine}" == "unreal2" ]; then |
|||
count=$((${scriptcount} + ${consolecount} + ${gamecount})) |
|||
else |
|||
count=$((${scriptcount} + ${consolecount})) |
|||
fi |
|||
if [ "${engine}" == "unreal2" ]; then |
|||
find "${gamelogdir}"/* -mtime +${logdays} -exec rm {} \; |
|||
fi |
|||
find "${scriptlogdir}"/* -mtime +${logdays} -exec rm {} \; |
|||
find "${consolelogdir}"/* -mtime +${logdays} -exec rm {} \; |
|||
fn_printok "Log cleaner removed ${count} log files" |
|||
fn_scriptlog "Log cleaner removed ${count} log files" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
fi |
|||
} |
|||
|
|||
fn_debugserver(){ |
|||
fn_rootcheck |
|||
fn_syscheck |
|||
fn_autoip |
|||
fn_distro |
|||
fn_uptime |
|||
fn_load |
|||
fn_parms |
|||
echo "" |
|||
echo "${gamename} Debug" |
|||
echo "============================" |
|||
echo "" |
|||
echo -e "Distro: ${os}" |
|||
echo -e "Arch: ${arch}" |
|||
echo -e "Kernel: ${kernel}" |
|||
echo -e "Hostname: $HOSTNAME" |
|||
echo "" |
|||
echo "Start parameters:" |
|||
echo ${parms} |
|||
echo "" |
|||
echo -e "Use for identifying server issues only!" |
|||
echo -e "Press CTRL+c to drop out of debug mode" |
|||
echo -e "\e[0;31mWARNING!\e[0;39m If ${servicename} is already running it will be stopped" |
|||
echo "" |
|||
while true; do |
|||
read -p "Continue? [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) break;; |
|||
[Nn]* ) echo Exiting; return 1;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
fn_stopserver |
|||
fn_printdots "Starting debug mode ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_printok "Starting debug mode ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_scriptlog "Started debug mode ${servername}" |
|||
echo -en "\n" |
|||
cd "${executabledir}" |
|||
${executable} ${parms} -debug |
|||
} |
|||
|
|||
fn_console(){ |
|||
fn_rootcheck |
|||
fn_syscheck |
|||
echo "" |
|||
echo "${gamename} Console" |
|||
echo "============================" |
|||
echo "" |
|||
echo "Press \"CTRL+b d\" to exit console" |
|||
echo -e "\e[0;31mWARNING!\e[0;39m Do NOT press CTRL+c to exit" |
|||
echo "" |
|||
while true; do |
|||
read -p "Continue? [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) break;; |
|||
[Nn]* ) echo Exiting; return 1;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
fn_printdots "Starting ${servicename} console" |
|||
sleep 1 |
|||
tmuxwc=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -v failed|grep -E "^${servicename}:"|wc -l) |
|||
if [ ${tmuxwc} -eq 1 ]; then |
|||
fn_printoknl "Starting ${servicename} console" |
|||
fn_scriptlog "Console accessed" |
|||
sleep 1 |
|||
tmux attach-session -t ${servicename} |
|||
else |
|||
fn_printfailnl "Starting ${servicename} console: ${servername} not running" |
|||
sleep 1 |
|||
while true; do |
|||
read -p "Do you want to start the server? [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) fn_startserver; break;; |
|||
[Nn]* ) break;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
fi |
|||
} |
|||
|
|||
fn_backupserver(){ |
|||
fn_rootcheck |
|||
fn_syscheck |
|||
backupname="${servicename}-$(date '+%Y-%m-%d-%H%M%S')" |
|||
echo "" |
|||
echo "${gamename} Backup" |
|||
echo "============================" |
|||
echo "" |
|||
echo "The following backup will be created." |
|||
echo "" |
|||
echo "${backupdir}/${backupname}.tar.gz" |
|||
echo "" |
|||
while true; do |
|||
read -p "Continue? [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) break;; |
|||
[Nn]* ) echo Exiting; return 1;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
tmuxwc=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -v failed|grep -E "^${servicename}:"|wc -l) |
|||
if [ ${tmuxwc} -eq 1 ]; then |
|||
echo -e "\e[0;31mWARNING!\e[0;39m ${servicename} is currently running" |
|||
while true; do |
|||
read -p "Would you like to stop ${servicename} while running the backup? [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) fn_stopserver; break;; |
|||
[Nn]* ) break;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
fi |
|||
fn_printdots "Starting backup ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_printok "Starting backup ${servicename}: ${servername}" |
|||
fn_scriptlog "Backup started" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
cd "${rootdir}" |
|||
mkdir -pv "${backupdir}" > /dev/null 2>&1 |
|||
tar -cvzf "${backupdir}/${backupname}.tar.gz" --exclude "${backupdir}" * |
|||
echo -en "\r\033[K${servicename} Backup complete" |
|||
fn_scriptlog "Backup complete" |
|||
} |
|||
|
|||
fn_distro(){ |
|||
arch=$(uname -m) |
|||
kernel=$(uname -r) |
|||
if [ -f /etc/lsb-release ]; then |
|||
os=$(lsb_release -s -d) |
|||
elif [ -f /etc/debian_version ]; then |
|||
os="Debian $(cat /etc/debian_version)" |
|||
elif [ -f /etc/redhat-release ]; then |
|||
os=$(cat /etc/redhat-release) |
|||
else |
|||
os="$(uname -s) $(uname -r)" |
|||
fi |
|||
} |
|||
|
|||
fn_uptime(){ |
|||
uptime=$(</proc/uptime) |
|||
uptime=${uptime%%.*} |
|||
minutes=$(( uptime/60%60 )) |
|||
hours=$(( uptime/60/60%24 )) |
|||
days=$(( uptime/60/60/24 )) |
|||
} |
|||
|
|||
fn_load(){ |
|||
load=$(uptime|awk -F 'load average' '{ print $2 }') |
|||
} |
|||
|
|||
fn_emailnotification(){ |
|||
fn_distro |
|||
fn_uptime |
|||
fn_load |
|||
{ |
|||
echo -e "========================================\n${servicename} details\n========================================\n" |
|||
echo -e "Service: ${servicename}" |
|||
echo -e "Server: ${servername}" |
|||
echo -e "Game: ${gamename}" |
|||
echo -e "Failure reason: ${failurereason}" |
|||
echo -e "Action Taken: ${actiontaken}\n" |
|||
echo -e "========================================\nServer details\n========================================\n" |
|||
echo -e "Date: $(date)" |
|||
echo -e "Distro: ${os}" |
|||
echo -e "Arch: ${arch}" |
|||
echo -e "Kernel: ${kernel}" |
|||
echo -e "Hostname: $HOSTNAME" |
|||
echo -e "Uptime: ${days}d, ${hours}h, ${minutes}m" |
|||
echo -e "Avg Load${load}\n" |
|||
echo -e "========================================\nLogs\n========================================\n" |
|||
echo -e "Script log\n===================\n" |
|||
}|tee "${scriptlogdir}/${servicename}-email.log" > /dev/null 2>&1 |
|||
tail -25 "${scriptlog}" >> "${emaillog}" |
|||
if [ ! -z "${consolelog}" ]; then |
|||
echo -e "\n\nConsole log\n====================\n" >> "${emaillog}" |
|||
tail -25 "${consolelog}" >> "${emaillog}" |
|||
fi |
|||
if [ ! -z "${gamelogdir}" ]; then |
|||
echo -e "\n\nServer log\n====================\n" >> "${emaillog}" |
|||
tail "${gamelogdir}"/*|grep -v "==>"|sed '/^$/d'|tail -25 >> "${emaillog}" |
|||
fi |
|||
mail -s "${subject}" ${email} < "${emaillog}" |
|||
fn_printinfo "Sent email notification to ${email}" |
|||
fn_scriptlog "Sent email notification to ${email}" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
} |
|||
|
|||
fn_emailtest(){ |
|||
fn_rootcheck |
|||
fn_syscheck |
|||
fn_scriptlog "Emailing test notification" |
|||
if [ "${emailnotification}" = "on" ]; then |
|||
subject="${servicename} Email Test Notification - Testing ${servername}" |
|||
failurereason="Testing ${servicename} email notification" |
|||
actiontaken="Sent test email...hello is this thing on?" |
|||
fn_emailnotification |
|||
else |
|||
fn_printfailnl "Email notification not enabled" |
|||
fn_scriptlog "Email notification not enabled" |
|||
fi |
|||
sleep 1 |
|||
echo -en "\n" |
|||
} |
|||
|
|||
fn_serverquery(){ |
|||
# uses gsquery.py to directly query the server |
|||
# detects if the server locks up |
|||
if [ -f gsquery.py ]; then |
|||
if [ "${engine}" == "unreal" ]||[ "${engine}" == "unreal2" ]; then |
|||
gameport=$(grep Port= ${systemdir}/${ini}|grep -v Master|grep -v LAN|grep -v Proxy|grep -v Listen|sed 's/\Port=//g') |
|||
port=$((${gameport} + 1)) |
|||
elif [ "${engine}" == "spark" ]; then |
|||
port=$((${port} + 1)) |
|||
elif [ "${engine}" == "realvirtuality" ]; then |
|||
port=${queryport} |
|||
fi |
|||
fn_printinfo "Monitoring ${servicename}: Detected gsquery.py" |
|||
fn_scriptlog "Detected gsquery.py" |
|||
sleep 1 |
|||
fn_printdots "Monitoring ${servicename}: Querying port: ${ip}:${port}: QUERYING" |
|||
fn_scriptlog "Querying port: ${ip}:${port}: QUERYING" |
|||
sleep 1 |
|||
serverquery=$(./gsquery.py -a ${ip} -p ${port} -e ${engine} 2>&1) |
|||
exitcode=$? |
|||
if [ "${exitcode}" == "1" ]||[ "${exitcode}" == "2" ]||[ "${exitcode}" == "3" ]||[ "${exitcode}" == "4" ]; then |
|||
fn_printfail "Monitoring ${servicename}: Querying port: ${ip}:${port}: ${serverquery}" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
fn_scriptlog "Querying port: ${ip}:${port}: ${serverquery}" |
|||
if [[ -z "${secondquery}" ]]; then |
|||
fn_printinfo "Monitoring ${servicename}: Waiting 30 seconds to re-query" |
|||
fn_scriptlog "Waiting 30 seconds to re-query" |
|||
sleep 30 |
|||
secondquery=1 |
|||
fn_serverquery |
|||
fi |
|||
if [ "${emailnotification}" = "on" ]; then |
|||
subject="${servicename} Monitor - Starting ${servername}" |
|||
failurereason="Failed to query ${servicename}: ${serverquery}" |
|||
actiontaken="restarted ${servicename}" |
|||
fn_emailnotification |
|||
fi |
|||
fn_restartserver |
|||
exit |
|||
elif [ "${exitcode}" == "0" ]; then |
|||
fn_printok "Monitoring ${servicename}: Querying port: ${ip}:${port}: OK" |
|||
fn_scriptlog "Querying port: ${ip}:${port}: OK" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
exit |
|||
elif [ "${exitcode}" == "126" ]; then |
|||
fn_printfail "Monitoring ${servicename}: Querying port: ${ip}:${port}: ERROR: ./gsquery.py: Permission denied" |
|||
fn_scriptlog "Querying port: ${ip}:${port}: ./gsquery.py: Permission denied" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
echo "Attempting to resolve automatically" |
|||
chmod +x -v gsquery.py |
|||
exitcode=$? |
|||
if [ "${exitcode}" == "0" ]; then |
|||
fn_serverquery |
|||
else |
|||
echo -en "\nUnable to resolve automatically. Please manually fix permissions\n" |
|||
owner=$(ls -al gsquery.py|awk '{ print $3 }') |
|||
echo "As user ${owner} or root run the following command" |
|||
whoami=$(whoami) |
|||
echo -en "\nchown ${whoami}:${whoami} gsquery.py\n\n" |
|||
exit |
|||
fi |
|||
else |
|||
fn_printfail "Monitoring ${servicename}: Querying port: ${ip}:${port}: UNKNOWN ERROR" |
|||
fn_scriptlog "Querying port: ${ip}:${port}: UNKNOWN ERROR" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
./gsquery.py -a ${ip} -p ${port} -e ${engine} |
|||
exit |
|||
fi |
|||
fi |
|||
} |
|||
|
|||
fn_monitorserver(){ |
|||
fn_rootcheck |
|||
fn_syscheck |
|||
fn_autoip |
|||
fn_printdots "Monitoring ${servicename}: ${servername}" |
|||
fn_scriptlog "Monitoring ${servername}" |
|||
sleep 1 |
|||
if [ ! -f ${lockselfname} ]; then |
|||
fn_printinfo "Monitoring ${servicename}: Monitor disabled: No lock file found" |
|||
fn_scriptlog "Monitor disabled: No lock file found" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
echo "To enable monitor run ${selfname} start" |
|||
exit |
|||
fi |
|||
updatecheck=$(ps -ef|grep "${selfname} update"|grep -v grep|wc -l) |
|||
if [ "${updatecheck}" = "0" ]; then |
|||
fn_printdots "Monitoring ${servicename}: Checking session: CHECKING" |
|||
fn_scriptlog "Checking session: CHECKING" |
|||
sleep 1 |
|||
tmuxwc=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -v failed|grep -E "^${servicename}:"|wc -l) |
|||
if [ ${tmuxwc} -eq 1 ]; then |
|||
fn_printok "Monitoring ${servicename}: Checking session: OK" |
|||
fn_scriptlog "Checking session: OK" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
fn_serverquery |
|||
exit |
|||
else |
|||
fn_printfail "Monitoring ${servicename}: Checking session: FAIL" |
|||
fn_scriptlog "Checking session: FAIL" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
if [ "${emailnotification}" = "on" ]; then |
|||
subject="${servicename} Monitor - Starting ${servername}" |
|||
failurereason="${servicename} process not running" |
|||
actiontaken="${servicename} has been restarted" |
|||
fn_emailnotification |
|||
fi |
|||
fn_scriptlog "Monitor is starting ${servername}" |
|||
fn_startserver |
|||
fi |
|||
else |
|||
fn_printinfonl "Monitoring ${servicename}: Detected SteamCMD is checking for updates" |
|||
fn_scriptlog "Detected SteamCMD is checking for updates" |
|||
sleep 1 |
|||
fn_printinfonl "Monitoring ${servicename}: When updates complete ${servicename} will start" |
|||
fn_scriptlog "When updates complete ${servicename} will start" |
|||
sleep 1 |
|||
fi |
|||
} |
|||
|
|||
fn_updateserver(){ |
|||
fn_rootcheck |
|||
fn_syscheck |
|||
fn_printdots "Updating ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_printok "Updating ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_scriptlog "Updating ${servername}" |
|||
cd "${rootdir}" |
|||
cd "steamcmd" |
|||
./steamcmd.sh +login ${steamuser} "${steampass}" +force_install_dir "${filesdir}" +app_update ${appid} +quit|tee -a "${scriptlog}" |
|||
} |
|||
|
|||
fn_validateserver(){ |
|||
fn_rootcheck |
|||
fn_syscheck |
|||
fn_printwarn "Validating may overwrite some customised files." |
|||
sleep 1 |
|||
echo -en "\n" |
|||
echo -en "https://developer.valvesoftware.com/wiki/SteamCMD#Validate" |
|||
sleep 5 |
|||
echo -en "\n" |
|||
fn_printdots "Validating ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_printok "Validating ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_scriptlog "Validating ${servername}" |
|||
cd "${rootdir}" |
|||
cd "steamcmd" |
|||
./steamcmd.sh +login ${steamuser} "${steampass}" +force_install_dir "${filesdir}" +app_update ${appid} validate +quit|tee -a "${scriptlog}" |
|||
} |
|||
|
|||
fn_restartserver(){ |
|||
fn_scriptlog "Restarting ${servername}" |
|||
fn_stopserver |
|||
fn_startserver |
|||
} |
|||
|
|||
fn_stopserver(){ |
|||
fn_rootcheck |
|||
fn_syscheck |
|||
pid=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -E "^${servicename}:"|wc -l) |
|||
fn_printdots "Stopping ${servicename}: ${servername}" |
|||
fn_scriptlog "Stopping ${servername}" |
|||
sleep 1 |
|||
if [ "${pid}" == "0" ]; then |
|||
fn_printfail "Stopping ${servicename}: ${servername} is already stopped" |
|||
fn_scriptlog "${servername} is already stopped" |
|||
else |
|||
tmux kill-session -t ${servicename} |
|||
fn_printok "Stopping ${servicename}: ${servername}" |
|||
fn_scriptlog "Stopped ${servername}" |
|||
fi |
|||
# Remove lock file |
|||
rm -f ${lockselfname} |
|||
sleep 1 |
|||
echo -en "\n" |
|||
} |
|||
|
|||
fn_startserver(){ |
|||
fn_rootcheck |
|||
fn_syscheck |
|||
fn_autoip |
|||
fn_parms |
|||
fn_logmanager |
|||
tmuxwc=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -v failed|grep -E "^${servicename}:"|wc -l) |
|||
if [ ${tmuxwc} -eq 0 ]; then |
|||
fn_scriptlog "Rotating log files" |
|||
if [ "${engine}" == "unreal2" ]; then |
|||
mv "${gamelog}" "${gamelogdate}" |
|||
fi |
|||
mv "${scriptlog}" "${scriptlogdate}" |
|||
mv "${consolelog}" "${consolelogdate}" |
|||
fi |
|||
fn_printdots "Starting ${servicename}: ${servername}" |
|||
fn_scriptlog "Starting ${servername}" |
|||
sleep 1 |
|||
if [ ${tmuxwc} -eq 1 ]; then |
|||
fn_printinfo "Starting ${servicename}: ${servername} is already running" |
|||
fn_scriptlog "${servername} is already running" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
exit |
|||
fi |
|||
# Create lock file |
|||
date > "${rootdir}/${lockselfname}" |
|||
cd "${executabledir}" |
|||
tmux new-session -d -s ${servicename} "${executable} ${parms}" 2> ${scriptlogdir}/.${servicename}-tmux-error.tmp |
|||
tmux pipe-pane -o -t ${servicename} "exec cat >> '${consolelog}'" |
|||
sleep 1 |
|||
tmuxwc=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -E "^${servicename}:"|wc -l) |
|||
if [ ${tmuxwc} -eq 0 ]; then |
|||
fn_printfailnl "Starting ${servicename}: Failed to start ${servername}" |
|||
echo -en " Check log files: ${rootdir}/log" |
|||
fn_scriptlog "failed to start ${servername}" |
|||
if [ -a ${scriptlogdir}/.${servicename}-tmux-error.tmp ]; then |
|||
fn_scriptlog "tmux returned the following error" |
|||
cat ${scriptlogdir}/.${servicename}-tmux-error.tmp >> ${scriptlog} |
|||
rm ${scriptlogdir}/.${servicename}-tmux-error.tmp |
|||
fi |
|||
else |
|||
fn_printok "Starting ${servicename}: ${servername}" |
|||
fn_scriptlog "Started ${servername}" |
|||
fi |
|||
sleep 1 |
|||
echo -en "\n" |
|||
} |
|||
|
|||
fn_jc2details(){ |
|||
fn_autoip |
|||
servername=$(grep -s hostname "${servercfgfullpath}"|sed 's/hostname //g'|sed 's/"//g') |
|||
pid=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -E "^${servicename}:"|wc -l) |
|||
echo "" |
|||
echo "${gamename} Server Details" |
|||
echo "============================" |
|||
echo "Server name: ${servername}" |
|||
echo "Server IP: ${ip}:${port}" |
|||
echo "Config file: ${servercfgfullpath}" |
|||
echo "" |
|||
echo "${servername} Ports" |
|||
echo "============================" |
|||
echo "Ports the server is currently using." |
|||
echo "" |
|||
echo "DIRECTION DESCRIPTION PORT" |
|||
echo "INBOUND Game port ${port}" |
|||
echo "" |
|||
echo "You can change ports by editing the" |
|||
echo "start parameters in ${selfname}." |
|||
echo "" |
|||
if [ "${pid}" == "0" ]; then |
|||
echo -e "Status:\e[0;31m OFFLINE\e[0;39m" |
|||
else |
|||
echo -e "Status:\e[0;32m ONLINE\e[0;39m" |
|||
fi |
|||
echo "" |
|||
} |
|||
|
|||
# |
|||
## Installer |
|||
# |
|||
|
|||
fn_header(){ |
|||
clear |
|||
echo "=================================" |
|||
echo "${gamename}" |
|||
echo "Linux Game Server Manager" |
|||
echo "by Daniel Gibbs" |
|||
echo "http://danielgibbs.co.uk" |
|||
echo "=================================" |
|||
echo "" |
|||
} |
|||
|
|||
fn_steamdl(){ |
|||
echo "Installing SteamCMD" |
|||
echo "=================================" |
|||
cd "${rootdir}" |
|||
mkdir -pv "steamcmd" |
|||
sleep 1 |
|||
cd "steamcmd" |
|||
if [ ! -f steamcmd.sh ]; then |
|||
wget -nv -N http://media.steampowered.com/client/steamcmd_linux.tar.gz |
|||
tar --verbose -zxf steamcmd_linux.tar.gz |
|||
rm -v steamcmd_linux.tar.gz |
|||
chmod +x steamcmd.sh |
|||
sleep 1 |
|||
else |
|||
echo "" |
|||
echo "Steam already installed!" |
|||
fi |
|||
sleep 1 |
|||
echo "" |
|||
} |
|||
|
|||
fn_steaminstall(){ |
|||
echo "Installing ${gamename} Server" |
|||
echo "=================================" |
|||
sleep 1 |
|||
mkdir -pv "${filesdir}" |
|||
cd "${rootdir}/steamcmd" |
|||
STEAMEXE=steamcmd ./steamcmd.sh +login ${steamuser} "${steampass}" +force_install_dir "${filesdir}" +app_update ${appid} validate +quit |
|||
echo "" |
|||
echo "=================================" |
|||
while true; do |
|||
read -p "Was the install successful? [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) break;; |
|||
[Nn]* ) fn_retryinstall;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
echo "" |
|||
} |
|||
|
|||
fn_loginstall(){ |
|||
echo "Creating log directorys" |
|||
echo "=================================" |
|||
sleep 1 |
|||
mkdir -pv "${rootdir}/log" |
|||
mkdir -pv "${scriptlogdir}" |
|||
touch "${scriptlog}" |
|||
mkdir -pv "${consolelogdir}" |
|||
touch "${consolelog}" |
|||
if [ ! -h ${rootdir}/log/server ]; then |
|||
ln -sv "${gamelogdir}" "${rootdir}/log/server" |
|||
else |
|||
echo "Symbolic link ${gamelogdir} => ${rootdir}/log/server already exists!" |
|||
fi |
|||
sleep 1 |
|||
echo "" |
|||
} |
|||
|
|||
fn_jc2config(){ |
|||
echo "Copying default_config.lua" |
|||
echo "=================================" |
|||
sleep 1 |
|||
cd "${filesdir}" |
|||
cp -v default_config.lua config.lua |
|||
sleep 1 |
|||
echo "" |
|||
} |
|||
|
|||
fn_getquery(){ |
|||
echo "GameServerQuery" |
|||
echo "============================" |
|||
while true; do |
|||
read -p "Do you want to install GameServerQuery? [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) cd "${rootdir}"; wget -nv -N "http://danielgibbs.co.uk/dl/gsquery.py"; chmod +x gsquery.py; break;; |
|||
[Nn]* ) echo -e "Not installing GameServerQuery.";break;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
echo "" |
|||
} |
|||
|
|||
fn_retryinstall(){ |
|||
while true; do |
|||
read -p "Retry install? [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) fn_install; exit;; |
|||
[Nn]* ) echo Exiting; exit;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
} |
|||
|
|||
fn_install(){ |
|||
fn_rootcheck |
|||
fn_header |
|||
if [ -d "${filesdir}" ]; then |
|||
echo "${gamename} Server is already installed here:" |
|||
pwd |
|||
echo "" |
|||
while true; do |
|||
read -p "Continue [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) fn_header; break;; |
|||
[Nn]* ) echo Exiting; return 1;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
fi |
|||
echo "Install Directory:" |
|||
pwd |
|||
echo "" |
|||
while true; do |
|||
read -p "Continue [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) break;; |
|||
[Nn]* ) echo Exiting; return 1;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
fn_header |
|||
fn_steamdl |
|||
fn_steaminstall |
|||
fn_loginstall |
|||
fn_jc2config |
|||
fn_getquery |
|||
sleep 1 |
|||
echo "" |
|||
fn_header |
|||
sleep 1 |
|||
fn_jc2details |
|||
sleep 1 |
|||
echo "=================================" |
|||
echo "Install Complete!" |
|||
echo "" |
|||
echo "To start server type:" |
|||
echo "${selfname} start" |
|||
echo "" |
|||
} |
|||
|
|||
case "$1" in |
|||
start) |
|||
fn_startserver;; |
|||
stop) |
|||
fn_stopserver;; |
|||
restart) |
|||
fn_restartserver;; |
|||
update) |
|||
fn_updateserver;; |
|||
update-restart) |
|||
fn_stopserver |
|||
fn_updateserver |
|||
fn_startserver;; |
|||
validate) |
|||
fn_validateserver;; |
|||
validate-restart) |
|||
fn_stopserver |
|||
fn_validateserver |
|||
fn_startserver;; |
|||
monitor) |
|||
fn_monitorserver;; |
|||
email-test) |
|||
fn_emailtest;; |
|||
details) |
|||
fn_details;; |
|||
backup) |
|||
fn_backupserver;; |
|||
console) |
|||
fn_console;; |
|||
debug) |
|||
fn_debugserver;; |
|||
install) |
|||
fn_install;; |
|||
*) |
|||
echo "Usage: $0 {start|stop|restart|update|update-restart|validate|validate-restart|monitor|email-test|details|backup|console|debug|install}" |
|||
exit 1;; |
|||
esac |
|||
exit |
@ -0,0 +1,915 @@ |
|||
#!/bin/bash |
|||
# Left 4 Dead |
|||
# Server Management Script |
|||
# Author: Daniel Gibbs |
|||
# Website: http://danielgibbs.co.uk |
|||
# Version: 061014 |
|||
|
|||
#### Variables #### |
|||
|
|||
# Notification Email |
|||
# (on|off) |
|||
emailnotification="off" |
|||
email="[email protected]" |
|||
|
|||
# Steam login |
|||
steamuser="anonymous" |
|||
steampass="" |
|||
|
|||
# Start Variables |
|||
defaultmap="l4d_hospital01_apartment" |
|||
maxplayers="8" |
|||
port="27015" |
|||
clientport="27005" |
|||
ip="0.0.0.0" |
|||
|
|||
# https://developer.valvesoftware.com/wiki/Command_Line_Options#Source_Dedicated_Server |
|||
fn_parms(){ |
|||
parms="-game left4dead -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} -tickrate ${tickrate} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" |
|||
} |
|||
|
|||
#### Advanced Variables #### |
|||
|
|||
# Steam |
|||
appid="222840" |
|||
|
|||
# Server Details |
|||
servicename="l4d-server" |
|||
gamename="Left 4 Dead" |
|||
engine="source" |
|||
|
|||
# Directories |
|||
rootdir="$(cd "$(dirname "${BASH_SOURCE[0]}" )" && pwd )" |
|||
selfname="$0" |
|||
lockselfname=$(echo ".${servicename}.lock") |
|||
filesdir="${rootdir}/serverfiles" |
|||
systemdir="${filesdir}/left4dead" |
|||
executabledir="${filesdir}" |
|||
executable="./srcds_run" |
|||
servercfgdir="${systemdir}/cfg" |
|||
servercfg="${servicename}.cfg" |
|||
servercfgfullpath="${servercfgdir}/${servercfg}" |
|||
defaultcfg="${servercfgdir}/server.cfg" |
|||
backupdir="backups" |
|||
|
|||
# Server Details |
|||
servername=$(grep -s hostname "${servercfgfullpath}"|sed 's/hostname //g'|sed 's/"//g') |
|||
rcon=$(grep -s rcon_password "${servercfgfullpath}"|sed 's/rcon_password //g'|sed 's/"//g') |
|||
|
|||
# Logging |
|||
logdays="7" |
|||
gamelogdir="${systemdir}/logs" |
|||
scriptlogdir="${rootdir}/log/script" |
|||
consolelogdir="${rootdir}/log/console" |
|||
|
|||
scriptlog="${scriptlogdir}/${servicename}-script.log" |
|||
consolelog="${consolelogdir}/${servicename}-console.log" |
|||
emaillog="${scriptlogdir}/${servicename}-email.log" |
|||
|
|||
scriptlogdate="${scriptlogdir}/${servicename}-script-$(date '+%d-%m-%Y-%H-%M-%S').log" |
|||
consolelogdate="${consolelogdir}/${servicename}-console-$(date '+%d-%m-%Y-%H-%M-%S').log" |
|||
|
|||
##### Script ##### |
|||
# Do not edit |
|||
# unless you know |
|||
# what you are doing |
|||
|
|||
fn_scriptlog(){ |
|||
echo -e "$(date '+%b %d %H:%M:%S') ${servicename}: ${1}" >> ${scriptlog} |
|||
} |
|||
|
|||
# [ FAIL ] |
|||
fn_printfail(){ |
|||
echo -en "\r\033[K[\e[0;31m FAIL \e[0;39m] $@" |
|||
} |
|||
|
|||
fn_printfailnl(){ |
|||
echo -e "\r\033[K[\e[0;31m FAIL \e[0;39m] $@" |
|||
} |
|||
|
|||
fn_printok(){ |
|||
echo -en "\r\033[K[\e[0;32m OK \e[0;39m] $@" |
|||
} |
|||
|
|||
# [ OK ] |
|||
fn_printoknl(){ |
|||
echo -e "\r\033[K[\e[0;32m OK \e[0;39m] $@" |
|||
} |
|||
|
|||
fn_printinfo(){ |
|||
echo -en "\r\033[K[\e[0;36m INFO \e[0;39m] $@" |
|||
} |
|||
|
|||
fn_printinfonl(){ |
|||
echo -e "\r\033[K[\e[0;36m INFO \e[0;39m] $@" |
|||
} |
|||
|
|||
# [ INFO ] |
|||
fn_printokinfonl(){ |
|||
echo -e "\r\033[K[\e[0;36m INFO \e[0;39m] $@" |
|||
} |
|||
|
|||
fn_printwarn(){ |
|||
echo -en "\r\033[K[\e[1;33m WARN \e[0;39m] $@" |
|||
} |
|||
|
|||
fn_printwarnnl(){ |
|||
echo -e "\r\033[K[\e[1;33m WARN \e[0;39m] $@" |
|||
} |
|||
|
|||
# [ .... ] |
|||
fn_printdots(){ |
|||
echo -en "\r\033[K[ .... ] $@" |
|||
} |
|||
|
|||
fn_rootcheck(){ |
|||
if [ `whoami` = "root" ]; then |
|||
fn_printfailnl "Script will not run as root!" |
|||
exit |
|||
fi |
|||
} |
|||
|
|||
fn_syscheck(){ |
|||
if [ ! -e "${systemdir}" ]; then |
|||
fn_printfailnl "Cannot access ${systemdir}: No such directory" |
|||
exit |
|||
fi |
|||
} |
|||
|
|||
fn_autoip(){ |
|||
# Identifies the server interface IP |
|||
# If multiple interfaces this will need to be set manually |
|||
getip=$(ip -o -4 addr|awk '{print $4 }'|grep -oe '\([0-9]\{1,3\}\.\?\)\{4\}'|grep -v 127.0.0) |
|||
getipwc=$(ip -o -4 addr|awk '{print $4 }'|grep -oe '\([0-9]\{1,3\}\.\?\)\{4\}'|grep -v 127.0.0|wc -l) |
|||
if [ "${ip}" == "0.0.0.0" ]||[ "${ip}" == "" ]; then |
|||
if [ "${getipwc}" -ge "2" ]; then |
|||
fn_printwarn "Multiple active network interfaces.\n\n" |
|||
echo -en "Manually specify the IP you want to use within the ${selfname} script.\n" |
|||
echo -en "Set ip=\"0.0.0.0\" to one of the following:\n" |
|||
echo -en "${getip}\n" |
|||
exit |
|||
else |
|||
ip=${getip} |
|||
fi |
|||
fi |
|||
} |
|||
|
|||
fn_logmanager(){ |
|||
if [ ! -e "${consolelog}" ]; then |
|||
touch "${consolelog}" |
|||
fi |
|||
# log manager will active if finds logs older than ${logdays} |
|||
if [ `find "${scriptlogdir}"/* -mtime +${logdays}|wc -l` -ne "0" ]; then |
|||
fn_printdots "Starting log cleaner" |
|||
sleep 1 |
|||
fn_printok "Starting log cleaner" |
|||
fn_scriptlog "Starting log cleaner" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
fn_printinfo "Removing logs older than ${logdays} days" |
|||
fn_scriptlog "Removing logs older than ${logdays} days" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
if [ "${engine}" == "unreal2" ]; then |
|||
find "${gamelogdir}"/* -mtime +${logdays}|tee >> "${scriptlog}" |
|||
fi |
|||
find "${scriptlogdir}"/* -mtime +${logdays}|tee >> "${scriptlog}" |
|||
find "${consolelogdir}"/* -mtime +${logdays}|tee >> "${scriptlog}" |
|||
if [ "${engine}" == "unreal2" ]; then |
|||
gamecount=$(find "${scriptlogdir}"/* -mtime +${logdays}|wc -l) |
|||
fi |
|||
scriptcount=$(find "${scriptlogdir}"/* -mtime +${logdays}|wc -l) |
|||
consolecount=$(find "${consolelogdir}"/* -mtime +${logdays}|wc -l) |
|||
count=$((${scriptcount} + ${consolecount})) |
|||
if [ "${engine}" == "unreal2" ]; then |
|||
count=$((${scriptcount} + ${consolecount} + ${gamecount})) |
|||
else |
|||
count=$((${scriptcount} + ${consolecount})) |
|||
fi |
|||
if [ "${engine}" == "unreal2" ]; then |
|||
find "${gamelogdir}"/* -mtime +${logdays} -exec rm {} \; |
|||
fi |
|||
find "${scriptlogdir}"/* -mtime +${logdays} -exec rm {} \; |
|||
find "${consolelogdir}"/* -mtime +${logdays} -exec rm {} \; |
|||
fn_printok "Log cleaner removed ${count} log files" |
|||
fn_scriptlog "Log cleaner removed ${count} log files" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
fi |
|||
} |
|||
|
|||
fn_debugserver(){ |
|||
fn_rootcheck |
|||
fn_syscheck |
|||
fn_autoip |
|||
fn_distro |
|||
fn_uptime |
|||
fn_load |
|||
fn_parms |
|||
echo "" |
|||
echo "${gamename} Debug" |
|||
echo "============================" |
|||
echo "" |
|||
echo -e "Distro: ${os}" |
|||
echo -e "Arch: ${arch}" |
|||
echo -e "Kernel: ${kernel}" |
|||
echo -e "Hostname: $HOSTNAME" |
|||
echo "" |
|||
echo "Start parameters:" |
|||
echo ${parms} |
|||
echo "" |
|||
echo -e "Use for identifying server issues only!" |
|||
echo -e "Press CTRL+c to drop out of debug mode" |
|||
echo -e "\e[0;31mWARNING!\e[0;39m If ${servicename} is already running it will be stopped" |
|||
echo "" |
|||
while true; do |
|||
read -p "Continue? [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) break;; |
|||
[Nn]* ) echo Exiting; return 1;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
fn_stopserver |
|||
fn_printdots "Starting debug mode ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_printok "Starting debug mode ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_scriptlog "Started debug mode ${servername}" |
|||
echo -en "\n" |
|||
cd "${executabledir}" |
|||
${executable} ${parms} -debug |
|||
} |
|||
|
|||
fn_console(){ |
|||
fn_rootcheck |
|||
fn_syscheck |
|||
echo "" |
|||
echo "${gamename} Console" |
|||
echo "============================" |
|||
echo "" |
|||
echo "Press \"CTRL+b d\" to exit console" |
|||
echo -e "\e[0;31mWARNING!\e[0;39m Do NOT press CTRL+c to exit" |
|||
echo "" |
|||
while true; do |
|||
read -p "Continue? [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) break;; |
|||
[Nn]* ) echo Exiting; return 1;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
fn_printdots "Starting ${servicename} console" |
|||
sleep 1 |
|||
tmuxwc=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -v failed|grep -E "^${servicename}:"|wc -l) |
|||
if [ ${tmuxwc} -eq 1 ]; then |
|||
fn_printoknl "Starting ${servicename} console" |
|||
fn_scriptlog "Console accessed" |
|||
sleep 1 |
|||
tmux attach-session -t ${servicename} |
|||
else |
|||
fn_printfailnl "Starting ${servicename} console: ${servername} not running" |
|||
sleep 1 |
|||
while true; do |
|||
read -p "Do you want to start the server? [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) fn_startserver; break;; |
|||
[Nn]* ) break;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
fi |
|||
} |
|||
|
|||
fn_backupserver(){ |
|||
fn_rootcheck |
|||
fn_syscheck |
|||
backupname="${servicename}-$(date '+%Y-%m-%d-%H%M%S')" |
|||
echo "" |
|||
echo "${gamename} Backup" |
|||
echo "============================" |
|||
echo "" |
|||
echo "The following backup will be created." |
|||
echo "" |
|||
echo "${backupdir}/${backupname}.tar.gz" |
|||
echo "" |
|||
while true; do |
|||
read -p "Continue? [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) break;; |
|||
[Nn]* ) echo Exiting; return 1;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
tmuxwc=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -v failed|grep -E "^${servicename}:"|wc -l) |
|||
if [ ${tmuxwc} -eq 1 ]; then |
|||
echo -e "\e[0;31mWARNING!\e[0;39m ${servicename} is currently running" |
|||
while true; do |
|||
read -p "Would you like to stop ${servicename} while running the backup? [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) fn_stopserver; break;; |
|||
[Nn]* ) break;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
fi |
|||
fn_printdots "Starting backup ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_printok "Starting backup ${servicename}: ${servername}" |
|||
fn_scriptlog "Backup started" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
cd "${rootdir}" |
|||
mkdir -pv "${backupdir}" > /dev/null 2>&1 |
|||
tar -cvzf "${backupdir}/${backupname}.tar.gz" --exclude "${backupdir}" * |
|||
echo -en "\r\033[K${servicename} Backup complete" |
|||
fn_scriptlog "Backup complete" |
|||
} |
|||
|
|||
fn_distro(){ |
|||
arch=$(uname -m) |
|||
kernel=$(uname -r) |
|||
if [ -f /etc/lsb-release ]; then |
|||
os=$(lsb_release -s -d) |
|||
elif [ -f /etc/debian_version ]; then |
|||
os="Debian $(cat /etc/debian_version)" |
|||
elif [ -f /etc/redhat-release ]; then |
|||
os=$(cat /etc/redhat-release) |
|||
else |
|||
os="$(uname -s) $(uname -r)" |
|||
fi |
|||
} |
|||
|
|||
fn_uptime(){ |
|||
uptime=$(</proc/uptime) |
|||
uptime=${uptime%%.*} |
|||
minutes=$(( uptime/60%60 )) |
|||
hours=$(( uptime/60/60%24 )) |
|||
days=$(( uptime/60/60/24 )) |
|||
} |
|||
|
|||
fn_load(){ |
|||
load=$(uptime|awk -F 'load average' '{ print $2 }') |
|||
} |
|||
|
|||
fn_emailnotification(){ |
|||
fn_distro |
|||
fn_uptime |
|||
fn_load |
|||
{ |
|||
echo -e "========================================\n${servicename} details\n========================================\n" |
|||
echo -e "Service: ${servicename}" |
|||
echo -e "Server: ${servername}" |
|||
echo -e "Game: ${gamename}" |
|||
echo -e "Failure reason: ${failurereason}" |
|||
echo -e "Action Taken: ${actiontaken}\n" |
|||
echo -e "========================================\nServer details\n========================================\n" |
|||
echo -e "Date: $(date)" |
|||
echo -e "Distro: ${os}" |
|||
echo -e "Arch: ${arch}" |
|||
echo -e "Kernel: ${kernel}" |
|||
echo -e "Hostname: $HOSTNAME" |
|||
echo -e "Uptime: ${days}d, ${hours}h, ${minutes}m" |
|||
echo -e "Avg Load${load}\n" |
|||
echo -e "========================================\nLogs\n========================================\n" |
|||
echo -e "Script log\n===================\n" |
|||
}|tee "${scriptlogdir}/${servicename}-email.log" > /dev/null 2>&1 |
|||
tail -25 "${scriptlog}" >> "${emaillog}" |
|||
if [ ! -z "${consolelog}" ]; then |
|||
echo -e "\n\nConsole log\n====================\n" >> "${emaillog}" |
|||
tail -25 "${consolelog}" >> "${emaillog}" |
|||
fi |
|||
if [ ! -z "${gamelogdir}" ]; then |
|||
echo -e "\n\nServer log\n====================\n" >> "${emaillog}" |
|||
tail "${gamelogdir}"/*|grep -v "==>"|sed '/^$/d'|tail -25 >> "${emaillog}" |
|||
fi |
|||
mail -s "${subject}" ${email} < "${emaillog}" |
|||
fn_printinfo "Sent email notification to ${email}" |
|||
fn_scriptlog "Sent email notification to ${email}" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
} |
|||
|
|||
fn_emailtest(){ |
|||
fn_rootcheck |
|||
fn_syscheck |
|||
fn_scriptlog "Emailing test notification" |
|||
if [ "${emailnotification}" = "on" ]; then |
|||
subject="${servicename} Email Test Notification - Testing ${servername}" |
|||
failurereason="Testing ${servicename} email notification" |
|||
actiontaken="Sent test email...hello is this thing on?" |
|||
fn_emailnotification |
|||
else |
|||
fn_printfailnl "Email notification not enabled" |
|||
fn_scriptlog "Email notification not enabled" |
|||
fi |
|||
sleep 1 |
|||
echo -en "\n" |
|||
} |
|||
|
|||
fn_serverquery(){ |
|||
# uses gsquery.py to directly query the server |
|||
# detects if the server locks up |
|||
if [ -f gsquery.py ]; then |
|||
if [ "${engine}" == "unreal" ]||[ "${engine}" == "unreal2" ]; then |
|||
gameport=$(grep Port= ${systemdir}/${ini}|grep -v Master|grep -v LAN|grep -v Proxy|grep -v Listen|sed 's/\Port=//g') |
|||
port=$((${gameport} + 1)) |
|||
elif [ "${engine}" == "spark" ]; then |
|||
port=$((${port} + 1)) |
|||
elif [ "${engine}" == "realvirtuality" ]; then |
|||
port=${queryport} |
|||
fi |
|||
fn_printinfo "Monitoring ${servicename}: Detected gsquery.py" |
|||
fn_scriptlog "Detected gsquery.py" |
|||
sleep 1 |
|||
fn_printdots "Monitoring ${servicename}: Querying port: ${ip}:${port}: QUERYING" |
|||
fn_scriptlog "Querying port: ${ip}:${port}: QUERYING" |
|||
sleep 1 |
|||
serverquery=$(./gsquery.py -a ${ip} -p ${port} -e ${engine} 2>&1) |
|||
exitcode=$? |
|||
if [ "${exitcode}" == "1" ]||[ "${exitcode}" == "2" ]||[ "${exitcode}" == "3" ]||[ "${exitcode}" == "4" ]; then |
|||
fn_printfail "Monitoring ${servicename}: Querying port: ${ip}:${port}: ${serverquery}" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
fn_scriptlog "Querying port: ${ip}:${port}: ${serverquery}" |
|||
if [[ -z "${secondquery}" ]]; then |
|||
fn_printinfo "Monitoring ${servicename}: Waiting 30 seconds to re-query" |
|||
fn_scriptlog "Waiting 30 seconds to re-query" |
|||
sleep 30 |
|||
secondquery=1 |
|||
fn_serverquery |
|||
fi |
|||
if [ "${emailnotification}" = "on" ]; then |
|||
subject="${servicename} Monitor - Starting ${servername}" |
|||
failurereason="Failed to query ${servicename}: ${serverquery}" |
|||
actiontaken="restarted ${servicename}" |
|||
fn_emailnotification |
|||
fi |
|||
fn_restartserver |
|||
exit |
|||
elif [ "${exitcode}" == "0" ]; then |
|||
fn_printok "Monitoring ${servicename}: Querying port: ${ip}:${port}: OK" |
|||
fn_scriptlog "Querying port: ${ip}:${port}: OK" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
exit |
|||
elif [ "${exitcode}" == "126" ]; then |
|||
fn_printfail "Monitoring ${servicename}: Querying port: ${ip}:${port}: ERROR: ./gsquery.py: Permission denied" |
|||
fn_scriptlog "Querying port: ${ip}:${port}: ./gsquery.py: Permission denied" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
echo "Attempting to resolve automatically" |
|||
chmod +x -v gsquery.py |
|||
exitcode=$? |
|||
if [ "${exitcode}" == "0" ]; then |
|||
fn_serverquery |
|||
else |
|||
echo -en "\nUnable to resolve automatically. Please manually fix permissions\n" |
|||
owner=$(ls -al gsquery.py|awk '{ print $3 }') |
|||
echo "As user ${owner} or root run the following command" |
|||
whoami=$(whoami) |
|||
echo -en "\nchown ${whoami}:${whoami} gsquery.py\n\n" |
|||
exit |
|||
fi |
|||
else |
|||
fn_printfail "Monitoring ${servicename}: Querying port: ${ip}:${port}: UNKNOWN ERROR" |
|||
fn_scriptlog "Querying port: ${ip}:${port}: UNKNOWN ERROR" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
./gsquery.py -a ${ip} -p ${port} -e ${engine} |
|||
exit |
|||
fi |
|||
fi |
|||
} |
|||
|
|||
fn_monitorserver(){ |
|||
fn_rootcheck |
|||
fn_syscheck |
|||
fn_autoip |
|||
fn_printdots "Monitoring ${servicename}: ${servername}" |
|||
fn_scriptlog "Monitoring ${servername}" |
|||
sleep 1 |
|||
if [ ! -f ${lockselfname} ]; then |
|||
fn_printinfo "Monitoring ${servicename}: Monitor disabled: No lock file found" |
|||
fn_scriptlog "Monitor disabled: No lock file found" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
echo "To enable monitor run ${selfname} start" |
|||
exit |
|||
fi |
|||
updatecheck=$(ps -ef|grep "${selfname} update"|grep -v grep|wc -l) |
|||
if [ "${updatecheck}" = "0" ]; then |
|||
fn_printdots "Monitoring ${servicename}: Checking session: CHECKING" |
|||
fn_scriptlog "Checking session: CHECKING" |
|||
sleep 1 |
|||
tmuxwc=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -v failed|grep -E "^${servicename}:"|wc -l) |
|||
if [ ${tmuxwc} -eq 1 ]; then |
|||
fn_printok "Monitoring ${servicename}: Checking session: OK" |
|||
fn_scriptlog "Checking session: OK" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
fn_serverquery |
|||
exit |
|||
else |
|||
fn_printfail "Monitoring ${servicename}: Checking session: FAIL" |
|||
fn_scriptlog "Checking session: FAIL" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
if [ "${emailnotification}" = "on" ]; then |
|||
subject="${servicename} Monitor - Starting ${servername}" |
|||
failurereason="${servicename} process not running" |
|||
actiontaken="${servicename} has been restarted" |
|||
fn_emailnotification |
|||
fi |
|||
fn_scriptlog "Monitor is starting ${servername}" |
|||
fn_startserver |
|||
fi |
|||
else |
|||
fn_printinfonl "Monitoring ${servicename}: Detected SteamCMD is checking for updates" |
|||
fn_scriptlog "Detected SteamCMD is checking for updates" |
|||
sleep 1 |
|||
fn_printinfonl "Monitoring ${servicename}: When updates complete ${servicename} will start" |
|||
fn_scriptlog "When updates complete ${servicename} will start" |
|||
sleep 1 |
|||
fi |
|||
} |
|||
|
|||
fn_updateserver(){ |
|||
fn_rootcheck |
|||
fn_syscheck |
|||
fn_printdots "Updating ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_printok "Updating ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_scriptlog "Updating ${servername}" |
|||
cd "${rootdir}" |
|||
cd "steamcmd" |
|||
./steamcmd.sh +login ${steamuser} "${steampass}" +force_install_dir "${filesdir}" +app_update ${appid} +quit|tee -a "${scriptlog}" |
|||
} |
|||
|
|||
fn_validateserver(){ |
|||
fn_rootcheck |
|||
fn_syscheck |
|||
fn_printwarn "Validating may overwrite some customised files." |
|||
sleep 1 |
|||
echo -en "\n" |
|||
echo -en "https://developer.valvesoftware.com/wiki/SteamCMD#Validate" |
|||
sleep 5 |
|||
echo -en "\n" |
|||
fn_printdots "Validating ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_printok "Validating ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_scriptlog "Validating ${servername}" |
|||
cd "${rootdir}" |
|||
cd "steamcmd" |
|||
./steamcmd.sh +login ${steamuser} "${steampass}" +force_install_dir "${filesdir}" +app_update ${appid} validate +quit|tee -a "${scriptlog}" |
|||
} |
|||
|
|||
fn_restartserver(){ |
|||
fn_scriptlog "Restarting ${servername}" |
|||
fn_stopserver |
|||
fn_startserver |
|||
} |
|||
|
|||
fn_stopserver(){ |
|||
fn_rootcheck |
|||
fn_syscheck |
|||
pid=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -E "^${servicename}:"|wc -l) |
|||
fn_printdots "Stopping ${servicename}: ${servername}" |
|||
fn_scriptlog "Stopping ${servername}" |
|||
sleep 1 |
|||
if [ "${pid}" == "0" ]; then |
|||
fn_printfail "Stopping ${servicename}: ${servername} is already stopped" |
|||
fn_scriptlog "${servername} is already stopped" |
|||
else |
|||
tmux kill-session -t ${servicename} |
|||
fn_printok "Stopping ${servicename}: ${servername}" |
|||
fn_scriptlog "Stopped ${servername}" |
|||
fi |
|||
# Remove lock file |
|||
rm -f ${lockselfname} |
|||
sleep 1 |
|||
echo -en "\n" |
|||
} |
|||
|
|||
fn_startserver(){ |
|||
fn_rootcheck |
|||
fn_syscheck |
|||
fn_autoip |
|||
fn_parms |
|||
fn_logmanager |
|||
tmuxwc=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -v failed|grep -E "^${servicename}:"|wc -l) |
|||
if [ ${tmuxwc} -eq 0 ]; then |
|||
fn_scriptlog "Rotating log files" |
|||
if [ "${engine}" == "unreal2" ]; then |
|||
mv "${gamelog}" "${gamelogdate}" |
|||
fi |
|||
mv "${scriptlog}" "${scriptlogdate}" |
|||
mv "${consolelog}" "${consolelogdate}" |
|||
fi |
|||
fn_printdots "Starting ${servicename}: ${servername}" |
|||
fn_scriptlog "Starting ${servername}" |
|||
sleep 1 |
|||
if [ ${tmuxwc} -eq 1 ]; then |
|||
fn_printinfo "Starting ${servicename}: ${servername} is already running" |
|||
fn_scriptlog "${servername} is already running" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
exit |
|||
fi |
|||
# Create lock file |
|||
date > "${rootdir}/${lockselfname}" |
|||
cd "${executabledir}" |
|||
tmux new-session -d -s ${servicename} "${executable} ${parms}" 2> ${scriptlogdir}/.${servicename}-tmux-error.tmp |
|||
tmux pipe-pane -o -t ${servicename} "exec cat >> '${consolelog}'" |
|||
sleep 1 |
|||
tmuxwc=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -E "^${servicename}:"|wc -l) |
|||
if [ ${tmuxwc} -eq 0 ]; then |
|||
fn_printfailnl "Starting ${servicename}: Failed to start ${servername}" |
|||
echo -en " Check log files: ${rootdir}/log" |
|||
fn_scriptlog "failed to start ${servername}" |
|||
if [ -a ${scriptlogdir}/.${servicename}-tmux-error.tmp ]; then |
|||
fn_scriptlog "tmux returned the following error" |
|||
cat ${scriptlogdir}/.${servicename}-tmux-error.tmp >> ${scriptlog} |
|||
rm ${scriptlogdir}/.${servicename}-tmux-error.tmp |
|||
fi |
|||
else |
|||
fn_printok "Starting ${servicename}: ${servername}" |
|||
fn_scriptlog "Started ${servername}" |
|||
fi |
|||
sleep 1 |
|||
echo -en "\n" |
|||
} |
|||
|
|||
fn_details(){ |
|||
fn_autoip |
|||
servername=$(grep -s hostname "${servercfgfullpath}"|sed 's/hostname //g'|sed 's/"//g') |
|||
rcon=$(grep -s rcon_password "${servercfgfullpath}"|sed 's/rcon_password //g'|sed 's/"//g') |
|||
pid=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -E "^${servicename}:"|wc -l) |
|||
echo "" |
|||
echo "${gamename} Server Details" |
|||
echo "============================" |
|||
echo "Server name: ${servername}" |
|||
echo "Server IP: ${ip}:${port}" |
|||
echo "RCON password: ${rcon}" |
|||
echo "Config file: ${servercfgfullpath}" |
|||
echo "" |
|||
echo "${servername} Ports" |
|||
echo "============================" |
|||
echo "Ports the server is currently using." |
|||
echo "" |
|||
echo "DIRECTION DESCRIPTION PORT" |
|||
echo "INBOUND Game/RCON port ${port}" |
|||
if [ ! -z ${sourcetvport} ]; then |
|||
echo "INBOUND SourceTV port ${sourcetvport}" |
|||
fi |
|||
echo "OUTBOUND Client port ${clientport}" |
|||
echo "" |
|||
echo "You can change ports by editing the" |
|||
echo "start parameters in ${selfname}." |
|||
echo "" |
|||
if [ "${pid}" == "0" ]; then |
|||
echo -e "Status:\e[0;31m OFFLINE\e[0;39m" |
|||
else |
|||
echo -e "Status:\e[0;32m ONLINE\e[0;39m" |
|||
fi |
|||
echo "" |
|||
} |
|||
|
|||
# |
|||
## Installer |
|||
# |
|||
|
|||
fn_l4ddeps(){ |
|||
echo "Copying libstdc++.so.6" |
|||
echo "=================================" |
|||
sleep 1 |
|||
cd "${filesdir}" |
|||
cp -v "${rootdir}/steamcmd/linux32/libstdc++.so.6" "${filesdir}" |
|||
sleep 1 |
|||
echo "" |
|||
} |
|||
|
|||
fn_header(){ |
|||
clear |
|||
echo "=================================" |
|||
echo "${gamename}" |
|||
echo "Linux Game Server Manager" |
|||
echo "by Daniel Gibbs" |
|||
echo "contributions by Summit Singh Thakur" |
|||
echo "http://danielgibbs.co.uk" |
|||
echo "=================================" |
|||
echo "" |
|||
} |
|||
|
|||
fn_steamdl(){ |
|||
echo "Installing SteamCMD" |
|||
echo "=================================" |
|||
cd "${rootdir}" |
|||
mkdir -pv "steamcmd" |
|||
sleep 1 |
|||
cd "steamcmd" |
|||
if [ ! -f steamcmd.sh ]; then |
|||
wget -nv -N http://media.steampowered.com/client/steamcmd_linux.tar.gz |
|||
tar --verbose -zxf steamcmd_linux.tar.gz |
|||
rm -v steamcmd_linux.tar.gz |
|||
chmod +x steamcmd.sh |
|||
sleep 1 |
|||
else |
|||
echo "" |
|||
echo "Steam already installed!" |
|||
fi |
|||
sleep 1 |
|||
echo "" |
|||
} |
|||
|
|||
fn_steaminstall(){ |
|||
echo "Installing ${gamename} Server" |
|||
echo "=================================" |
|||
sleep 1 |
|||
mkdir -pv "${filesdir}" |
|||
cd "${rootdir}/steamcmd" |
|||
STEAMEXE=steamcmd ./steamcmd.sh +login ${steamuser} "${steampass}" +force_install_dir "${filesdir}" +app_update ${appid} validate +quit |
|||
echo "" |
|||
echo "=================================" |
|||
while true; do |
|||
read -p "Was the install successful? [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) break;; |
|||
[Nn]* ) fn_retryinstall;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
echo "" |
|||
} |
|||
|
|||
fn_steamfix(){ |
|||
echo "Applying steamclient.so fix" |
|||
echo "=================================" |
|||
sleep 1 |
|||
mkdir -pv "${HOME}/.steam" |
|||
mkdir -pv "${HOME}/.steam/sdk32" |
|||
cp -v "${rootdir}/steamcmd/linux32/steamclient.so" "${HOME}/.steam/sdk32/steamclient.so" |
|||
sleep 1 |
|||
echo "" |
|||
} |
|||
|
|||
fn_loginstall(){ |
|||
echo "Creating log directorys" |
|||
echo "=================================" |
|||
sleep 1 |
|||
mkdir -pv "${rootdir}/log" |
|||
mkdir -pv "${scriptlogdir}" |
|||
touch "${scriptlog}" |
|||
mkdir -pv "${consolelogdir}" |
|||
touch "${consolelog}" |
|||
if [ ! -h ${rootdir}/log/server ]; then |
|||
ln -sv "${gamelogdir}" "${rootdir}/log/server" |
|||
else |
|||
echo "Symbolic link ${gamelogdir} => ${rootdir}/log/server already exists!" |
|||
fi |
|||
sleep 1 |
|||
echo "" |
|||
} |
|||
|
|||
fn_getquery(){ |
|||
echo "GameServerQuery" |
|||
echo "============================" |
|||
while true; do |
|||
read -p "Do you want to install GameServerQuery? [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) cd "${rootdir}"; wget -nv -N "http://danielgibbs.co.uk/dl/gsquery.py"; chmod +x gsquery.py; break;; |
|||
[Nn]* ) echo -e "Not installing GameServerQuery.";break;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
echo "" |
|||
} |
|||
|
|||
fn_retryinstall(){ |
|||
while true; do |
|||
read -p "Retry install? [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) fn_install; exit;; |
|||
[Nn]* ) echo Exiting; exit;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
} |
|||
|
|||
fn_install(){ |
|||
fn_rootcheck |
|||
fn_header |
|||
if [ -d "${filesdir}" ]; then |
|||
echo "${gamename} Server is already installed here:" |
|||
pwd |
|||
echo "" |
|||
while true; do |
|||
read -p "Continue [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) fn_header; break;; |
|||
[Nn]* ) echo Exiting; return 1;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
fi |
|||
echo "Install Directory:" |
|||
pwd |
|||
echo "" |
|||
while true; do |
|||
read -p "Continue [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) break;; |
|||
[Nn]* ) echo Exiting; return 1;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
fn_header |
|||
fn_steamdl |
|||
fn_steaminstall |
|||
fn_steamfix |
|||
fn_loginstall |
|||
fn_getquery |
|||
fn_l4ddeps |
|||
echo "Configuring ${gamename} Server" |
|||
echo "=================================" |
|||
sleep 1 |
|||
read -p "Enter server name: " servername |
|||
read -p "Enter rcon password: " rconpass |
|||
sleep 1 |
|||
echo "Creating server.cfg." |
|||
touch "${defaultcfg}" |
|||
echo "exec ${servicename}.cfg" > "${defaultcfg}" |
|||
sleep 1 |
|||
echo "Creating ${servicename}.cfg config file." |
|||
touch "${servercfgfullpath}" |
|||
{ |
|||
echo -e "// server name" |
|||
echo -e "hostname \"${servername}\"" |
|||
echo -e "" |
|||
echo -e "// rcon passsword" |
|||
echo -e "rcon_password \"${rconpass}\"" |
|||
echo -e "" |
|||
echo -e "// Server password" |
|||
echo -e "sv_password \"\"" |
|||
echo -e "" |
|||
echo -e "// server logging" |
|||
echo -e "log on" |
|||
echo -e "sv_logbans 1" |
|||
echo -e "sv_logecho 1" |
|||
echo -e "sv_logfile 1" |
|||
echo -e "sv_log_onefile 0" |
|||
}|tee "${servercfgfullpath}" > /dev/null 2>&1 |
|||
sleep 1 |
|||
echo "" |
|||
fn_header |
|||
sleep 1 |
|||
fn_details |
|||
sleep 1 |
|||
echo "=================================" |
|||
echo "Install Complete!" |
|||
echo "" |
|||
echo "To start server type:" |
|||
echo "${selfname} start" |
|||
echo "" |
|||
} |
|||
|
|||
case "$1" in |
|||
start) |
|||
fn_startserver;; |
|||
stop) |
|||
fn_stopserver;; |
|||
restart) |
|||
fn_restartserver;; |
|||
update) |
|||
fn_updateserver;; |
|||
update-restart) |
|||
fn_stopserver |
|||
fn_updateserver |
|||
fn_startserver;; |
|||
validate) |
|||
fn_validateserver;; |
|||
validate-restart) |
|||
fn_stopserver |
|||
fn_validateserver |
|||
fn_startserver;; |
|||
monitor) |
|||
fn_monitorserver;; |
|||
email-test) |
|||
fn_emailtest;; |
|||
details) |
|||
fn_details;; |
|||
backup) |
|||
fn_backupserver;; |
|||
console) |
|||
fn_console;; |
|||
debug) |
|||
fn_debugserver;; |
|||
install) |
|||
fn_install;; |
|||
*) |
|||
echo "Usage: $0 {start|stop|restart|update|update-restart|validate|validate-restart|monitor|email-test|details|backup|console|debug|install}" |
|||
exit 1;; |
|||
esac |
|||
exit |
Binary file not shown.
@ -1,14 +1,28 @@ |
|||
linuxgameservers |
|||
================ |
|||
<h1>Linux Game Server Manager</h1> |
|||
|
|||
<a href="http://danielgibbs.co.uk/scripts"><img src="http://danielgibbs.co.uk/wp-content/uploads/2014/02/linux-game-server-manager-full.png" alt="linux game server manager" width="600" /></a> |
|||
|
|||
The Linux Game Server Managers are command line tools for quick, simple deployment and management of various dedicated game servers and voice comms servers. |
|||
|
|||
Main features |
|||
<h2>Main features</h2> |
|||
|
|||
Server installer<br> |
|||
Start/Stop/Restart server<br> |
|||
Server updater<br> |
|||
Server monitor (includes optional email notification)<br> |
|||
<ul> |
|||
<li>Server installer (SteamCMD).</li> |
|||
<li>Start/Stop/Restart server.</li> |
|||
<li>Server update (SteamCMD).</li> |
|||
<li>Server monitor (including email notification).</li> |
|||
<li>Server backup.</li> |
|||
<li>Server console.</li> |
|||
</ul> |
|||
<h2>Compatibility</h2> |
|||
The Linux Game Server Manager is tested to work on the following Linux systems. |
|||
<ul> |
|||
<li>Debian based distros (Ubuntu, Mint etc.).</li> |
|||
<li>Redhat based distros (CentOS, Fedora etc.).</li> |
|||
</ul> |
|||
The scripts are written in BASH and Python and would probably work with other distros. |
|||
|
|||
Full Documentation and details at: |
|||
<h2>Instructions</h2> |
|||
Full documentation and instructions can be found here. |
|||
|
|||
http://danielgibbs.co.uk/scripts |
|||
<b><a href="http://danielgibbs.co.uk/scripts">http://danielgibbs.co.uk/scripts</a></b> |
|||
|
@ -3,7 +3,7 @@ |
|||
# Server Management Script |
|||
# Author: Daniel Gibbs |
|||
# Website: http://danielgibbs.co.uk |
|||
# Version: 050214 |
|||
# Version: 061014 |
|||
|
|||
#### Variables #### |
|||
|
|||
@ -12,14 +12,14 @@ |
|||
emailnotification="off" |
|||
email="[email protected]" |
|||
|
|||
# Directorys |
|||
# Directories |
|||
rootdir="$(cd "$(dirname "${BASH_SOURCE[0]}" )" && pwd )" |
|||
selfname="$0" |
|||
lockselfname=$(echo ".${servicename}.lock") |
|||
filesdir="${rootdir}/serverfiles" |
|||
systemdir="${filesdir}/System" |
|||
executabledir="${systemdir}" |
|||
executable="./ucc-bin" |
|||
executable64="./ucc-bin-linux-amd64" |
|||
compressedmapsdir="${rootdir}/Maps-Compressed" |
|||
defaultcfg="${systemdir}/UT2004.ini" |
|||
backupdir="backups" |
|||
@ -34,20 +34,23 @@ ip="0.0.0.0" |
|||
|
|||
# Logging |
|||
logdays="7" |
|||
gamelogdir="${rootdir}/log/server" |
|||
scriptlogdir="${rootdir}/log/script" |
|||
consolelogdir="${rootdir}/log/console" |
|||
|
|||
gamelog="${gamelogdir}/${servicename}-game.log" |
|||
scriptlog="${scriptlogdir}/${servicename}-script.log" |
|||
consolelog="${consolelogdir}/${servicename}-console.log" |
|||
emaillog="${scriptlogdir}/${servicename}-email.log" |
|||
|
|||
gamelogdate="${gamelogdir}/${servicename}-game-$(date '+%d-%m-%Y-%H-%M-%S').log" |
|||
scriptlogdate="${scriptlogdir}/${servicename}-script-$(date '+%d-%m-%Y-%H-%M-%S').log" |
|||
consolelogdate="${consolelogdir}/${servicename}-console-$(date '+%d-%m-%Y-%H-%M-%S').log" |
|||
|
|||
# Start Variables |
|||
fn_parms(){ |
|||
defaultmap="DM-Rankin" |
|||
parms="server ${defaultmap}?game=XGame.xDMGame -nohomedir ini=${ini} log=${logfile}" |
|||
parms="server ${defaultmap}?game=XGame.xDeathMatch -nohomedir ini=${ini} log=${gamelog}" |
|||
} |
|||
|
|||
##### Script ##### |
|||
@ -56,7 +59,7 @@ parms="server ${defaultmap}?game=XGame.xDMGame -nohomedir ini=${ini} log=${logfi |
|||
# what you are doing |
|||
|
|||
fn_scriptlog(){ |
|||
echo -e "$(date '+%b %d %H:%M:%S') ${servicename}: '$1'" >> ${scriptlog} |
|||
echo -e "$(date '+%b %d %H:%M:%S') ${servicename}: ${1}" >> ${scriptlog} |
|||
} |
|||
|
|||
# [ FAIL ] |
|||
@ -120,8 +123,8 @@ fi |
|||
fn_autoip(){ |
|||
# Identifies the server interface IP |
|||
# If multiple interfaces this will need to be set manually |
|||
getip=$(ip -o -4 addr|awk '{print $4 }'|grep -oe '\([0-9]\{1,3\}\.\?\)\{4\}'|grep -v 127.0.0.1) |
|||
getipwc=$(ip -o -4 addr|awk '{print $4 }'|grep -oe '\([0-9]\{1,3\}\.\?\)\{4\}'|grep -v 127.0.0.1|wc -l) |
|||
getip=$(ip -o -4 addr|awk '{print $4 }'|grep -oe '\([0-9]\{1,3\}\.\?\)\{4\}'|grep -v 127.0.0) |
|||
getipwc=$(ip -o -4 addr|awk '{print $4 }'|grep -oe '\([0-9]\{1,3\}\.\?\)\{4\}'|grep -v 127.0.0|wc -l) |
|||
if [ "${ip}" == "0.0.0.0" ]||[ "${ip}" == "" ]; then |
|||
if [ "${getipwc}" -ge "2" ]; then |
|||
fn_printwarn "Multiple active network interfaces.\n\n" |
|||
@ -144,26 +147,38 @@ if [ `find "${scriptlogdir}"/* -mtime +${logdays}|wc -l` -ne "0" ]; then |
|||
fn_printdots "Starting log cleaner" |
|||
sleep 1 |
|||
fn_printok "Starting log cleaner" |
|||
sleep 1 |
|||
fn_scriptlog "Starting log cleaner" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
fn_printinfo "Removing logs older than ${logdays} days" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
fn_scriptlog "Removing logs older than ${logdays} days" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
if [ "${engine}" == "unreal2" ]; then |
|||
find "${gamelogdir}"/* -mtime +${logdays}|tee >> "${scriptlog}" |
|||
fi |
|||
find "${scriptlogdir}"/* -mtime +${logdays}|tee >> "${scriptlog}" |
|||
find "${consolelogdir}"/* -mtime +${logdays}|tee >> "${scriptlog}" |
|||
if [ "${engine}" == "unreal2" ]; then |
|||
gamecount=$(find "${scriptlogdir}"/* -mtime +${logdays}|wc -l) |
|||
fi |
|||
scriptcount=$(find "${scriptlogdir}"/* -mtime +${logdays}|wc -l) |
|||
consolecount=$(find "${consolelogdir}"/* -mtime +${logdays}|wc -l) |
|||
count=$((${scriptcount} + ${consolecount})) |
|||
if [ "${engine}" == "unreal2" ]; then |
|||
count=$((${scriptcount} + ${consolecount} + ${gamecount})) |
|||
else |
|||
count=$((${scriptcount} + ${consolecount})) |
|||
fi |
|||
if [ "${engine}" == "unreal2" ]; then |
|||
find "${gamelogdir}"/* -mtime +${logdays} -exec rm {} \; |
|||
fi |
|||
find "${scriptlogdir}"/* -mtime +${logdays} -exec rm {} \; |
|||
find "${consolelogdir}"/* -mtime +${logdays} -exec rm {} \; |
|||
fn_printok "Log cleaner removed ${count} log files" |
|||
fn_scriptlog "Log cleaner removed ${count} log files" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
fn_scriptlog "Log cleaner removed ${count} log files" |
|||
fi |
|||
} |
|||
|
|||
@ -171,18 +186,26 @@ fn_debugserver(){ |
|||
fn_rootcheck |
|||
fn_syscheck |
|||
fn_autoip |
|||
fn_distro |
|||
fn_uptime |
|||
fn_load |
|||
fn_parms |
|||
echo "" |
|||
echo "${gamename} Debug" |
|||
echo "============================" |
|||
echo "" |
|||
echo -e "Use for identifying server issues only!" |
|||
echo -e "Press CTRL+c to drop out of debug mode" |
|||
echo -e "\e[0;31mWARNING!\e[0;39m If ${servicename} is already running it will be stopped" |
|||
echo -e "Distro: ${os}" |
|||
echo -e "Arch: ${arch}" |
|||
echo -e "Kernel: ${kernel}" |
|||
echo -e "Hostname: $HOSTNAME" |
|||
echo "" |
|||
echo "Start parameters:" |
|||
echo ${parms} |
|||
echo "" |
|||
echo -e "Use for identifying server issues only!" |
|||
echo -e "Press CTRL+c to drop out of debug mode" |
|||
echo -e "\e[0;31mWARNING!\e[0;39m If ${servicename} is already running it will be stopped" |
|||
echo "" |
|||
while true; do |
|||
read -p "Continue? [y/N]" yn |
|||
case $yn in |
|||
@ -199,11 +222,7 @@ sleep 1 |
|||
fn_scriptlog "Started debug mode ${servername}" |
|||
echo -en "\n" |
|||
cd "${executabledir}" |
|||
if [ `getconf LONG_BIT` = "64" ]; then |
|||
${executable64} ${parms} |
|||
else |
|||
${executable} ${parms} |
|||
fi |
|||
${executable} ${parms} |
|||
} |
|||
|
|||
fn_console(){ |
|||
@ -229,8 +248,8 @@ sleep 1 |
|||
tmuxwc=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -v failed|grep -E "^${servicename}:"|wc -l) |
|||
if [ ${tmuxwc} -eq 1 ]; then |
|||
fn_printoknl "Starting ${servicename} console" |
|||
sleep 1 |
|||
fn_scriptlog "Console accessed" |
|||
sleep 1 |
|||
tmux attach-session -t ${servicename} |
|||
else |
|||
fn_printfailnl "Starting ${servicename} console: ${servername} not running" |
|||
@ -281,8 +300,8 @@ fi |
|||
fn_printdots "Starting backup ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_printok "Starting backup ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_scriptlog "Backup started" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
cd "${rootdir}" |
|||
mkdir -pv "${backupdir}" > /dev/null 2>&1 |
|||
@ -350,9 +369,9 @@ if [ ! -z "${gamelogdir}" ]; then |
|||
fi |
|||
mail -s "${subject}" ${email} < "${emaillog}" |
|||
fn_printinfo "Sent email notification to ${email}" |
|||
fn_scriptlog "Sent email notification to ${email}" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
fn_scriptlog "Sent email notification to ${email}" |
|||
} |
|||
|
|||
fn_emailtest(){ |
|||
@ -381,13 +400,15 @@ if [ -f gsquery.py ]; then |
|||
port=$((${gameport} + 1)) |
|||
elif [ "${engine}" == "spark" ]; then |
|||
port=$((${port} + 1)) |
|||
elif [ "${engine}" == "realvirtuality" ]; then |
|||
port=${queryport} |
|||
fi |
|||
fn_printinfo "Monitoring ${servicename}: Detected gsquery.py" |
|||
sleep 1 |
|||
fn_scriptlog "Detected gsquery.py" |
|||
fn_printdots "Monitoring ${servicename}: Querying port: ${ip}:${port}: QUERYING" |
|||
sleep 1 |
|||
fn_printdots "Monitoring ${servicename}: Querying port: ${ip}:${port}: QUERYING" |
|||
fn_scriptlog "Querying port: ${ip}:${port}: QUERYING" |
|||
sleep 1 |
|||
serverquery=$(./gsquery.py -a ${ip} -p ${port} -e ${engine} 2>&1) |
|||
exitcode=$? |
|||
if [ "${exitcode}" == "1" ]||[ "${exitcode}" == "2" ]||[ "${exitcode}" == "3" ]||[ "${exitcode}" == "4" ]; then |
|||
@ -397,9 +418,8 @@ if [ -f gsquery.py ]; then |
|||
fn_scriptlog "Querying port: ${ip}:${port}: ${serverquery}" |
|||
if [[ -z "${secondquery}" ]]; then |
|||
fn_printinfo "Monitoring ${servicename}: Waiting 30 seconds to re-query" |
|||
sleep 1 |
|||
fn_scriptlog "Waiting 30 seconds to re-query" |
|||
sleep 29 |
|||
sleep 30 |
|||
secondquery=1 |
|||
fn_serverquery |
|||
fi |
|||
@ -413,14 +433,14 @@ if [ -f gsquery.py ]; then |
|||
exit |
|||
elif [ "${exitcode}" == "0" ]; then |
|||
fn_printok "Monitoring ${servicename}: Querying port: ${ip}:${port}: OK" |
|||
sleep 1 |
|||
fn_scriptlog "Querying port: ${ip}:${port}: OK" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
exit |
|||
elif [ "${exitcode}" == "126" ]; then |
|||
fn_printfail "Monitoring ${servicename}: Querying port: ${ip}:${port}: ERROR: ./gsquery.py: Permission denied" |
|||
sleep 1 |
|||
fn_scriptlog "Querying port: ${ip}:${port}: ./gsquery.py: Permission denied" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
echo "Attempting to resolve automatically" |
|||
chmod +x -v gsquery.py |
|||
@ -437,9 +457,9 @@ if [ -f gsquery.py ]; then |
|||
fi |
|||
else |
|||
fn_printfail "Monitoring ${servicename}: Querying port: ${ip}:${port}: UNKNOWN ERROR" |
|||
fn_scriptlog "Querying port: ${ip}:${port}: UNKNOWN ERROR" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
fn_scriptlog "Querying port: ${ip}:${port}: UNKNOWN ERROR" |
|||
./gsquery.py -a ${ip} -p ${port} -e ${engine} |
|||
exit |
|||
fi |
|||
@ -451,19 +471,27 @@ fn_rootcheck |
|||
fn_syscheck |
|||
fn_autoip |
|||
fn_printdots "Monitoring ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_scriptlog "Monitoring ${servername}" |
|||
sleep 1 |
|||
if [ ! -f ${lockselfname} ]; then |
|||
fn_printinfo "Monitoring ${servicename}: Monitor disabled: No lock file found" |
|||
fn_scriptlog "Monitor disabled: No lock file found" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
echo "To enable monitor run ${selfname} start" |
|||
exit |
|||
fi |
|||
updatecheck=$(ps -ef|grep "${selfname} update"|grep -v grep|wc -l) |
|||
if [ "${updatecheck}" = "0" ]; then |
|||
fn_printdots "Monitoring ${servicename}: Checking session: CHECKING" |
|||
sleep 1 |
|||
fn_scriptlog "Checking session: CHECKING" |
|||
sleep 1 |
|||
tmuxwc=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -v failed|grep -E "^${servicename}:"|wc -l) |
|||
if [ ${tmuxwc} -eq 1 ]; then |
|||
fn_printok "Monitoring ${servicename}: Checking session: OK" |
|||
fn_scriptlog "Checking session: OK" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
fn_scriptlog "Checking session: OK" |
|||
fn_serverquery |
|||
exit |
|||
else |
|||
@ -482,11 +510,11 @@ if [ "${updatecheck}" = "0" ]; then |
|||
fi |
|||
else |
|||
fn_printinfonl "Monitoring ${servicename}: Detected SteamCMD is checking for updates" |
|||
sleep 1 |
|||
fn_scriptlog "Detected SteamCMD is checking for updates" |
|||
fn_printinfonl "Monitoring ${servicename}: When updates complete ${servicename} will start" |
|||
sleep 1 |
|||
fn_printinfonl "Monitoring ${servicename}: When updates complete ${servicename} will start" |
|||
fn_scriptlog "When updates complete ${servicename} will start" |
|||
sleep 1 |
|||
fi |
|||
} |
|||
|
|||
@ -501,8 +529,8 @@ fn_rootcheck |
|||
fn_syscheck |
|||
pid=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -E "^${servicename}:"|wc -l) |
|||
fn_printdots "Stopping ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_scriptlog "Stopping ${servername}" |
|||
sleep 1 |
|||
if [ "${pid}" == "0" ]; then |
|||
fn_printfail "Stopping ${servicename}: ${servername} is already stopped" |
|||
fn_scriptlog "${servername} is already stopped" |
|||
@ -511,6 +539,8 @@ else |
|||
fn_printok "Stopping ${servicename}: ${servername}" |
|||
fn_scriptlog "Stopped ${servername}" |
|||
fi |
|||
# Remove lock file |
|||
rm -f ${lockselfname} |
|||
sleep 1 |
|||
echo -en "\n" |
|||
} |
|||
@ -523,30 +553,39 @@ fn_parms |
|||
fn_logmanager |
|||
tmuxwc=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -v failed|grep -E "^${servicename}:"|wc -l) |
|||
if [ ${tmuxwc} -eq 0 ]; then |
|||
fn_scriptlog "Rotating log files" |
|||
if [ "${engine}" == "unreal2" ]; then |
|||
mv "${gamelog}" "${gamelogdate}" |
|||
fi |
|||
mv "${scriptlog}" "${scriptlogdate}" |
|||
mv "${consolelog}" "${consolelogdate}" |
|||
fi |
|||
fn_printdots "Starting ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_scriptlog "Starting ${servername}" |
|||
sleep 1 |
|||
if [ ${tmuxwc} -eq 1 ]; then |
|||
fn_printinfo "Starting ${servicename}: ${servername} is already running" |
|||
fn_scriptlog "${servername} is already running" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
fn_scriptlog "${servername} is already running" |
|||
exit |
|||
fi |
|||
# Create lock file |
|||
date > "${rootdir}/${lockselfname}" |
|||
cd "${executabledir}" |
|||
if [ `getconf LONG_BIT` = "64" ]; then |
|||
tmux new-session -d -s ${servicename} "${executable64} ${parms}|tee -a '${consolelog}'" |
|||
else |
|||
tmux new-session -d -s ${servicename} "${executable} ${parms}|tee -a '${consolelog}'" |
|||
fi |
|||
tmux new-session -d -s ${servicename} "${executable} ${parms}" 2> ${scriptlogdir}/.${servicename}-tmux-error.tmp |
|||
tmux pipe-pane -o -t ${servicename} "exec cat >> '${consolelog}'" |
|||
sleep 1 |
|||
tmuxwc=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -E "^${servicename}:"|wc -l) |
|||
if [ ${tmuxwc} -eq 0 ]; then |
|||
fn_printfail "Starting ${servicename}: Failed to start ${servername}" |
|||
fn_printfailnl "Starting ${servicename}: Failed to start ${servername}" |
|||
echo -en " Check log files: ${rootdir}/log" |
|||
fn_scriptlog "failed to start ${servername}" |
|||
if [ -a ${scriptlogdir}/.${servicename}-tmux-error.tmp ]; then |
|||
fn_scriptlog "tmux returned the following error" |
|||
cat ${scriptlogdir}/.${servicename}-tmux-error.tmp >> ${scriptlog} |
|||
rm ${scriptlogdir}/.${servicename}-tmux-error.tmp |
|||
fi |
|||
else |
|||
fn_printok "Starting ${servicename}: ${servername}" |
|||
fn_scriptlog "Started ${servername}" |
|||
@ -673,7 +712,7 @@ cd "${rootdir}" |
|||
mkdir -pv "${filesdir}" |
|||
cd "${filesdir}" |
|||
if [ ! -f dedicatedserver3339-bonuspack.zip ]; then |
|||
wget http://downloads.unrealadmin.org/UT2004/Server/dedicatedserver3339-bonuspack.zip |
|||
wget -nv -N http://downloads.unrealadmin.org/UT2004/Server/dedicatedserver3339-bonuspack.zip |
|||
else |
|||
echo "dedicatedserver3339-bonuspack.zip already downloaded!" |
|||
fi |
|||
@ -694,7 +733,7 @@ else |
|||
echo "MD5 checksum: PASSED" |
|||
fi |
|||
if [ ! -f ut2004-lnxpatch3369-2.tar.bz2 ]; then |
|||
wget http://downloads.unrealadmin.org/UT2004/Patches/Linux/ut2004-lnxpatch3369-2.tar.bz2 |
|||
wget -nv -N http://downloads.unrealadmin.org/UT2004/Patches/Linux/ut2004-lnxpatch3369-2.tar.bz2 |
|||
else |
|||
echo "ut2004-lnxpatch3369-2.tar.bz2 already downloaded!" |
|||
fi |
|||
@ -780,15 +819,31 @@ mkdir -pv "${scriptlogdir}" |
|||
touch "${scriptlog}" |
|||
mkdir -pv "${consolelogdir}" |
|||
touch "${consolelog}" |
|||
mkdir -pv "${gamelogdir}" |
|||
touch "${gamelog}" |
|||
sleep 1 |
|||
echo "" |
|||
} |
|||
|
|||
fn_getquery(){ |
|||
echo "GameServerQuery" |
|||
echo "============================" |
|||
while true; do |
|||
read -p "Do you want to install GameServerQuery? [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) cd "${rootdir}"; wget -nv -N "http://danielgibbs.co.uk/dl/gsquery.py"; chmod +x gsquery.py; break;; |
|||
[Nn]* ) echo -e "Not installing GameServerQuery.";break;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
echo "" |
|||
} |
|||
|
|||
fn_retryinstall(){ |
|||
while true; do |
|||
read -p "Retry install? [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) fn_install;; |
|||
[Yy]* ) fn_install; exit;; |
|||
[Nn]* ) echo Exiting; exit;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
@ -827,6 +882,7 @@ fn_ut2k4filesdl |
|||
fn_ut2k4install |
|||
fn_ut2k4key |
|||
fn_utloginstall |
|||
fn_getquery |
|||
echo "Configuring ${gamename} Server" |
|||
echo "=================================" |
|||
sleep 1 |
|||
|
@ -3,7 +3,7 @@ |
|||
# Server Management Script |
|||
# Author: Daniel Gibbs |
|||
# Website: http://danielgibbs.co.uk |
|||
# Version: 050214 |
|||
# Version: 061014 |
|||
|
|||
#### Variables #### |
|||
|
|||
@ -12,9 +12,10 @@ |
|||
emailnotification="off" |
|||
email="[email protected]" |
|||
|
|||
# Directorys |
|||
# Directories |
|||
rootdir="$(cd "$(dirname "${BASH_SOURCE[0]}" )" && pwd )" |
|||
selfname="$0" |
|||
lockselfname=$(echo ".${servicename}.lock") |
|||
filesdir="${rootdir}/serverfiles" |
|||
systemdir="${filesdir}/System" |
|||
executabledir="${systemdir}" |
|||
@ -55,7 +56,7 @@ parms="server ${defaultmap}.unr ini=${systemdir}/${ini}" |
|||
# what you are doing |
|||
|
|||
fn_scriptlog(){ |
|||
echo -e "$(date '+%b %d %H:%M:%S') ${servicename}: '$1'" >> ${scriptlog} |
|||
echo -e "$(date '+%b %d %H:%M:%S') ${servicename}: ${1}" >> ${scriptlog} |
|||
} |
|||
|
|||
# [ FAIL ] |
|||
@ -119,8 +120,8 @@ fi |
|||
fn_autoip(){ |
|||
# Identifies the server interface IP |
|||
# If multiple interfaces this will need to be set manually |
|||
getip=$(ip -o -4 addr|awk '{print $4 }'|grep -oe '\([0-9]\{1,3\}\.\?\)\{4\}'|grep -v 127.0.0.1) |
|||
getipwc=$(ip -o -4 addr|awk '{print $4 }'|grep -oe '\([0-9]\{1,3\}\.\?\)\{4\}'|grep -v 127.0.0.1|wc -l) |
|||
getip=$(ip -o -4 addr|awk '{print $4 }'|grep -oe '\([0-9]\{1,3\}\.\?\)\{4\}'|grep -v 127.0.0) |
|||
getipwc=$(ip -o -4 addr|awk '{print $4 }'|grep -oe '\([0-9]\{1,3\}\.\?\)\{4\}'|grep -v 127.0.0|wc -l) |
|||
if [ "${ip}" == "0.0.0.0" ]||[ "${ip}" == "" ]; then |
|||
if [ "${getipwc}" -ge "2" ]; then |
|||
fn_printwarn "Multiple active network interfaces.\n\n" |
|||
@ -143,26 +144,38 @@ if [ `find "${scriptlogdir}"/* -mtime +${logdays}|wc -l` -ne "0" ]; then |
|||
fn_printdots "Starting log cleaner" |
|||
sleep 1 |
|||
fn_printok "Starting log cleaner" |
|||
sleep 1 |
|||
fn_scriptlog "Starting log cleaner" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
fn_printinfo "Removing logs older than ${logdays} days" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
fn_scriptlog "Removing logs older than ${logdays} days" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
if [ "${engine}" == "unreal2" ]; then |
|||
find "${gamelogdir}"/* -mtime +${logdays}|tee >> "${scriptlog}" |
|||
fi |
|||
find "${scriptlogdir}"/* -mtime +${logdays}|tee >> "${scriptlog}" |
|||
find "${consolelogdir}"/* -mtime +${logdays}|tee >> "${scriptlog}" |
|||
if [ "${engine}" == "unreal2" ]; then |
|||
gamecount=$(find "${scriptlogdir}"/* -mtime +${logdays}|wc -l) |
|||
fi |
|||
scriptcount=$(find "${scriptlogdir}"/* -mtime +${logdays}|wc -l) |
|||
consolecount=$(find "${consolelogdir}"/* -mtime +${logdays}|wc -l) |
|||
count=$((${scriptcount} + ${consolecount})) |
|||
if [ "${engine}" == "unreal2" ]; then |
|||
count=$((${scriptcount} + ${consolecount} + ${gamecount})) |
|||
else |
|||
count=$((${scriptcount} + ${consolecount})) |
|||
fi |
|||
if [ "${engine}" == "unreal2" ]; then |
|||
find "${gamelogdir}"/* -mtime +${logdays} -exec rm {} \; |
|||
fi |
|||
find "${scriptlogdir}"/* -mtime +${logdays} -exec rm {} \; |
|||
find "${consolelogdir}"/* -mtime +${logdays} -exec rm {} \; |
|||
fn_printok "Log cleaner removed ${count} log files" |
|||
fn_scriptlog "Log cleaner removed ${count} log files" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
fn_scriptlog "Log cleaner removed ${count} log files" |
|||
fi |
|||
} |
|||
|
|||
@ -170,18 +183,26 @@ fn_debugserver(){ |
|||
fn_rootcheck |
|||
fn_syscheck |
|||
fn_autoip |
|||
fn_distro |
|||
fn_uptime |
|||
fn_load |
|||
fn_parms |
|||
echo "" |
|||
echo "${gamename} Debug" |
|||
echo "============================" |
|||
echo "" |
|||
echo -e "Use for identifying server issues only!" |
|||
echo -e "Press CTRL+c to drop out of debug mode" |
|||
echo -e "\e[0;31mWARNING!\e[0;39m If ${servicename} is already running it will be stopped" |
|||
echo -e "Distro: ${os}" |
|||
echo -e "Arch: ${arch}" |
|||
echo -e "Kernel: ${kernel}" |
|||
echo -e "Hostname: $HOSTNAME" |
|||
echo "" |
|||
echo "Start parameters:" |
|||
echo ${parms} |
|||
echo "" |
|||
echo -e "Use for identifying server issues only!" |
|||
echo -e "Press CTRL+c to drop out of debug mode" |
|||
echo -e "\e[0;31mWARNING!\e[0;39m If ${servicename} is already running it will be stopped" |
|||
echo "" |
|||
while true; do |
|||
read -p "Continue? [y/N]" yn |
|||
case $yn in |
|||
@ -224,8 +245,8 @@ sleep 1 |
|||
tmuxwc=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -v failed|grep -E "^${servicename}:"|wc -l) |
|||
if [ ${tmuxwc} -eq 1 ]; then |
|||
fn_printoknl "Starting ${servicename} console" |
|||
sleep 1 |
|||
fn_scriptlog "Console accessed" |
|||
sleep 1 |
|||
tmux attach-session -t ${servicename} |
|||
else |
|||
fn_printfailnl "Starting ${servicename} console: ${servername} not running" |
|||
@ -276,8 +297,8 @@ fi |
|||
fn_printdots "Starting backup ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_printok "Starting backup ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_scriptlog "Backup started" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
cd "${rootdir}" |
|||
mkdir -pv "${backupdir}" > /dev/null 2>&1 |
|||
@ -345,9 +366,9 @@ if [ ! -z "${gamelogdir}" ]; then |
|||
fi |
|||
mail -s "${subject}" ${email} < "${emaillog}" |
|||
fn_printinfo "Sent email notification to ${email}" |
|||
fn_scriptlog "Sent email notification to ${email}" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
fn_scriptlog "Sent email notification to ${email}" |
|||
} |
|||
|
|||
fn_emailtest(){ |
|||
@ -376,13 +397,15 @@ if [ -f gsquery.py ]; then |
|||
port=$((${gameport} + 1)) |
|||
elif [ "${engine}" == "spark" ]; then |
|||
port=$((${port} + 1)) |
|||
elif [ "${engine}" == "realvirtuality" ]; then |
|||
port=${queryport} |
|||
fi |
|||
fn_printinfo "Monitoring ${servicename}: Detected gsquery.py" |
|||
sleep 1 |
|||
fn_scriptlog "Detected gsquery.py" |
|||
fn_printdots "Monitoring ${servicename}: Querying port: ${ip}:${port}: QUERYING" |
|||
sleep 1 |
|||
fn_printdots "Monitoring ${servicename}: Querying port: ${ip}:${port}: QUERYING" |
|||
fn_scriptlog "Querying port: ${ip}:${port}: QUERYING" |
|||
sleep 1 |
|||
serverquery=$(./gsquery.py -a ${ip} -p ${port} -e ${engine} 2>&1) |
|||
exitcode=$? |
|||
if [ "${exitcode}" == "1" ]||[ "${exitcode}" == "2" ]||[ "${exitcode}" == "3" ]||[ "${exitcode}" == "4" ]; then |
|||
@ -392,9 +415,8 @@ if [ -f gsquery.py ]; then |
|||
fn_scriptlog "Querying port: ${ip}:${port}: ${serverquery}" |
|||
if [[ -z "${secondquery}" ]]; then |
|||
fn_printinfo "Monitoring ${servicename}: Waiting 30 seconds to re-query" |
|||
sleep 1 |
|||
fn_scriptlog "Waiting 30 seconds to re-query" |
|||
sleep 29 |
|||
sleep 30 |
|||
secondquery=1 |
|||
fn_serverquery |
|||
fi |
|||
@ -408,14 +430,14 @@ if [ -f gsquery.py ]; then |
|||
exit |
|||
elif [ "${exitcode}" == "0" ]; then |
|||
fn_printok "Monitoring ${servicename}: Querying port: ${ip}:${port}: OK" |
|||
sleep 1 |
|||
fn_scriptlog "Querying port: ${ip}:${port}: OK" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
exit |
|||
elif [ "${exitcode}" == "126" ]; then |
|||
fn_printfail "Monitoring ${servicename}: Querying port: ${ip}:${port}: ERROR: ./gsquery.py: Permission denied" |
|||
sleep 1 |
|||
fn_scriptlog "Querying port: ${ip}:${port}: ./gsquery.py: Permission denied" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
echo "Attempting to resolve automatically" |
|||
chmod +x -v gsquery.py |
|||
@ -432,9 +454,9 @@ if [ -f gsquery.py ]; then |
|||
fi |
|||
else |
|||
fn_printfail "Monitoring ${servicename}: Querying port: ${ip}:${port}: UNKNOWN ERROR" |
|||
fn_scriptlog "Querying port: ${ip}:${port}: UNKNOWN ERROR" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
fn_scriptlog "Querying port: ${ip}:${port}: UNKNOWN ERROR" |
|||
./gsquery.py -a ${ip} -p ${port} -e ${engine} |
|||
exit |
|||
fi |
|||
@ -446,19 +468,27 @@ fn_rootcheck |
|||
fn_syscheck |
|||
fn_autoip |
|||
fn_printdots "Monitoring ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_scriptlog "Monitoring ${servername}" |
|||
sleep 1 |
|||
if [ ! -f ${lockselfname} ]; then |
|||
fn_printinfo "Monitoring ${servicename}: Monitor disabled: No lock file found" |
|||
fn_scriptlog "Monitor disabled: No lock file found" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
echo "To enable monitor run ${selfname} start" |
|||
exit |
|||
fi |
|||
updatecheck=$(ps -ef|grep "${selfname} update"|grep -v grep|wc -l) |
|||
if [ "${updatecheck}" = "0" ]; then |
|||
fn_printdots "Monitoring ${servicename}: Checking session: CHECKING" |
|||
sleep 1 |
|||
fn_scriptlog "Checking session: CHECKING" |
|||
sleep 1 |
|||
tmuxwc=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -v failed|grep -E "^${servicename}:"|wc -l) |
|||
if [ ${tmuxwc} -eq 1 ]; then |
|||
fn_printok "Monitoring ${servicename}: Checking session: OK" |
|||
fn_scriptlog "Checking session: OK" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
fn_scriptlog "Checking session: OK" |
|||
fn_serverquery |
|||
exit |
|||
else |
|||
@ -477,11 +507,11 @@ if [ "${updatecheck}" = "0" ]; then |
|||
fi |
|||
else |
|||
fn_printinfonl "Monitoring ${servicename}: Detected SteamCMD is checking for updates" |
|||
sleep 1 |
|||
fn_scriptlog "Detected SteamCMD is checking for updates" |
|||
fn_printinfonl "Monitoring ${servicename}: When updates complete ${servicename} will start" |
|||
sleep 1 |
|||
fn_printinfonl "Monitoring ${servicename}: When updates complete ${servicename} will start" |
|||
fn_scriptlog "When updates complete ${servicename} will start" |
|||
sleep 1 |
|||
fi |
|||
} |
|||
|
|||
@ -496,8 +526,8 @@ fn_rootcheck |
|||
fn_syscheck |
|||
pid=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -E "^${servicename}:"|wc -l) |
|||
fn_printdots "Stopping ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_scriptlog "Stopping ${servername}" |
|||
sleep 1 |
|||
if [ "${pid}" == "0" ]; then |
|||
fn_printfail "Stopping ${servicename}: ${servername} is already stopped" |
|||
fn_scriptlog "${servername} is already stopped" |
|||
@ -506,6 +536,8 @@ else |
|||
fn_printok "Stopping ${servicename}: ${servername}" |
|||
fn_scriptlog "Stopped ${servername}" |
|||
fi |
|||
# Remove lock file |
|||
rm -f ${lockselfname} |
|||
sleep 1 |
|||
echo -en "\n" |
|||
} |
|||
@ -518,26 +550,39 @@ fn_parms |
|||
fn_logmanager |
|||
tmuxwc=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -v failed|grep -E "^${servicename}:"|wc -l) |
|||
if [ ${tmuxwc} -eq 0 ]; then |
|||
fn_scriptlog "Rotating log files" |
|||
if [ "${engine}" == "unreal2" ]; then |
|||
mv "${gamelog}" "${gamelogdate}" |
|||
fi |
|||
mv "${scriptlog}" "${scriptlogdate}" |
|||
mv "${consolelog}" "${consolelogdate}" |
|||
fi |
|||
fn_printdots "Starting ${servicename}: ${servername}" |
|||
sleep 1 |
|||
fn_scriptlog "Starting ${servername}" |
|||
sleep 1 |
|||
if [ ${tmuxwc} -eq 1 ]; then |
|||
fn_printinfo "Starting ${servicename}: ${servername} is already running" |
|||
fn_scriptlog "${servername} is already running" |
|||
sleep 1 |
|||
echo -en "\n" |
|||
fn_scriptlog "${servername} is already running" |
|||
exit |
|||
fi |
|||
# Create lock file |
|||
date > "${rootdir}/${lockselfname}" |
|||
cd "${executabledir}" |
|||
tmux new-session -d -s ${servicename} "${executable} ${parms}|tee -a '${consolelog}'" |
|||
tmux new-session -d -s ${servicename} "${executable} ${parms}" 2> ${scriptlogdir}/.${servicename}-tmux-error.tmp |
|||
tmux pipe-pane -o -t ${servicename} "exec cat >> '${consolelog}'" |
|||
sleep 1 |
|||
tmuxwc=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -E "^${servicename}:"|wc -l) |
|||
if [ ${tmuxwc} -eq 0 ]; then |
|||
fn_printfail "Starting ${servicename}: Failed to start ${servername}" |
|||
fn_printfailnl "Starting ${servicename}: Failed to start ${servername}" |
|||
echo -en " Check log files: ${rootdir}/log" |
|||
fn_scriptlog "failed to start ${servername}" |
|||
if [ -a ${scriptlogdir}/.${servicename}-tmux-error.tmp ]; then |
|||
fn_scriptlog "tmux returned the following error" |
|||
cat ${scriptlogdir}/.${servicename}-tmux-error.tmp >> ${scriptlog} |
|||
rm ${scriptlogdir}/.${servicename}-tmux-error.tmp |
|||
fi |
|||
else |
|||
fn_printok "Starting ${servicename}: ${servername}" |
|||
fn_scriptlog "Started ${servername}" |
|||
@ -660,7 +705,7 @@ cd "${rootdir}" |
|||
mkdir -pv "${filesdir}" |
|||
cd "${filesdir}" |
|||
if [ ! -f ut-server-436.tar.gz ]; then |
|||
wget http://danielgibbs.co.uk/wp-content/uploads/ut-server-436.tar.gz |
|||
wget -nv -N http://danielgibbs.co.uk/wp-content/uploads/ut-server-436.tar.gz |
|||
else |
|||
echo "ut-server-436.tar.gz already downloaded!" |
|||
fi |
|||
@ -681,7 +726,7 @@ else |
|||
echo "MD5 checksum: PASSED" |
|||
fi |
|||
if [ ! -f UTPGPatch451.tar.bz2 ]; then |
|||
wget http://danielgibbs.co.uk/wp-content/uploads/UTPGPatch451.tar.bz2 |
|||
wget -nv -N http://danielgibbs.co.uk/wp-content/uploads/UTPGPatch451.tar.bz2 |
|||
else |
|||
echo "UTPGPatch451.tar.bz2 already downloaded!" |
|||
fi |
|||
@ -757,11 +802,25 @@ sleep 1 |
|||
echo "" |
|||
} |
|||
|
|||
fn_getquery(){ |
|||
echo "GameServerQuery" |
|||
echo "============================" |
|||
while true; do |
|||
read -p "Do you want to install GameServerQuery? [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) cd "${rootdir}"; wget -nv -N "http://danielgibbs.co.uk/dl/gsquery.py"; chmod +x gsquery.py; break;; |
|||
[Nn]* ) echo -e "Not installing GameServerQuery.";break;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
done |
|||
echo "" |
|||
} |
|||
|
|||
fn_retryinstall(){ |
|||
while true; do |
|||
read -p "Retry install? [y/N]" yn |
|||
case $yn in |
|||
[Yy]* ) fn_install;; |
|||
[Yy]* ) fn_install; exit;; |
|||
[Nn]* ) echo Exiting; exit;; |
|||
* ) echo "Please answer yes or no.";; |
|||
esac |
|||
@ -799,6 +858,7 @@ fn_header |
|||
fn_ut99filesdl |
|||
fn_ut99install |
|||
fn_utloginstall |
|||
fn_getquery |
|||
echo "Configuring ${gamename} Server" |
|||
echo "=================================" |
|||
sleep 1 |
|||
|
Loading…
Reference in new issue