You've already forked proxmox-backup
291 lines
12 KiB
Django/Jinja
291 lines
12 KiB
Django/Jinja
# {{ ansible_managed }}
|
|
#!/bin/bash
|
|
|
|
[ ! -f /usr/bin/proxmox-backup-client ] && echo "proxmox-backup-client is not installed: exiting." && exit 1
|
|
|
|
{% if pbs_random_delay | int > 0 %}
|
|
## random delay to avoid PBS connection flood ##
|
|
delay=$((RANDOM % {{ pbs_random_delay }}))
|
|
echo "Sleeping ${delay}s before starting backup (max delay: {{ pbs_random_delay }}s)..."
|
|
sleep $delay
|
|
## end of random delay ##
|
|
|
|
{% endif %}
|
|
today=`date +%Y-%m-%d`
|
|
backup_dir={{ backup_dir }}
|
|
backup_local_retention={{ backup_local_retention }}
|
|
|
|
### PBS ####
|
|
PBS_RATE={{ pbs_rate | default('60000000') }}
|
|
|
|
export PBS_FINGERPRINT="{{ pbs_fingerprint }}"
|
|
export PBS_PASSWORD="{{ pbs_password }}"
|
|
export PBS_USER="{{ pbs_user }}"
|
|
export PBS_SERVER="{{ pbs_server }}"
|
|
export PBS_DATASTORE="{{ pbs_datastore }}"
|
|
export PBS_REPOSITORY="${PBS_USER}@${PBS_SERVER}:${PBS_DATASTORE}"
|
|
export PBS_LOG="{{ pbs_log_level | default('error') }}"
|
|
|
|
## PBS login ##
|
|
/usr/bin/proxmox-backup-client login
|
|
if [ $? -ne 0 ]; then
|
|
echo "Error on PBS login - exiting."
|
|
exit 1
|
|
fi
|
|
## end of PBS login ##
|
|
|
|
## today symlink ##
|
|
mkdir -p $backup_dir/$today
|
|
ln -sfn $backup_dir/$today $backup_dir/today
|
|
## end of today symlink ##
|
|
|
|
## audit ##
|
|
mkdir -p $backup_dir/$today/audit
|
|
|
|
/usr/bin/tar cfz $backup_dir/$today/audit/crontab.tgz -C /var/spool/cron/ crontabs/
|
|
/usr/bin/dpkg -l > $backup_dir/$today/audit/dpkg.txt
|
|
[ -f /sbin/iptables ] && /sbin/iptables -L -n > $backup_dir/$today/audit/firewall.txt
|
|
[ -f /sbin/iptables ] && /sbin/iptables -L -n -t nat > $backup_dir/$today/audit/firewall_nat.txt
|
|
[ -f /sbin/ip6tables ] && /sbin/ip6tables -L -n > $backup_dir/$today/audit/firewall6.txt
|
|
[ -f /sbin/ip6tables ] && /sbin/ip6tables -L -n -t nat > $backup_dir/$today/audit/firewall6_nat.txt
|
|
[ -f /usr/bin/pstree ] && /usr/bin/pstree > $backup_dir/$today/audit/pstree.txt
|
|
/bin/ps faux > $backup_dir/$today/audit/ps.txt
|
|
/bin/systemctl list-units > $backup_dir/$today/audit/systemctl_unit.txt
|
|
/usr/bin/getent passwd > $backup_dir/$today/audit/users.txt
|
|
[ -f /usr/bin/pvs ] && /usr/sbin/pvs > $backup_dir/$today/audit/pvs.txt
|
|
[ -f /usr/bin/vgs ] && /usr/sbin/vgs > $backup_dir/$today/audit/vgs.txt
|
|
[ -f /usr/bin/lvs ] && /usr/sbin/lvs > $backup_dir/$today/audit/lvs.txt
|
|
|
|
for dev in /sys/block/*; do
|
|
dev=$(basename $dev)
|
|
if test -b /dev/$dev && file -s /dev/$dev | egrep -q 'partition table|boot sector'; then
|
|
/usr/sbin/sfdisk -d /dev/$dev >> $backup_dir/$today/audit/partition-table_$dev.txt
|
|
fi
|
|
done
|
|
## end of audit ##
|
|
|
|
{% if backup_mysql_enabled is sameas true %}
|
|
## mysql ##
|
|
backup_mysql_host="{{ backup_mysql_host | default('') }}"
|
|
backup_mysql_user="{{ backup_mysql_user | default('') }}"
|
|
backup_mysql_password="{{ backup_mysql_password | default('') }}"
|
|
backup_mysql_docker_enabled="{{ (backup_mysql_docker_enabled | default(false)) | ternary('true', 'false') }}"
|
|
backup_mysql_docker_container="{{ backup_mysql_docker_container | default('') }}"
|
|
|
|
mysql_cmd=(/usr/bin/mysql)
|
|
mysqldump_cmd=(/usr/bin/mysqldump)
|
|
|
|
if [ "$backup_mysql_docker_enabled" = "true" ]; then
|
|
if [ -z "$backup_mysql_docker_container" ]; then
|
|
echo "MySQL Docker mode enabled but container name is empty: exiting."
|
|
exit 1
|
|
fi
|
|
mysql_cmd=(/usr/bin/docker exec -i "$backup_mysql_docker_container" mysql)
|
|
mysqldump_cmd=(/usr/bin/docker exec -i "$backup_mysql_docker_container" mysqldump)
|
|
fi
|
|
|
|
mysql_connection_args=()
|
|
[ -n "$backup_mysql_host" ] && mysql_connection_args+=("--host=$backup_mysql_host")
|
|
[ -n "$backup_mysql_user" ] && mysql_connection_args+=("--user=$backup_mysql_user")
|
|
[ -n "$backup_mysql_password" ] && mysql_connection_args+=("--password=$backup_mysql_password")
|
|
|
|
mysql_databases=$("${mysql_cmd[@]}" "${mysql_connection_args[@]}" -e "SHOW DATABASES;" | grep -Ev "(Database|information_schema|performance_schema)")
|
|
|
|
mkdir -p $backup_dir/$today/mysql
|
|
|
|
for db in $mysql_databases;
|
|
do "${mysqldump_cmd[@]}" "${mysql_connection_args[@]}" -e -q -Q --single-transaction --routines --events --triggers "$db" | gzip -c > $backup_dir/$today/mysql/dump_$db.sql.gz;
|
|
done
|
|
## end of mysql ##
|
|
{% endif %}
|
|
|
|
{% if backup_mariadb_enabled is sameas true %}
|
|
## mariadb ##
|
|
backup_mariadb_host="{{ backup_mariadb_host | default('') }}"
|
|
backup_mariadb_user="{{ backup_mariadb_user | default('') }}"
|
|
backup_mariadb_password="{{ backup_mariadb_password | default('') }}"
|
|
backup_mariadb_docker_enabled="{{ (backup_mariadb_docker_enabled | default(false)) | ternary('true', 'false') }}"
|
|
backup_mariadb_docker_container="{{ backup_mariadb_docker_container | default('') }}"
|
|
|
|
mariadb_cmd=(/usr/bin/mariadb)
|
|
mariadbdump_cmd=(/usr/bin/mariadb-dump)
|
|
|
|
if [ "$backup_mariadb_docker_enabled" = "true" ]; then
|
|
if [ -z "$backup_mariadb_docker_container" ]; then
|
|
echo "MariaDB Docker mode enabled but container name is empty: exiting."
|
|
exit 1
|
|
fi
|
|
mariadb_cmd=(/usr/bin/docker exec -i "$backup_mariadb_docker_container" mariadb)
|
|
mariadbdump_cmd=(/usr/bin/docker exec -i "$backup_mariadb_docker_container" mariadb-dump)
|
|
fi
|
|
|
|
mariadb_connection_args=()
|
|
[ -n "$backup_mariadb_host" ] && mariadb_connection_args+=("--host=$backup_mariadb_host")
|
|
[ -n "$backup_mariadb_user" ] && mariadb_connection_args+=("--user=$backup_mariadb_user")
|
|
[ -n "$backup_mariadb_password" ] && mariadb_connection_args+=("--password=$backup_mariadb_password")
|
|
|
|
mariadb_databases=$("${mariadb_cmd[@]}" "${mariadb_connection_args[@]}" -e "SHOW DATABASES;" | grep -Ev "(Database|information_schema|performance_schema)")
|
|
|
|
mkdir -p $backup_dir/$today/mariadb
|
|
|
|
for db in $mariadb_databases;
|
|
do "${mariadbdump_cmd[@]}" "${mariadb_connection_args[@]}" -e -q -Q --single-transaction --routines --events --triggers "$db" | gzip -c > $backup_dir/$today/mariadb/dump_$db.sql.gz;
|
|
done
|
|
## end of mariadb ##
|
|
{% endif %}
|
|
|
|
{% if backup_pgsql_enabled is sameas true %}
|
|
## postgresql ##
|
|
pg_port={{ backup_pg_port | default('5432') }}
|
|
mkdir -p $backup_dir/$today/postgresql
|
|
backup_pg_host="{{ backup_pg_host | default('') }}"
|
|
backup_pg_user="{{ backup_pg_user | default('') }}"
|
|
backup_pg_password="{{ backup_pg_password | default('') }}"
|
|
backup_pg_docker_enabled="{{ (backup_pg_docker_enabled | default(false)) | ternary('true', 'false') }}"
|
|
backup_pg_docker_container="{{ backup_pg_docker_container | default('') }}"
|
|
|
|
if [ "$backup_pg_docker_enabled" = "true" ]; then
|
|
if [ -z "$backup_pg_docker_container" ]; then
|
|
echo "PostgreSQL Docker mode enabled but container name is empty: exiting."
|
|
exit 1
|
|
fi
|
|
|
|
pg_connection_args=("-p" "$pg_port")
|
|
[ -n "$backup_pg_host" ] && pg_connection_args+=("-h" "$backup_pg_host")
|
|
[ -n "$backup_pg_user" ] && pg_connection_args+=("-U" "$backup_pg_user")
|
|
|
|
if [ -n "$backup_pg_password" ]; then
|
|
pg_databases=$(/usr/bin/docker exec -e PGPASSWORD="$backup_pg_password" -i "$backup_pg_docker_container" psql "${pg_connection_args[@]}" -At -c "SELECT datname FROM pg_database WHERE datistemplate = false;")
|
|
else
|
|
pg_databases=$(/usr/bin/docker exec -i "$backup_pg_docker_container" psql "${pg_connection_args[@]}" -At -c "SELECT datname FROM pg_database WHERE datistemplate = false;")
|
|
fi
|
|
|
|
for db in $pg_databases; do
|
|
if [ -n "$backup_pg_password" ]; then
|
|
/usr/bin/docker exec -e PGPASSWORD="$backup_pg_password" -i "$backup_pg_docker_container" pg_dump "${pg_connection_args[@]}" -Z9 -Fc -b "$db" > "$backup_dir/$today/postgresql/dump_$db.sql"
|
|
else
|
|
/usr/bin/docker exec -i "$backup_pg_docker_container" pg_dump "${pg_connection_args[@]}" -Z9 -Fc -b "$db" > "$backup_dir/$today/postgresql/dump_$db.sql"
|
|
fi
|
|
done
|
|
|
|
if [ -n "$backup_pg_password" ]; then
|
|
/usr/bin/docker exec -e PGPASSWORD="$backup_pg_password" -i "$backup_pg_docker_container" pg_dumpall "${pg_connection_args[@]}" --roles-only > "$backup_dir/$today/postgresql/role.sql"
|
|
else
|
|
/usr/bin/docker exec -i "$backup_pg_docker_container" pg_dumpall "${pg_connection_args[@]}" --roles-only > "$backup_dir/$today/postgresql/role.sql"
|
|
fi
|
|
elif [ -n "$backup_pg_host" ] || [ -n "$backup_pg_user" ] || [ -n "$backup_pg_password" ]; then
|
|
pg_connection_args=("-p" "$pg_port")
|
|
[ -n "$backup_pg_host" ] && pg_connection_args+=("-h" "$backup_pg_host")
|
|
[ -n "$backup_pg_user" ] && pg_connection_args+=("-U" "$backup_pg_user")
|
|
|
|
if [ -n "$backup_pg_password" ]; then
|
|
export PGPASSWORD="$backup_pg_password"
|
|
fi
|
|
|
|
pg_databases=$(/usr/bin/psql "${pg_connection_args[@]}" -At -c "SELECT datname FROM pg_database WHERE datistemplate = false;")
|
|
|
|
for db in $pg_databases; do
|
|
/usr/bin/pg_dump "${pg_connection_args[@]}" -Z9 -Fc -b -f "$backup_dir/$today/postgresql/dump_$db.sql" "$db"
|
|
done
|
|
|
|
/usr/bin/pg_dumpall "${pg_connection_args[@]}" --roles-only > "$backup_dir/$today/postgresql/role.sql"
|
|
|
|
if [ -n "$backup_pg_password" ]; then
|
|
unset PGPASSWORD
|
|
fi
|
|
else
|
|
chown -R postgres: $backup_dir/$today/postgresql
|
|
|
|
pg_databases=`sudo su - postgres -c "/usr/bin/psql -p $pg_port -t -c 'SELECT datname FROM pg_database'"|grep -v "template0"`
|
|
|
|
for db in $pg_databases;
|
|
do sudo su - postgres -c "/usr/bin/pg_dump -p $pg_port -Z9 -Fc -b -f $backup_dir/$today/postgresql/dump_$db.sql $db";
|
|
done
|
|
|
|
sudo su - postgres -c "/usr/bin/pg_dumpall --roles-only > $backup_dir/$today/postgresql/role.sql"
|
|
fi
|
|
## end of postresql ##
|
|
{% endif %}
|
|
|
|
{% if backup_gitea_enabled is sameas true %}
|
|
## gitea ##
|
|
backup_gitea_config="{{ backup_gitea_config | default('/data/gitea/conf/app.ini') }}"
|
|
backup_gitea_docker_enabled="{{ (backup_gitea_docker_enabled | default(false)) | ternary('true', 'false') }}"
|
|
backup_gitea_docker_container="{{ backup_gitea_docker_container | default('') }}"
|
|
|
|
mkdir -p "$backup_dir/$today/gitea"
|
|
|
|
if [ "$backup_gitea_docker_enabled" = "true" ]; then
|
|
if [ -z "$backup_gitea_docker_container" ]; then
|
|
echo "Gitea Docker mode enabled but container name is empty: exiting."
|
|
exit 1
|
|
fi
|
|
|
|
/usr/bin/docker exec -u git -w /tmp gitea bash -c '/usr/local/bin/gitea dump -c "$backup_gitea_config" -q --type tar.gz -f -' > "$backup_dir/$today/gitea/gitea-dump.tar.gz"
|
|
|
|
else
|
|
sudo su -s /bin/bash - git -c "cd $backup_dir/$today/gitea && /usr/local/bin/gitea dump -c \"$backup_gitea_config\" -q --type tar.gz"
|
|
fi
|
|
## end of gitea ##
|
|
{% endif %}
|
|
|
|
{% if backup_sshportal_enabled is sameas true %}
|
|
## sshportal ##
|
|
backup_sshportal_db_path="{{ backup_sshportal_db_path | default('/var/lib/docker/volumes/sshportal__var_lib_sshportal/_data/sshportal.db') }}"
|
|
backup_sshportal_ssh_host="{{ backup_sshportal_ssh_host | default('localhost') }}"
|
|
backup_sshportal_ssh_port="{{ backup_sshportal_ssh_port | default('2222') }}"
|
|
backup_sshportal_ssh_user="{{ backup_sshportal_ssh_user | default('admin') }}"
|
|
backup_sshportal_ssh_key="{{ backup_sshportal_ssh_key | default('/opt/docker-compose/sshportal/ed25519_sshportal_admin') }}"
|
|
|
|
mkdir -p "$backup_dir/$today/sshportal"
|
|
|
|
/usr/bin/sqlite3 "$backup_sshportal_db_path" .dump > "$backup_dir/$today/sshportal/sshportal.sql.bkp"
|
|
|
|
/usr/bin/ssh -i "$backup_sshportal_ssh_key" -p "$backup_sshportal_ssh_port" -l "$backup_sshportal_ssh_user" "$backup_sshportal_ssh_host" config backup > "$backup_dir/$today/sshportal/backup.json"
|
|
## end of sshportal ##
|
|
{% endif %}
|
|
|
|
# purge old backups
|
|
find $backup_dir -maxdepth 1 -mindepth 1 -type d -mtime +$backup_local_retention -exec rm -rf {} \;
|
|
|
|
## send to PBS ##
|
|
/usr/bin/proxmox-backup-client backup \
|
|
{% if backup_host_id is defined %}
|
|
--backup-id {{ backup_host_id }} \
|
|
{% endif %}
|
|
{% if backup_exclude is defined %}
|
|
{% for item in backup_exclude %}
|
|
--exclude {{ item }} \
|
|
{% endfor %}
|
|
{% endif %}
|
|
etc.pxar:/etc \
|
|
audit.pxar:$backup_dir/$today/audit \
|
|
{% if backup_path_include is defined %}
|
|
{% for item in backup_path_include %}
|
|
{{ item | regex_replace('^/', '') | replace('/', '_') }}.pxar:{{ item }} \
|
|
{% endfor %}
|
|
{% endif %}
|
|
{% if backup_pgsql_enabled is sameas true %}
|
|
postgresql.pxar:$backup_dir/$today/postgresql \
|
|
{% endif %}
|
|
{% if backup_mysql_enabled is sameas true %}
|
|
mysql.pxar:$backup_dir/$today/mysql \
|
|
{% endif %}
|
|
{% if backup_mariadb_enabled is sameas true %}
|
|
mariadb.pxar:$backup_dir/$today/mariadb \
|
|
{% endif %}
|
|
{% if backup_gitea_enabled is sameas true %}
|
|
gitea.pxar:$backup_dir/$today/gitea \
|
|
{% endif %}
|
|
{% if backup_sshportal_enabled is sameas true %}
|
|
sshportal.pxar:$backup_dir/$today/sshportal \
|
|
{% endif %}
|
|
--rate ${PBS_RATE}
|
|
## end of send to PBS ##
|
|
|
|
## PBS logout ##
|
|
# not working at this time, script end with "Error: $XDG_RUNTIME_DIR must be set"
|
|
#/usr/bin/proxmox-backup-client logout
|
|
## end of PBS logout ##
|
|
|