rsync_backup: Initial version of role
This commit is contained in:
parent
46c41d2d77
commit
3efe44b50b
3 changed files with 206 additions and 0 deletions
150
roles/rsync_backup/files/backup-daily.sh
Executable file
150
roles/rsync_backup/files/backup-daily.sh
Executable file
|
@ -0,0 +1,150 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
umask 077
|
||||
|
||||
ROTATED=30
|
||||
|
||||
CONFDIR="/etc/rsync-backup"
|
||||
DESTDIR="/srv/backup"
|
||||
LOGDIR="/var/log/rsync-backup"
|
||||
RUNDIR="/var/run/rsync-backup"
|
||||
|
||||
find_rotated() {
|
||||
# sort dailys from oldest to newest, daily.7 daily.6 daily.5 ...
|
||||
find "$1" -mindepth 1 -maxdepth 1 -type d -name "daily.*" | sort -V -r
|
||||
}
|
||||
|
||||
rotate_dirs() {
|
||||
for host in "$@"; do
|
||||
# rotate dailys starting from oldest
|
||||
if [ ! -d "${DESTDIR}/${host}" ]; then
|
||||
continue
|
||||
fi
|
||||
find_rotated "${DESTDIR}/${host}" | while read -r dir; do
|
||||
ext="${dir##*.}"
|
||||
next="${dir%.*}.$((ext+1))"
|
||||
mv "$dir" "$next"
|
||||
done
|
||||
done
|
||||
# compress logs over 1 day old
|
||||
find "$LOGDIR" -type f -name '*.log' -mtime +1 -execdir gzip -f {} ';'
|
||||
}
|
||||
|
||||
prune_dirs() {
|
||||
for host in "$@"; do
|
||||
# remove oldest dailys
|
||||
find_rotated "${DESTDIR}/${host}" | while read -r dir ; do
|
||||
num="$(basename "$dir" | sed -e 's/^daily.//')"
|
||||
if [ "$num" -gt $ROTATED ]; then
|
||||
rm -rf "$dir"
|
||||
fi
|
||||
done
|
||||
done
|
||||
# remove logs over ROTATED*2 days old
|
||||
find "$LOGDIR" -type f -name '*.log.gz' -mtime +$((ROTATED*2)) -delete
|
||||
}
|
||||
|
||||
rsync_pull() {
|
||||
dirs=""
|
||||
opts=""
|
||||
host="$1"
|
||||
conf="${CONFDIR}/${host}.conf"
|
||||
if [ -s "$conf" ] && [ -x "$conf" ]; then
|
||||
# shellcheck source=/dev/null
|
||||
. "$conf" || return
|
||||
else
|
||||
echo "skipped: ${1}" 1>&2
|
||||
return
|
||||
fi
|
||||
|
||||
lockdir="${RUNDIR}/${host}.lock"
|
||||
mkdir -m 0755 "$lockdir" || return
|
||||
|
||||
if [ "$host" = "$(hostname)" ]; then
|
||||
# skip ssh for localhost
|
||||
set -- $dirs
|
||||
else
|
||||
set -- $(for d in $dirs; do echo "${host}:${d}" ; done)
|
||||
fi
|
||||
|
||||
base="${DESTDIR}/${host}"
|
||||
if [ ! -d "$base" ]; then
|
||||
mkdir -m 0700 "$base" || return
|
||||
fi
|
||||
dest="${base}/daily.0"
|
||||
last="${base}/daily.1"
|
||||
if [ ! -d "$dest" ]; then
|
||||
mkdir -m 0700 "$dest" || return
|
||||
fi
|
||||
if [ -d "$last" ]; then
|
||||
# hardlink unchanged files to previous daily
|
||||
opts="--ignore-existing --link-dest=${last}"
|
||||
fi
|
||||
|
||||
logfile="${LOGDIR}/${host}.$(date +%Y%m%d-%H%M%S).log"
|
||||
if ! /usr/local/bin/rsync \
|
||||
-e "ssh -o BatchMode=yes -i ${CONFDIR}/id_ed25519" \
|
||||
-Raqxz --no-devices $opts \
|
||||
--log-file="$logfile" \
|
||||
"$@" "$dest"
|
||||
then
|
||||
echo "rsync log: ${logfile}" 1>&2
|
||||
fi
|
||||
rmdir "$lockdir"
|
||||
}
|
||||
|
||||
if [ ! -d "$DESTDIR" ]; then
|
||||
echo "ERROR: ${DESTDIR} does not exist" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -d "$LOGDIR" ]; then
|
||||
echo "ERROR: ${LOGDIR} does not exist" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -d "$RUNDIR" ]; then
|
||||
mkdir -m 0755 "$RUNDIR"
|
||||
fi
|
||||
|
||||
ALL=false
|
||||
PRUNE=false
|
||||
ROTATE=false
|
||||
while getopts "apr" OPT; do
|
||||
case "$OPT" in
|
||||
a)
|
||||
ALL=true
|
||||
;;
|
||||
p)
|
||||
PRUNE=true
|
||||
;;
|
||||
r)
|
||||
ROTATE=true
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $(basename "$0") [-apr] [host ...]" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND-1))
|
||||
|
||||
mkdir -m 0755 "${RUNDIR}/daily.lock"
|
||||
trap 'rmdir "${RUNDIR}/daily.lock"' EXIT
|
||||
|
||||
if [ $ALL ]; then
|
||||
for conf in "${CONFDIR}"/*.conf ; do
|
||||
host="$(basename "$conf" ".conf")"
|
||||
set -- "$host" "$@"
|
||||
done
|
||||
fi
|
||||
|
||||
$ROTATE && rotate_dirs "$@"
|
||||
|
||||
for host in "$@" ; do
|
||||
rsync_pull "$host"
|
||||
done
|
||||
|
||||
$PRUNE && prune_dirs "$@"
|
4
roles/rsync_backup/meta/main.yml
Normal file
4
roles/rsync_backup/meta/main.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
dependencies:
|
||||
- {role: backup_base}
|
||||
- {role: ssh_known_hosts}
|
52
roles/rsync_backup/tasks/main.yml
Normal file
52
roles/rsync_backup/tasks/main.yml
Normal file
|
@ -0,0 +1,52 @@
|
|||
---
|
||||
- name: Copy backup script
|
||||
ansible.builtin.copy:
|
||||
dest: /usr/local/sbin/backup-daily
|
||||
src: backup-daily.sh
|
||||
mode: "0755"
|
||||
owner: root
|
||||
group: "{{ ansible_wheel }}"
|
||||
|
||||
- name: Create config directory
|
||||
ansible.builtin.file:
|
||||
path: /etc/rsync-backup
|
||||
state: directory
|
||||
mode: "0755"
|
||||
owner: root
|
||||
group: "{{ ansible_wheel }}"
|
||||
|
||||
- name: Create logdir
|
||||
ansible.builtin.file:
|
||||
path: /var/log/rsync-backup
|
||||
state: directory
|
||||
mode: "0700"
|
||||
owner: root
|
||||
group: "{{ ansible_wheel }}"
|
||||
|
||||
- name: Create ssh keys
|
||||
ansible.builtin.command:
|
||||
argv:
|
||||
- ssh-keygen
|
||||
- -t
|
||||
- ed25519
|
||||
- -C
|
||||
- "root@{{ inventory_hostname }}"
|
||||
- -N
|
||||
- ""
|
||||
- -f
|
||||
- /etc/rsync-backup/id_ed25519
|
||||
creates: /etc/rsync-backup/id_ed25519
|
||||
|
||||
- name: Fetch ssh public key
|
||||
ansible.builtin.fetch:
|
||||
src: /etc/rsync-backup/id_ed25519.pub
|
||||
dest: ../files/ssh/rsync-backup.pub
|
||||
flat: true
|
||||
|
||||
- name: Install cron job
|
||||
ansible.builtin.cron:
|
||||
name: daily rsync backup
|
||||
job: /usr/local/sbin/backup-daily -a -p -r
|
||||
hour: "00"
|
||||
minute: "30"
|
||||
|
Loading…
Add table
Reference in a new issue