Files
multiarch-docker-images/restic-auto/restic-auto
2020-04-25 16:07:15 +02:00

110 lines
4.6 KiB
Bash
Executable File

#!/bin/bash
# Backup one directory
function backup_dir {
# Check if the dir to backup is mounted as a subdirectory of /root inside this container
if [ -d "/root_fs$1" ]; then
restic backup /root_fs$1
return $?
else
echo "[ERROR] Directory $1 not found. Have you mounted the root fs from your host with the following option : '-v /:/root_fs:ro' ?"
return -1
fi
}
# Backup one file
function backup_file {
cat $1 | restic backup --stdin --stdin-filename $2
return $?
}
# Firt, check the repository is unlocked and try to unlock it
if [ "$(restic --no-lock list locks -q)" != "" ]; then
echo "[INFO] Repository locked, trying to unlock"
restic unlock
if [ $? -ne 0 ]; then
echo "[ERROR] Could not unlock repository"
return -1
fi
fi
count_success=0
count_failure=0
# List all the containers
containers=$(curl -s --unix-socket /var/run/docker.sock http:/v1.26/containers/json)
for container_id in $(echo $containers | jq ".[].Id") ; do
container=$(echo $containers | jq -c ".[] | select(.Id==$container_id)")
# Get the name and namespace (in case of a container run in a swarm stack)
container_name=$(echo $container | jq -r ".Names | .[0]" | cut -d'.' -f1 | cut -d'/' -f2)
namespace=$(echo $container | jq -r ".Labels | .[\"com.docker.stack.namespace\"]")
# Backup the dirs labelled with "napnap75.backup.dirs"
if $(echo $container | jq ".Labels | has(\"napnap75.backup.dirs\")") ; then
for dir_name in $(echo $container | jq -r ".Labels | .[\"napnap75.backup.dirs\"]") ; do
echo "[INFO] Backing up dir" $dir_name "for container" $container_name
backup_dir $dir_name
if [ $? -ne 0 ]; then
((++count_failure))
else
((++count_success))
fi
done
fi
# Backup the volumes labelled with "napnap75.backup.volumes"
if $(echo $container | jq ".Labels | has(\"napnap75.backup.volumes\")") ; then
for volume_name in $(echo $container | jq -r ".Labels | .[\"napnap75.backup.volumes\"]") ; do
if [ $namespace != "null" ] ; then volume_name="${namespace}_${volume_name}" ; fi
volume_mount=$(echo $container | jq -r ".Mounts[] | select(.Name==\"$volume_name\") | .Source")
echo "[INFO] Backing up volume" $volume_name "with mount" $volume_mount "for container" $container_name
backup_dir $volume_mount
if [ $? -ne 0 ]; then
((++count_failure))
else
((++count_success))
fi
done
fi
# Backup the databases labelled with "napnap75.backup.databases"
if $(echo $container | jq ".Labels | has(\"napnap75.backup.databases\")") ; then
container_id=$(echo $container_id | sed "s/\"//g")
database_password=$(curl -s --unix-socket /var/run/docker.sock http:/v1.26/containers/$container_id/json | jq -r ".Config.Env[] | match(\"MYSQL_ROOT_PASSWORD=(.*)\") | .captures[0].string")
for database_name in $(echo $container | jq -r ".Labels | .[\"napnap75.backup.databases\"]") ; do
echo "[INFO] Backing up database" $database_name "for container" $container_name
if [[ "$database_password" != "" ]] ; then
exec_id=$(curl -s --unix-socket /var/run/docker.sock -X POST -H "Content-Type: application/json" -d '{"AttachStdout":true,"AttachStderr":true,"Tty":true,"Cmd":["/bin/bash", "-c", "mysqldump -p'$database_password' --databases '$database_name'"]}' http:/v1.26/containers/$container_id/exec | jq ".Id" | sed "s/\"//g")
else
exec_id=$(curl -s --unix-socket /var/run/docker.sock -X POST -H "Content-Type: application/json" -d '{"AttachStdout":true,"AttachStderr":true,"Tty":true,"Cmd":["/bin/bash", "-c", "mysqldump --databases '$database_name'"]}' http:/v1.26/containers/$container_id/exec | jq ".Id" | sed "s/\"//g")
fi
curl -s --unix-socket /var/run/docker.sock -X POST -H "Content-Type: application/json" -d '{"Detach":false,"Tty":false}' http:/v1.26/exec/$exec_id/start | gzip > /tmp/database_backup.gz
exit_code=$(curl -s --unix-socket /var/run/docker.sock http:/v1.26/exec/$exec_id/json | jq ".ExitCode")
if [ $exit_code -ne 0 ]; then
echo "[ERROR] Unable to backup database $database_name from container $container_name"
cat /tmp/database_backup.gz | gzip -d
((++count_failure))
else
backup_file /tmp/database_backup.gz ${container_name}${database_name}.sql.gz
if [ $? -ne 0 ]; then
((++count_failure))
else
((++count_success))
fi
fi
rm /tmp/database_backup.gz
done
fi
done
# Send a notification to Slack
if [[ "$SLACK_URL" != "" ]] ; then
curl -s -X POST --data-urlencode "payload={\"username\": \"rpi-docker-backup\", \"icon_emoji\": \":dvd:\", \"text\": \"Backup finished on host $HOSTNAME : $count_success succeeded, $count_failure failed\"}" $SLACK_URL
fi
# Return a non zero exit code if an error happened
if [ $count_failure -ne 0 ]; then
exit -1
fi