diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..231689a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +FROM mcuadros/ofelia:latest + +COPY --chmod=775 ./scripts /usr/local/bin + +RUN mkdir -p ${BACKUP_PATH:-/var/data/backup} + +ARG OFELIA_CONFIG_PATH=/etc/ofelia/config.ini +ARG DEBUG +ARG BACKUP_DATABASES + +RUN ofelia-config.sh --save \ No newline at end of file diff --git a/scripts/.DS_Store b/scripts/.DS_Store new file mode 100755 index 0000000..5008ddf Binary files /dev/null and b/scripts/.DS_Store differ diff --git a/scripts/backup-mysql.sh b/scripts/backup-mysql.sh new file mode 100644 index 0000000..6ccf0e6 --- /dev/null +++ b/scripts/backup-mysql.sh @@ -0,0 +1,69 @@ +#! /bin/sh + +# +# MySQL Backup +# Do backup of one or all databases of a given MySQL server +# + +# +# List Databases +# + +# only argument is a database url +DB_URL="$1"; + +# load database values as environment variables while checking URL validity +dburl-parser.sh ${DB_URL} > /tmp/ofelia.dotenv; +source /tmp/ofelia.dotenv; +rm /tmp/ofelia.dotenv; + +# set backup destination +## directory path +BACKUP_DATABASES_PATH=${BACKUP_DATABASES_PATH:-/var/data/backup-databases}; +mkdir -p ${BACKUP_DATABASES_PATH}; +## file name +BACKUP_DATABASES_PREFIX="backup-"; +BACKUP_DATABASES_SUFFIX="SQL"; + +if test "${DB_NAME}" = '*'; then + databases=$(mysql\ + --user=${DB_USERNAME}\ + --password=${DB_PASSWORD}\ + --host="${DB_HOST}"\ + --execute="SHOW DATABASES;"\ + --vertical\ + --column-names=false\ + | grep -ve ^\*\ + | xargs + ); +else + databases="${DB_NAME:-:ALL_DATABASES:}"; +fi + +for database_item in ${databases}; do + if test -z "${database_item}"; then + continue; + elif test "${database_item}" = ":ALL_DATABASES:"; then + database="--all-databases"; + filename_database="all-databases"; + else + database="--databases ${database_item}"; + filename_database="${database_item}"; + fi + cat | xargs mysqldump << HEREDOC +$(test -n ${DB_USERNAME} && echo "--user=${DB_USERNAME}") +$(test -n ${DB_PASSWORD} && echo "--password=${DB_PASSWORD}") +$(test -n ${DB_HOST} && echo "--host=${DB_HOST}") +$(test -n ${DB_PORT} && echo "--port=${DB_PORT}") +--result-file=$( + printf '%s/%s%s-%s_%s.%s'\ + ${BACKUP_DATABASES_PATH}\ + ${BACKUP_DATABASES_PREFIX}\ + ${DB_HOST}\ + ${filename_database}\ + $(date +%s)\ + ${BACKUP_DATABASES_SUFFIX} +) +${database} +HEREDOC +done \ No newline at end of file diff --git a/scripts/dburl-parser.sh b/scripts/dburl-parser.sh new file mode 100755 index 0000000..081c416 --- /dev/null +++ b/scripts/dburl-parser.sh @@ -0,0 +1,40 @@ +#! /bin/sh + +# +# Parses a database URL in the format schema://user: +# + +DB_URL="$1"; + +SCHEMA="${DB_URL%//*}"; +SCHEMALESS_URL=${DB_URL#*//}; +LEFT_HAND=${SCHEMALESS_URL%@*}; +if test ! ${LEFT_HAND} = ${SCHEMALESS_URL}; then + USERNAME=$(echo ${LEFT_HAND} | cut -d ':' -f 1); + if test ! ${USERNAME} = ${LEFT_HAND}; then + PASSWORD=$(echo ${LEFT_HAND} | cut -d ':' -f 2); + fi +fi +RIGHT_HAND=${SCHEMALESS_URL#*@}; +HOST=$(echo ${RIGHT_HAND} | cut -d ':' -f 1 | cut -d '/' -f 1); +if test -n "$(echo ${RIGHT_HAND} | grep -o ':')"; then + PORT=$(echo ${RIGHT_HAND} | cut -d ':' -f 2 | cut -d '/' -f 1); +fi +if test -n "$(echo ${RIGHT_HAND} | grep -o '/')"; then + DATABASE=$(echo ${RIGHT_HAND} | cut -d ':' -f 2 | cut -d '/' -f 2); +fi + +# throw an error if DB_URL does not contains at least a HOST +if test -z "${HOST}"; then + echo "database URL providen was invalid" && exit 1; +fi + +cat << HEREDOC +DB_SCHEMA=${SCHEMA%:} +DB_USERNAME=${USERNAME} +DB_PASSWORD=${PASSWORD} +DB_HOST=${HOST} +DB_PORT=${PORT} +DB_NAME=${DATABASE} +HEREDOC + diff --git a/scripts/install-mysql-tools.sh b/scripts/install-mysql-tools.sh new file mode 100644 index 0000000..25b6090 --- /dev/null +++ b/scripts/install-mysql-tools.sh @@ -0,0 +1,8 @@ +#! /bin/sh + +# +# MySQL install tools +# Install mysql and mysqldump to container +# + +apk update && apk add mysql-client; \ No newline at end of file diff --git a/scripts/ofelia-config.sh b/scripts/ofelia-config.sh new file mode 100755 index 0000000..bb3cad9 --- /dev/null +++ b/scripts/ofelia-config.sh @@ -0,0 +1,69 @@ +#! /bin/sh + +# +# Do nothing if there is no URLs to proccess +# +if test -z "${BACKUP_DATABASES}"; then + echo >&2 "missing a list of db urls on \$BACKUP_DATABASES env var"\ + && exit 1; +fi + +# +# Create output file if --saved option was set +# +while test $# -gt 0; do + arg_value="$1"; + shift; + if test "${arg_value}" = "--save"; then + output_path=${OFELIA_CONFIG_PATH:-/etc/ofelia/config.ini}; + mkdir $(dirname $output_path); + touch ${output_path}; + fi +done +if test -z "${output_path}"; then + output_path=/dev/stdout; +fi + +for entry in "${BACKUP_DATABASES}"; do + # normalize spaces + backup_data=$(echo ${entry} | xargs); + # skip if it is a empty line + if test -z "${backup_data}"; then + continue; + fi + # remove everything after first space to filter URL + DB_URL=${backup_data%% *}; + # remove everything before the first space to get cron label + BACKUP_SCHEDULE=${backup_data#* }; + # load url data as variables + dburl-parser.sh ${DB_URL} > /tmp/ofelia.dotenv; + source /tmp/ofelia.dotenv; + rm /tmp/ofelia.dotenv; + # fail if $DB_URL has no schema + if test -z "${DB_SCHEMA}"; then + 1>&2 echo "invalid entry in \$BACKUP_DATABASES: ${entry}"; + exit 7; + fi + # strip final : and convert schema to lowercase + schema="$(echo ${DB_SCHEMA%:} | tr '[:upper:]' '[:lower:]')"; + # install schema related tools in advance + install-${schema}-tools.sh + # save backup command : should there be one script per database type + bkp_command="backup-${schema}.sh --url=${DB_URL}"; + # BACKUP_SCHEDULE defaults to @daily + bkp_schedule="${BACKUP_SCHEDULE:-@daily}"; + # set a title to ofelia job + bkp_title="backup-${DB_HOST}"; + if test -n "${DB_NAME}"; then + bkp_title="${bkp_title}-${DB_NAME}"; + fi + # add a entry to this backup in ofelia config file + cat >> ${output_path} << HEREDOC +# sending data to ${output_path} +[job-local "${bkp_title}"] +$(if test "${DEBUG}" = "on"; then echo "save-only-on-error = false"; fi) +no-overlap = true +command = ${bkp_command} +schedule = ${bkp_schedule} +HEREDOC +done; \ No newline at end of file diff --git a/scripts/ofelia-run.sh b/scripts/ofelia-run.sh new file mode 100755 index 0000000..cd478d0 --- /dev/null +++ b/scripts/ofelia-run.sh @@ -0,0 +1,3 @@ +#! /bin/sh + +ofelia-config.sh && ofelia daemon; \ No newline at end of file