Sergiy Markin fa49a102c9 [dbutils] Increase timeout for ON_DEMAND_POD
This PS is intended to fix intermittent issue on some sites when
database backup ondemand job fails to detect ON_DEMAND_POD when it is
still creating.

Also this PS has fixes related to using focal as base build image.
tox.ini also fixed for compatibility with tox4. This PS also uplifts
latest stable HTK version and changes openstackutility version to
Yoga.

Change-Id: I36e55091adf7dc68758fb9b7145cfa34776522d6
2023-02-14 19:35:47 +00:00

1083 lines
31 KiB
Smarty
Executable File

#!/bin/bash
# This file contains database utility scripts which a user can execute
# to perform database specific tasks such as backup, restore, and showing
# tables.
#
# The user can execute this script by calling:
# dbutils
#
# No arguments required. However the script will require the
# following variables to be exported:
#
# export BACKUP_RESTORE_NAMESPACE_LIST A comma deliminated list of the namespaces the databases can be found in the respective utility yaml
trap do_trap SIGINT SIGTERM
ARGS=("$@")
function setup() {
source /tmp/mysqlutils.sh
if [[ $? -ne 0 ]]; then
echo "ERROR: source /tmp/mysqlutils.sh failed. Cannot continue. Exiting..."
exit 1
fi
if [[ -z "$BACKUP_RESTORE_NAMESPACE_LIST" ]]; then
echo "ERROR: Namespaces are not defined. Exiting..."
exit 1
fi
export ONDEMAND_JOB="mariadb-ondemand"
export KEEP_POD="false"
IFS=', ' read -re -a NAMESPACE_ARRAY <<< "$BACKUP_RESTORE_NAMESPACE_LIST"
}
function check_args() {
# There should always be 3 parameters
if [[ -z "$3" ]]; then
echo "ERROR: Incorrect number of parameters provided (requires three). Exiting..."
exit 1
fi
ARGS=$1[@]
ARGS_ARRAY=("${!ARGS}")
ARGS_MIN=$2+1
ARGS_MAX=$3+1
ARGS_COUNT="${#ARGS_ARRAY[@]}"
# Confirm that there is a correct number of arguments passed to the command.
if [[ $ARGS_COUNT -lt $ARGS_MIN ]]; then
echo "ERROR: not enough arguments"
help
return 1
elif [[ $ARGS_COUNT -gt $ARGS_MAX ]]; then
echo "ERROR: too many arguments"
help
return 1
fi
NAMESPACE_POS=1
# Check if the first parameter is the remote flag.
if [[ "${ARGS_ARRAY[1]}" =~ ^-rp|^-pr|^-r ]]; then
export LOC_STRING="remote RGW"
export LOCATION="remote"
NAMESPACE_POS=2
else
export LOC_STRING="local"
export LOCATION=""
fi
# Check if persistent on-demand pod is enabled
if [[ "${ARGS_ARRAY[1]}" =~ ^-rp|^-pr|^-p ]]; then
export KEEP_POD="true"
NAMESPACE_POS=2
else
export KEEP_POD="false"
fi
setup_namespace "${ARGS_ARRAY[$NAMESPACE_POS]}"
if [[ "$?" -ne 0 ]]; then
return 1
fi
return 0
}
# Ensure that the ondemand pod is running
function ensure_ondemand_pod_exists() {
# Determine the status of the on demand pod if it exists
POD_LISTING=$(kubectl get pod -n "$NAMESPACE" | grep "$ONDEMAND_JOB")
if [[ ! -z "$POD_LISTING" ]]; then
ONDEMAND_POD=$(echo "$POD_LISTING" | awk '{print $1}')
STATUS=$(echo "$POD_LISTING" | awk '{print $3}')
if [[ "$STATUS" == "Terminating" ]]; then
kubectl wait -n "$NAMESPACE" --for=delete pod/"$ONDEMAND_POD" --timeout=30s
unset ONDEMAND_POD
elif [[ "$STATUS" != "Running" ]]; then
kubectl wait -n "$NAMESPACE" --for condition=ready pod/"$ONDEMAND_POD" --timeout=30s
fi
fi
POD_LISTING=$(kubectl get pod -n "$NAMESPACE" | grep "$ONDEMAND_JOB")
if [[ ! -z "$POD_LISTING" ]]; then
STATUS=$(echo "$POD_LISTING" | awk '{print $3}')
CONTAINERS=$(echo "$POD_LISTING" | awk '{print $2}')
# There should only ever be one ondemand pod existing at any time, so if
# we find any which are not ready remove them, even if completed.
if [[ $STATUS != "Running" || $CONTAINERS != "2/2" ]]; then
echo "Found an old on-demand pod; removing it."
remove_job "$NAMESPACE" "$ONDEMAND_JOB"
if [[ $? -ne 0 ]]; then
echo "ERROR: Failed to remove old on-demand pod. Exiting..."
exit 1
fi
else
# Pod is already running and ready
ONDEMAND_POD=$(kubectl get pod -n "$NAMESPACE" | grep "$ONDEMAND_JOB" | awk '{print $1}')
fi
fi
# If we reached this point with no ONDEMAND_POD, then we need to create
# a new on-demand job.
if [[ -z "$ONDEMAND_POD" ]]; then
echo "Creating new on-demand job in the $NAMESPACE namespace..."
/tmp/mariadb-ondemand-job.sh "$NAMESPACE"
if [[ $? -ne 0 ]]; then
echo "ERROR: Failed to execute: /tmp/mariadb-ondemand-job.sh $NAMESPACE. Exiting..."
exit 1
fi
sleep 10s
ONDEMAND_POD=$(kubectl get pods -n "$NAMESPACE" --selector=job-name="$ONDEMAND_JOB" -o json | jq -r .items[].metadata.name)
if [[ -z "$ONDEMAND_POD" ]]; then
echo "ERROR: Failed to obtain the ONDEMAND_POD name."
exit 1
fi
kubectl wait --for condition=ready --timeout=300s -n "$NAMESPACE" "pod/${ONDEMAND_POD}"
if [[ $? -ne 0 ]]; then
echo "ERROR: Failed to create a new on-demand pod. Exiting..."
exit 1
fi
fi
export ONDEMAND_POD
}
# Params: ArrayToSearch StringToSearchFor
function in_array() {
ARGS=$1[@]
ARGS_ARRAY=("${!ARGS}")
local i
for i in "${ARGS_ARRAY[@]}"; do [[ "$i" == "$2" ]] && return 0; done
return 1
}
# Setup the NAMESPACE env, confirm that the entered NAMESPACE is valid
function setup_namespace() {
if [[ -z "$1" ]]; then
if [[ "${#NAMESPACE_ARRAY[@]}" -gt 1 ]]; then
echo "ERROR: Namespace is required since there are multiple namespaces: ${NAMESPACE_ARRAY[*]}"
return 1
else
export NAMESPACE="${NAMESPACE_ARRAY[0]}"
fi
else
if [[ "${#NAMESPACE_ARRAY[@]}" -gt 1 ]]; then
in_array NAMESPACE_ARRAY "$1"
if [[ "$?" -eq 0 ]]; then
export NAMESPACE="$1"
unset ONDEMAND_POD
else
echo "ERROR: Namespace $1 is not valid"
return 1
fi
else
export NAMESPACE="${NAMESPACE_ARRAY[0]}"
fi
fi
if [[ ! "$USED_NAMESPACES" =~ $NAMESPACE ]]; then
export USED_NAMESPACES="$USED_NAMESPACES $NAMESPACE"
fi
return 0
}
# Params: <namespace> <job>
function remove_job() {
NAMESPACE=$1
JOB=$2
# Cleanup the last attempted job if there is one, wait for the pod to be deleted.
kubectl get job -n "$NAMESPACE" "$JOB"
if [[ $? -eq 0 ]]; then
echo "Removing on-demand job $NAMESPACE $JOB"
ONDEMAND_POD=$(kubectl get pod -n "$NAMESPACE" | grep "$JOB" | awk '{print $1}')
kubectl delete job --ignore-not-found -n "$NAMESPACE" "$JOB"
kubectl wait --for=delete --timeout=300s -n "$NAMESPACE" pod/"${ONDEMAND_POD}" &>/dev/null
if [[ $? -ne 0 ]]; then
echo "ERROR: could not destroy the $NAMESPACE $JOB job. Exiting..."
exit 1
fi
fi
}
# Params: timeout (how long in seconds flock waited on the lock to be released)
function flock_error() {
echo "ERROR: Lock did not release after $1 seconds."
echo " Another process may have locked /tmp/dbutils.lock"
echo " If you are sure no other process is running, rm /tmp/dbutils.lock"
echo " and run dbutils again."
exit 1
}
# Params: timeout (if locked, how long should flock wait on the lock to be released)
function lock() {
timeout=$1
exec 200>/tmp/dbutils.lock
flock -w "$timeout" 200 || flock_error "$timeout"
export MY_LOCK="true"
echo "Acquired lock."
}
function unlock() {
flock -u 200
export MY_LOCK="false"
echo "Lock Removed."
}
# Params: [-p] <namespace> [database]
function do_backup() {
BACKUP_ARGS=("$@")
check_args BACKUP_ARGS 1 3
if [[ $? -ne 0 ]]; then
return 1
fi
# Be sure that an ondemand pod is ready (start if not started)
ensure_ondemand_pod_exists
lock 300
# Execute the command in the on-demand pod
if [[ "${BACKUP_ARGS[1]}" == "-p" ]]; then
if [[ -z "${BACKUP_ARGS[3]}" ]]; then
DB_LOC=0
else
DB_LOC=3
fi
elif [[ -z "${BACKUP_ARGS[2]}" ]]; then
DB_LOC=0
else
DB_LOC=2
fi
if [[ "${DB_LOC}" == 0 ]]; then
COMMAND="/tmp/backup_mariadb.sh"
else
COMMAND="/tmp/backup_mariadb.sh ${BACKUP_ARGS[${DB_LOC}]}"
fi
kubectl exec -i -n "${NAMESPACE}" "${ONDEMAND_POD}" -- ${COMMAND}
unlock
}
# Params: [-rp] <namespace>
function do_list_archives() {
LIST_ARGS=("$@")
check_args LIST_ARGS 1 2
if [[ $? -ne 0 ]]; then
return 1
fi
# Be sure that an ondemand pod is ready (start if not started)
ensure_ondemand_pod_exists
# Execute the command in the on-demand pod
kubectl exec -i -n "$NAMESPACE" "$ONDEMAND_POD" -- /tmp/restore_mariadb.sh list_archives "$LOCATION"
}
# Params: [-rp] <archive>
function do_list_databases() {
# Determine which argument is the ARCHIVE in order to detect the NAMESPACE
LIST_ARGS=("$@")
if [[ "${LIST_ARGS[1]}" =~ .tar.gz ]]; then
ARCHIVE="${LIST_ARGS[1]}"
ARCHIVE_POS=1
elif [[ "${LIST_ARGS[2]}" =~ .tar.gz ]]; then
ARCHIVE="${LIST_ARGS[2]}"
ARCHIVE_POS=2
else
echo "ERROR: Archive file not found in 1st or 2nd argument position."
return 1
fi
NAMESPACE="$(echo "$ARCHIVE" | awk -F '.' '{print $2}')"
LIST_ARGS=("${LIST_ARGS[@]:0:$ARCHIVE_POS}" "$NAMESPACE" "${LIST_ARGS[@]:$ARCHIVE_POS}")
# NAMESPACE is pulled from the ARCHIVE name, and is inserted into LIST_ARGS increases max arguments by 1
check_args LIST_ARGS 1 3
if [[ $? -ne 0 ]]; then
return 1
fi
# Be sure that an ondemand pod is ready (start if not started)
ensure_ondemand_pod_exists
# Execute the command in the on-demand pod
kubectl exec -i -n "$NAMESPACE" "$ONDEMAND_POD" -- /tmp/restore_mariadb.sh list_databases "$ARCHIVE" "$LOCATION"
}
# Params: [-rp] <archive> <database>
function do_list_tables() {
# Determine which argument is the ARCHIVE in order to detect the NAMESPACE
LIST_ARGS=("$@")
if [[ "${LIST_ARGS[1]}" =~ .tar.gz ]]; then
ARCHIVE="${LIST_ARGS[1]}"
ARCHIVE_POS=1
elif [[ "${LIST_ARGS[2]}" =~ .tar.gz ]]; then
ARCHIVE="${LIST_ARGS[2]}"
ARCHIVE_POS=2
else
echo "ERROR: Archive file not found in 1st or 2nd argument position."
return 1
fi
NAMESPACE="$(echo "$ARCHIVE" | awk -F '.' '{print $2}')"
LIST_ARGS=("${LIST_ARGS[@]:0:$ARCHIVE_POS}" "$NAMESPACE" "${LIST_ARGS[@]:$ARCHIVE_POS}")
# NAMESPACE is pulled from the ARCHIVE name, and is inserted into LIST_ARGS increases max arguments by 1
check_args LIST_ARGS 2 4
if [[ $? -ne 0 ]]; then
return 1
fi
DATABASE=${LIST_ARGS[$ARCHIVE_POS+2]}
# Be sure that an ondemand pod is ready (start if not started)
ensure_ondemand_pod_exists
# Execute the command in the on-demand pod
kubectl exec -i -n "$NAMESPACE" "$ONDEMAND_POD" -- /tmp/restore_mariadb.sh list_tables "$ARCHIVE" "$DATABASE" "$LOCATION"
}
# Params: [-rp] <archive> <database> <table>
function do_list_rows() {
# Determine which argument is the ARCHIVE in order to detect the NAMESPACE
LIST_ARGS=("$@")
if [[ "${LIST_ARGS[1]}" =~ .tar.gz ]]; then
ARCHIVE="${LIST_ARGS[1]}"
ARCHIVE_POS=1
elif [[ "${LIST_ARGS[2]}" =~ .tar.gz ]]; then
ARCHIVE="${LIST_ARGS[2]}"
ARCHIVE_POS=2
else
echo "ERROR: Archive file not found in 1st or 2nd argument position."
return 1
fi
NAMESPACE="$(echo "$ARCHIVE" | awk -F '.' '{print $2}')"
LIST_ARGS=("${LIST_ARGS[@]:0:$ARCHIVE_POS}" "$NAMESPACE" "${LIST_ARGS[@]:$ARCHIVE_POS}")
check_args LIST_ARGS 3 5
if [[ $? -ne 0 ]]; then
return 1
fi
DATABASE=${LIST_ARGS[$ARCHIVE_POS+2]}
TABLE=${LIST_ARGS[$ARCHIVE_POS+3]}
# Be sure that an ondemand pod is ready (start if not started)
ensure_ondemand_pod_exists
# Execute the command in the on-demand pod
kubectl exec -i -n "$NAMESPACE" "$ONDEMAND_POD" -- /tmp/restore_mariadb.sh list_rows "$ARCHIVE" "$DATABASE" "$TABLE" "$LOCATION"
}
# Params: [-rp] <archive> <database> <table>
function do_list_schema() {
# Determine which argument is the ARCHIVE in order to detect the NAMESPACE
LIST_ARGS=("$@")
if [[ "${LIST_ARGS[1]}" =~ .tar.gz ]]; then
ARCHIVE="${LIST_ARGS[1]}"
ARCHIVE_POS=1
elif [[ "${LIST_ARGS[2]}" =~ .tar.gz ]]; then
ARCHIVE="${LIST_ARGS[2]}"
ARCHIVE_POS=2
else
echo "ERROR: Archive file not found in 1st or 2nd argument position."
return 1
fi
NAMESPACE="$(echo "$ARCHIVE" | awk -F '.' '{print $2}')"
LIST_ARGS=("${LIST_ARGS[@]:0:$ARCHIVE_POS}" "$NAMESPACE" "${LIST_ARGS[@]:$ARCHIVE_POS}")
check_args LIST_ARGS 3 5
if [[ $? -ne 0 ]]; then
return 1
fi
DATABASE=${LIST_ARGS[$ARCHIVE_POS+2]}
TABLE=${LIST_ARGS[$ARCHIVE_POS+3]}
# Be sure that an ondemand pod is ready (start if not started)
ensure_ondemand_pod_exists
# Execute the command in the on-demand pod
kubectl exec -i -n "$NAMESPACE" "$ONDEMAND_POD" -- /tmp/restore_mariadb.sh list_schema "$ARCHIVE" "$DATABASE" "$TABLE" "$LOCATION"
}
# Params: [-rp] <archive>
function do_delete_archive() {
# Determine which argument is the ARCHIVE in order to detect the NAMESPACE
DELETE_ARCH_ARGS=("$@")
if [[ "${DELETE_ARCH_ARGS[1]}" =~ .tar.gz ]]; then
ARCHIVE="${DELETE_ARCH_ARGS[1]}"
ARCHIVE_POS=1
elif [[ "${DELETE_ARCH_ARGS[2]}" =~ .tar.gz ]]; then
ARCHIVE="${DELETE_ARCH_ARGS[2]}"
ARCHIVE_POS=2
else
echo "ERROR: Archive file not found in 1st or 2nd argument position."
return 1
fi
NAMESPACE="$(echo "${ARCHIVE}" | awk -F '.' '{print $2}')"
DELETE_ARCH_ARGS=("${DELETE_ARCH_ARGS[@]:0:$ARCHIVE_POS}" "$NAMESPACE" "${DELETE_ARCH_ARGS[@]:$ARCHIVE_POS}")
# NAMESPACE is pulled from the ARCHIVE name, and is inserted into DELETE_ARCH_ARGS increases max arguments by 1
check_args DELETE_ARCH_ARGS 1 3
if [[ $? -ne 0 ]]; then
return 1
fi
# Be sure that an ondemand pod is ready (start if not started)
ensure_ondemand_pod_exists
# Execute the command in the on-demand pod
kubectl exec -i -n "${NAMESPACE}" "${ONDEMAND_POD}" -- /tmp/restore_mariadb.sh delete_archive "${ARCHIVE}" "${LOCATION}"
}
# Params: [-p] <namespace>
function do_show_databases() {
SHOW_ARGS=("$@")
check_args SHOW_ARGS 1 2
if [[ $? -ne 0 ]]; then
return 1
fi
# Be sure that an ondemand pod is ready (start if not started)
ensure_ondemand_pod_exists
if [[ "${SHOW_ARGS[1]}" =~ ^-rp|^-pr|^-p ]]; then
unset -v SHOW_ARGS[1]
fi
SHOW_ARGS[3]=$ONDEMAND_POD
show_databases "${SHOW_ARGS[@]}"
if [[ $? -ne 0 ]]; then
return 1
fi
}
# Params: [-p] <namespace> <database>
function do_show_tables() {
SHOW_ARGS=("$@")
check_args SHOW_ARGS 2 3
if [[ $? -ne 0 ]]; then
return 1
fi
# Be sure that an ondemand pod is ready (start if not started)
ensure_ondemand_pod_exists
if [[ "${SHOW_ARGS[1]}" =~ ^-rp|^-pr|^-p ]]; then
unset -v SHOW_ARGS[1]
fi
SHOW_ARGS[4]=$ONDEMAND_POD
show_tables "${SHOW_ARGS[@]}"
if [[ $? -ne 0 ]]; then
return 1
fi
}
# Params: [-p] <namespace> <database> <table>
function do_show_rows() {
SHOW_ARGS=("$@")
check_args SHOW_ARGS 3 4
if [[ $? -ne 0 ]]; then
return 1
fi
# Be sure that an ondemand pod is ready (start if not started)
ensure_ondemand_pod_exists
if [[ "${SHOW_ARGS[1]}" =~ ^-rp|^-pr|^-p ]]; then
unset -v SHOW_ARGS[1]
fi
SHOW_ARGS[5]=$ONDEMAND_POD
show_rows "${SHOW_ARGS[@]}"
if [[ $? -ne 0 ]]; then
return 1
fi
}
# Params: [-p] <namespace> <database> <table>
function do_show_schema() {
SHOW_ARGS=("$@")
check_args SHOW_ARGS 3 4
if [[ $? -ne 0 ]]; then
return 1
fi
# Be sure that an ondemand pod is ready (start if not started)
ensure_ondemand_pod_exists
if [[ "${SHOW_ARGS[1]}" =~ ^-rp|^-pr|^-p ]]; then
unset -v SHOW_ARGS[1]
fi
SHOW_ARGS[5]=$ONDEMAND_POD
show_schema "${SHOW_ARGS[@]}"
if [[ $? -ne 0 ]]; then
return 1
fi
}
# Params: [-p] <namespace> <tablename>
# Column names and types will be hardcoded for now
# NOTE: In order for this function to work, create_test_database in
# values.yaml file needs to be set to true to create a test database
# at bootstrap time.
function do_create_table() {
CREATE_ARGS=("$@")
check_args CREATE_ARGS 2 3
if [[ $? -ne 0 ]]; then
return 1
fi
# Be sure that an ondemand pod is ready (start if not started)
ensure_ondemand_pod_exists
if [[ "${CREATE_ARGS[1]}" =~ ^-rp|^-pr|^-p ]]; then
unset -v CREATE_ARGS[1]
fi
CREATE_ARGS[4]=$ONDEMAND_POD
create_table "${CREATE_ARGS[@]}"
if [[ $? -ne 0 ]]; then
return 1
fi
}
# Params: [-p] <namespace> <table>
# The row values are hardcoded for now.
# NOTE: In order for this function to work, create_test_database in
# values.yaml file needs to be set to true to create a test database
# at bootstrap time.
function do_create_row() {
CREATE_ARGS=("$@")
check_args CREATE_ARGS 2 3
if [[ $? -ne 0 ]]; then
return 1
fi
# Be sure that an ondemand pod is ready (start if not started)
ensure_ondemand_pod_exists
if [[ "${CREATE_ARGS[1]}" =~ ^-rp|^-pr|^-p ]]; then
unset -v CREATE_ARGS[1]
fi
CREATE_ARGS[4]=$ONDEMAND_POD
create_row "${CREATE_ARGS[@]}"
if [[ $? -ne 0 ]]; then
return 1
fi
}
# Params: [-p] <namespace>
# Create grants for the test user to access the test database.
# NOTE: In order for this function to create a user, create_test_database in
# values.yaml file needs to be set to true to create the test database
# at bootstrap time. Otherwise it cannot correctly give the user any
# privileges.
function do_create_user_grants() {
CREATE_GRANTS_ARGS=("$@")
check_args CREATE_GRANTS_ARGS 1 2
if [[ $? -ne 0 ]]; then
return 1
fi
# Be sure that an ondemand pod is ready (start if not started)
ensure_ondemand_pod_exists
if [[ "${CREATE_GRANTS_ARGS[1]}" =~ ^-rp|^-pr|^-p ]]; then
unset -v CREATE_GRANTS_ARGS[1]
fi
CREATE_GRANTS_ARGS[3]=${ONDEMAND_POD}
create_user_grants "${CREATE_GRANTS_ARGS[@]}"
if [[ $? -ne 0 ]]; then
return 1
fi
}
# Params: [-p] <namespace>
# Query the test user of the test database (test for existence).
# Returns a string indicating whether or not the query was successful.
# NOTE: In order for this function to show a user, create_test_database in
# values.yaml file needs to be set to true to create the test user
# at bootstrap time.
function do_query_user() {
QUERY_ARGS=("$@")
check_args QUERY_ARGS 1 2
if [[ $? -ne 0 ]]; then
return 1
fi
# Be sure that an ondemand pod is ready (start if not started)
ensure_ondemand_pod_exists
if [[ "${QUERY_ARGS[1]}" =~ ^-rp|^-pr|^-p ]]; then
unset -v QUERY_ARGS[1]
fi
QUERY_ARGS[3]=${ONDEMAND_POD}
query_user "${QUERY_ARGS[@]}"
if [[ $? -ne 0 ]]; then
return 1
fi
}
# Params: [-p] <namespace>
# Delete the grants for the test user in the test database.
# NOTE: In order for this function to delete a user, create_test_database in
# values.yaml file needs to be set to true to create the test user
# at bootstrap time. If the user isn't there this will fail.
function do_delete_user_grants() {
DELETE_GRANTS_ARGS=("$@")
check_args DELETE_GRANTS_ARGS 1 2
if [[ $? -ne 0 ]]; then
return 1
fi
# Be sure that an ondemand pod is ready (start if not started)
ensure_ondemand_pod_exists
if [[ "${DELETE_GRANTS_ARGS[1]}" =~ ^-rp|^-pr|^-p ]]; then
unset -v DELETE_GRANTS_ARGS[1]
fi
DELETE_GRANTS_ARGS[3]=${ONDEMAND_POD}
delete_user_grants "${DELETE_GRANTS_ARGS[@]}"
if [[ $? -ne 0 ]]; then
return 1
fi
}
# Params: [-p] <namespace> <table> <colname> <value>
# Where: <colname> = <value> is the condition used to find the row to be deleted.
# NOTE: In order for this function to work, create_test_database in
# values.yaml file needs to be set to true to create a test database
# at bootstrap time.
function do_delete_row() {
DELETE_ARGS=("$@")
check_args DELETE_ARGS 4 5
if [[ $? -ne 0 ]]; then
return 1
fi
# Be sure that an ondemand pod is ready (start if not started)
ensure_ondemand_pod_exists
if [[ "${DELETE_ARGS[1]}" =~ ^-rp|^-pr|^-p ]]; then
unset -v DELETE_ARGS[1]
fi
DELETE_ARGS[6]=$ONDEMAND_POD
delete_row "${DELETE_ARGS[@]}"
if [[ $? -ne 0 ]]; then
return 1
fi
}
# Params: [-p] <namespace> <tablename>
# NOTE: In order for this function to work, create_test_database in
# values.yaml file needs to be set to true to create a test database
# at bootstrap time.
function do_delete_table() {
DELETE_ARGS=("$@")
check_args DELETE_ARGS 2 3
if [[ $? -ne 0 ]]; then
return 1
fi
# Be sure that an ondemand pod is ready (start if not started)
ensure_ondemand_pod_exists
if [[ "${DELETE_ARGS[1]}" =~ ^-rp|^-pr|^-p ]]; then
unset -v DELETE_ARGS[1]
fi
DELETE_ARGS[4]=$ONDEMAND_POD
delete_table "${DELETE_ARGS[@]}"
if [[ $? -ne 0 ]]; then
return 1
fi
}
# Params: [-p] <namespace>
# Delete the test backups that have been created by the test functions above.
# NOTE: only backups associated with the test database will be deleted.
# Both local and remote test backups will be deleted.
function do_delete_backups() {
DELETE_BACKUPS_ARGS=("$@")
check_args DELETE_BACKUPS_ARGS 1 2
if [[ $? -ne 0 ]]; then
return 1
fi
# Be sure that an ondemand pod is ready (start if not started)
ensure_ondemand_pod_exists
if [[ "${DELETE_BACKUPS_ARGS[1]}" =~ ^-rp|^-pr|^-p ]]; then
unset -v DELETE_BACKUPS_ARGS[1]
fi
DELETE_BACKUPS_ARGS[3]=${ONDEMAND_POD}
delete_backups "${DELETE_BACKUPS_ARGS[@]}"
if [[ $? -ne 0 ]]; then
return 1
fi
}
# Params: [-rp] <archive> <db_name>
function do_restore() {
# Determine which argument is the ARCHIVE in order to detect the NAMESPACE
RESTORE_ARGS=("$@")
if [[ "${RESTORE_ARGS[1]}" =~ .tar.gz ]]; then
ARCHIVE="${RESTORE_ARGS[1]}"
ARCHIVE_POS=1
elif [[ "${RESTORE_ARGS[2]}" =~ .tar.gz ]]; then
ARCHIVE="${RESTORE_ARGS[2]}"
ARCHIVE_POS=2
else
echo "ERROR: Archive file not found in 1st or 2nd argument position."
return 1
fi
NAMESPACE="$(echo "$ARCHIVE" | awk -F '.' '{print $2}')"
RESTORE_ARGS=("${RESTORE_ARGS[@]:0:$ARCHIVE_POS}" "$NAMESPACE" "${RESTORE_ARGS[@]:$ARCHIVE_POS}")
# NAMESPACE is pulled from the ARCHIVE name, and is inserted into RESTORE_ARGS increases max arguments by 1
check_args RESTORE_ARGS 2 4
if [[ $? -ne 0 ]]; then
return 1
fi
DATABASE=${RESTORE_ARGS[$ARCHIVE_POS+2]}
# Be sure that an ondemand pod is ready (start if not started)
ensure_ondemand_pod_exists
lock 300
# Execute the command in the on-demand pod
kubectl exec -i -n "$NAMESPACE" "$ONDEMAND_POD" -- /tmp/restore_mariadb.sh restore "$ARCHIVE" "$DATABASE" "$LOCATION"
unlock
}
# Params: [-p] <namespace>
function do_sql_prompt() {
PROMPT_ARGS=("$@")
check_args PROMPT_ARGS 1 2
if [[ $? -ne 0 ]]; then
return 1
fi
# Be sure that an ondemand pod is ready (start if not started)
ensure_ondemand_pod_exists
if [[ "${PROMPT_ARGS[1]}" =~ ^-rp|^-pr|^-p ]]; then
unset -v PROMPT_ARGS[1]
fi
PROMPT_ARGS[3]=$ONDEMAND_POD
sql_prompt "${PROMPT_ARGS[@]}"
if [[ $? -ne 0 ]]; then
return 1
fi
}
# Params: [namespace]
function do_cleanup() {
# If a namespace is given go ahead and try to clean it up.
if [[ ! -z "$2" ]]; then
remove_job "$2" "$ONDEMAND_JOB"
unset ONDEMAND_POD
elif [[ "$KEEP_POD" == "false" && ! -z "$ONDEMAND_POD" ]]; then
IFS=', ' read -re -a USED_NAMESPACE_ARRAY <<< "$USED_NAMESPACES"
for NAMESPACE in "${USED_NAMESPACE_ARRAY[@]}";
do
remove_job "$NAMESPACE" "$ONDEMAND_JOB"
if [[ $? -ne 0 ]]; then
return 1
fi
done
unset USED_NAMESPACES
unset ONDEMAND_POD
echo "Cleanup complete."
else
if [[ "$KEEP_POD" == "true" ]]; then
echo "Persistent Pod -p enabled, no cleanup performed on $ONDEMAND_POD"
else
echo "Nothing to cleanup."
fi
fi
}
function do_command_history() {
echo ""
echo "Command History:"
for j in "${HISTORY[@]}";
do
echo "$j"
done
}
function do_trap() {
if [[ "$MY_LOCK" == "true" ]]; then
unlock
fi
do_cleanup
exit
}
function help() {
echo "Usage:"
echo " -r Remote flag. When used will use the remote RGW location."
echo " Not using this flag will use the local filesystem."
echo ""
echo " -p Persistent On-Demand Pod. The On-Demand Pod will not be"
echo " removed when the command finishes if applicable."
echo ""
echo " utilscli dbutils backup (b) [-p] <namespace>"
echo " Performs a manual backup of all databases within mariadb for the given namespace."
echo ""
echo " utilscli dbutils list_archives (la) [-rp] <namespace>"
echo " Retrieves the list of archives."
echo ""
echo " utilscli dbutils list_databases (ld) [-rp] <archive>"
echo " Retrieves the list of databases contained within the given"
echo " archive tarball."
echo ""
echo " utilscli dbutils list_tables (lt) [-rp] <archive> <database>"
echo " Retrieves the list of tables contained within the given"
echo " database from the given archive tarball."
echo ""
echo " utilscli dbutils list_rows (lr) [-rp] <archive> <database> <table>"
echo " Retrieves the list of rows in the given table contained"
echo " within the given database from the given archive tarball."
echo ""
echo " utilscli dbutils list_schema (ls) [-rp] <archive> <database> <table>"
echo " Retrieves the table schema information for the given table"
echo " of the given database from the given archive tarball."
echo ""
echo " utilscli dbutils show_databases (sd) [-p] <namespace>"
echo " Retrieves the list of databases in the currently active"
echo " mariadb database system for the given namespace."
echo ""
echo " utilscli dbutils show_tables (st) [-p] <namespace> <database>"
echo " Retrieves the list of tables of the given database in the"
echo " currently active mariadb database system."
echo ""
echo " utilscli dbutils show_rows (sr) [-p] <namespace> <database> <table>"
echo " Retrieves the list of rows in the given table of the given"
echo " database from the currently active mariadb database system."
echo ""
echo " utilscli dbutils show_schema (ss) [-p] <namespace> <database> <table>"
echo " Retrieves the table schema information for the given table"
echo " of the given database from the currently active mariadb"
echo " database system."
echo ""
echo " utilscli dbutils restore (r) [-rp] <archive> <db_name>"
echo " where <db_name> can be either a database name or 'all', which"
echo " means all databases are to be restored"
echo " Restores the specified database(s)."
echo ""
echo " utilscli dbutils delete_archive (da) [-rp] <archive>"
echo " Deletes the specified archive from either the local file"
echo " system or the remove rgw location."
echo ""
echo " utilscli dbutils sql_prompt (sql) [-p] <namespace>"
echo " For manual table/row restoration, this command allows access"
echo " to the Mariadb mysql interactive user interface. Type quit"
echo " to quit the interface and return back to the dbutils menu."
echo ""
echo " utilscli dbutils cleanup (c) [namespace]"
echo " Cleans up (kills) any jobs/pods which are left running for"
echo " any namespaces which have been used during this session."
echo " For non-interactive mode, namespace is required for cleanup."
echo ""
echo " utilscli dbutils command_history (ch)"
echo " Displays a list of all entered commands during this session."
echo ""
echo " utilscli dbutils <"
echo " Fills the prompt with the previous command. Use multiple times"
echo " to go further back in the command history."
}
function menu() {
echo "Please select from the available options:"
echo "Execution methods: backup (b) [-p] <namespace>"
echo " restore (r) [-rp] <archive> <db_name | all>"
echo " sql_prompt (sql) [-p] <namespace>"
echo " delete_archive (da) [-rp] <archive>"
echo " cleanup (c) [namespace]"
echo "Show Archived details: list_archives (la) [-rp] <namespace>"
echo " list_databases (ld) [-rp] <archive>"
echo " list_tables (lt) [-rp] <archive> <database>"
echo " list_rows (lr) [-rp] <archive> <database> <table>"
echo " list_schema (ls) [-rp] <archive> <database> <table>"
echo "Show Live Database details: show_databases (sd) [-p] <namespace>"
echo " show_tables (st) [-p] <namespace> <database>"
echo " show_rows (sr) [-p] <namespace> <database> <table>"
echo " show_schema (ss) [-p] <namespace> <database> <table>"
echo "Other: command_history (ch)"
echo " repeat_cmd (<)"
echo " help (h)"
echo " quit (q)"
echo "Valid namespaces: ${BACKUP_RESTORE_NAMESPACE_LIST[*]}"
}
function execute_selection() {
case "${ARGS[0]}" in
"backup"|"b") do_backup "${ARGS[@]}";;
"list_archives"|"la") do_list_archives "${ARGS[@]}";;
"list_databases"|"ld") do_list_databases "${ARGS[@]}";;
"list_tables"|"lt") do_list_tables "${ARGS[@]}";;
"list_rows"|"lr") do_list_rows "${ARGS[@]}";;
"list_schema"|"ls") do_list_schema "${ARGS[@]}";;
"delete_archive"|"da") do_delete_archive "${ARGS[@]}";;
"show_databases"|"sd") do_show_databases "${ARGS[@]}";;
"show_tables"|"st") do_show_tables "${ARGS[@]}";;
"show_rows"|"sr") do_show_rows "${ARGS[@]}";;
"show_schema"|"ss") do_show_schema "${ARGS[@]}";;
"create_test_table"|"ctt") do_create_table "${ARGS[@]}";;
"create_test_row"|"ctr") do_create_row "${ARGS[@]}";;
"create_test_user_grants"|"ctug") do_create_user_grants "${ARGS[@]}";;
"query_test_user"|"qtu") do_query_user "${ARGS[@]}";;
"delete_test_user_grants"|"dtug") do_delete_user_grants "${ARGS[@]}";;
"delete_test_row"|"dtr") do_delete_row "${ARGS[@]}";;
"delete_test_table"|"dtt") do_delete_table "${ARGS[@]}";;
"delete_test_backups"|"dtb") do_delete_backups "${ARGS[@]}";;
"restore"|"r") do_restore "${ARGS[@]}";;
"sql_prompt"|"sql") do_sql_prompt "${ARGS[@]}";;
"command_history"|"ch") do_command_history;;
"<") ;;
"cleanup"|"c"|"quit"|"q") do_cleanup "${ARGS[@]}";;
*) help;;
esac
}
function main() {
setup
# If no arguments are passed, enter interactive mode
if [[ "${#ARGS[@]}" -eq 0 ]]; then
CURRENT_COMMAND=0
while [[ ${ARGS[0]} != "quit" && ${ARGS[0]} != "q" ]]
do
menu
read -re -p "selection: " -a ARGS -i "${HISTORY[$CURRENT_COMMAND]}"
if [[ ${ARGS[0]} == '<' ]]; then
if [[ CURRENT_COMMAND -gt 0 ]]; then
(( CURRENT_COMMAND = CURRENT_COMMAND - 1 ))
fi
else
HISTORY[${#HISTORY[@]}]="${ARGS[*]}"
(( CURRENT_COMMAND = ${#HISTORY[@]} ))
execute_selection "${ARGS[@]}"
echo ""
if [[ ${ARGS[0]} != "quit" && ${ARGS[0]} != "q" ]]; then
read -re -n1 -p "press any key to continue..."
fi
fi
done
# Arguments are passed, execute the requested command then exit
else
execute_selection "${ARGS[@]}"
if [[ "${ARGS[0]}" != "c" && "${ARGS[0]}" != "cleanup" && "${ARGS[0]}" != "quit" && "${ARGS[0]}" != "q" ]]; then
do_cleanup
fi
echo "Task Complete"
fi
}
# Begin program
main "${ARGS[@]}"