Skip to content

Instantly share code, notes, and snippets.

@DrJume
Last active September 12, 2020 00:03
Show Gist options
  • Save DrJume/dfcdc3de9a6e7b4876689462e4f90f35 to your computer and use it in GitHub Desktop.
Save DrJume/dfcdc3de9a6e7b4876689462e4f90f35 to your computer and use it in GitHub Desktop.
TeamSpeak server query snapshot helper script
#!/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