Compare commits

...

12 Commits

Author SHA1 Message Date
Clemens Schwaighofer ab21c2ca79 Merge branch 'development' into refactor/TTD-3115/shellcheck-cleanup 2026-04-28 11:51:57 +09:00
Clemens Schwaighofer 92225a588b v4.9.0: forgejo backup v1.0.0
Add backup to forgejo like for gitea
2026-04-28 11:44:36 +09:00
Clemens Schwaighofer 03925562ff Merge branch 'development' into refactor/TTD-3115/shellcheck-cleanup 2025-12-04 11:46:31 +09:00
Clemens Schwaighofer 924014688e Update gitignore file with backup lock files 2025-12-04 09:57:54 +09:00
Clemens Schwaighofer f9a58171cc Bump version to v4.8.0 2025-12-04 09:35:08 +09:00
Clemens Schwaighofer 1b52af909a Update PostgreSQL module to run as normal user with sudo for PostgreSQL
also clean up all PostgreSQL command calls as array type calls
clean up binary finder for postgresql installations
and add port/host override options
2025-12-04 09:28:57 +09:00
Clemens Schwaighofer 783bf2adb9 Merge branch 'development' into shellcheck-cleanup 2025-12-02 10:02:17 +09:00
Clemens Schwaighofer dd2a85f5d6 Merge branch 'development' into shellcheck-cleanup 2025-12-01 18:16:01 +09:00
Clemens Schwaighofer 2e5f0648f1 Merge branch 'development' into shellcheck-cleanup 2025-08-21 10:42:20 +09:00
Clemens Schwaighofer acd5d369eb Merge branch 'development' into shellcheck-cleanup 2025-08-20 22:41:54 +09:00
Clemens Schwaighofer de9d5d3588 Zabbix backup set port to 5432 default to override internal set ports 2025-08-20 22:11:38 +09:00
Clemens Schwaighofer 8407defe4f Starting shellcheck cleanup 2024-09-04 10:58:48 +09:00
13 changed files with 331 additions and 76 deletions
+2
View File
@@ -1,5 +1,6 @@
.cache/ .cache/
.config/ .config/
# various borg files that need to be ignored
borg.backup.settings borg.backup.settings
borg.backup.*.settings borg.backup.*.settings
borg.backup.*.include borg.backup.*.include
@@ -7,3 +8,4 @@ borg.backup.*.exclude
borg.backup.*.schema-only borg.backup.*.schema-only
borg.backup.*.init borg.backup.*.init
borg.backup.*.compact borg.backup.*.compact
borg.backup.*.lock
+22 -3
View File
@@ -254,23 +254,42 @@ backup.borg.mysql.schema-only
## gitea backup settings ## gitea backup settings
Note that the backup needs the GIT_USER set that runs gitea. Note that the backup needs the GITEA_GIT_USER set that runs gitea.
This user is neede to create the temporary dump folder and access for the git files and database. This user is neede to create the temporary dump folder and access for the git files and database.
### gitea Config Variables ### gitea Config Variables
| Variable | Default | Description | | Variable | Default | Description |
| - | - | - | | - | - | - |
| GIT_USER | git | The user that runs gitea | | GITEA_GIT_USER | git | The user that runs gitea |
| GITEA_WORKING_DIR | /var/tmp/gitea/ | Where the temporary dump files from the backup are stored, as user git | | GITEA_WORKING_DIR | /var/tmp/gitea/ | Where the temporary dump files from the backup are stored, as user git |
| GITEA_TEMP_DIR | /var/tmp/ | General temporary folder | | GITEA_TEMP_DIR | /var/tmp/ | General temporary folder |
| GITEA_BIN | /usr/local/bin/gitea | Where the gitea binary is located | | GITEA_BIN | /usr/local/bin/gitea | Where the gitea binary is located |
| GITEA_CONFIG | /etc/gitea/app.ini | The configuration file for gitea | | GITEA_CONFIG | /etc/gitea/app.ini or /var/lib/gitea/custom/conf/app.ini | The configuration file for gitea |
### gitea Control files ### gitea Control files
There are no control files for gitea backup There are no control files for gitea backup
## forgejo backup settings
Note that the backup needs the FORGEJO_GIT_USER set that runs forgejo.
This user is neede to create the temporary dump folder and access for the git files and database.
### forgejo Config Variables
| Variable | Default | Description |
| - | - | - |
| FORGEJO_GIT_USER | git | The user that runs forgejo |
| FORGEJO_WORKING_DIR | /var/tmp/forgejo/ | Where the temporary dump files from the backup are stored, as user git |
| FORGEJO_TEMP_DIR | /var/tmp/ | General temporary folder |
| FORGEJO_BIN | /usr/local/bin/forgejo | Where the forgejo binary is located |
| FORGEJO_CONFIG | /etc/forgejo/app.ini or /var/lib/forgejo/custom/conf/app.ini | The configuration file for forgejo |
### forgejo Control files
There are no control files for forgejo backup
## zabbix config backup settings ## zabbix config backup settings
The `zabbix-dump` dump script must be installed from: <https://github.com/gullevek/zabbix-backup> The `zabbix-dump` dump script must be installed from: <https://github.com/gullevek/zabbix-backup>
+5 -4
View File
@@ -31,16 +31,16 @@ MODULE_LIST="file gitea mysql pgsql zabbix"
# -n for dry run test # -n for dry run test
while getopts ":c:snd" opt; do while getopts ":c:snd" opt; do
case "${opt}" in case "${opt}" in
c|config) c) # config
BASE_FOLDER=${OPTARG}; BASE_FOLDER=${OPTARG};
;; ;;
s|nosudo) s) # nosudo
PGSQL_SUDO=0; PGSQL_SUDO=0;
;; ;;
d|debug) d) # debug
DEBUG=1; DEBUG=1;
;; ;;
n|dryrun) n) # dryrun
DRYRUN=1; DRYRUN=1;
;; ;;
:) :)
@@ -64,6 +64,7 @@ if [ ! -f "${BASE_FOLDER}${SETTINGS_FILE}" ]; then
echo "Could not find: ${BASE_FOLDER}${SETTINGS_FILE}"; echo "Could not find: ${BASE_FOLDER}${SETTINGS_FILE}";
exit; exit;
fi; fi;
# shellcheck source="borg.backup.settings"
. "${BASE_FOLDER}${SETTINGS_FILE}"; . "${BASE_FOLDER}${SETTINGS_FILE}";
if [ -n "${TARGET_BORG_PATH}" ]; then if [ -n "${TARGET_BORG_PATH}" ]; then
+9
View File
@@ -0,0 +1,9 @@
# Borg backup wrapper scripts settings: forgejo
# rename to borg.backup.forgejo.settings to use
FORGEJO_GIT_USER="";
FORGEJO_WORKING_DIR="";
FORGEJO_TEMP_DIR="";
FORGEJO_BIN="";
FORGEJO_CONFIG="";
+115
View File
@@ -0,0 +1,115 @@
#!/usr/bin/env bash
# allow variables in printf format string
# shellcheck disable=SC2059
# Backup forgejo database, all git folders and forgejo settings
MODULE="forgejo"
MODULE_VERSION="1.0.0";
DIR="${BASH_SOURCE%/*}"
if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi
# init system
. "${DIR}/borg.backup.functions.init.sh";
# init verify, compact and check file
BACKUP_INIT_FILE="borg.backup.${MODULE}.init";
BACKUP_COMPACT_FILE="borg.backup.${MODULE}.compact";
BACKUP_CHECK_FILE="borg.backup.${MODULE}.check";
# lock file
BACKUP_LOCK_FILE="borg.backup.${MODULE}.lock";
# verify valid data
. "${DIR}/borg.backup.functions.verify.sh";
# if info print info and then abort run
. "${DIR}/borg.backup.functions.info.sh";
# NOTE: because a tmp directory is needed it is more recommended
# to run this as root and have only the dump command itself run as FORGEJO_GIT_USER
# set git user
if [ -z "${FORGEJO_GIT_USER}" ]; then
FORGEJO_GIT_USER="git";
fi;
# set FORGEJO_* if not set
if [ -z "${FORGEJO_WORKING_DIR}" ]; then
# run forgejo backup (user mktemp?)
FORGEJO_WORKING_DIR="/var/tmp/forgejo/";
fi;
# general temp folder for temporary data storage, this is not working output folder
if [ -z "${FORGEJO_TEMP_DIR}" ]; then
FORGEJO_TEMP_DIR="/var/tmp";
fi;
if [ -z "${FORGEJO_BIN}" ]; then
FORGEJO_BIN="/usr/local/bin/forgejo";
fi;
if [ -z "${FORGEJO_CONFIG}" ]; then
FORGEJO_CONFIG="/etc/forgejo/app.ini"
fi;
# This one is not advertised in the config file as it is not recommended to change
if [ -z "${FORGEJO_EXPORT_TYPE}" ]; then
FORGEJO_EXPORT_TYPE="zip";
fi;
if [ ! -f "${FORGEJO_BIN}" ]; then
echo "[! $(date +'%F %T')] Cannot find forgejo binary";
. "${DIR}/borg.backup.functions.close.sh" 1;
exit 1;
fi;
if [ ! -f "${FORGEJO_CONFIG}" ]; then
echo "[! $(date +'%F %T')] Cannot find forgejo config";
. "${DIR}/borg.backup.functions.close.sh" 1;
exit 1;
fi;
# some basic checks with abort
if [ ! -d "${FORGEJO_TEMP_DIR}" ]; then
echo "Temp directory does not exist: ${FORGEJO_TEMP_DIR}";
exit;
fi;
# we should check FORGEJO_EXPORT_TYPE too at some point for an allow list
# At the moment warn if not zip
if [ "${FORGEJO_EXPORT_TYPE}" != "zip" ]; then
echo "[!!!!] The forgejo export type has been changed from 'zip' to '${FORGEJO_EXPORT_TYPE}'. This can either break or make exports take very ling";
fi;
# Filename
FILENAME="forgejo.backup.zip";
# backup set and prefix
BACKUP_SET_PREFIX="${MODULE},";
BACKUP_SET_NAME="${ONE_TIME_TAG}${BACKUP_SET_PREFIX}${BACKUP_SET}";
# borg call
BORG_CALL=$(echo "${_BORG_CALL}" | sed -e "s/##FILENAME##/${FILENAME}/" | sed -e "s/##BACKUP_SET##/${BACKUP_SET_NAME}/");
BORG_PRUNE=$(echo "${_BORG_PRUNE}" | sed -e "s/##BACKUP_SET_PREFIX##/${BACKUP_SET_PREFIX}/");
printf "${PRINTF_SUB_BLOCK}" "BACKUP: git data and database" "$(date +'%F %T')" "${MODULE}";
if [ ${DEBUG} -eq 1 ] || [ ${DRYRUN} -eq 1 ]; then
echo "sudo -u ${FORGEJO_GIT_USER} ${FORGEJO_BIN} dump -c ${FORGEJO_CONFIG} -w ${FORGEJO_WORKING_DIR} -t ${FORGEJO_TEMP_DIR} --type ${FORGEJO_EXPORT_TYPE} -L -f - | ${BORG_CALL}";
if [ -z "${ONE_TIME_TAG}" ]; then
echo "${BORG_PRUNE}";
fi;
fi;
if [ ${DRYRUN} -eq 0 ]; then
(
# below was an old workaround
#export USER="${LOGNAME}" # workaround for broken forgejo EUID check
# make sure temp folder is there and is set as git. user
if [ ! -d "${FORGEJO_WORKING_DIR}" ]; then
mkdir -p "${FORGEJO_WORKING_DIR}";
fi;
chown -R ${FORGEJO_GIT_USER}: "${FORGEJO_WORKING_DIR}";
# this needs to be run in a folder that can be stat by git user
cd "${FORGEJO_WORKING_DIR}" || exit 1;
sudo -u ${FORGEJO_GIT_USER} ${FORGEJO_BIN} dump -c ${FORGEJO_CONFIG} -w ${FORGEJO_WORKING_DIR} -t ${FORGEJO_TEMP_DIR} --type ${FORGEJO_EXPORT_TYPE} -L -f - | ${BORG_CALL};
) 2>&1 | sed 's/\x1B\[[0-9;]\{1,\}[A-Za-z]//g' # remove all ESC strings
fi;
if [ -z "${ONE_TIME_TAG}" ]; then
printf "${PRINTF_SUB_BLOCK}" "PRUNE" "$(date +'%F %T')" "${MODULE}";
echo "Prune repository with keep${KEEP_INFO:1}";
${BORG_PRUNE};
# if this is borg version >1.2 we need to run compact after prune
. "${DIR}/borg.backup.functions.compact.sh" "auto";
# check in auto mode
. "${DIR}/borg.backup.functions.check.sh" "auto";
fi;
. "${DIR}/borg.backup.functions.close.sh";
# __END__
+5
View File
@@ -10,6 +10,7 @@ fi;
# compact (only if BORG COMPACT is set) # compact (only if BORG COMPACT is set)
# only for borg 1.2 # only for borg 1.2
if [ "$(version "$BORG_VERSION")" -ge "$(version "1.2.0")" ]; then
if [ "$(version "$BORG_VERSION")" -ge "$(version "1.2.0")" ]; then if [ "$(version "$BORG_VERSION")" -ge "$(version "1.2.0")" ]; then
RUN_COMPACT=0; RUN_COMPACT=0;
if [ $# -ge 1 ] && [ "$1" = "auto" ]; then if [ $# -ge 1 ] && [ "$1" = "auto" ]; then
@@ -21,10 +22,13 @@ if [ "$(version "$BORG_VERSION")" -ge "$(version "1.2.0")" ]; then
fi; fi;
# get current date timestmap # get current date timestmap
CURRENT_DATE=$(date +%s); CURRENT_DATE=$(date +%s);
if [ "${COMPACT_INTERVAL}" -eq 1 ]; then
if [ "${COMPACT_INTERVAL}" -eq 1 ]; then if [ "${COMPACT_INTERVAL}" -eq 1 ]; then
RUN_COMPACT=1; RUN_COMPACT=1;
# set new compact time here # set new compact time here
echo "${CURRENT_DATE}" > "${BASE_FOLDER}${BACKUP_COMPACT_FILE}"; echo "${CURRENT_DATE}" > "${BASE_FOLDER}${BACKUP_COMPACT_FILE}";
elif [ "${COMPACT_INTERVAL}" -gt 1 ]; then
echo "${CURRENT_DATE}" > "${BASE_FOLDER}${BACKUP_COMPACT_FILE}";
elif [ "${COMPACT_INTERVAL}" -gt 1 ]; then elif [ "${COMPACT_INTERVAL}" -gt 1 ]; then
# else load last timestamp and check if today - last time stamp > days # else load last timestamp and check if today - last time stamp > days
if [ -z "${LAST_COMPACT_DATE}" ]; then if [ -z "${LAST_COMPACT_DATE}" ]; then
@@ -48,6 +52,7 @@ if [ "$(version "$BORG_VERSION")" -ge "$(version "1.2.0")" ]; then
if [ "${RUN_COMPACT}" -eq 1 ]; then if [ "${RUN_COMPACT}" -eq 1 ]; then
# reset to normal IFS, so command works here # reset to normal IFS, so command works here
IFS=${_IFS}; IFS=${_IFS};
# shellcheck disable=SC2059
printf "${PRINTF_SUB_BLOCK}" "COMPACT" "$(date +'%F %T')" "${MODULE}"; printf "${PRINTF_SUB_BLOCK}" "COMPACT" "$(date +'%F %T')" "${MODULE}";
BORG_COMPACT="${BORG_COMMAND} compact ${OPT_REMOTE} -v ${OPT_PROGRESS} ${REPOSITORY}"; BORG_COMPACT="${BORG_COMMAND} compact ${OPT_REMOTE} -v ${OPT_PROGRESS} ${REPOSITORY}";
if [ "${DEBUG}" -eq 1 ]; then if [ "${DEBUG}" -eq 1 ]; then
+15 -2
View File
@@ -32,7 +32,7 @@ function version {
} }
# version for all general files # version for all general files
VERSION="4.7.2"; VERSION="4.9.0";
# borg version and borg comamnd # borg version and borg comamnd
BORG_VERSION=""; BORG_VERSION="";
@@ -93,6 +93,8 @@ REGEX="";
REGEX_COMMENT="^[\ \t]*#"; REGEX_COMMENT="^[\ \t]*#";
REGEX_GLOB='\*'; REGEX_GLOB='\*';
REGEX_NUMERIC="^[0-9]{1,2}$"; REGEX_NUMERIC="^[0-9]{1,2}$";
# port regex, but only approximately
REGEX_PORT="^[0-9]{2,5}$";
REGEX_ERROR="^Some part of the script failed with ERROR:"; REGEX_ERROR="^Some part of the script failed with ERROR:";
PRUNE_DEBUG=""; PRUNE_DEBUG="";
INIT_REPOSITORY=0; INIT_REPOSITORY=0;
@@ -156,16 +158,27 @@ SUB_BACKUP_SET="";
# for database backup only # for database backup only
DATABASE_FULL_DUMP=""; DATABASE_FULL_DUMP="";
DATABASE_USER=""; DATABASE_USER="";
DATABASE_USE_SUDO="";
DATABASE_SUDO_USER="";
DATABASE_PORT="";
DATABASE_HOST="";
# only for mysql old config file # only for mysql old config file
MYSQL_DB_CONFIG=""; MYSQL_DB_CONFIG="";
MYSQL_DB_CONFIG_PARAM=""; MYSQL_DB_CONFIG_PARAM="";
# gitea module # gitea module
GIT_USER=""; GITEA_GIT_USER="";
GITEA_WORKING_DIR=""; GITEA_WORKING_DIR="";
GITEA_TEMP_DIR=""; GITEA_TEMP_DIR="";
GITEA_BIN=""; GITEA_BIN="";
GITEA_CONFIG=""; GITEA_CONFIG="";
GITEA_EXPORT_TYPE=""; GITEA_EXPORT_TYPE="";
# forgejo module
FORGEJO_GIT_USER="";
FORGEJO_WORKING_DIR="";
FORGEJO_TEMP_DIR="";
FORGEJO_BIN="";
FORGEJO_CONFIG="";
FORGEJO_EXPORT_TYPE="";
# zabbix module # zabbix module
ZABBIX_DUMP_BIN=""; ZABBIX_DUMP_BIN="";
ZABBIX_CONFIG=""; ZABBIX_CONFIG="";
+1 -1
View File
@@ -2,7 +2,7 @@
# rename to borg.backup.gitea.settings to use # rename to borg.backup.gitea.settings to use
GIT_USER=""; GITEA_GIT_USER="";
GITEA_WORKING_DIR=""; GITEA_WORKING_DIR="";
GITEA_TEMP_DIR=""; GITEA_TEMP_DIR="";
GITEA_BIN=""; GITEA_BIN="";
+6 -6
View File
@@ -26,10 +26,10 @@ BACKUP_LOCK_FILE="borg.backup.${MODULE}.lock";
. "${DIR}/borg.backup.functions.info.sh"; . "${DIR}/borg.backup.functions.info.sh";
# NOTE: because a tmp directory is needed it is more recommended # NOTE: because a tmp directory is needed it is more recommended
# to run this as root and have only the dump command itself run as GIT_USER # to run this as root and have only the dump command itself run as GITEA_GIT_USER
# set git user # set git user
if [ -z "${GIT_USER}" ]; then if [ -z "${GITEA_GIT_USER}" ]; then
GIT_USER="git"; GITEA_GIT_USER="git";
fi; fi;
# set GITEA_* if not set # set GITEA_* if not set
if [ -z "${GITEA_WORKING_DIR}" ]; then if [ -z "${GITEA_WORKING_DIR}" ]; then
@@ -81,7 +81,7 @@ BORG_CALL=$(echo "${_BORG_CALL}" | sed -e "s/##FILENAME##/${FILENAME}/" | sed -e
BORG_PRUNE=$(echo "${_BORG_PRUNE}" | sed -e "s/##BACKUP_SET_PREFIX##/${BACKUP_SET_PREFIX}/"); BORG_PRUNE=$(echo "${_BORG_PRUNE}" | sed -e "s/##BACKUP_SET_PREFIX##/${BACKUP_SET_PREFIX}/");
printf "${PRINTF_SUB_BLOCK}" "BACKUP: git data and database" "$(date +'%F %T')" "${MODULE}"; printf "${PRINTF_SUB_BLOCK}" "BACKUP: git data and database" "$(date +'%F %T')" "${MODULE}";
if [ ${DEBUG} -eq 1 ] || [ ${DRYRUN} -eq 1 ]; then if [ ${DEBUG} -eq 1 ] || [ ${DRYRUN} -eq 1 ]; then
echo "sudo -u ${GIT_USER} ${GITEA_BIN} dump -c ${GITEA_CONFIG} -w ${GITEA_WORKING_DIR} -t ${GITEA_TEMP_DIR} --type ${GITEA_EXPORT_TYPE} -L -f - | ${BORG_CALL}"; echo "sudo -u ${GITEA_GIT_USER} ${GITEA_BIN} dump -c ${GITEA_CONFIG} -w ${GITEA_WORKING_DIR} -t ${GITEA_TEMP_DIR} --type ${GITEA_EXPORT_TYPE} -L -f - | ${BORG_CALL}";
if [ -z "${ONE_TIME_TAG}" ]; then if [ -z "${ONE_TIME_TAG}" ]; then
echo "${BORG_PRUNE}"; echo "${BORG_PRUNE}";
fi; fi;
@@ -94,10 +94,10 @@ if [ ${DRYRUN} -eq 0 ]; then
if [ ! -d "${GITEA_WORKING_DIR}" ]; then if [ ! -d "${GITEA_WORKING_DIR}" ]; then
mkdir -p "${GITEA_WORKING_DIR}"; mkdir -p "${GITEA_WORKING_DIR}";
fi; fi;
chown -R ${GIT_USER}: "${GITEA_WORKING_DIR}"; chown -R ${GITEA_GIT_USER}: "${GITEA_WORKING_DIR}";
# this needs to be run in a folder that can be stat by git user # this needs to be run in a folder that can be stat by git user
cd "${GITEA_WORKING_DIR}" || exit 1; cd "${GITEA_WORKING_DIR}" || exit 1;
sudo -u ${GIT_USER} ${GITEA_BIN} dump -c ${GITEA_CONFIG} -w ${GITEA_WORKING_DIR} -t ${GITEA_TEMP_DIR} --type ${GITEA_EXPORT_TYPE} -L -f - | ${BORG_CALL}; sudo -u ${GITEA_GIT_USER} ${GITEA_BIN} dump -c ${GITEA_CONFIG} -w ${GITEA_WORKING_DIR} -t ${GITEA_TEMP_DIR} --type ${GITEA_EXPORT_TYPE} -L -f - | ${BORG_CALL};
) 2>&1 | sed 's/\x1B\[[0-9;]\{1,\}[A-Za-z]//g' # remove all ESC strings ) 2>&1 | sed 's/\x1B\[[0-9;]\{1,\}[A-Za-z]//g' # remove all ESC strings
fi; fi;
if [ -z "${ONE_TIME_TAG}" ]; then if [ -z "${ONE_TIME_TAG}" ]; then
+11 -1
View File
@@ -9,5 +9,15 @@
# note that with this databases that have been dropped need to be pruned manually # note that with this databases that have been dropped need to be pruned manually
# if 'schema' word is used, only schema data is dumped # if 'schema' word is used, only schema data is dumped
DATABASE_FULL_DUMP=""; DATABASE_FULL_DUMP="";
# override default postgres user # override default postgres user and sudo user for all postgres commands
# All commands must be run as the postgres admin user
DATABASE_USER=""; DATABASE_USER="";
# disable sudo usage by setting to "0", default is to use sudo
DATABASE_USE_SUDO="";
# set the sudo user, if not set postgres or DATABASE_USER is used
DATABASE_SUDO_USER="";
# override port
DATABASE_PORT="";
# override database host, if set to local, localhost or 127.0.0.1 it will use sockets to connect
# for socket connection ident or sudo has to be used
DATABASE_HOST="";
+137 -56
View File
@@ -10,11 +10,13 @@
# set last edit date + time # set last edit date + time
MODULE="pgsql" MODULE="pgsql"
MODULE_VERSION="1.2.8"; MODULE_VERSION="1.3.0";
DIR="${BASH_SOURCE%/*}" DIR="${BASH_SOURCE%/*}"
if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi
DEFAULT_DATABASE_USE_SUDO="1";
DEFAULT_DATABASE_USER="postgres";
# init system # init system
. "${DIR}/borg.backup.functions.init.sh"; . "${DIR}/borg.backup.functions.init.sh";
@@ -35,15 +37,41 @@ BACKUP_LOCK_FILE="borg.backup.${MODULE}.lock";
# if info print info and then abort run # if info print info and then abort run
. "${DIR}/borg.backup.functions.info.sh"; . "${DIR}/borg.backup.functions.info.sh";
# set db and sudo user
if [ -n "${DATABASE_USER}" ]; then if [ -n "${DATABASE_USER}" ]; then
DB_USER=${DATABASE_USER}; DB_USER="${DATABASE_USER}";
else else
DB_USER='postgres'; DB_USER="${DEFAULT_DATABASE_USER}";
fi; fi;
if [ -n "${DATABASE_SUDO_USER}" ]; then
DB_SUDO_USER="${DATABASE_SUDO_USER}";
else
DB_SUDO_USER="${DB_USER}";
fi;
# set flag if we should use sudo
if [ -n "${DATABASE_USE_SUDO}" ]; then
USE_SUDO="${DATABASE_USE_SUDO}";
else
USE_SUDO="${DEFAULT_DATABASE_USE_SUDO}";
fi;
# sudo command, or none if not requested
SUDO_COMMAND_A=("sudo" "-u" "${DB_SUDO_USER}");
if [ "${USE_SUDO}" -eq "0" ]; then
SUDO_COMMAND_A=()
fi;
# get current pgsql version first # get current pgsql version first
# if first part <10 then user full, else only first part # if first part <10 then user full, else only first part
# eg 9.4 -> 9.4, 12.5 -> 12 # eg 9.4 -> 9.4, 12.5 -> 12
PG_VERSION=$(pgv=$(psql -U ${DB_USER} -d template1 -t -A -F "," -X -q -c 'select version();' | sed -e 's/^PostgreSQL \([0-9]\{1,\}\.[0-9]\{1,\}\).*/\1/'); if [[ $(echo "${pgv}" | cut -d "." -f 1) -ge 10 ]]; then echo "${pgv}" | cut -d "." -f 1; else echo "${pgv}" | cut -d "." -f 1,2; fi ); PG_VERSION_CMD=("${SUDO_COMMAND_A[@]}" "psql" "-U" "${DB_USER}" "-d" "template1" "-t" "-A" "-F" "," "-X" "-q" "-c" "select version();");
PG_VERSION=$(
pgv=$("${PG_VERSION_CMD[@]}" | sed -e 's/^PostgreSQL \([0-9]\{1,\}\.[0-9]\{1,\}\).*/\1/');
if [[ $(echo "${pgv}" | cut -d "." -f 1) -ge 10 ]]; then
echo "${pgv}" | cut -d "." -f 1;
else
echo "${pgv}" | cut -d "." -f 1,2;
fi;
);
_PATH_PG_VERSION=${PG_VERSION}; _PATH_PG_VERSION=${PG_VERSION};
_backup_error=$?; _backup_error=$?;
if [ $_backup_error -ne 0 ] || [ -z "${PG_VERSION}" ]; then if [ $_backup_error -ne 0 ] || [ -z "${PG_VERSION}" ]; then
@@ -53,49 +81,75 @@ if [ $_backup_error -ne 0 ] || [ -z "${PG_VERSION}" ]; then
fi; fi;
# path set per Distribution type and current running DB version # path set per Distribution type and current running DB version
# Debian/Ubuntu: PG_BASE_PATH='/usr/lib/postgresql/';
# Redhat: PG_BASE_PATH='/usr/pgsql-'; # Redhat: PG_BASE_PATH='/usr/pgsql-';
# AWS 1: PG_BASE_PATH='/usr/lib64/pgsql'; PG_BASE_PATH_LIST=("/usr/lib/postgresql" "/usr/lib64/pgsql");
# Debian: PG_BASE_PATH='/usr/lib/postgresql/'; PG_BASE_PATH="";
PG_BASE_PATH='/usr/lib/postgresql/'; for path in "${PG_BASE_PATH_LIST[@]}"; do
if [ ! -f "${PG_BASE_PATH}${_PATH_PG_VERSION}/bin/psql" ]; then if [ -f "${path}/${_PATH_PG_VERSION}/bin/psql" ]; then
PG_BASE_PATH='/usr/pgsql-'; PG_BASE_PATH="${path}/";
if [ ! -f "${PG_BASE_PATH}${_PATH_PG_VERSION}/bin/psql" ]; then break;
PG_BASE_PATH='/usr/lib64/pgsql';
_PATH_PG_VERSION=$(echo "${PG_VERSION}" | sed -e 's/\.//');
if [ ! -f "${PG_BASE_PATH}${_PATH_PG_VERSION}/bin/psql" ]; then
echo "[! $(date +'%F %T')] PostgreSQL not found in any paths";
. "${DIR}/borg.backup.functions.close.sh" 1;
exit 1;
fi;
fi; fi;
done;
if [ -z "${PG_BASE_PATH}" ]; then
echo "[! $(date +'%F %T')] PostgreSQL not found in any paths";
. "${DIR}/borg.backup.functions.close.sh" 1;
exit 1;
fi; fi;
PG_PATH=${PG_BASE_PATH}${_PATH_PG_VERSION}'/bin/'; PG_PATH="${PG_BASE_PATH}${_PATH_PG_VERSION}/bin/";
PG_PSQL=${PG_PATH}'psql'; PG_PSQL=("${PG_PATH}psql");
PG_DUMP=${PG_PATH}'pg_dump'; PG_DUMP=("${PG_PATH}pg_dump");
PG_DUMPALL=${PG_PATH}'pg_dumpall'; PG_DUMPALL=("${PG_PATH}pg_dumpall");
PG_ERROR=0
# check that command are here # check that command are here
if [ ! -f "${PG_PSQL}" ]; then if [ ! -f "${PG_PSQL[0]}" ]; then
echo "[! $(date +'%F %T')] psql binary not found in ${PG_PATH}"; echo "[!] ($(date +'%F %T')) psql binary not found in ${PG_PATH}";
. "${DIR}/borg.backup.functions.close.sh" 1; PG_ERROR=1;
exit 1;
fi; fi;
if [ ! -f "${PG_DUMP}" ]; then if [ ! -f "${PG_DUMP[0]}" ]; then
echo "[! $(date +'%F %T')] pg_dump binary not found in ${PG_PATH}"; echo "[!] ($(date +'%F %T')) pg_dump binary not found in ${PG_PATH}";
. "${DIR}/borg.backup.functions.close.sh" 1; PG_ERROR=1;
exit 1;
fi; fi;
if [ ! -f "${PG_DUMPALL}" ]; then if [ ! -f "${PG_DUMPALL[0]}" ]; then
echo "[! $(date +'%F %T')] pg_dumpall binary not found in ${PG_PATH}"; echo "[!] ($(date +'%F %T')) pg_dumpall binary not found in ${PG_PATH}";
PG_ERROR=1;
fi;
if [ ${PG_ERROR} -ne 0 ]; then
. "${DIR}/borg.backup.functions.close.sh" 1; . "${DIR}/borg.backup.functions.close.sh" 1;
exit 1; exit ${PG_ERROR};
fi;
# prefix with sudo, if sudo command is requested
if [ "${USE_SUDO}" -ne "0" ]; then
PG_PSQL=("${SUDO_COMMAND_A[@]}" "${PG_PSQL[@]}");
PG_DUMP=("${SUDO_COMMAND_A[@]}" "${PG_DUMP[@]}");
PG_DUMPALL=("${SUDO_COMMAND_A[@]}" "${PG_DUMPALL[@]}");
fi; fi;
DB_VERSION=${PG_VERSION}; DB_VERSION=${PG_VERSION};
# TODO override port/host info # override for port or host name
DB_PORT='5432'; if [ -n "${DATABASE_PORT}" ] && [[ "${DATABASE_PORT}" =~ ${REGEX_PORT} ]]; then
DB_HOST='local'; # or <host> DB_PORT="${DATABASE_PORT}";
CONN_DB_HOST=''; # -h <host> else
CONN_DB_PORT=''; # -p <port> DB_PORT="5432";
fi;
if [ -n "${DATABASE_HOST}" ]; then
DB_HOST="${DATABASE_HOST}";
else
DB_HOST="local";
fi;
# use socket for local
if [ "${DB_HOST}" = "local" ] || [ "${DB_HOST}" = "localhost" ] || [ "${DB_HOST}" = "127.0.0.1" ]; then
DB_HOST='local';
CONN_DB_HOST=();
CONN_DB_PORT=();
else
CONN_DB_HOST=("-p" "${DB_HOST}"); # -h <host>
CONN_DB_PORT=("-h" "${DB_HOSTNAME}"); # -p <port>
fi;
# now add user, con, host to all commands
PG_PSQL=("${PG_PSQL[@]}" "-U" "${DB_USER}" "${CONN_DB_HOST[@]}" "${CONN_DB_PORT[@]}");
PG_DUMP=("${PG_DUMP[@]}" "-U" "${DB_USER}" "${CONN_DB_HOST[@]}" "${CONN_DB_PORT[@]}");
PG_DUMPALL=("${PG_DUMPALL[@]}" "-U" "${DB_USER}" "${CONN_DB_HOST[@]}" "${CONN_DB_PORT[@]}");
# ALL IN ONE FILE or PER DATABASE FLAG # ALL IN ONE FILE or PER DATABASE FLAG
if [ -n "${DATABASE_FULL_DUMP}" ]; then if [ -n "${DATABASE_FULL_DUMP}" ]; then
@@ -113,17 +167,25 @@ if [ -n "${DATABASE_FULL_DUMP}" ]; then
BACKUP_SET_PREFIX="${MODULE},all-"; BACKUP_SET_PREFIX="${MODULE},all-";
BACKUP_SET_NAME="${ONE_TIME_TAG}${BACKUP_SET_PREFIX}${schema_flag}-${BACKUP_SET}"; BACKUP_SET_NAME="${ONE_TIME_TAG}${BACKUP_SET_PREFIX}${schema_flag}-${BACKUP_SET}";
# borg call # borg call
BORG_CALL=$(echo "${_BORG_CALL}" | sed -e "s/##FILENAME##/${FILENAME}/" | sed -e "s/##BACKUP_SET##/${BACKUP_SET_NAME}/"); BORG_CALL=$(
BORG_PRUNE=$(echo "${_BORG_PRUNE}" | sed -e "s/##BACKUP_SET_PREFIX##/${BACKUP_SET_PREFIX}/"); echo "${_BORG_CALL}" |
sed -e "s/##FILENAME##/${FILENAME}/" |
sed -e "s/##BACKUP_SET##/${BACKUP_SET_NAME}/"
);
BORG_PRUNE=$(
echo "${_BORG_PRUNE}" |
sed -e "s/##BACKUP_SET_PREFIX##/${BACKUP_SET_PREFIX}/"
);
PG_DUMPALL_CMD=("${PG_DUMPALL[@]}" "${SCHEMA_ONLY}" "-c");
if [ ${DEBUG} -eq 1 ] || [ ${DRYRUN} -eq 1 ]; then if [ ${DEBUG} -eq 1 ] || [ ${DRYRUN} -eq 1 ]; then
echo "export BORG_BASE_DIR=\"${BASE_FOLDER}\";"; echo "export BORG_BASE_DIR=\"${BASE_FOLDER}\";";
echo "${PG_DUMPALL} -U ${DB_USER} ${CONN_DB_HOST} ${CONN_DB_PORT} ${SCHEMA_ONLY} -c | ${BORG_CALL}"; echo "${PG_DUMPALL_CMD[*]} | ${BORG_CALL}";
if [ -z "${ONE_TIME_TAG}" ]; then if [ -z "${ONE_TIME_TAG}" ]; then
echo "${BORG_PRUNE}"; echo "${BORG_PRUNE}";
fi; fi;
fi; fi;
if [ ${DRYRUN} -eq 0 ]; then if [ ${DRYRUN} -eq 0 ]; then
${PG_DUMPALL} -U ${DB_USER} ${CONN_DB_HOST} ${CONN_DB_PORT} ${SCHEMA_ONLY} -c | ${BORG_CALL}; "${PG_DUMPALL_CMD[@]}" | ${BORG_CALL};
_backup_error=$?; _backup_error=$?;
if [ $_backup_error -ne 0 ]; then if [ $_backup_error -ne 0 ]; then
echo "[! $(date +'%F %T')] Backup creation failed for full dump with error code: ${_backup_error}"; echo "[! $(date +'%F %T')] Backup creation failed for full dump with error code: ${_backup_error}";
@@ -150,17 +212,25 @@ else
BACKUP_SET_PREFIX="${MODULE},${db}-"; BACKUP_SET_PREFIX="${MODULE},${db}-";
BACKUP_SET_NAME="${ONE_TIME_TAG}${BACKUP_SET_PREFIX}${schema_flag}-${BACKUP_SET}"; BACKUP_SET_NAME="${ONE_TIME_TAG}${BACKUP_SET_PREFIX}${schema_flag}-${BACKUP_SET}";
# borg call # borg call
BORG_CALL=$(echo "${_BORG_CALL}" | sed -e "s/##FILENAME##/${FILENAME}/" | sed -e "s/##BACKUP_SET##/${BACKUP_SET_NAME}/"); BORG_CALL=$(
BORG_PRUNE=$(echo "${_BORG_PRUNE}" | sed -e "s/##BACKUP_SET_PREFIX##/${BACKUP_SET_PREFIX}/"); echo "${_BORG_CALL}" |
sed -e "s/##FILENAME##/${FILENAME}/" |
sed -e "s/##BACKUP_SET##/${BACKUP_SET_NAME}/"
);
BORG_PRUNE=$(
echo "${_BORG_PRUNE}" |
sed -e "s/##BACKUP_SET_PREFIX##/${BACKUP_SET_PREFIX}/"
);
PG_DUMPALL_CMD=("${PG_DUMPALL[@]}" "--globals-only");
if [ ${DEBUG} -eq 1 ] || [ ${DRYRUN} -eq 1 ]; then if [ ${DEBUG} -eq 1 ] || [ ${DRYRUN} -eq 1 ]; then
echo "export BORG_BASE_DIR=\"${BASE_FOLDER}\";"; echo "export BORG_BASE_DIR=\"${BASE_FOLDER}\";";
echo "${PG_DUMPALL} -U ${DB_USER} ${CONN_DB_HOST} ${CONN_DB_PORT} --globals-only | ${BORG_CALL}"; echo "${PG_DUMPALL_CMD[*]} | ${BORG_CALL}";
if [ -z "${ONE_TIME_TAG}" ]; then if [ -z "${ONE_TIME_TAG}" ]; then
echo "${BORG_PRUNE}"; echo "${BORG_PRUNE}";
fi; fi;
fi; fi;
if [ ${DRYRUN} -eq 0 ]; then if [ ${DRYRUN} -eq 0 ]; then
${PG_DUMPALL} -U ${DB_USER} ${CONN_DB_HOST} ${CONN_DB_PORT} --globals-only | ${BORG_CALL}; "${PG_DUMPALL_CMD[@]}" | ${BORG_CALL};
_backup_error=$?; _backup_error=$?;
if [ $_backup_error -ne 0 ]; then if [ $_backup_error -ne 0 ]; then
echo "[! $(date +'%F %T')] Backup creation failed for ${db} dump with error code: ${_backup_error}"; echo "[! $(date +'%F %T')] Backup creation failed for ${db} dump with error code: ${_backup_error}";
@@ -177,7 +247,11 @@ else
printf "${PRINTF_DB_RUN_TIME_SUB_BLOCK}" "DONE" "${db}" "${MODULE}" "$(convert_time ${DURATION})"; printf "${PRINTF_DB_RUN_TIME_SUB_BLOCK}" "DONE" "${db}" "${MODULE}" "$(convert_time ${DURATION})";
# get list of tables # get list of tables
for owner_db in $(${PG_PSQL} -U ${DB_USER} ${CONN_DB_HOST} ${CONN_DB_PORT} -d template1 -t -A -F "," -X -q -c "SELECT pg_catalog.pg_get_userbyid(datdba) AS owner, datname, pg_catalog.pg_encoding_to_char(encoding) AS encoding FROM pg_catalog.pg_database WHERE datname !~ 'template(0|1)' ORDER BY datname;"); do GET_DB_CMD=(
"${PG_PSQL[@]}" "-d" "template1" "-t" "-A" "-F" "," "-X" "-q" "-c"
"SELECT pg_catalog.pg_get_userbyid(datdba) AS owner, datname, pg_catalog.pg_encoding_to_char(encoding) AS encoding FROM pg_catalog.pg_database WHERE datname !~ 'template(0|1)' ORDER BY datname;"
);
for owner_db in $("${GET_DB_CMD[@]}"); do
LOCAL_START=$(date +'%s'); LOCAL_START=$(date +'%s');
# get the user who owns the DB too # get the user who owns the DB too
owner=$(echo "${owner_db}" | cut -d "," -f 1); owner=$(echo "${owner_db}" | cut -d "," -f 1);
@@ -206,17 +280,15 @@ else
done<"${BASE_FOLDER}${EXCLUDE_FILE}"; done<"${BASE_FOLDER}${EXCLUDE_FILE}";
fi; fi;
if [ ${include} -eq 1 ] && [ ${exclude} -eq 0 ]; then if [ ${include} -eq 1 ] && [ ${exclude} -eq 0 ]; then
PG_DUMP_CMD=("${PG_DUMP[@]}" "-c" "--format=c");
# set dump type # set dump type
SCHEMA_ONLY='';
schema_flag=''; # schema or data schema_flag=''; # schema or data
# schema exclude over data exclude, can't have both # schema exclude over data exclude, can't have both
if [ -s "${BASE_FOLDER}${SCHEMA_ONLY_FILE}" ]; then if [ -s "${BASE_FOLDER}${SCHEMA_ONLY_FILE}" ]; then
# default is data dump # default is data dump
SCHEMA_ONLY='';
schema_flag='data'; schema_flag='data';
while read -r schema_db; do while read -r schema_db; do
if [ "${db}" = "${schema_db}" ]; then if [ "${db}" = "${schema_db}" ]; then
SCHEMA_ONLY='-s';
schema_flag='schema'; schema_flag='schema';
# skip out # skip out
break; break;
@@ -224,11 +296,9 @@ else
done<"${BASE_FOLDER}${SCHEMA_ONLY_FILE}"; done<"${BASE_FOLDER}${SCHEMA_ONLY_FILE}";
elif [ -s "${BASE_FOLDER}${DATA_ONLY_FILE}" ]; then elif [ -s "${BASE_FOLDER}${DATA_ONLY_FILE}" ]; then
# default to schema, unless in data list # default to schema, unless in data list
SCHEMA_ONLY='-s';
schema_flag='schema'; schema_flag='schema';
while read -r data_db; do while read -r data_db; do
if [ "${db}" = "${data_db}" ]; then if [ "${db}" = "${data_db}" ]; then
SCHEMA_ONLY='';
schema_flag='data'; schema_flag='data';
# skip out # skip out
break; break;
@@ -237,9 +307,13 @@ else
fi; fi;
# if nothing is set, default to data # if nothing is set, default to data
if [ -z "${schema_flag}" ]; then if [ -z "${schema_flag}" ]; then
SCHEMA_ONLY=''
schema_flag="data"; schema_flag="data";
fi; fi;
# set schema flag if schmea only is requested
if [ $schema_flag = "schema" ]; then
PG_DUMP_CMD+=("-s");
fi;
PG_DUMP_CMD+=("${db}");
# Filename # Filename
# Database.User.Encoding.pgsql|data|schema-Version_Host_Port_YearMonthDay_HourMinute_Counter.Fromat(c).sql # Database.User.Encoding.pgsql|data|schema-Version_Host_Port_YearMonthDay_HourMinute_Counter.Fromat(c).sql
FILENAME="${db}.${owner}.${encoding}.${schema_flag}-${DB_VERSION}_${DB_HOST}_${DB_PORT}.c.sql" FILENAME="${db}.${owner}.${encoding}.${schema_flag}-${DB_VERSION}_${DB_HOST}_${DB_PORT}.c.sql"
@@ -248,18 +322,25 @@ else
# backup set: # backup set:
BACKUP_SET_NAME="${ONE_TIME_TAG}${BACKUP_SET_PREFIX}${schema_flag}-${BACKUP_SET}"; BACKUP_SET_NAME="${ONE_TIME_TAG}${BACKUP_SET_PREFIX}${schema_flag}-${BACKUP_SET}";
# borg call # borg call
BORG_CALL=$(echo "${_BORG_CALL}" | sed -e "s/##FILENAME##/${FILENAME}/" | sed -e "s/##BACKUP_SET##/${BACKUP_SET_NAME}/"); BORG_CALL=$(
echo "${_BORG_CALL}" |
sed -e "s/##FILENAME##/${FILENAME}/" |
sed -e "s/##BACKUP_SET##/${BACKUP_SET_NAME}/"
);
# borg prune # borg prune
BORG_PRUNE=$(echo "${_BORG_PRUNE}" | sed -e "s/##BACKUP_SET_PREFIX##/${BACKUP_SET_PREFIX}/"); BORG_PRUNE=$(
echo "${_BORG_PRUNE}" |
sed -e "s/##BACKUP_SET_PREFIX##/${BACKUP_SET_PREFIX}/"
);
if [ ${DEBUG} -eq 1 ] || [ ${DRYRUN} -eq 1 ]; then if [ ${DEBUG} -eq 1 ] || [ ${DRYRUN} -eq 1 ]; then
echo "export BORG_BASE_DIR=\"${BASE_FOLDER}\";"; echo "export BORG_BASE_DIR=\"${BASE_FOLDER}\";";
echo "${PG_DUMP} -U ${DB_USER} ${CONN_DB_HOST} ${CONN_DB_PORT} -c ${SCHEMA_ONLY} --format=c ${db} | ${BORG_CALL}"; echo "${PG_DUMP_CMD[*]} | ${BORG_CALL}";
if [ -z "${ONE_TIME_TAG}" ]; then if [ -z "${ONE_TIME_TAG}" ]; then
echo "${BORG_PRUNE}"; echo "${BORG_PRUNE}";
fi; fi;
fi; fi;
if [ ${DRYRUN} -eq 0 ]; then if [ ${DRYRUN} -eq 0 ]; then
${PG_DUMP} -U ${DB_USER} ${CONN_DB_HOST} ${CONN_DB_PORT} -c ${SCHEMA_ONLY} --format=c "${db}" | ${BORG_CALL}; "${PG_DUMP_CMD[@]}" | ${BORG_CALL};
_backup_error=$?; _backup_error=$?;
if [ $_backup_error -ne 0 ]; then if [ $_backup_error -ne 0 ]; then
echo "[! $(date +'%F %T')] Backup creation failed for ${db} dump with error code: ${_backup_error}"; echo "[! $(date +'%F %T')] Backup creation failed for ${db} dump with error code: ${_backup_error}";
+1 -1
View File
@@ -55,7 +55,7 @@ if [ ! -f "${ZABBIX_DUMP_BIN}" ]; then
exit 1; exit 1;
fi; fi;
# -i (ignore)/ -f (backup) # -i (ignore)/ -f (backup)
if [ ! -z "${ZABBIX_UNKNOWN_TABLES}" ]; then if [ -n "${ZABBIX_UNKNOWN_TABLES}" ]; then
OPT_ZABBIX_UNKNOWN_TABLES="-f"; OPT_ZABBIX_UNKNOWN_TABLES="-f";
else else
OPT_ZABBIX_UNKNOWN_TABLES="-i"; OPT_ZABBIX_UNKNOWN_TABLES="-i";
+2 -2
View File
@@ -80,7 +80,7 @@ if [ ${UMOUNT} -eq 0 ]; then
. ${BASE_FOLDER}${SETTINGS_FILE} . ${BASE_FOLDER}${SETTINGS_FILE}
# set the borg backup file base on the settings data # set the borg backup file base on the settings data
# if we have user/host then we build the ssh command # if we have user/host then we build the ssh command
if [ ! -z "${TARGET_USER}" ] && [ ! -z "${TARGET_HOST}" ]; then if [ -n "${TARGET_USER}" ] && [ -n "${TARGET_HOST}" ]; then
TARGET_SERVER=${TARGET_USER}"@"${TARGET_HOST}":"; TARGET_SERVER=${TARGET_USER}"@"${TARGET_HOST}":";
fi; fi;
REPOSITORY=${TARGET_SERVER}${TARGET_FOLDER}${BACKUP_FILE}; REPOSITORY=${TARGET_SERVER}${TARGET_FOLDER}${BACKUP_FILE};
@@ -90,7 +90,7 @@ if [ ${UMOUNT} -eq 0 ]; then
# check that the repostiory exists # check that the repostiory exists
REPOSITORY_OK=0; REPOSITORY_OK=0;
if [ ! -z "${TARGET_SERVER}" ]; then if [ -n "${TARGET_SERVER}" ]; then
# remove trailing : for this # remove trailing : for this
TARGET_SERVER=${TARGET_SERVER/:}; TARGET_SERVER=${TARGET_SERVER/:};
# use ssh command to check remote existense # use ssh command to check remote existense