From 0545edaa1a7f1c6a9b03acec380febb377ab2edd Mon Sep 17 00:00:00 2001 From: NUZAT-TABASSUM Date: Mon, 14 Jul 2025 16:56:18 +0200 Subject: [PATCH 1/6] adding database backup configuration for multiple database --- README.md | 4 +- defaults/main.yml | 12 +++++- molecule/default/converge.yml | 2 +- molecule/default/verify.yml | 58 +++++++++++++++++++++++++++- tasks/backup.yml | 51 ++++++++++++++++++++++++ tasks/main.yml | 18 +++++++++ templates/database-backup.service.j2 | 15 +++++++ templates/database-backup.sh.j2 | 25 ++++++++++++ templates/database-backup.timer.j2 | 10 +++++ 9 files changed, 190 insertions(+), 5 deletions(-) create mode 100644 tasks/backup.yml create mode 100644 templates/database-backup.service.j2 create mode 100644 templates/database-backup.sh.j2 create mode 100644 templates/database-backup.timer.j2 diff --git a/README.md b/README.md index 3fe74c5b2..f2edd6479 100644 --- a/README.md +++ b/README.md @@ -18,10 +18,10 @@ Role Variables -------------- - `opencast_postgresql_version` - - PostgreSQL major version to install (default: `12`) + - PostgreSQL major version to install (default: `16`) - Enables CentOS AppStream - `opencast_postgresql_user:` - - Database user to create (default: `opencast`) + - Database user to create (default: `postgres`) - `opencast_postgresql_password` - Databse password for user (_required_) - `opencast_postgresql_database` diff --git a/defaults/main.yml b/defaults/main.yml index 74bd42ffc..81279dc19 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -1,8 +1,18 @@ --- opencast_postgresql_version: 16 -opencast_postgresql_user: opencast +opencast_postgresql_user: postgres opencast_postgresql_database: opencast opencast_postgresql_connection_hosts: - 127.0.0.1/32 - ::1/128 + +# === Database backup feature (disabled by default) === + +database_backup_enabled: false +database_backup_output_path: None # e.g. /var/backups/postgresql +database_backup_schedule: "*-*-* 05:00:00" # Systemd OnCalendar format +database_backup_keep: 7 # number of dumps to retain per DB +database_backup_dbs: [] # list of database names to dump +database_backup_owner: postgres +database_backup_group: postgres diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml index 23b7512f6..0223844f2 100644 --- a/molecule/default/converge.yml +++ b/molecule/default/converge.yml @@ -2,6 +2,6 @@ - name: Converge hosts: all tasks: - - name: "Include opencast_postgresql" + - name: Include opencast_postgresql ansible.builtin.include_role: name: elan.opencast_postgresql diff --git a/molecule/default/verify.yml b/molecule/default/verify.yml index 39690b1ed..a9480ed6f 100644 --- a/molecule/default/verify.yml +++ b/molecule/default/verify.yml @@ -1,11 +1,14 @@ --- -- name: Verify PostgreSQL Installation +- name: Verify PostgreSQL & Backup Configuration hosts: all gather_facts: true vars_files: - ../../defaults/main.yml tasks: + # ─────────────────────────────────────────────────────────── + # Basic PostgreSQL installation + # ─────────────────────────────────────────────────────────── - name: Ensure PostgreSQL service is running on RedHat/CentOS ansible.builtin.systemd: name: "postgresql-{{ opencast_postgresql_version }}" @@ -39,3 +42,56 @@ ansible.builtin.debug: msg: "PostgreSQL version on {{ inventory_hostname }} (Debian): {{ psql_version_debian.stdout }}" when: ansible_os_family == "Debian" + # ─────────────────────────────────────────────────────────── + # Backup configuration (only when enabled) + # ─────────────────────────────────────────────────────────── + - block: + - name: Assert backups are enabled + ansible.builtin.assert: + that: + - database_backup_enabled | default(false) + fail_msg: "Backups are disabled; skipping backup verification." + + - name: Ensure backup directory exists + ansible.builtin.stat: + path: "{{ database_backup_output_path }}" + register: backup_dir_stat + + - name: Assert backup directory is present and writable + ansible.builtin.assert: + that: + - backup_dir_stat.stat.exists + - backup_dir_stat.stat.isdir + fail_msg: > + Backup directory {{ database_backup_output_path }} is missing, + not a directory + + - name: Check database-backup.service is installed and enabled + ansible.builtin.systemd: + name: database-backup.service + enabled: true + state: started + + - name: Check database-backup.timer is installed and enabled + ansible.builtin.systemd: + name: database-backup.timer + enabled: true + state: started + + - name: Slurp timer unit file for inspection + ansible.builtin.slurp: + path: /etc/systemd/system/database-backup.timer + register: timer_unit + + - name: Assert OnCalendar line in timer unit matches schedule + ansible.builtin.assert: + that: + - "'OnCalendar={{ database_backup_schedule }}' in (timer_unit.content | b64decode)" + fail_msg: > + database-backup.timer does not contain + OnCalendar={{ database_backup_schedule }}. + success_msg: > + Timer unit file correctly contains + OnCalendar={{ database_backup_schedule }}. + + when: database_backup_enabled | default(false) diff --git a/tasks/backup.yml b/tasks/backup.yml new file mode 100644 index 000000000..d65a0e437 --- /dev/null +++ b/tasks/backup.yml @@ -0,0 +1,51 @@ +--- +- name: Fail if backup enabled but no output path given + ansible.builtin.fail: + msg: "database_backup_output_path must be set when database_backup_enabled = true" + when: + - database_backup_enabled + - database_backup_output_path | length == 0 + +- name: Ensure backup output directory exists + ansible.builtin.file: + path: "{{ database_backup_output_path }}" + state: directory + owner: "{{ database_backup_owner }}" + group: "{{ database_backup_group }}" + mode: "0750" + when: database_backup_enabled + +- name: Install backup script + ansible.builtin.template: + src: database-backup.sh.j2 + dest: "{{ database_backup_output_path }}/database-backup.sh" + owner: "{{ database_backup_owner }}" + group: "{{ database_backup_group }}" + mode: "0750" + when: database_backup_enabled + +- name: Install systemd service unit + ansible.builtin.template: + src: database-backup.service.j2 + dest: /etc/systemd/system/database-backup.service + mode: "0644" + when: database_backup_enabled + +- name: Install systemd timer unit + ansible.builtin.template: + src: database-backup.timer.j2 + dest: /etc/systemd/system/database-backup.timer + mode: "0644" + when: database_backup_enabled + +- name: Reload systemd daemon (if timers changed) + ansible.builtin.systemd: + daemon_reload: true + when: database_backup_enabled + +- name: Ensure backup timer is enabled and running + ansible.builtin.systemd: + name: database-backup.timer + enabled: true + state: started + when: database_backup_enabled diff --git a/tasks/main.yml b/tasks/main.yml index f999592c4..236fb1a28 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -2,6 +2,17 @@ ############################################################################### # CentOS / RHEL ############################################################################### +# ── CentOS Stream 9 has frequent mirrorlist outages in CI ────────────── +# - name: CentOS-Stream | pin baseos/appstream/extras to vault.centos.org +# ansible.builtin.shell: | +# dnf -y config-manager \ +# --setopt={{ item }}.baseurl=https://vault.centos.org/9-stream/{{ item }}/$basearch/os \ +# --setopt={{ item }}.mirrorlist= \ +# --save +# loop: [ baseos, appstream, extras ] +# when: ansible_distribution == "CentOS Stream" +# changed_when: false # idempotent, no facts modified +# # ─────────────────────────────────────────────────────────────────────── - name: Install PostgreSQL PGDG repository (CentOS/RHEL) ansible.builtin.dnf: @@ -145,3 +156,10 @@ community.postgresql.postgresql_db: name: "{{ opencast_postgresql_database }}" owner: "{{ opencast_postgresql_user }}" + +############################################################################### +# database backup +############################################################################### +- name: Include backup setup tasks + ansible.builtin.include_tasks: backup.yml + when: database_backup_enabled diff --git a/templates/database-backup.service.j2 b/templates/database-backup.service.j2 new file mode 100644 index 000000000..7f25ace8d --- /dev/null +++ b/templates/database-backup.service.j2 @@ -0,0 +1,15 @@ +[Unit] +Description=Opencast Database Backup +After=network.target +After=local-fs.target +After=remote-fs.target + +[Service] +Type=oneshot +User={{ database_backup_owner }} +Group={{ database_backup_group }} +ExecStart={{ database_backup_output_path }}/database-backup.sh + +[Install] +WantedBy=multi-user.target + diff --git a/templates/database-backup.sh.j2 b/templates/database-backup.sh.j2 new file mode 100644 index 000000000..220e4cef2 --- /dev/null +++ b/templates/database-backup.sh.j2 @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +# DATABASE="{{ opencast_postgresql_database }}" +DBUSER="{{ database_backup_owner }}" +OUTDIR="{{ database_backup_output_path }}" +KEEP={{ database_backup_keep }} +DBS=( {{ database_backup_dbs | join(" ") }} ) +TS=$(date +%Y%m%d-%H%M%S) + +# Export PostgreSQL password so pg_dump doesn't prompt +export PGPASSWORD="{{opencast_postgresql_password}}" + +# Loop through each database name +for DB in "${DBS[@]}"; do + echo "Backing up $DB → $OUTDIR/db-backup-${DB}-${TS}.dump.gz" + + # Run pg_dump and compress into a .gz file + pg_dump -F c "$DB" \ + | gzip > "${OUTDIR}/db-backup-${DB}-${TS}.dump.gz" + + # Remove older dumps, keep only the newest $KEEP + ls -1t "${OUTDIR}/db-backup-${DB}-"*.dump.gz \ + | tail -n +$((KEEP + 1)) \ + | xargs -r rm -- +done \ No newline at end of file diff --git a/templates/database-backup.timer.j2 b/templates/database-backup.timer.j2 new file mode 100644 index 000000000..42355bdda --- /dev/null +++ b/templates/database-backup.timer.j2 @@ -0,0 +1,10 @@ +[Unit] +Description=Run database backup daily + +[Timer] +OnCalendar={{ database_backup_schedule }} +Persistent=true + +[Install] +WantedBy=timers.target + From 255f428b01130b979fcfb178b726658ad512693e Mon Sep 17 00:00:00 2001 From: NUZAT-TABASSUM Date: Mon, 14 Jul 2025 17:01:17 +0200 Subject: [PATCH 2/6] adding database backup configuration for multiple databases --- defaults/main.yml | 2 +- tasks/main.yml | 14 -------------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/defaults/main.yml b/defaults/main.yml index 81279dc19..5bded556b 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -10,7 +10,7 @@ opencast_postgresql_connection_hosts: # === Database backup feature (disabled by default) === database_backup_enabled: false -database_backup_output_path: None # e.g. /var/backups/postgresql +database_backup_output_path: None database_backup_schedule: "*-*-* 05:00:00" # Systemd OnCalendar format database_backup_keep: 7 # number of dumps to retain per DB database_backup_dbs: [] # list of database names to dump diff --git a/tasks/main.yml b/tasks/main.yml index 236fb1a28..c7e44eba9 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -1,18 +1,4 @@ --- -############################################################################### -# CentOS / RHEL -############################################################################### -# ── CentOS Stream 9 has frequent mirrorlist outages in CI ────────────── -# - name: CentOS-Stream | pin baseos/appstream/extras to vault.centos.org -# ansible.builtin.shell: | -# dnf -y config-manager \ -# --setopt={{ item }}.baseurl=https://vault.centos.org/9-stream/{{ item }}/$basearch/os \ -# --setopt={{ item }}.mirrorlist= \ -# --save -# loop: [ baseos, appstream, extras ] -# when: ansible_distribution == "CentOS Stream" -# changed_when: false # idempotent, no facts modified -# # ─────────────────────────────────────────────────────────────────────── - name: Install PostgreSQL PGDG repository (CentOS/RHEL) ansible.builtin.dnf: From e44170551674e09802caa6a24cabe592a76f5bbf Mon Sep 17 00:00:00 2001 From: NUZAT-TABASSUM Date: Mon, 14 Jul 2025 17:22:18 +0200 Subject: [PATCH 3/6] fix lint issue --- .github/workflows/lint.yml | 1 + .github/workflows/molecule.yml | 1 + defaults/main.yml | 8 +++----- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 8a80fa3c0..880e509d6 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -19,3 +19,4 @@ jobs: - run: yamllint --strict -c .yamllint . - run: ansible-lint + diff --git a/.github/workflows/molecule.yml b/.github/workflows/molecule.yml index 1ed464366..5eee674b2 100644 --- a/.github/workflows/molecule.yml +++ b/.github/workflows/molecule.yml @@ -20,3 +20,4 @@ jobs: run: molecule test -- -e opencast_postgresql_password=123 env: PY_COLORS: '1' + diff --git a/defaults/main.yml b/defaults/main.yml index 5bded556b..594ae6af9 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -1,5 +1,4 @@ --- - opencast_postgresql_version: 16 opencast_postgresql_user: postgres opencast_postgresql_database: opencast @@ -8,11 +7,10 @@ opencast_postgresql_connection_hosts: - ::1/128 # === Database backup feature (disabled by default) === - database_backup_enabled: false -database_backup_output_path: None +database_backup_output_path: None database_backup_schedule: "*-*-* 05:00:00" # Systemd OnCalendar format -database_backup_keep: 7 # number of dumps to retain per DB -database_backup_dbs: [] # list of database names to dump +database_backup_keep: 7 +database_backup_dbs: [] database_backup_owner: postgres database_backup_group: postgres From 64d3d9b6ea2ede2bda86c667edb5dde92a5b36ab Mon Sep 17 00:00:00 2001 From: NUZAT-TABASSUM Date: Mon, 14 Jul 2025 17:26:46 +0200 Subject: [PATCH 4/6] fix lint issue --- molecule/default/verify.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/molecule/default/verify.yml b/molecule/default/verify.yml index a9480ed6f..0e74bb2c6 100644 --- a/molecule/default/verify.yml +++ b/molecule/default/verify.yml @@ -45,7 +45,8 @@ # ─────────────────────────────────────────────────────────── # Backup configuration (only when enabled) # ─────────────────────────────────────────────────────────── - - block: + - name: Verify backup configuration when enabled + block: - name: Assert backups are enabled ansible.builtin.assert: that: @@ -94,4 +95,4 @@ Timer unit file correctly contains OnCalendar={{ database_backup_schedule }}. - when: database_backup_enabled | default(false) + when: database_backup_enabled | default(false) From e824b0ce899bd273a468eba23009ef8e0c6f5ef9 Mon Sep 17 00:00:00 2001 From: NUZAT-TABASSUM Date: Mon, 14 Jul 2025 17:29:58 +0200 Subject: [PATCH 5/6] fix lint error --- molecule/default/verify.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/molecule/default/verify.yml b/molecule/default/verify.yml index 0e74bb2c6..4ca415fed 100644 --- a/molecule/default/verify.yml +++ b/molecule/default/verify.yml @@ -7,7 +7,7 @@ tasks: # ─────────────────────────────────────────────────────────── - # Basic PostgreSQL installation + # Basic PostgreSQL installation # ─────────────────────────────────────────────────────────── - name: Ensure PostgreSQL service is running on RedHat/CentOS ansible.builtin.systemd: @@ -42,11 +42,12 @@ ansible.builtin.debug: msg: "PostgreSQL version on {{ inventory_hostname }} (Debian): {{ psql_version_debian.stdout }}" when: ansible_os_family == "Debian" + # ─────────────────────────────────────────────────────────── # Backup configuration (only when enabled) # ─────────────────────────────────────────────────────────── - - name: Verify backup configuration when enabled - block: + - name: Verify backup configuration when enabled + block: - name: Assert backups are enabled ansible.builtin.assert: that: @@ -64,8 +65,8 @@ - backup_dir_stat.stat.exists - backup_dir_stat.stat.isdir fail_msg: > - Backup directory {{ database_backup_output_path }} is missing, - not a directory + Backup directory {{ database_backup_output_path }} + is missing or not a directory. - name: Check database-backup.service is installed and enabled ansible.builtin.systemd: @@ -94,5 +95,4 @@ success_msg: > Timer unit file correctly contains OnCalendar={{ database_backup_schedule }}. - - when: database_backup_enabled | default(false) + when: database_backup_enabled | default(false) From 83bba4a5bb2133cdb355be727bed7dc430fd384a Mon Sep 17 00:00:00 2001 From: NUZAT-TABASSUM Date: Mon, 14 Jul 2025 17:33:40 +0200 Subject: [PATCH 6/6] fix issue of rule violations --- molecule/default/verify.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/molecule/default/verify.yml b/molecule/default/verify.yml index 4ca415fed..7b4bc42d8 100644 --- a/molecule/default/verify.yml +++ b/molecule/default/verify.yml @@ -47,6 +47,7 @@ # Backup configuration (only when enabled) # ─────────────────────────────────────────────────────────── - name: Verify backup configuration when enabled + when: database_backup_enabled | default(false) block: - name: Assert backups are enabled ansible.builtin.assert: @@ -95,4 +96,3 @@ success_msg: > Timer unit file correctly contains OnCalendar={{ database_backup_schedule }}. - when: database_backup_enabled | default(false)