Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 1 | #!/usr/bin/env bash |
| 2 | |
Matthias Andreas Benkard | 1ba5381 | 2022-12-27 17:32:58 +0100 | [diff] [blame] | 3 | DEBIAN_DOCKER_IMAGE="mailcow/backup:latest" |
Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 4 | |
| 5 | if [[ ! -z ${MAILCOW_BACKUP_LOCATION} ]]; then |
| 6 | BACKUP_LOCATION="${MAILCOW_BACKUP_LOCATION}" |
| 7 | fi |
| 8 | |
| 9 | if [[ ! ${1} =~ (backup|restore) ]]; then |
| 10 | echo "First parameter needs to be 'backup' or 'restore'" |
| 11 | exit 1 |
| 12 | fi |
| 13 | |
| 14 | if [[ ${1} == "backup" && ! ${2} =~ (crypt|vmail|redis|rspamd|postfix|mysql|all|--delete-days) ]]; then |
| 15 | echo "Second parameter needs to be 'vmail', 'crypt', 'redis', 'rspamd', 'postfix', 'mysql', 'all' or '--delete-days'" |
| 16 | exit 1 |
| 17 | fi |
| 18 | |
| 19 | if [[ -z ${BACKUP_LOCATION} ]]; then |
| 20 | while [[ -z ${BACKUP_LOCATION} ]]; do |
| 21 | read -ep "Backup location (absolute path, starting with /): " BACKUP_LOCATION |
| 22 | done |
| 23 | fi |
| 24 | |
| 25 | if [[ ! ${BACKUP_LOCATION} =~ ^/ ]]; then |
| 26 | echo "Backup directory needs to be given as absolute path (starting with /)." |
| 27 | exit 1 |
| 28 | fi |
| 29 | |
| 30 | if [[ -f ${BACKUP_LOCATION} ]]; then |
| 31 | echo "${BACKUP_LOCATION} is a file!" |
| 32 | exit 1 |
| 33 | fi |
| 34 | |
| 35 | if [[ ! -d ${BACKUP_LOCATION} ]]; then |
| 36 | echo "${BACKUP_LOCATION} is not a directory" |
| 37 | read -p "Create it now? [y|N] " CREATE_BACKUP_LOCATION |
| 38 | if [[ ! ${CREATE_BACKUP_LOCATION,,} =~ ^(yes|y)$ ]]; then |
| 39 | exit 1 |
| 40 | else |
| 41 | mkdir -p ${BACKUP_LOCATION} |
| 42 | chmod 755 ${BACKUP_LOCATION} |
| 43 | fi |
| 44 | else |
| 45 | if [[ ${1} == "backup" ]] && [[ -z $(echo $(stat -Lc %a ${BACKUP_LOCATION}) | grep -oE '[0-9][0-9][5-7]') ]]; then |
| 46 | echo "${BACKUP_LOCATION} is not write-able for others, that's required for a backup." |
| 47 | exit 1 |
| 48 | fi |
| 49 | fi |
| 50 | |
| 51 | BACKUP_LOCATION=$(echo ${BACKUP_LOCATION} | sed 's#/$##') |
| 52 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" |
| 53 | COMPOSE_FILE=${SCRIPT_DIR}/../docker-compose.yml |
| 54 | ENV_FILE=${SCRIPT_DIR}/../.env |
Matthias Andreas Benkard | 1ba5381 | 2022-12-27 17:32:58 +0100 | [diff] [blame] | 55 | THREADS=$(echo ${THREADS:-1}) |
| 56 | |
| 57 | if ! [[ "${THREADS}" =~ ^[1-9]+$ ]] ; then |
| 58 | echo "Thread input is not a number!" |
| 59 | exit 1 |
| 60 | elif [[ "${THREADS}" =~ ^[1-9]+$ ]] ; then |
| 61 | echo "Using ${THREADS} Thread(s) for this run." |
| 62 | echo "Notice: You can set the Thread count with the THREADS Variable before you run this script." |
| 63 | fi |
Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 64 | |
| 65 | if [ ! -f ${COMPOSE_FILE} ]; then |
| 66 | echo "Compose file not found" |
| 67 | exit 1 |
| 68 | fi |
| 69 | |
| 70 | if [ ! -f ${ENV_FILE} ]; then |
| 71 | echo "Environment file not found" |
| 72 | exit 1 |
| 73 | fi |
| 74 | |
| 75 | echo "Using ${BACKUP_LOCATION} as backup/restore location." |
| 76 | echo |
| 77 | |
| 78 | source ${SCRIPT_DIR}/../mailcow.conf |
| 79 | |
| 80 | if [[ -z ${COMPOSE_PROJECT_NAME} ]]; then |
| 81 | echo "Could not determine compose project name" |
| 82 | exit 1 |
| 83 | else |
| 84 | echo "Found project name ${COMPOSE_PROJECT_NAME}" |
| 85 | CMPS_PRJ=$(echo ${COMPOSE_PROJECT_NAME} | tr -cd "[0-9A-Za-z-_]") |
| 86 | fi |
| 87 | |
Matthias Andreas Benkard | 1ba5381 | 2022-12-27 17:32:58 +0100 | [diff] [blame] | 88 | if grep --help 2>&1 | head -n 1 | grep -q -i "busybox"; then |
| 89 | >&2 echo -e "\e[31mBusyBox grep detected on local system, please install GNU grep\e[0m" |
| 90 | exit 1 |
| 91 | fi |
| 92 | |
| 93 | |
Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 94 | function backup() { |
| 95 | DATE=$(date +"%Y-%m-%d-%H-%M-%S") |
| 96 | mkdir -p "${BACKUP_LOCATION}/mailcow-${DATE}" |
| 97 | chmod 755 "${BACKUP_LOCATION}/mailcow-${DATE}" |
| 98 | cp "${SCRIPT_DIR}/../mailcow.conf" "${BACKUP_LOCATION}/mailcow-${DATE}" |
Matthias Andreas Benkard | 1ba5381 | 2022-12-27 17:32:58 +0100 | [diff] [blame] | 99 | for bin in docker; do |
| 100 | if [[ -z $(which ${bin}) ]]; then |
| 101 | >&2 echo -e "\e[31mCannot find ${bin} in local PATH, exiting...\e[0m" |
| 102 | exit 1 |
| 103 | fi |
| 104 | done |
Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 105 | while (( "$#" )); do |
| 106 | case "$1" in |
| 107 | vmail|all) |
| 108 | docker run --name mailcow-backup --rm \ |
| 109 | -v ${BACKUP_LOCATION}/mailcow-${DATE}:/backup:z \ |
Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 110 | -v $(docker volume ls -qf name=^${CMPS_PRJ}_vmail-vol-1$):/vmail:ro,z \ |
Matthias Andreas Benkard | 1ba5381 | 2022-12-27 17:32:58 +0100 | [diff] [blame] | 111 | ${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="pigz --rsyncable -p ${THREADS}" -Pcvpf /backup/backup_vmail.tar.gz /vmail |
Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 112 | ;;& |
| 113 | crypt|all) |
| 114 | docker run --name mailcow-backup --rm \ |
| 115 | -v ${BACKUP_LOCATION}/mailcow-${DATE}:/backup:z \ |
Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 116 | -v $(docker volume ls -qf name=^${CMPS_PRJ}_crypt-vol-1$):/crypt:ro,z \ |
Matthias Andreas Benkard | 1ba5381 | 2022-12-27 17:32:58 +0100 | [diff] [blame] | 117 | ${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="pigz --rsyncable -p ${THREADS}" -Pcvpf /backup/backup_crypt.tar.gz /crypt |
Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 118 | ;;& |
| 119 | redis|all) |
| 120 | docker exec $(docker ps -qf name=redis-mailcow) redis-cli save |
| 121 | docker run --name mailcow-backup --rm \ |
| 122 | -v ${BACKUP_LOCATION}/mailcow-${DATE}:/backup:z \ |
Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 123 | -v $(docker volume ls -qf name=^${CMPS_PRJ}_redis-vol-1$):/redis:ro,z \ |
Matthias Andreas Benkard | 1ba5381 | 2022-12-27 17:32:58 +0100 | [diff] [blame] | 124 | ${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="pigz --rsyncable -p ${THREADS}" -Pcvpf /backup/backup_redis.tar.gz /redis |
Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 125 | ;;& |
| 126 | rspamd|all) |
| 127 | docker run --name mailcow-backup --rm \ |
| 128 | -v ${BACKUP_LOCATION}/mailcow-${DATE}:/backup:z \ |
Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 129 | -v $(docker volume ls -qf name=^${CMPS_PRJ}_rspamd-vol-1$):/rspamd:ro,z \ |
Matthias Andreas Benkard | 1ba5381 | 2022-12-27 17:32:58 +0100 | [diff] [blame] | 130 | ${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="pigz --rsyncable -p ${THREADS}" -Pcvpf /backup/backup_rspamd.tar.gz /rspamd |
Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 131 | ;;& |
| 132 | postfix|all) |
| 133 | docker run --name mailcow-backup --rm \ |
| 134 | -v ${BACKUP_LOCATION}/mailcow-${DATE}:/backup:z \ |
Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 135 | -v $(docker volume ls -qf name=^${CMPS_PRJ}_postfix-vol-1$):/postfix:ro,z \ |
Matthias Andreas Benkard | 1ba5381 | 2022-12-27 17:32:58 +0100 | [diff] [blame] | 136 | ${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="pigz --rsyncable -p ${THREADS}" -Pcvpf /backup/backup_postfix.tar.gz /postfix |
Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 137 | ;;& |
| 138 | mysql|all) |
| 139 | SQLIMAGE=$(grep -iEo '(mysql|mariadb)\:.+' ${COMPOSE_FILE}) |
| 140 | if [[ -z "${SQLIMAGE}" ]]; then |
| 141 | echo "Could not determine SQL image version, skipping backup..." |
| 142 | shift |
| 143 | continue |
| 144 | else |
| 145 | echo "Using SQL image ${SQLIMAGE}, starting..." |
| 146 | docker run --name mailcow-backup --rm \ |
Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 147 | --network $(docker network ls -qf name=^${CMPS_PRJ}_mailcow-network$) \ |
| 148 | -v $(docker volume ls -qf name=^${CMPS_PRJ}_mysql-vol-1$):/var/lib/mysql/:ro,z \ |
| 149 | -t --entrypoint= \ |
Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 150 | --sysctl net.ipv6.conf.all.disable_ipv6=1 \ |
| 151 | -v ${BACKUP_LOCATION}/mailcow-${DATE}:/backup:z \ |
| 152 | ${SQLIMAGE} /bin/sh -c "mariabackup --host mysql --user root --password ${DBROOT} --backup --rsync --target-dir=/backup_mariadb ; \ |
| 153 | mariabackup --prepare --target-dir=/backup_mariadb ; \ |
| 154 | chown -R 999:999 /backup_mariadb ; \ |
| 155 | /bin/tar --warning='no-file-ignored' --use-compress-program='gzip --rsyncable' -Pcvpf /backup/backup_mariadb.tar.gz /backup_mariadb ;" |
| 156 | fi |
| 157 | ;;& |
| 158 | --delete-days) |
| 159 | shift |
| 160 | if [[ "${1}" =~ ^[0-9]+$ ]]; then |
| 161 | find ${BACKUP_LOCATION}/mailcow-* -maxdepth 0 -mmin +$((${1}*60*24)) -exec rm -rvf {} \; |
| 162 | else |
| 163 | echo "Parameter of --delete-days is not a number." |
| 164 | fi |
| 165 | ;; |
| 166 | esac |
| 167 | shift |
| 168 | done |
| 169 | } |
| 170 | |
| 171 | function restore() { |
Matthias Andreas Benkard | 1ba5381 | 2022-12-27 17:32:58 +0100 | [diff] [blame] | 172 | for bin in docker; do |
| 173 | if [[ -z $(which ${bin}) ]]; then |
| 174 | >&2 echo -e "\e[31mCannot find ${bin} in local PATH, exiting...\e[0m" |
| 175 | exit 1 |
| 176 | fi |
| 177 | done |
| 178 | |
| 179 | if [ "${DOCKER_COMPOSE_VERSION}" == "native" ]; then |
| 180 | COMPOSE_COMMAND="docker compose" |
| 181 | |
| 182 | elif [ "${DOCKER_COMPOSE_VERSION}" == "standalone" ]; then |
| 183 | COMPOSE_COMMAND="docker-compose" |
| 184 | |
| 185 | else |
| 186 | echo -e "\e[31mCan not read DOCKER_COMPOSE_VERSION variable from mailcow.conf! Is your mailcow up to date? Exiting...\e[0m" |
| 187 | exit 1 |
| 188 | fi |
| 189 | |
Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 190 | echo |
| 191 | echo "Stopping watchdog-mailcow..." |
| 192 | docker stop $(docker ps -qf name=watchdog-mailcow) |
| 193 | echo |
| 194 | RESTORE_LOCATION="${1}" |
| 195 | shift |
| 196 | while (( "$#" )); do |
| 197 | case "$1" in |
| 198 | vmail) |
| 199 | docker stop $(docker ps -qf name=dovecot-mailcow) |
| 200 | docker run -it --name mailcow-backup --rm \ |
| 201 | -v ${RESTORE_LOCATION}:/backup:z \ |
Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 202 | -v $(docker volume ls -qf name=^${CMPS_PRJ}_vmail-vol-1$):/vmail:z \ |
Matthias Andreas Benkard | 1ba5381 | 2022-12-27 17:32:58 +0100 | [diff] [blame] | 203 | ${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="pigz -d -p ${THREADS}" -Pxvf /backup/backup_vmail.tar.gz |
Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 204 | docker start $(docker ps -aqf name=dovecot-mailcow) |
| 205 | echo |
| 206 | echo "In most cases it is not required to run a full resync, you can run the command printed below at any time after testing wether the restore process broke a mailbox:" |
| 207 | echo |
| 208 | echo "docker exec $(docker ps -qf name=dovecot-mailcow) doveadm force-resync -A '*'" |
| 209 | echo |
| 210 | read -p "Force a resync now? [y|N] " FORCE_RESYNC |
| 211 | if [[ ${FORCE_RESYNC,,} =~ ^(yes|y)$ ]]; then |
| 212 | docker exec $(docker ps -qf name=dovecot-mailcow) doveadm force-resync -A '*' |
| 213 | else |
| 214 | echo "OK, skipped." |
| 215 | fi |
| 216 | ;; |
| 217 | redis) |
| 218 | docker stop $(docker ps -qf name=redis-mailcow) |
| 219 | docker run -it --name mailcow-backup --rm \ |
| 220 | -v ${RESTORE_LOCATION}:/backup:z \ |
Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 221 | -v $(docker volume ls -qf name=^${CMPS_PRJ}_redis-vol-1$):/redis:z \ |
Matthias Andreas Benkard | 1ba5381 | 2022-12-27 17:32:58 +0100 | [diff] [blame] | 222 | ${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="pigz -d -p ${THREADS}" -Pxvf /backup/backup_redis.tar.gz |
Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 223 | docker start $(docker ps -aqf name=redis-mailcow) |
| 224 | ;; |
| 225 | crypt) |
| 226 | docker stop $(docker ps -qf name=dovecot-mailcow) |
| 227 | docker run -it --name mailcow-backup --rm \ |
| 228 | -v ${RESTORE_LOCATION}:/backup:z \ |
Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 229 | -v $(docker volume ls -qf name=^${CMPS_PRJ}_crypt-vol-1$):/crypt:z \ |
Matthias Andreas Benkard | 1ba5381 | 2022-12-27 17:32:58 +0100 | [diff] [blame] | 230 | ${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="pigz -d -p ${THREADS}" -Pxvf /backup/backup_crypt.tar.gz |
Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 231 | docker start $(docker ps -aqf name=dovecot-mailcow) |
| 232 | ;; |
| 233 | rspamd) |
| 234 | docker stop $(docker ps -qf name=rspamd-mailcow) |
| 235 | docker run -it --name mailcow-backup --rm \ |
| 236 | -v ${RESTORE_LOCATION}:/backup:z \ |
Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 237 | -v $(docker volume ls -qf name=^${CMPS_PRJ}_rspamd-vol-1$):/rspamd:z \ |
Matthias Andreas Benkard | 1ba5381 | 2022-12-27 17:32:58 +0100 | [diff] [blame] | 238 | ${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="pigz -d -p ${THREADS}" -Pxvf /backup/backup_rspamd.tar.gz |
Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 239 | docker start $(docker ps -aqf name=rspamd-mailcow) |
| 240 | ;; |
| 241 | postfix) |
| 242 | docker stop $(docker ps -qf name=postfix-mailcow) |
| 243 | docker run -it --name mailcow-backup --rm \ |
| 244 | -v ${RESTORE_LOCATION}:/backup:z \ |
Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 245 | -v $(docker volume ls -qf name=^${CMPS_PRJ}_postfix-vol-1$):/postfix:z \ |
Matthias Andreas Benkard | 1ba5381 | 2022-12-27 17:32:58 +0100 | [diff] [blame] | 246 | ${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="pigz -d -p ${THREADS}" -Pxvf /backup/backup_postfix.tar.gz |
Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 247 | docker start $(docker ps -aqf name=postfix-mailcow) |
| 248 | ;; |
| 249 | mysql|mariadb) |
| 250 | SQLIMAGE=$(grep -iEo '(mysql|mariadb)\:.+' ${COMPOSE_FILE}) |
| 251 | if [[ -z "${SQLIMAGE}" ]]; then |
| 252 | echo "Could not determine SQL image version, skipping restore..." |
| 253 | shift |
| 254 | continue |
| 255 | elif [ ! -f "${RESTORE_LOCATION}/mailcow.conf" ]; then |
| 256 | echo "Could not find the corresponding mailcow.conf in ${RESTORE_LOCATION}, skipping restore." |
| 257 | echo "If you lost that file, copy the last working mailcow.conf file to ${RESTORE_LOCATION} and restart the restore process." |
| 258 | shift |
| 259 | continue |
| 260 | else |
| 261 | read -p "mailcow will be stopped and the currently active mailcow.conf will be modified to use the DB parameters found in ${RESTORE_LOCATION}/mailcow.conf - do you want to proceed? [Y|n] " MYSQL_STOP_MAILCOW |
| 262 | if [[ ${MYSQL_STOP_MAILCOW,,} =~ ^(no|n|N)$ ]]; then |
| 263 | echo "OK, skipped." |
| 264 | shift |
| 265 | continue |
| 266 | else |
| 267 | echo "Stopping mailcow..." |
Matthias Andreas Benkard | 1ba5381 | 2022-12-27 17:32:58 +0100 | [diff] [blame] | 268 | ${COMPOSE_COMMAND} -f ${COMPOSE_FILE} --env-file ${ENV_FILE} down |
Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 269 | fi |
| 270 | #docker stop $(docker ps -qf name=mysql-mailcow) |
| 271 | if [[ -d "${RESTORE_LOCATION}/mysql" ]]; then |
| 272 | docker run --name mailcow-backup --rm \ |
Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 273 | -v $(docker volume ls -qf name=^${CMPS_PRJ}_mysql-vol-1$):/var/lib/mysql/:rw,z \ |
Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 274 | --entrypoint= \ |
| 275 | -v ${RESTORE_LOCATION}/mysql:/backup:z \ |
| 276 | ${SQLIMAGE} /bin/bash -c "shopt -s dotglob ; /bin/rm -rf /var/lib/mysql/* ; rsync -avh --usermap=root:mysql --groupmap=root:mysql /backup/ /var/lib/mysql/" |
| 277 | elif [[ -f "${RESTORE_LOCATION}/backup_mysql.gz" ]]; then |
| 278 | docker run \ |
| 279 | -it --name mailcow-backup --rm \ |
Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 280 | -v $(docker volume ls -qf name=^${CMPS_PRJ}_mysql-vol-1$):/var/lib/mysql/:z \ |
Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 281 | --entrypoint= \ |
| 282 | -u mysql \ |
| 283 | -v ${RESTORE_LOCATION}:/backup:z \ |
| 284 | ${SQLIMAGE} /bin/sh -c "mysqld --skip-grant-tables & \ |
| 285 | until mysqladmin ping; do sleep 3; done && \ |
| 286 | echo Restoring... && \ |
| 287 | gunzip < backup/backup_mysql.gz | mysql -uroot && \ |
| 288 | mysql -uroot -e SHUTDOWN;" |
| 289 | elif [[ -f "${RESTORE_LOCATION}/backup_mariadb.tar.gz" ]]; then |
| 290 | docker run --name mailcow-backup --rm \ |
Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 291 | -v $(docker volume ls -qf name=^${CMPS_PRJ}_mysql-vol-1$):/backup_mariadb/:rw,z \ |
Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 292 | --entrypoint= \ |
| 293 | -v ${RESTORE_LOCATION}:/backup:z \ |
| 294 | ${SQLIMAGE} /bin/bash -c "shopt -s dotglob ; \ |
| 295 | /bin/rm -rf /backup_mariadb/* ; \ |
| 296 | /bin/tar -Pxvzf /backup/backup_mariadb.tar.gz" |
| 297 | fi |
| 298 | echo "Modifying mailcow.conf..." |
| 299 | source ${RESTORE_LOCATION}/mailcow.conf |
| 300 | sed -i --follow-symlinks "/DBNAME/c\DBNAME=${DBNAME}" ${SCRIPT_DIR}/../mailcow.conf |
| 301 | sed -i --follow-symlinks "/DBUSER/c\DBUSER=${DBUSER}" ${SCRIPT_DIR}/../mailcow.conf |
| 302 | sed -i --follow-symlinks "/DBPASS/c\DBPASS=${DBPASS}" ${SCRIPT_DIR}/../mailcow.conf |
| 303 | sed -i --follow-symlinks "/DBROOT/c\DBROOT=${DBROOT}" ${SCRIPT_DIR}/../mailcow.conf |
| 304 | source ${SCRIPT_DIR}/../mailcow.conf |
| 305 | echo "Starting mailcow..." |
Matthias Andreas Benkard | 1ba5381 | 2022-12-27 17:32:58 +0100 | [diff] [blame] | 306 | ${COMPOSE_COMMAND} -f ${COMPOSE_FILE} --env-file ${ENV_FILE} up -d |
Matthias Andreas Benkard | b382b10 | 2021-01-02 15:32:21 +0100 | [diff] [blame] | 307 | #docker start $(docker ps -aqf name=mysql-mailcow) |
| 308 | fi |
| 309 | ;; |
| 310 | esac |
| 311 | shift |
| 312 | done |
| 313 | echo |
| 314 | echo "Starting watchdog-mailcow..." |
| 315 | docker start $(docker ps -aqf name=watchdog-mailcow) |
| 316 | } |
| 317 | |
| 318 | if [[ ${1} == "backup" ]]; then |
| 319 | backup ${@,,} |
| 320 | elif [[ ${1} == "restore" ]]; then |
| 321 | i=1 |
| 322 | declare -A FOLDER_SELECTION |
| 323 | if [[ $(find ${BACKUP_LOCATION}/mailcow-* -maxdepth 1 -type d 2> /dev/null| wc -l) -lt 1 ]]; then |
| 324 | echo "Selected backup location has no subfolders" |
| 325 | exit 1 |
| 326 | fi |
| 327 | for folder in $(ls -d ${BACKUP_LOCATION}/mailcow-*/); do |
| 328 | echo "[ ${i} ] - ${folder}" |
| 329 | FOLDER_SELECTION[${i}]="${folder}" |
| 330 | ((i++)) |
| 331 | done |
| 332 | echo |
| 333 | input_sel=0 |
| 334 | while [[ ${input_sel} -lt 1 || ${input_sel} -gt ${i} ]]; do |
| 335 | read -p "Select a restore point: " input_sel |
| 336 | done |
| 337 | i=1 |
| 338 | echo |
| 339 | declare -A FILE_SELECTION |
| 340 | RESTORE_POINT="${FOLDER_SELECTION[${input_sel}]}" |
| 341 | if [[ -z $(find "${FOLDER_SELECTION[${input_sel}]}" -maxdepth 1 \( -type d -o -type f \) -regex ".*\(redis\|rspamd\|mariadb\|mysql\|crypt\|vmail\|postfix\).*") ]]; then |
| 342 | echo "No datasets found" |
| 343 | exit 1 |
| 344 | fi |
| 345 | |
| 346 | echo "[ 0 ] - all" |
| 347 | # find all files in folder with *.gz extension, print their base names, remove backup_, remove .tar (if present), remove .gz |
| 348 | FILE_SELECTION[0]=$(find "${FOLDER_SELECTION[${input_sel}]}" -maxdepth 1 \( -type d -o -type f \) \( -name '*.gz' -o -name 'mysql' \) -printf '%f\n' | sed 's/backup_*//' | sed 's/\.[^.]*$//' | sed 's/\.[^.]*$//') |
| 349 | for file in $(ls -f "${FOLDER_SELECTION[${input_sel}]}"); do |
| 350 | if [[ ${file} =~ vmail ]]; then |
| 351 | echo "[ ${i} ] - Mail directory (/var/vmail)" |
| 352 | FILE_SELECTION[${i}]="vmail" |
| 353 | ((i++)) |
| 354 | elif [[ ${file} =~ crypt ]]; then |
| 355 | echo "[ ${i} ] - Crypt data" |
| 356 | FILE_SELECTION[${i}]="crypt" |
| 357 | ((i++)) |
| 358 | elif [[ ${file} =~ redis ]]; then |
| 359 | echo "[ ${i} ] - Redis DB" |
| 360 | FILE_SELECTION[${i}]="redis" |
| 361 | ((i++)) |
| 362 | elif [[ ${file} =~ rspamd ]]; then |
| 363 | echo "[ ${i} ] - Rspamd data" |
| 364 | FILE_SELECTION[${i}]="rspamd" |
| 365 | ((i++)) |
| 366 | elif [[ ${file} =~ postfix ]]; then |
| 367 | echo "[ ${i} ] - Postfix data" |
| 368 | FILE_SELECTION[${i}]="postfix" |
| 369 | ((i++)) |
| 370 | elif [[ ${file} =~ mysql ]] || [[ ${file} =~ mariadb ]]; then |
| 371 | echo "[ ${i} ] - SQL DB" |
| 372 | FILE_SELECTION[${i}]="mysql" |
| 373 | ((i++)) |
| 374 | fi |
| 375 | done |
| 376 | echo |
| 377 | input_sel=-1 |
| 378 | while [[ ${input_sel} -lt 0 || ${input_sel} -gt ${i} ]]; do |
| 379 | read -p "Select a dataset to restore: " input_sel |
| 380 | done |
| 381 | echo "Restoring ${FILE_SELECTION[${input_sel}]} from ${RESTORE_POINT}..." |
| 382 | restore "${RESTORE_POINT}" ${FILE_SELECTION[${input_sel}]} |
| 383 | fi |