Skip to content

Commit 9816205

Browse files
committed
Use environment and pgpass to connect to PostgreSQL
Closes jazzband#384.
1 parent 9d1909c commit 9816205

File tree

1 file changed

+45
-31
lines changed

1 file changed

+45
-31
lines changed

Diff for: dbbackup/db/postgresql.py

+45-31
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,46 @@
1-
from urllib.parse import quote
1+
from tempfile import mkstemp
22
import logging
3+
import os
34

45
from .base import BaseCommandDBConnector
56
from .exceptions import DumpError
67

78
logger = logging.getLogger('dbbackup.command')
89

910

10-
def create_postgres_uri(self):
11-
host = self.settings.get('HOST')
12-
if not host:
13-
raise DumpError('A host name is required')
11+
class PgEnvWrapper:
12+
def __init__(self, settings):
13+
self.settings = settings
1414

15-
dbname = self.settings.get('NAME') or ''
16-
user = quote(self.settings.get('USER') or '')
17-
password = self.settings.get('PASSWORD') or ''
18-
password = ':{}'.format(quote(password)) if password else ''
19-
if not user:
20-
password = ''
21-
else:
22-
host = '@' + host
15+
def __enter__(self):
16+
pghost = self.settings.get('HOST', None)
17+
pgport = self.settings.get('PORT', None)
18+
pguser = self.settings.get('USER', None)
19+
pgdatabase = self.settings.get('NAME', None)
20+
pgpassword = self.settings.get('PASSWORD', None)
2321

24-
port = ':{}'.format(self.settings.get('PORT')) if self.settings.get('PORT') else ''
25-
dbname = f'--dbname=postgresql://{user}{password}{host}{port}/{dbname}'
26-
return dbname
22+
env = os.environ.copy()
23+
if pghost:
24+
env['PGHOST'] = pghost
25+
if pgport:
26+
env['PGPORT'] = pgport
27+
if pguser:
28+
env['PGUSER'] = pguser
29+
if pgdatabase:
30+
env['PGDATABASE'] = pgdatabase
31+
32+
if pgpassword:
33+
self.pgpass_fd, self.pgpass_path = mkstemp(text=True)
34+
os.write(self.pgpass_fd, f'*:*:*:*:{pgpassword}\n')
35+
os.close(self.pgpass_fd)
36+
env['PGPASSFILE'] = self.pgpass_path
37+
else:
38+
self.pgpass_fd, self.pgpass_path = None, None
39+
40+
return env
41+
42+
def __exit__(self):
43+
os.unlink(self.pgpass_path)
2744

2845

2946
class PgDumpConnector(BaseCommandDBConnector):
@@ -39,28 +56,27 @@ class PgDumpConnector(BaseCommandDBConnector):
3956

4057
def _create_dump(self):
4158
cmd = '{} '.format(self.dump_cmd)
42-
cmd = cmd + create_postgres_uri(self)
4359

4460
for table in self.exclude:
4561
cmd += ' --exclude-table-data={}'.format(table)
4662
if self.drop:
4763
cmd += ' --clean'
4864

4965
cmd = '{} {} {}'.format(self.dump_prefix, cmd, self.dump_suffix)
50-
stdout, stderr = self.run_command(cmd, env=self.dump_env)
66+
with PgEnvWrapper(self.settings) as env:
67+
stdout, stderr = self.run_command(cmd, env={**self.dump_env, **env})
5168
return stdout
5269

5370
def _restore_dump(self, dump):
5471
cmd = '{} '.format(self.restore_cmd)
55-
cmd = cmd + create_postgres_uri(self)
5672

5773
# without this, psql terminates with an exit value of 0 regardless of errors
5874
cmd += ' --set ON_ERROR_STOP=on'
5975
if self.single_transaction:
6076
cmd += ' --single-transaction'
61-
cmd += ' {}'.format(self.settings['NAME'])
6277
cmd = '{} {} {}'.format(self.restore_prefix, cmd, self.restore_suffix)
63-
stdout, stderr = self.run_command(cmd, stdin=dump, env=self.restore_env)
78+
with PgEnvWrapper(self.settings) as env:
79+
stdout, stderr = self.run_command(cmd, stdin=dump, env={**self.restore_env, **env})
6480
return stdout, stderr
6581

6682

@@ -76,11 +92,8 @@ def _enable_postgis(self):
7692
self.psql_cmd)
7793
cmd += ' --username={}'.format(self.settings['ADMIN_USER'])
7894
cmd += ' --no-password'
79-
if self.settings.get('HOST'):
80-
cmd += ' --host={}'.format(self.settings['HOST'])
81-
if self.settings.get('PORT'):
82-
cmd += ' --port={}'.format(self.settings['PORT'])
83-
return self.run_command(cmd)
95+
with PgEnvWrapper(self.settings) as env:
96+
return self.run_command(cmd, env=env)
8497

8598
def _restore_dump(self, dump):
8699
if self.settings.get('ADMIN_USER'):
@@ -101,23 +114,24 @@ class PgDumpBinaryConnector(PgDumpConnector):
101114

102115
def _create_dump(self):
103116
cmd = '{} '.format(self.dump_cmd)
104-
cmd = cmd + create_postgres_uri(self)
105117

106118
cmd += ' --format=custom'
107119
for table in self.exclude:
108120
cmd += ' --exclude-table-data={}'.format(table)
109121
cmd = '{} {} {}'.format(self.dump_prefix, cmd, self.dump_suffix)
110-
stdout, stderr = self.run_command(cmd, env=self.dump_env)
122+
with PgEnvWrapper(self.settings) as env:
123+
stdout, stderr = self.run_command(cmd, env={**self.dump_env, **env})
111124
return stdout
112125

113126
def _restore_dump(self, dump):
114-
dbname = create_postgres_uri(self)
115-
cmd = '{} {}'.format(self.restore_cmd, dbname)
127+
cmd = '{} '.format(self.restore_cmd)
116128

117129
if self.single_transaction:
118130
cmd += ' --single-transaction'
119131
if self.drop:
120132
cmd += ' --clean'
133+
cmd += '-d {}'.format(self.settings.get('NAME'))
121134
cmd = '{} {} {}'.format(self.restore_prefix, cmd, self.restore_suffix)
122-
stdout, stderr = self.run_command(cmd, stdin=dump, env=self.restore_env)
135+
with PgEnvWrapper(self.settings) as env:
136+
stdout, stderr = self.run_command(cmd, stdin=dump, env={**self.restore_env, **env})
123137
return stdout, stderr

0 commit comments

Comments
 (0)