diff --git a/docker/Dockerfile_Mongo b/docker/Dockerfile_Mongo index d5f45a9..6995e43 100644 --- a/docker/Dockerfile_Mongo +++ b/docker/Dockerfile_Mongo @@ -1,5 +1,8 @@ # This image provides a mongo installation from which to run backups -FROM registry.access.redhat.com/rhscl/mongodb-36-rhel7 +FROM mongodb/mongodb-community-server:6.0.6-ubi8 + +ARG uid=998 +ARG user=mongod # Change timezone to PST for convenience ENV TZ=PST8PDT @@ -23,6 +26,10 @@ ADD https://github.com/$SOURCE_REPO/go-crond/releases/download/$GOCROND_VERSION/ USER root RUN chmod +x /usr/bin/go-crond +RUN chown -R $user:root /data/db && \ + chmod -R ug+rw /data/db + +RUN usermod -a -G 0 $user # ======================================================================================================== # ======================================================================================================== @@ -32,7 +39,7 @@ RUN echo $TZ > /etc/timezone # ======================================================================================================== # Important - Reset to the base image's user account. -USER 26 +USER $uid # Set the default CMD. -CMD sh /backup.sh \ No newline at end of file +CMD bash /backup.sh diff --git a/docker/backup.container.utils b/docker/backup.container.utils index 135228e..2d44960 100644 --- a/docker/backup.container.utils +++ b/docker/backup.container.utils @@ -14,7 +14,7 @@ function isPostgres(){ function isMongo(){ ( - if isInstalled "mongo"; then + if isInstalled "mongosh"; then return 0 else return 1 @@ -79,4 +79,4 @@ function isForContainerType(){ fi ) } -# ====================================================================================== \ No newline at end of file +# ====================================================================================== diff --git a/docker/backup.misc.utils b/docker/backup.misc.utils index 6d42080..d636cd8 100644 --- a/docker/backup.misc.utils +++ b/docker/backup.misc.utils @@ -38,10 +38,16 @@ function getElapsedTime(){ } function getElapsedTimeFromDuration(){ - ( - local duration=${1} - local elapsedTime="$(($duration/3600))h:$(($duration%3600/60))m:$(($duration%60))s" + local duration_ns=${1} + + local hours=$((duration_ns / 3600000000000)) + local minutes=$(( (duration_ns % 3600000000000) / 60000000000 )) + local seconds=$(( (duration_ns % 60000000000) / 1000000000 )) + local milliseconds=$(( (duration_ns % 1000000000) / 1000000 )) + local microseconds=$(( (duration_ns % 1000000) / 1000 )) + local nanoseconds=$(( duration_ns % 1000 )) + + local elapsedTime="${hours}h:${minutes}m:${seconds}s:${milliseconds}ms:${microseconds}µs:${nanoseconds}ns" echo ${elapsedTime} - ) } -# ====================================================================================== \ No newline at end of file +# ====================================================================================== diff --git a/docker/backup.mongo.plugin b/docker/backup.mongo.plugin index 402e0c2..3483721 100644 --- a/docker/backup.mongo.plugin +++ b/docker/backup.mongo.plugin @@ -3,7 +3,7 @@ # Mongo Backup and Restore Functions: # - Dynamically loaded as a plug-in # ----------------------------------------------------------------------------------------------------------------- -export serverDataDirectory="/var/lib/mongodb/data" +export serverDataDirectory="/data/db" function onBackupDatabase(){ ( @@ -69,6 +69,52 @@ function onRestoreDatabase(){ ) } +function onDatabaseInit() { + local OPTIND + local unset flags + while getopts : FLAG; do + case $FLAG in + ? ) flags+="-${OPTARG} ";; + esac + done + shift $((OPTIND-1)) + + # Retrieve database details + local _databaseSpec=${1} + local _database=$(getDatabaseName "${_databaseSpec}") + local _username=$(getUsername "${_databaseSpec}") + local _password=$(getPassword "${_databaseSpec}") + + # Check if the database already exists + if mongosh --quiet --eval "db.getMongo().getDBNames().indexOf('$_database') >= 0"; then + echoYellow "Database '$_database' already exists, skipping initialization." + return 0 + fi + + # Initialize the database by creating the user with the roles + mongosh "$_database" --quiet --eval " + db.createUser({ + user: '$_username', + pwd: '$_password', + roles: [ + { role: 'dbOwner', db: '$_database' }, + { role: 'readWrite', db: '$_database' }, + { role: 'clusterAdmin', db: 'admin' } + ] + }); + " + + # Check the exit status of the createUser command + if [ $? -eq 0 ]; then + echoGreen "Database '$_database' initialized successfully." + return 0 + else + echoRed "Failed to initialize database '$_database'." + return 1 + fi +} + + function onStartServer(){ ( local OPTIND @@ -82,12 +128,13 @@ function onStartServer(){ _databaseSpec=${1} + _hostname=$(getHostname ${flags} ${_databaseSpec}) + # Start a local MongoDb instance - MONGODB_DATABASE=$(getDatabaseName "${_databaseSpec}") \ - MONGODB_USER=$(getUsername "${_databaseSpec}") \ - MONGODB_PASSWORD=$(getPassword "${_databaseSpec}") \ - MONGODB_ADMIN_PASSWORD=$(getPassword "${_databaseSpec}") \ - run-mongod >/dev/null 2>&1 & + mongod --bind_ip $_hostname > /dev/null 2>&1 & + + # Initialize database if necessary + onDatabaseInit "${_databaseSpec}" ) } @@ -104,21 +151,18 @@ function onStopServer(){ _databaseSpec=${1} - _port=$(getPort ${_databaseSpec}) - _portArg=${_port:+"--port ${_port}"} - _username=admin - _password=$(getPassword ${_databaseSpec}) + _hostname=$(getHostname ${flags} ${_databaseSpec}) - _authDbArg=${MONGODB_AUTHENTICATION_DATABASE:+"--authenticationDatabase ${MONGODB_AUTHENTICATION_DATABASE}"} - mongo admin ${_authDbArg} ${_portArg} -u "${_username}" -p "${_password}" --quiet --eval "db.shutdownServer()" + mongosh ${_hostname}/admin --quiet --eval "db.shutdownServer()" > /dev/null 2>&1 # Wait for server to stop ... - local startTime=${SECONDS} + local startTime=$(date +%s%N) + printf "waiting for server to stop" - while onPingDbServer ${@}; do + while onPingDbServer -l ${@}; do printf "." - local duration=$(($SECONDS - $startTime)) - if (( ${duration} >= ${DATABASE_SERVER_TIMEOUT} )); then + local duration_ns=$(($(date +%s%N) - $startTime)) + if (( ${duration_ns} >= ${DATABASE_SERVER_TIMEOUT_NS} )); then echoRed "\nThe server failed to stop within $(getElapsedTimeFromDuration ${duration})." echoRed "Killing the mongod process ...\n" pkill -INT mongod @@ -163,10 +207,14 @@ function onPingDbServer(){ _dbAddressArg=${_hostname}${_port:+:${_port}}${_database:+/${_database}} _authDbArg=${MONGODB_AUTHENTICATION_DATABASE:+"--authenticationDatabase ${MONGODB_AUTHENTICATION_DATABASE}"} - if mongo ${_dbAddressArg} ${_authDbArg} -u "${_username}" -p "${_password}" --quiet --eval='quit()' >/dev/null 2>&1; then - return 0 - else + + mongosh ${_dbAddressArg} ${_authDbArg} -u "${_username}" -p "${_password}" --quiet --eval='db.runCommand("ping").ok' > /dev/null 2>&1 + local mongoshExitCode=$? + + if (( ${mongoshExitCode} != 0 )); then return 1 + else + return 0 fi ) } @@ -193,7 +241,7 @@ function onVerifyBackup(){ _dbAddressArg=${_hostname}${_port:+:${_port}}${_database:+/${_database}} _authDbArg=${MONGODB_AUTHENTICATION_DATABASE:+"--authenticationDatabase ${MONGODB_AUTHENTICATION_DATABASE}"} - collections=$(mongo ${_dbAddressArg} ${_authDbArg} -u "${_username}" -p "${_password}" --quiet --eval 'var dbs = [];dbs = db.getCollectionNames();for (i in dbs){ print(db.dbs[i]);}';) + collections=$(mongosh ${_dbAddressArg} ${_authDbArg} -u "${_username}" -p "${_password}" --quiet --eval 'var dbs = [];dbs = db.getCollectionNames();for (i in dbs){ print(db.dbs[i]);}';) rtnCd=${?} # Get the size of the restored database @@ -241,11 +289,11 @@ function onGetDbSize(){ _dbAddressArg=${_hostname}${_port:+:${_port}}${_database:+/${_database}} _authDbArg=${MONGODB_AUTHENTICATION_DATABASE:+"--authenticationDatabase ${MONGODB_AUTHENTICATION_DATABASE}"} - size=$(mongo ${_dbAddressArg} ${_authDbArg} -u "${_username}" -p "${_password}" --quiet --eval 'printjson(db.stats().fsTotalSize)') + size=$(mongosh ${_dbAddressArg} ${_authDbArg} -u "${_username}" -p "${_password}" --quiet --eval 'printjson(db.stats().fsTotalSize)') rtnCd=${?} echo ${size} return ${rtnCd} ) } -# ================================================================================================================= \ No newline at end of file +# ================================================================================================================= diff --git a/docker/backup.settings b/docker/backup.settings index 9ba6c41..47ad203 100644 --- a/docker/backup.settings +++ b/docker/backup.settings @@ -51,4 +51,5 @@ export CONTAINER_TYPE="$(getContainerType)" # Other: export DATABASE_SERVER_TIMEOUT=${DATABASE_SERVER_TIMEOUT:-120} -# ====================================================================================== \ No newline at end of file +export DATABASE_SERVER_TIMEOUT_NS=$((DATABASE_SERVER_TIMEOUT * 1000000000)) +# ====================================================================================== diff --git a/docker/backup.utils b/docker/backup.utils index 756e98a..4c562c1 100644 --- a/docker/backup.utils +++ b/docker/backup.utils @@ -68,11 +68,11 @@ function restoreDatabase(){ echo -e "\n" fi - local startTime=${SECONDS} + local startTime=$(date +%s%N) onRestoreDatabase ${flags} "${_databaseSpec}" "${_fileName}" "${_adminPassword}" _rtnCd=${?} - local endTime=${SECONDS} + local endTime=$(date +%s%N) if (( ${_rtnCd} == 0 )); then echoGreen "\nRestore complete - Elapsed time: $(getElapsedTime ${startTime} ${endTime})\n" else @@ -92,11 +92,11 @@ function runBackups(){ for database in ${databases}; do if isForContainerType ${database}; then - local startTime=${SECONDS} + local startTime=$(date +%s%N) filename=$(generateFilename "${backupDir}" "${database}") backupDatabase "${database}" "${filename}" rtnCd=${?} - local endTime=${SECONDS} + local endTime=$(date +%s%N) local elapsedTime="\n\nElapsed time: $(getElapsedTime ${startTime} ${endTime}) - Status Code: ${rtnCd}" if (( ${rtnCd} == 0 )); then @@ -124,13 +124,13 @@ function startServer(){ onStartServer ${@} # Wait for server to start ... - local startTime=${SECONDS} + local startTime=$(date +%s%N) rtnCd=0 printf "waiting for server to start" while ! pingDbServer ${@}; do printf "." - local duration=$(($SECONDS - $startTime)) - if (( ${duration} >= ${DATABASE_SERVER_TIMEOUT} )); then + local duration_ns=$(($(date +%s%N) - $startTime)) + if (( ${duration_ns} >= ${DATABASE_SERVER_TIMEOUT_NS} )); then echoRed "\nThe server failed to start within $(getElapsedTimeFromDuration ${duration}).\n" rtnCd=1 break @@ -231,7 +231,7 @@ function verifyBackup(){ # Make sure things have been cleaned up before we start ... cleanUp - local startTime=${SECONDS} + local startTime=$(date +%s%N) startServer -l "${_databaseSpec}" rtnCd=${?} @@ -262,10 +262,10 @@ function verifyBackup(){ fi # Stop the database server and clean up ... - stopServer "${_databaseSpec}" + stopServer -l "${_databaseSpec}" cleanUp - local endTime=${SECONDS} + local endTime=$(date +%s%N) local elapsedTime="\n\nElapsed time: $(getElapsedTime ${startTime} ${endTime}) - Status Code: ${rtnCd}" if (( ${rtnCd} == 0 )); then