Last active
September 12, 2020 00:03
-
-
Save DrJume/dfcdc3de9a6e7b4876689462e4f90f35 to your computer and use it in GitHub Desktop.
TeamSpeak server query snapshot helper script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
set -e | |
set -u | |
# set -x # during dev | |
printUsage() { | |
cat <<EOF >/dev/stderr | |
Usage: $0 [protocol://][user@]host[:port] (password) action [-s sid] [-f snapshot_file] | |
protocol "raw", "ssh" - Protocol used to connect to the server query. (Default: "raw") | |
<password> can only be provided as an argument when using the RAW protocol. | |
user Server query user. (Default: "serveradmin") | |
port Port of the RAW (telnet) or SSH server query. | |
Default: 10011 (raw), 10022 (ssh) | |
Actions: | |
create Create a server snapshot of virtual server with id <sid>. (Default: 1) | |
Without a <snapshot_file> specified, STDOUT is used. | |
deploy Deploy a server snapshot to virtual server with id <sid>. (Default: 1) | |
Without a <snapshot_file> specified, the script reads from STDIN. | |
Options: [-keepfiles] | |
-keepfiles The channels that exist on the virtualserver and the | |
backup keep will have their files preserved. | |
EOF | |
} | |
readFlagParameter() { | |
local input_string=$(cat -) | |
local match=$(echo "$input_string" | grep -o -E "(^|[^-])\\-$1\>") | |
# if the flag is not specified: everything ok | |
if [[ -z "$match" ]]; then | |
echo "" | |
return 0 | |
fi | |
local parameter=$(echo "$input_string" | grep -E -o "\\-$1 [^- ]+" | sed -E "s/-$1 (.+)/\\1/") | |
# when flag is specified, but no value is provided: error | |
if [[ -z "$parameter" ]]; then | |
printUsage | |
exit 1 | |
fi | |
echo "$parameter" | |
return 0 | |
} | |
CONNECT_LOCATION=$(echo "$1" | sed -E 's/(([a-z]+):\/\/)?((.+)@)?([^:]+)(:([0-9]+))?/\2 \4 \5 \7/') | |
CHECK_CONNECT_LOCATION=$(echo "$CONNECT_LOCATION" | grep -o -E "^[a-z]* [^:/]* [^:]+ [0-9]*$" || true) | |
if [[ -z "$CHECK_CONNECT_LOCATION" ]]; then | |
( | |
echo "Invalid URL: $1" | |
echo | |
) >/dev/stderr | |
printUsage | |
exit 1 | |
fi | |
PROTOCOL=$(echo "$CONNECT_LOCATION" | cut -d' ' -f 1) | |
PROTOCOL=${PROTOCOL:-"raw"} | |
USER=$(echo "$CONNECT_LOCATION" | cut -d' ' -f 2) | |
USER=${USER:-"serveradmin"} | |
HOST=$(echo "$CONNECT_LOCATION" | cut -d' ' -f 3) | |
PORT=$(echo "$CONNECT_LOCATION" | cut -d' ' -f 4) | |
case "$PROTOCOL" in | |
raw) | |
if [ $# -lt 3 ]; then | |
printUsage | |
exit 1 | |
fi | |
PORT=${PORT:-"10011"} | |
PASSWORD=$2 | |
ACTION=$3 | |
OPTION_FLAGS=$(echo "$@" | cut -d' ' -f 4-) | |
;; | |
ssh) | |
if [ $# -lt 2 ]; then | |
printUsage | |
exit 1 | |
fi | |
PORT=${PORT:-"10022"} | |
ACTION=$2 | |
OPTION_FLAGS=$(echo "$@" | cut -d' ' -f 3-) | |
;; | |
*) | |
( | |
echo "No such protocol: $PROTOCOL" | |
echo | |
) >/dev/stderr | |
printUsage | |
exit 1 | |
;; | |
esac | |
SID=$(echo "$OPTION_FLAGS" | readFlagParameter 's') | |
SID=${SID:-1} | |
SNAPSHOT_FILE=$(echo "$OPTION_FLAGS" | readFlagParameter 'f') | |
KEEPFILES=$(echo "$OPTION_FLAGS" | grep -o -E '(^|[^-])\-keepfiles\>' | tr -d ' ') | |
case "$ACTION" in | |
create) | |
if [[ -n "$SNAPSHOT_FILE" ]] && [[ -f "$SNAPSHOT_FILE" ]]; then | |
echo "A snapshot file '$SNAPSHOT_FILE' already exists. An overwrite would delete the old snapshot!" >/dev/stderr | |
echo "Remove the old snapshot file manually or choose a different name." >/dev/stderr | |
exit 3 | |
fi | |
QUERY_COMMAND=$( | |
echo "use $SID" | |
[[ "$PROTOCOL" == "raw" ]] && echo "login $USER $PASSWORD" | |
echo "serversnapshotcreate" | |
echo "quit" | |
) | |
case "$PROTOCOL" in | |
raw) | |
QUERY_RESPONSE=$( | |
echo "$QUERY_COMMAND" | | |
nc $HOST $PORT | | |
tr -d '\r' | |
) | |
;; | |
ssh) | |
QUERY_RESPONSE=$( | |
echo "$QUERY_COMMAND" | | |
ssh $USER@$HOST -p$PORT | | |
tr -d '\r' | |
) | |
;; | |
esac | |
if [[ -z "$QUERY_RESPONSE" ]]; then | |
echo "Server did not respond." >/dev/stderr | |
exit 6 | |
fi | |
# "grep ... || true": prevent non-zero exit code from grep when no match | |
QUERY_ERRORS=$(echo "$QUERY_RESPONSE" | grep "^error" | grep -v "id=0" || true) | |
if [[ -n "$QUERY_ERRORS" ]]; then | |
( | |
echo "Server query returned with errors:" | |
echo | |
echo "$QUERY_ERRORS" | |
) >/dev/stderr | |
exit 4 | |
fi | |
SNAPSHOT_DATA=$(echo "$QUERY_RESPONSE" | grep -E '^version=\d+ data=.*$' || true) | |
if [[ -z "$SNAPSHOT_DATA" ]]; then | |
( | |
echo "No snapshot data received!" | |
echo | |
echo "Got following reponse:" | |
echo | |
echo "$QUERY_RESPONSE" | |
) >/dev/stderr | |
exit 5 | |
fi | |
echo "$SNAPSHOT_DATA" >${SNAPSHOT_FILE:-/dev/stdout} | |
;; | |
deploy) | |
if [[ -n "$SNAPSHOT_FILE" ]] && [[ ! -f "$SNAPSHOT_FILE" ]]; then | |
echo "Snapshot file '$SNAPSHOT_FILE' is not a regular file or does not exist." >/dev/stderr | |
exit 2 | |
fi | |
# prevent reading from STDIN on interactive shell | |
if [ -t 0 ] && [[ -z "$SNAPSHOT_FILE" ]]; then | |
# interactive | |
( | |
echo "Not reading from STDIN on an interactive shell." | |
echo | |
echo "Use -f to specify the snapshot file." | |
) >/dev/stderr | |
exit 7 | |
fi | |
QUERY_COMMAND=$( | |
echo "use $SID" | |
[[ "$PROTOCOL" == "raw" ]] && echo "login $USER $PASSWORD" | |
echo -n "serversnapshotdeploy $KEEPFILES " | |
cat ${SNAPSHOT_FILE:-/dev/stdin} | |
echo | |
echo "quit" | |
) | |
case "$PROTOCOL" in | |
raw) | |
QUERY_RESPONSE=$( | |
echo "$QUERY_COMMAND" | | |
nc $HOST $PORT | | |
tr -d '\r' | |
) | |
;; | |
ssh) | |
QUERY_RESPONSE=$( | |
echo "$QUERY_COMMAND" | | |
ssh $USER@$HOST -p$PORT | | |
tr -d '\r' | |
) | |
;; | |
esac | |
if [[ -z "$QUERY_RESPONSE" ]]; then | |
echo "Server did not respond." >/dev/stderr | |
exit 6 | |
fi | |
# "grep ... || true": prevent non-zero exit code from grep when no match | |
QUERY_ERRORS=$(echo "$QUERY_RESPONSE" | grep "^error" | grep -v "id=0" || true) | |
if [[ -n "$QUERY_ERRORS" ]]; then | |
( | |
echo "Server query returned with errors:" | |
echo | |
echo "$QUERY_ERRORS" | |
) >/dev/stderr | |
exit 4 | |
fi | |
;; | |
*) | |
printUsage | |
exit 1 | |
;; | |
esac |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment