Skip to content
Open
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
2 changes: 1 addition & 1 deletion dbclean/dbclean.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def err(msg, *args):
if args.section == 'DEFAULT':
parser.error("--section must not be 'DEFAULT'.")

config = configparser.SafeConfigParser({
config = configparser.ConfigParser({
'format': '%%Y-%%m-%%d_%%H:%%M:%%S',
'hourly': '24', 'daily': '31',
'monthly': '12', 'yearly': '3',
Expand Down
9 changes: 9 additions & 0 deletions dbdump/dbdump.conf.example
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@
# unchanged (optional):
remote = user@backup.example.com

# Store dumps with borgbackup. Specify the common directory, each db will have
# its own repository.
#borg = user@backup.example.com

# Encrypt borg backups, store the keyfile on the server and encrypt it with the
# password specified in borg-key, if this parameter is given.
#borg-key = add-a-secret-password-here

# Override the default ssh connect-timeout of 10 seconds:
#ssh-timeout = 10

Expand Down Expand Up @@ -70,6 +78,7 @@ remote = user@backup.example.com
# POSTGRESQL OPTIONS:

# Additional command-line parameters for psql and pgdump (optional):
#postgresql-connectstring = host=localhost port=5432
#postgresql-psql-opts = --someopt
#postgresql-pgdump-opts = --otheropt

Expand Down
2 changes: 1 addition & 1 deletion dbdump/dbdump.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def err(msg, *args):

section = config[args.section]

if 'remote' not in section:
if 'remote' not in section and 'borg' not in section:
# Note that if we dump to a remote location, there is no real way to check to check if datadir
# exists and is writeable. We have to rely on the competence of the admin in that case.
datadir = section['datadir']
Expand Down
47 changes: 46 additions & 1 deletion dbdump/libdump/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,52 @@ def dump(self, db, timestamp):
sha = ['sha256sum']
sed = ['sed', 's/-$/%s/' % os.path.basename(path)]

if 'remote' in self.section:
if 'borg' in self.section:
borg_check = ['borg', 'info']
borg_init = ['borg', 'init', '--umask', '0077', '--make-parent-dirs']
borg_create = ['borg', 'create', '--umask', '0077', '--noctime', '--nobirthtime', '--compression', 'zstd', '--files-cache', 'disabled', '--content-from-command', '--']
borg_repo = self.section['borg']

borg_env = os.environ.copy()
borg_env['BORG_RELOCATED_REPO_ACCESS_IS_OK'] = 'yes'

if 'borg-key' in self.section:
borg_env['BORG_PASSPHRASE'] = self.section['borg-key']
borg_init += ['--encryption', 'repokey-blake2']
else:
borg_env['BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK'] = 'yes'
borg_init += ['--encryption', 'none']

borg_check += [f"{borg_repo}/{db}"]
borg_init += [f"{borg_repo}/{db}"]
borg_create += [f"{borg_repo}/{db}" + "::" + f"{timestamp}"]
borg_create += cmd

if self.args.verbose:
str_cmds = [' '.join(c) for c in cmd]
print('# Dump databases:')
print(' | '.join(str_cmds))

# check if repo already exists
p_check = Popen(borg_check, env=borg_env, stdout=PIPE)
stdout, stderr = p_check.communicate()
if p_check.returncode != 0:
# repo is missing, create it
p_init = Popen(borg_init, env=borg_env, stdout=PIPE)
stdout, stderr = p_init.communicate()
if p_init.returncode != 0:
raise RuntimeError(f"{borg_init} returned with exit code {p_init.returncode}. (stderr: {stderr})")

# create backup
p_create = Popen(borg_create, env=borg_env, stdout=PIPE)
stdout, stderr = p_create.communicate()
if self.args.verbose:
print("# borg_create:")
print(' | '.join)
if p_create.returncode != 0:
raise RuntimeError(f"{borg_create} returned with exit code {p_create.returncode}. (stderr: {stderr})")

elif 'remote' in self.section:
ssh = self.get_ssh(path, [tee, sha, sed])

cmds = [cmd, gzip, ] # just for output
Expand Down
17 changes: 14 additions & 3 deletions dbdump/libdump/postgresql.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,18 @@

class postgresql(backend.backend):
def get_db_list(self):
cmd = ['psql', '-Aqt', '-c', '"select datname from pg_database"']
cmd = ['psql', '-Aqt', '-c', 'select datname from pg_database']

if 'postgresql-psql-opts' in self.section:
cmd += self.section['postgresql-psql-opts'].split(' ')

if 'postgresql-connectstring' in self.section:
cmd.append(self.section['postgresql-connectstring'])

if 'su' in self.section:
quoted_args = [f"\"{arg}\"" if ' ' in arg else arg for arg in cmd ]
cmd = ['su', self.section['su'], '-s', '/bin/bash', '-c',
' '.join(cmd)]
' '.join(quoted_args)]

p_list = Popen(cmd, stdout=PIPE, stderr=PIPE)
stdout, stderr = p_list.communicate()
Expand All @@ -44,5 +48,12 @@ def get_command(self, database):
cmd = ['pg_dump', '-c']
if 'postgresql-pgdump-opts' in self.section:
cmd += self.section['postgresql-pgdump-opts'].split(' ')
cmd.append(database)

connectstring_options = []
if 'postgresql-connectstring' in self.section:
connectstring_options = self.section['postgresql-connectstring'].split(' ')

connectstring_options.append(f"dbname={database}")
cmd.append(' '.join(connectstring_options))

return cmd