diff --git a/SOURCES/kf2-srv b/SOURCES/kf2-srv new file mode 100755 index 0000000..3fb0223 --- /dev/null +++ b/SOURCES/kf2-srv @@ -0,0 +1,337 @@ +#!/bin/bash + +# kf2-srv is a command line tool for managing a set of Killing Floor 2 servers. +# Copyright (C) 2019 GenZmeY +# mailto: genzmey@gmail.com +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +source /etc/steamcmd/steamcmd.conf +source /etc/kf2-srv/kf2-srv.conf + +ScriptFullname=$(readlink -e "$0") +ScriptName=$(echo "$ScriptFullname" | awk -F '/' '{print $NF;}') +AppNum="232130" +InstallDir="/usr/games/kf2-srv" +AppBin="$InstallDir/Binaries/Win64/KFGameSteamServer.bin.x86_64" +DefaultConfigDir="$InstallDir/KFGame/Config" +InstanceConfigDir="$DefaultConfigDir/instances" +InstanceConfigLnk="/etc/kf2-srv/instances" +MainConfigTemplate="/etc/kf2-srv/main.conf.template" + +function show_help () +{ + echo "kf2-srv" + echo "" + echo "Usage:" + echo "$ScriptName OPTION [INSTANCE]" + echo "" + echo "Mandatory arguments to long options are mandatory for short options too." + echo " -n, --new INSTANCE TODO: description" + echo " -d, --delete [INSTANCE] TODO: description" + echo " -l, --list TODO: description" + echo " -s, --status [INSTANCE] TODO: description" + echo " -u, --update TODO: description" + echo " -r. --run TODO: description" + echo " --start [INSTANCE] TODO: description" + echo " --stop [INSTANCE] TODO: description" + echo " --enable [INSTANCE] TODO: description" + echo " --disable [INSTANCE] TODO: description" + echo " --map-sync TODO: description" + echo " --ban-sync TODO: description" + echo " --map-rotate-save TODO: description" + echo " --map-rotate-load TODO: description" + echo " -h, --help display this help and exit" +} + +# Use this function with non-root user only!!! +function run_as_root () # $@: Args +{ + if [[ -n $(groups "$USER" | grep -Fo 'wheel') ]]; then + sudo "$ScriptFullname" $@ + else + echo "You must be root or sudo-user to run this command." + return 1 + fi +} + +function service_name () # $1: Instance +{ + echo "kf2-srv@$1.service" +} + +function show_instances () +{ + find "$InstanceConfigDir" -maxdepth 1 -mindepth 1 -type d -printf "%f\n" +} + +function instance_exists () # $1: Instance +{ + if show_instances | grep -qP "^.*[ ]*$1[ ]*.*$" ; then + return 0 + else + return 1 + fi +} + +function server_exists () +{ + if [[ -n $(ls "$InstallDir") ]]; then + return 0 + else + return 1 + fi +} + +function updates_aviable () +{ + # TODO: implementation + return 0 +} + +function new_instance () # $1: InstanceName +{ + local Instance="$1" + if [[ -z "$Instance" ]]; then + echo "Name of instance must be set" + exit 1 + elif ! server_exists; then + echo "You must install server first" + echo "Run \"$ScriptName --update\" to install it" + exit 1 + elif instance_exists "$Instance"; then + echo "Instance $Instance already exists" + exit 1 + fi + + local InstanceDir="$InstanceConfigDir/$Instance" + if [[ -d "$InstanceDir" ]]; then + echo "$InstanceDir already exists" + exit 1 + fi + + mkdir -p "$InstanceDir/LinuxServer" && chown -R "$SteamUser:$SteamUser" "$InstanceDir" + + cp -a "$MainConfigTemplate" "$InstanceDir/main.conf" + cp -a "$DefaultConfigDir/KFAI.ini" "$InstanceDir" + cp -a "$DefaultConfigDir/KFWeb.ini" "$InstanceDir" + cp -a "$DefaultConfigDir/LinuxServer-KFEngine.ini" "$InstanceDir" + cp -a "$DefaultConfigDir/LinuxServer-KFGame.ini" "$InstanceDir" + cp -a "$DefaultConfigDir/LinuxServer-KFInput.ini" "$InstanceDir" + cp -a "$DefaultConfigDir/LinuxServer-KFSystemSettings.ini" "$InstanceDir" + cp -a "$DefaultConfigDir/LinuxServer/LinuxServerEngine.ini" "$InstanceDir/LinuxServer" + cp -a "$DefaultConfigDir/LinuxServer/LinuxServerGame.ini" "$InstanceDir/LinuxServer" + cp -a "$DefaultConfigDir/LinuxServer/LinuxServerInput.ini" "$InstanceDir/LinuxServer" + cp -a "$DefaultConfigDir/LinuxServer/LinuxServerSystemSettings.ini" "$InstanceDir/LinuxServer" + + echo "Instance $Instance created. See $InstanceDir for edit configuration" +} + +function delete_instance () # $1: [InstanceName] +{ + local Instance="$1" + if [[ -z "$Instance" ]]; then + echo "Are you sure you want to delete all instances? [y/N]" + local Answ="N" + read Answ + if [[ "$Answ" == "y" || "$Answ" == "Y" ]]; then + for Instance in $(show_instances) + do + stop_instance "$Instance" + delete_instance "$Instance" + done + fi + elif instance_exists "$Instance"; then + local InstanceDir="$InstanceConfigDir/$Instance" + stop_instance "$Instance" + rm -rf "$InstanceDir" + echo "Instance $Instance removed" + else + echo "Instance $Instance not exists" + fi +} + +function show_status_implementation () # $1: [InstanceName] +{ + local Instance="$1" + if [[ -n "$Instance" ]]; then + if systemctl -q is-enabled $(service_name "$Instance"); then + local IsEnabled="enabled" + else + local IsEnabled="disabled" + fi + if systemctl | grep $(service_name "$Instance") | grep -q 'running' ; then + local IsRuning="running" + else + local IsRuning="dead" + fi + local Description=$(grep -P 'Description=' "$InstanceConfigDir/$Instance/main.conf" | sed -r 's/(Description=|")//g') + echo -e "$Instance:$IsEnabled:$IsRuning:$Description" + else + echo -e "INSTANCE:AUTORUN:STATE:DESCRIPTION" + for Instance in $(show_instances) + do + show_status_implementation "$Instance" + done + fi +} + +function show_status () # $1: [InstanceName] +{ + show_status_implementation "$1" | column -t -s : +} + +function update_kf2 () +{ + if [[ -n "$BranchName" ]]; then + local BetaArg="-beta $BranchName" + fi + if ! server_exists; then # First install + chown "root:$SteamUser" "$InstallDir" + steamcmd +login $SteamLogin +force_install_dir $InstallDir +app_update $AppNum $BetaArg validate +exit + mkdir "$InstanceConfigDir" && chown "$SteamUser:$SteamUser" "$InstanceConfigDir" + ln -s "$InstanceConfigDir" "$InstanceConfigLnk" + elif updates_aviable; then # Update + stop_instance + steamcmd +login $SteamLogin +force_install_dir $InstallDir +app_update $AppNum $BetaArg +exit + start_instance + fi +} + +function start_instance () # $1: [InstanceName] +{ + local Instance="$1" + if [[ -n "$Instance" ]] ; then + if instance_exists "$Instance"; then + systemctl start $(service_name "$Instance") + else + echo "Instance $Instance not exitst" + fi + else + for Instance in $(show_instances) + do + if systemctl -q is-enabled $(service_name "$Instance") ; then + start_instance "$Instance" + fi + done + fi +} + +function stop_instance () # $1: [InstanceName] +{ + local Instance="$1" + if [[ -n "$Instance" ]]; then + if instance_exists "$Instance"; then + systemctl stop $(service_name "$Instance") + else + echo "Instance $Instance not exitst" + fi + else + for Instance in $(show_instances) + do + stop_instance "$Instance" + done + fi +} + +function enable_instance () # $1: [InstanceName] +{ + local Instance="$1" + if [[ -n "$Instance" ]]; then + if instance_exists "$Instance"; then + systemctl enable $(service_name "$Instance") + else + echo "Instance $Instance not exitst" + fi + else + for Instance in $(show_instances) + do + enable_instance "$Instance" + done + fi +} + +function disable_instance () # $1: [InstanceName] +{ + local Instance="$1" + if [[ -n "$Instance" ]]; then + if instance_exists "$Instance"; then + systemctl disable $(service_name "$Instance") + else + echo "Instance $Instance not exitst" + fi + else + for Instance in $(show_instances) + do + disable_instance "$Instance" + done + fi +} + +function run () +{ + if [[ "$USER" == "$SteamUser" ]]; then + "$AppBin" "$@" + elif [[ -n $(groups "$USER" | grep -Fo 'wheel') ]] || [[ "$EUID" -eq 0 ]]; then + sudo -u "$SteamUser" "$AppBin" "$@" + else + echo "You must be a $SteamUser, root or sudo-user to run this command." + fi +} + +function map_sync () +{ + # TODO: implementation + # подсмотреть в скрипте старого серва + # либо забить хер и перевести всё на steamworkshop + # последний вариант наверное даже правильнее + echo "Dummy..." +} + +function ban_sync () +{ + # TODO: implementation + echo "Dummy..." +} + +function map_rotate_save () +{ + # TODO: implementation + echo "Dummy..." +} + +function map_rotate_load () +{ + # TODO: implementation + echo "Dummy..." +} + +if [[ $# -eq 0 ]]; then show_help; exit 0; fi +case $1 in + -h|--help ) show_help; ;; + -n|--new ) if [[ "$EUID" -eq 0 ]]; then new_instance "$2"; else run_as_root $@; fi;; + -d|--delete ) if [[ "$EUID" -eq 0 ]]; then delete_instance "$2"; else run_as_root $@; fi;; + -l|--list ) show_instances; ;; + -s|--status ) show_status "$2"; ;; + -u|--update ) if [[ "$EUID" -eq 0 ]]; then update_kf2 ; else run_as_root $@; fi;; + -r|--run ) run $@ ; ;; + --start ) if [[ "$EUID" -eq 0 ]]; then start_instance "$2"; else run_as_root $@; fi;; + --stop ) if [[ "$EUID" -eq 0 ]]; then stop_instance "$2"; else run_as_root $@; fi;; + --enable ) if [[ "$EUID" -eq 0 ]]; then enable_instance "$2"; else run_as_root $@; fi;; + --disable ) if [[ "$EUID" -eq 0 ]]; then disable_instance "$2"; else run_as_root $@; fi;; + --map-sync ) map_sync; ;; + --ban-sync ) ban_sync; ;; + --map-rotate-save ) map_rotate_save; ;; + --map-rotate-load ) map_rotate_load; ;; +esac diff --git a/SOURCES/kf2-srv-update.service b/SOURCES/kf2-srv-update.service new file mode 100644 index 0000000..965a156 --- /dev/null +++ b/SOURCES/kf2-srv-update.service @@ -0,0 +1,14 @@ +[Unit] +Description=Check and Update Killing Floor 2 server + +[Service] +Type=simple +ExecStart=/usr/bin/kf2-srv --update + +PrivateTmp=true +PrivateDevices=true +ProtectHome=false +ProtectSystem=false + +[Install] +WantedBy=multi-user.target diff --git a/SOURCES/kf2-srv-update.timer b/SOURCES/kf2-srv-update.timer new file mode 100644 index 0000000..b6ce218 --- /dev/null +++ b/SOURCES/kf2-srv-update.timer @@ -0,0 +1,9 @@ +[Unit] +Description=Check and Update killing Floor 2 job + +[Timer] +OnCalendar=Wed, 04:00 +Unit=kf2-srv-update.service + +[Install] +WantedBy=multi-user.target diff --git a/SOURCES/kf2-srv.conf b/SOURCES/kf2-srv.conf new file mode 100644 index 0000000..ce4849f --- /dev/null +++ b/SOURCES/kf2-srv.conf @@ -0,0 +1 @@ +BranchName="preview" diff --git a/SOURCES/kf2-srv.xml b/SOURCES/kf2-srv.xml new file mode 100644 index 0000000..3d62cde --- /dev/null +++ b/SOURCES/kf2-srv.xml @@ -0,0 +1,10 @@ + + + kf2-srv + Killing Floor 2 server + + + + + + diff --git a/SOURCES/kf2-srv@.service b/SOURCES/kf2-srv@.service new file mode 100644 index 0000000..3879b2e --- /dev/null +++ b/SOURCES/kf2-srv@.service @@ -0,0 +1,21 @@ +[Unit] +Description=Killing Floor 2 Server Daemon - %i + +[Service] +User=steam +Group=steam +Type=simple +StandardOutput=null +StandardError=null +EnvironmentFile=/etc/kf2-srv/instances/%i/main.conf +ExecStart=/usr/games/kf2-srv/Binaries/Win64/KFGameSteamServer.bin.x86_64 $Map configsubdir=instances/%i $Arg1 $Arg2 $Arg3 +Restart=always + +NoNewPrivileges=yes +PrivateTmp=true +PrivateDevices=true +ProtectHome=true +ProtectSystem=false + +[Install] +WantedBy=multi-user.target diff --git a/SOURCES/main.conf.template b/SOURCES/main.conf.template new file mode 100644 index 0000000..49d26c8 --- /dev/null +++ b/SOURCES/main.conf.template @@ -0,0 +1,9 @@ +LANG=en_US.UTF-8 + +Map=kf-bioticslab + +Arg1="-webadminport=8080" +Arg2="-queryport=27015" +Arg3="-port=7777" + +Description="Default description" diff --git a/SPECS/kf2-srv.spec b/SPECS/kf2-srv.spec new file mode 100644 index 0000000..6098337 --- /dev/null +++ b/SPECS/kf2-srv.spec @@ -0,0 +1,79 @@ +Name: kf2-srv +Version: 0.1.0 +Release: 1%{dist} +Summary: Killing Floor 2 server +Group: Amusements/Games +License: GNU GPLv3 +BuildArch: noarch + +Source1: %{name} +Source2: %{name}.conf +Source3: %{name}.xml +Source4: %{name}@.service +Source5: %{name}-update.service +Source6: %{name}-update.timer +Source7: main.conf.template + +Requires: systemd >= 219 +Requires: steamcmd + +Provides: %{name} + +%description +Killing Floor 2 server + +%prep + +%build + +%install +rm -rf $RPM_BUILD_ROOT + +install -m 755 -d %{buildroot}/%{_bindir} +install -m 755 -d %{buildroot}/%{_prefix}/lib/systemd/system +install -m 755 -d %{buildroot}/%{_prefix}/lib/firewalld/services +install -m 755 -d %{buildroot}/%{_sysconfdir}/%{name} +install -m 644 -d %{buildroot}/%{_prefix}/games/%{name} + +install -m 755 %{SOURCE1} %{buildroot}/%{_bindir} +install -m 644 %{SOURCE2} %{buildroot}/%{_sysconfdir}/%{name} +install -m 644 %{SOURCE3} %{buildroot}/%{_prefix}/lib/firewalld/services +install -m 644 %{SOURCE4} %{buildroot}/%{_prefix}/lib/systemd/system +install -m 644 %{SOURCE5} %{buildroot}/%{_prefix}/lib/systemd/system +install -m 644 %{SOURCE6} %{buildroot}/%{_prefix}/lib/systemd/system +install -m 644 %{SOURCE7} %{buildroot}/%{_sysconfdir}/%{name} + +sed -i -r "s|^(InstallDir=).*$|\1\"%{_prefix}/games/%{name}\"|g" %{buildroot}/%{_bindir}/%{name} + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%attr(775,root,root) %dir %{_prefix}/games/%{name} +%attr(755,root,root) %dir %{_sysconfdir}/%{name} +%attr(644,root,root) %{_sysconfdir}/%{name}/main.conf.template +%attr(644,root,root) %config(noreplace) %{_sysconfdir}/%{name}/%{name}.conf +%attr(644,root,root) %config(noreplace) %{_prefix}/lib/firewalld/services/%{name}.xml +%attr(755,root,root) %{_bindir}/%{name} +%attr(644,root,root) %{_prefix}/lib/systemd/system/* + +%post +#/bin/env bash +#if [[ $1 -eq 1 ]]; then # First installation +# +#fi +#exit 0 + +%preun +#/bin/env bash +if [[ $1 -eq 0 ]] ; then # Uninstall + %{_bindir}/%{name} --stop + %{_bindir}/%{name} --disable + yes | %{_bindir}/%{name} --delete + rm -f %{_sysconfdir}/%{name}/instances + rm -rf %{_prefix}/games/%{name}/* +fi + +%changelog +* Sat Sep 14 2019 GenZmeY - 0.1.0-1 +- First version of spec.