Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,188 changes: 582 additions & 606 deletions cli/scripts/cluster.py

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion cli/scripts/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import sys, os, tarfile, platform

VER = "25.0.0-alpha3"
VER = "25.0.0-alpha4"
REPO = os.getenv("REPO", "https://pgedge-upstream.s3.amazonaws.com/REPO")

if sys.version_info < (3, 9):
Expand Down
2 changes: 1 addition & 1 deletion cli/scripts/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import os
import time

MY_VERSION = "25.0.0-alpha3"
MY_VERSION = "25.0.0-alpha4"
MY_CODENAME = ""

DEFAULT_PG = "16"
Expand Down
3 changes: 2 additions & 1 deletion devel/setup/Dockerfile.rocky810
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ USER root

ENV install="dnf install -y --allowerasing"
RUN $install dnf-plugins-core
RUN $install epel-release
RUN $install python3 python3-pip git wget curl pigz which zip sqlite
RUN $install openssh-server systemd sudo
RUN $install openssh-server systemd sudo inotify-tools lsof

RUN useradd build -U -m -d /home/build \
&& echo "build ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
Expand Down
3 changes: 2 additions & 1 deletion devel/setup/Dockerfile.rocky95
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ USER root

ENV install="dnf install -y --allowerasing"
RUN $install dnf-plugins-core
RUN $install epel-release
RUN $install python3 python3-pip git wget curl pigz which zip sqlite
RUN $install openssh-server systemd sudo
RUN $install openssh-server systemd sudo inotify-tools lsof

RUN useradd build -U -m -d /home/build \
&& echo "build ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
Expand Down
2 changes: 1 addition & 1 deletion devel/setup/compose/Dockerfile.node.rocky95
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ RUN chmod 700 /home/pgedge/.ssh/
RUN sudo chown pgedge:pgedge /home/pgedge/.ssh/id_rsa
RUN sudo chmod 600 /home/pgedge/.ssh/id_rsa

RUN sed -i '1iexport PGBACKREST_REPO1_CIPHER_PASS=Really_s3cure_password' ~/.bashrc
RUN sed -i '1iexport PGBACKREST_REPO1_CIPHER_PASS=supersecret' ~/.bashrc

USER root
EXPOSE 22
Expand Down
2 changes: 1 addition & 1 deletion devel/setup/compose/Dockerfile.node.ubuntu2204
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ RUN chmod 700 /home/pgedge/.ssh/
RUN sudo chown pgedge:pgedge /home/pgedge/.ssh/id_rsa
RUN sudo chmod 600 /home/pgedge/.ssh/id_rsa

RUN echo 'export PGBACKREST_REPO1_CIPHER_PASS=Really_s3cure_password' >> ~/.bashrc
RUN echo 'export PGBACKREST_REPO1_CIPHER_PASS=supersecret' >> ~/.bashrc

USER root
EXPOSE 22
Expand Down
4 changes: 2 additions & 2 deletions env.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
hubV=25.0.0-alpha3
hubVV=25.0.0-alpha3
hubV=25.0.0-alpha4
hubVV=25.0.0-alpha4

aceV=$hubV
kirkV=$hubV
Expand Down
33 changes: 22 additions & 11 deletions src/backrest/backrest.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
import sys
from datetime import datetime
from tabulate import tabulate
import yaml
from typing import Optional

def pgV():
"""Return the first found PostgreSQL version (v14 thru v17)."""
Expand Down Expand Up @@ -94,7 +92,7 @@ def create_stanza(stanza, verbose=True):

# Modify postgresql.conf to ensure archiving is on
modify_postgresql_conf(
stanza, config['pg1-path'], config['repo1-path'], config['repo1-type']
stanza, config['pg1-path'], config['repo1-path'], config['repo1-type'], config['repo1-cipher-type']
)
# Modify pg_hba.conf for replication, if needed
modify_hba_conf()
Expand Down Expand Up @@ -183,6 +181,7 @@ def backup(stanza, type="full", verbose=True):
)
else:
util.message(f"Successfully completed {type} backup for stanza '{stanza}'")

def restore(stanza, data_dir=None, backup_label=None, recovery_target_time=None, verbose=True):
"""Restore a database cluster to a specified state."""
config = fetch_config()
Expand Down Expand Up @@ -254,6 +253,19 @@ def pitr(stanza, data_dir=None, recovery_target_time=None, verbose=True):
if restore(stanza, data_dir, None, recovery_target_time, verbose):
_configure_pitr(stanza, data_dir, recovery_target_time)

def cleanup_replica(pg1_path):
"""Cleanup the replica configuration and restore remnants."""
conf_file = os.path.join(pg1_path, "postgresql.conf")
changes = {
"hot_standby": "off",
"primary_conninfo": "",
"archive_command": "",
"archive_mode": "off"
}
for key, value in changes.items():
change_pgconf_keyval(conf_file, key, value)


def _configure_pitr(stanza, pg_data_dir=None, recovery_target_time=None):
"""Configure PostgreSQL for point-in-time recovery."""
config = fetch_config()
Expand All @@ -264,7 +276,6 @@ def _configure_pitr(stanza, pg_data_dir=None, recovery_target_time=None):
config_file = os.path.join(pg_data_dir, "postgresql.conf")
changes = {
"port": "5433",
"log_directory": os.path.join(pg_data_dir, "log"),
"archive_command": "",
"archive_mode": "off",
"hot_standby": "on",
Expand All @@ -288,6 +299,7 @@ def change_pgconf_keyval(config_path, key, value):
file.write(line)
if not key_found:
file.write(f"{key} = '{value}'\n")

def create_replica(stanza, data_dir=None, backup_label=None, verbose=True):
"""Create a replica by restoring from a backup."""
if restore(stanza, data_dir, backup_label, verbose=verbose):
Expand All @@ -302,8 +314,6 @@ def configure_replica(stanza, pg1_path, pg1_host, pg1_port, pg1_user):
changes = {
"hot_standby": "on",
"primary_conninfo": primary_conninfo,
"port": pg1_port,
"log_directory": os.path.join(pg1_path, "log"),
"archive_command": "cd .",
"archive_mode": "on"
}
Expand Down Expand Up @@ -396,12 +406,12 @@ def modify_hba_conf():
}]
util.update_pg_hba_conf(pgV(), new_rules)

def modify_postgresql_conf(stanza, pg1_path, repo1_path, repo1_type):
def modify_postgresql_conf(stanza, pg1_path, repo1_path, repo1_type, repo1_cipher_type="aes-256-cbc"):
"""Modify 'postgresql.conf' to integrate with pgbackrest."""
aCmd = (
f"pgbackrest --stanza={stanza} --pg1-path={pg1_path} "
f"--repo1-type={repo1_type} --repo1-path={repo1_path} "
f"--repo1-cipher-type=aes-256-cbc archive-push %p"
f"--repo1-cipher-type={repo1_cipher_type} archive-push %p"
)
util.change_pgconf_keyval(pgV(), "archive_command", aCmd, p_replace=True)
util.change_pgconf_keyval(pgV(), "archive_mode", "on", p_replace=True)
Expand Down Expand Up @@ -518,12 +528,13 @@ def update_config(verbose=True):
"pitr": pitr,
"create-stanza": create_stanza,
"create-replica": create_replica,
"configure_replica": configure_replica,
"configure-replica": configure_replica,
"list-backups": list_backups,
"show-config": show_config,
"write-config": write_config,
"update-config": update_config,
"set_hbaconf": modify_hba_conf,
"set_postgresqlconf": modify_postgresql_conf,
"set-hbaconf": modify_hba_conf,
"set-postgresqlconf": modify_postgresql_conf,
"cleanup-replica": cleanup_replica,
"command": run_external_command,
})
88 changes: 1 addition & 87 deletions src/backrest/install-backrest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,7 @@
# Copyright (c) 2022-2025 PGEDGE #

import os
import subprocess
import time
import sys
import getpass
from crontab import CronTab
import subprocess
import util

thisDir = os.path.dirname(os.path.realpath(__file__))
Expand Down Expand Up @@ -36,6 +31,7 @@ def osSys(p_input, p_display=False):
util.message("# " + p_input)
rc = os.system(p_input)
return rc

def configure_backup_settings():
"""Configure and return the pgBackRest settings."""
stanza = "pg16"
Expand Down Expand Up @@ -93,94 +89,12 @@ def setup_pgbackrest_links():
osSys("sudo mkdir -p -m 770 /var/lib/pgbackrest")
osSys(f"sudo chown {usrUsr} -R /var/lib/pgbackrest")

def modify_hba_conf():
new_rules = [
{
"type": "host",
"database": "replication",
"user": "all",
"address": "127.0.0.1/0",
"method": "trust"
}
]
util.update_pg_hba_conf(pgV(), new_rules)

def create_or_update_job(crontab_lines, job_comment, detailed_comment, new_job):
job_identifier = f"# {job_comment}"
detailed_comment_line = f"# {detailed_comment}\n"
job_exists = False

for i, line in enumerate(crontab_lines):
if job_identifier in line:
crontab_lines[i] = job_identifier + "\n"
if i + 1 < len(crontab_lines):
crontab_lines[i + 1] = detailed_comment_line
crontab_lines[i + 2] = new_job
job_exists = True
break

if not job_exists:
crontab_lines.extend([job_identifier + "\n", detailed_comment_line, new_job])

def define_cron_job():
stanza = util.get_value("BACKUP", "stanza")
full_backup_command = f"pgbackrest --stanza={stanza} --type=full backup"
incr_backup_command = f"pgbackrest --stanza={stanza} --type=incr backup"
expire_backup_command = f"pgbackrest --stanza={stanza} expire"

run_as_user = 'root'

# Crontab entries with detailed comments
full_backup_cron = f"0 1 * * * {run_as_user} {full_backup_command}\n"
incr_backup_cron = f"0 * * * * {run_as_user} {incr_backup_command}\n"
expire_backup_cron = f"30 1 * * * {run_as_user} {expire_backup_command}\n"

# Detailed comments for each job
full_backup_comment = "Performs a full backup daily at 1 AM."
incr_backup_comment = "Performs an incremental backup every hour."
expire_backup_comment = "Manages backup retention, expiring old backups at 1:30 AM daily."

system_crontab_path = "/etc/crontab"
backrest_crontab_path = "backrest.crontab"

with open(system_crontab_path, 'r') as file:
existing_crontab = file.readlines()

create_or_update_job(existing_crontab, "FullBackup", full_backup_comment, full_backup_cron)
create_or_update_job(existing_crontab, "IncrementalBackup", incr_backup_comment, incr_backup_cron)
create_or_update_job(existing_crontab, "ExpireBackup", expire_backup_comment, expire_backup_cron)

with open(backrest_crontab_path, 'w') as file:
file.writelines(existing_crontab)

osSys(f"sudo cat {backrest_crontab_path} | sudo tee {system_crontab_path} > /dev/null", False)

def fetch_backup_config():
"""Fetch and return the pgBackRest configuration from system settings."""
config = {}
params = [
"stanza", "restore_path", "backup-type", "repo1-retention-full",
"repo1-retention-full-type", "repo1-path", "repo1-host-user",
"repo1-host", "repo1-cipher-type", "repo1-cipher-pass", "repo1-s3-bucket",
"repo1-s3-key-secret", "repo1-s3-key", "repo1-s3-region", "repo1-s3-endpoint",
"log-level-console", "repo1-type", "process-max", "compress-level",
"pg1-path", "pg1-user", "pg1-database", "db-socket-path", "pg1-port",
"pg1-host"
]

# Fetch all parameters
for param in params:
config[param] = util.get_value("BACKUP", param)

return config

def print_header(header):
bold_start = "\033[1m"
bold_end = "\033[0m"
print(bold_start + "##### " + header + " #####"+ bold_end)

def main():
stanza = pgV()
if os.path.isdir(f"/var/lib/pgbackrest/"):
util.message("/var/lib/pgbackrest directory already exists")

Expand Down
2 changes: 1 addition & 1 deletion src/conf/versions.sql
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

DROP TABLE IF EXISTS hub;
CREATE TABLE hub(v TEXT NOT NULL PRIMARY KEY, c TEXT NOT NULL, d TEXT NOT NULL);
INSERT INTO hub VALUES ('25.0.0-alpha3', 'Constellation', '20250421');
INSERT INTO hub VALUES ('25.0.0-alpha4', 'Constellation', '20250421');

DROP VIEW IF EXISTS v_versions;
DROP VIEW IF EXISTS v_products;
Expand Down