From 7e3ba93dc152b2dcb2fe8e371284b9890c9bb125 Mon Sep 17 00:00:00 2001 From: Price Hiller Date: Sat, 25 Dec 2021 21:23:27 -0600 Subject: [PATCH] Major overhauls, backups, backup_configs, shifting of directory paths by overwriting serverconfig.xml --- CentOS/7-Days-To-Die/7D2D-Manage.bash | 228 +++++++++++++++++++++++--- 1 file changed, 207 insertions(+), 21 deletions(-) diff --git a/CentOS/7-Days-To-Die/7D2D-Manage.bash b/CentOS/7-Days-To-Die/7D2D-Manage.bash index 308f032..cae0a0f 100644 --- a/CentOS/7-Days-To-Die/7D2D-Manage.bash +++ b/CentOS/7-Days-To-Die/7D2D-Manage.bash @@ -1,15 +1,146 @@ -### IMPORTS ### -# "Import" our needed functions from our library -LIBRARY_PATH="/usr/local/lib/Custom-Scripts" -# shellcheck source=/usr/local/lib/ -if ! source "${LIBRARY_PATH}/Logging-RGB.bash"; then - echo "Unable to source Logging-RGB.bash at ${LIBRARY_PATH}" - exit 1 -fi -# shellcheck source=/usr/local/lib/ -if ! source "${LIBRARY_PATH}/Confirmation.bash"; then - log "error" "Unable to source Confirmation.bash at ${LIBRARY_PATH}" -fi +#!/bin/bash + + +echo_rgb() { + # Echo a colored string to the terminal based on rgb values + # + # Positional Arguments: + # + # message + # - The message to be printed to stdout + # red + # - The red value from 0 to 255 + # green + # - The green value from 0 to 255 + # blue + # - The blue value from 0 to 255 + # + # Usage: + # echo_rgb "Yep" 10 8 30 + # + # POSIX Compliant: + # N/A + # + + local red + local green + local blue + local input + + input="${1}" + red="${2}" + green="${3}" + blue="${4}" + + printf "\e[0;38;2;%s;%s;%sm%s\e[m\n" "${red}" "${green}" "${blue}" "${input}" +} + +log() { + # Print a message and send it to stdout or stderr depending upon log level, also configurable with debug etc. + # + # Arguments: + # level + # - The log level, defined within a case check in this function + # message + # - The info message + # line_number + # - The line number of the calling function (${LINNO}) + # + # Usage: + # log "info" "Could not find that directory" + # + # POSIX Compliant: + # Yes + # + + # Set debug status depending if a global debug variable has been set to either 1 or 0 + local debug + if [ ${DEBUG} ]; then + debug=${DEBUG} + else + debug=0 + fi + + local FORMAT + FORMAT="[$(echo_rgb "$(date +%Y-%m-%dT%H:%M:%S)" 180 140 255)]" + + # Convert the level to uppercase + local level + level=$(echo "${1}" | tr '[:lower:]' '[:upper:]') + + local message + message="${2}" + + case "${level}" in + INFO) + # Output all info log levels to stdout + printf "${FORMAT}[$(echo_rgb "INFO" 0 140 255)] %s\n" "${message}" >&1 + return 0 + ;; + WARN | WARNING) + # Output all warning log levels to stdout + printf "${FORMAT}[$(echo_rgb "WARNING" 255 255 0)] %s\n" "${message}" >&1 + return 0 + ;; + DEBUG) + # Output all debug log levels to stdout + if [ "${DEBUG}" ]; then + printf "${FORMAT}[$(echo_rgb "DEBUG" 0 160 110)] %s\n" "${message}" >&1 + fi + return 0 + ;; + ERROR) + # Output all error log levels to stderr + printf "${FORMAT}[$(echo_rgb "ERROR" 255 0 0)] %s\n" "${message}" >&2 + return 0 + ;; + # Further log levels can be added by extending this switch statement with more comparisons + + *) # Default case, no matches + # Returns non-zero code as an improper log option was passed, this helps with using `set -e` + printf "${FORMAT}[ERROR] %s\n" "Invalid log level passed, received level \"${level}\" with message \"${message}\"" >&2 + return 1 + ;; + esac +} + +confirmation() { + # Receive confirmation from user as y, Y, n, or N + # returns 0 when answer is yes and 1 when answer is no + # + # Arguments: + # message + # - The confirmation prompt sent to the user, for example: + # Would you like to overwrite foobar.txt (y/N)? + # + # Usage: + # confirmation "Some prompt" + # - Sends "Some prompt" to the user and gets their input + # + # POSIX Compliant: + # Yes + # + + local message + message="${1}" + + local choice + + while true; do + read -p "${message} " -n 1 -r choice + case "$choice" in + y | Y) + echo "" + return 0 + ;; + n | N) + echo "" + return 1 + ;; + *) echo -e "\nInput must be either y, Y, n, or N" ;; + esac + done +} ### IMPORTS ### @@ -71,6 +202,7 @@ start_server() { local server_directory local server_config + local server_save_dir local server_name local prefix local server_session_name @@ -78,6 +210,8 @@ start_server() { server_name="Server-${server_id}" server_directory="${BASE_DIR}/${server_name}" server_config="${server_directory}/serverconfig.xml" + server_save_dir="${server_directory}/Saves/" + server_userdata_dir="${server_directory}/UserData" prefix="7D2D" server_session_name="${prefix}-${server_name}" @@ -85,20 +219,39 @@ start_server() { log "error" "Unable to find the server directory for $(important "${server_name}")" && return 1 + backup_configs "${server_directory}" + local server_port server_port="$(( START_PORT_RANGE + server_id ))" - log "info" "Starting $(important "${server_name}") located at $(important "${server_directory}") on port $(important "${server_port}")" + log "info" "Generating a few required directories in $(important "${server_directory}")" + mkdir -p "${server_save_dir}" + mkdir -p "${server_userdata_dir}" + + log "info" "Configuring serverconfig.xml" + # Overwrite values that we want to control, e.g. server port while IFS='' read -r; do - if [[ "${REPLY}" = *"ServerPort"* ]]; then + if [[ "${REPLY}" = *"property name=\"ServerPort\""* ]]; then printf "\t%s\n" "" + + # Override SaveGameFolder, opiniated in that it should exist in the Server Directory + elif [[ "${REPLY}" = *"property name=\"SaveGameFolder\""* ]]; then + printf "\t%s\n" "" + # Override UserDataFolder, opiniated in that it should exist in the Server Directory + elif [[ "${REPLY}" = *"property name=\"UserDataFolder\""* ]]; then + printf "\t%s\n" " "temp-serverconfig.xml" + # Occasionally the closing tag in serverconfig.xml will be missing, this ensures it is there in that scenario if [[ ! "$(tail "temp-serverconfig.xml" -n 1 )" = *"ServerSettings"* ]]; then printf "\n" >> "temp-serverconfig.xml" fi @@ -111,6 +264,8 @@ start_server() { cp "${server_config}" "${backup_file}" mv "temp-serverconfig.xml" "${server_config}" + log "info" "Starting $(important "${server_name}") located at $(important "${server_directory}") on port $(important "${server_port}")" + if tmux has-session -t "${server_session_name}" >/dev/null 2>&1; then log "warning" "$(important "${server_name}") is currently running" @@ -136,12 +291,10 @@ start_server() { sleep 60; done" C-m log "info" "Finished starting $(important "${server_name}") on port $(important "${server_port}") as tmux session $(important "${server_session_name}")" - } kill_server() { local prefix - local tmux_response local server_id server_id="" @@ -228,8 +381,10 @@ install() { local server_name local server_directory + local server_admin_xml server_name="Server-${server_id}" server_directory="${BASE_DIR}/${server_name}" + server_admin_xml="${HOME}/.local/share/7DaysToDie/Saves/serveradmin.xml" # Ensure that the global mods directory exists [[ -d "${server_directory}" ]] && @@ -239,6 +394,14 @@ install() { log "info" "Installing $(important "${server_name}") to $(important "${server_directory}")" steamcmd +force_install_dir "${server_directory}" +login anonymous +app_update 294420 validate +quit mkdir -p "${server_directory}/Mods" + + log "info" "Running $(important "${server_name}") to get a valid $(important "serveradmin.xml")" + start_server -s "${server_id}" -c + log "info" "Waiting to kill $(important "${server_name}")" + sleep 5 + kill_server -s "${server_id}" + + cp "${server_admin_xml}" "${server_directory}/" log "info" "Successfully installed $(important "${server_name}") to $(important "${server_directory}")" } @@ -284,9 +447,15 @@ update() { local server_directory local server_name + local wait_time server_name="Server-${server_id}" server_directory="${BASE_DIR}/${server_name}" - backup -s "${server_id}" + wait_time="5" + + log "info" "Recommend running a $(important "backup") operation before running this, waiting $(important "${wait_time}") seconds before continuing..." + sleep "${wait_time}" + + backup_configs "${server_directory}" log "info" "Updating server $(important "${server_name}") located at $(important "${server_directory}")..." steamcmd +force_install_dir "${server_directory}" +login anonymous +app_update 294420 validate +quit @@ -294,6 +463,18 @@ update() { } +backup_configs() { + local server_directory + local config_backup_directory + + server_directory="${1}" + config_backup_directory="${server_directory}/config-backups/$(date +s)" + log "info" "Backing up $(important ".xml configurations") in $(important "${server_directory}") to $(important "${config_backup_directory}")" + + mkdir -p "${config_backup_directory}" + cp "${server_directory}/"*.xml "${config_backup_directory}/" +} + backup() { local server_id @@ -341,16 +522,21 @@ backup() { local server_name server_name="Server-${server_id}" server_directory="${BASE_DIR}/${server_name}" - backup_dir="${HOME}/Server-Backups/${server_name}" + backup_dir="${HOME}/7D2D-Server-Backups/${server_name}" backup_full_path="${backup_dir}/$(date +%s).tar.gz" [[ ! -d "${server_directory}" ]] && log "info" "The server $(important "${server_name}") had no directory located at $(important "${server_directory}")" && exit 1 log "info" "Backing up server $(important "${server_name}") to $(important "${backup_full_path}"), this may take a while" mkdir -p "${backup_dir}" - tar cf - "${server_directory}" -P | pv -s "$(du -sb "${server_directory}" | awk '{print $1}')" | \ - gzip > "${backup_full_path}" - tar -czf "${server_directory}" "${backup_dir}"/ + + # Do a check if pv is there, pv is used for showing progress + if which pv > /dev/null 2>&1; then + tar cf - "${server_directory}" -P 2> /dev/null | pv -s "$(du -sb "${server_directory}" | awk '{print $1}')" | gzip > "${backup_full_path}" + else + log "info" "$(important "pv") not installed, not showing progress..." + tar czf "${server_directory}" "${backup_full_path}" 2> /dev/null + fi } list_servers() {